diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/CMakeLists.txt b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..1e61617367ab0bf20663ce8d6510ae1386700d31 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/CMakeLists.txt @@ -0,0 +1,6 @@ +project(my_first_test) +cmake_minimum_required(VERSION 3.0.0) + +find_package(Akantu REQUIRED) + +add_akantu_simulation(clip_compute_damage clip_compute_damage.cc material.dat square.msh) diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/clip_compute_damage.cc b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/clip_compute_damage.cc new file mode 100644 index 0000000000000000000000000000000000000000..8995d5966a72962e1a1bb942ca8990557c26ff92 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/clip_compute_damage.cc @@ -0,0 +1,112 @@ +/** + * Copyright (©) 2013-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * 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 <chrono> +#include <iostream> +#include "data_accessor.hh" +#include "mesh.hh" +#include "mesh_accessor.hh" +//#include "mesh_partition_scotch.hh" +#include "periodic_node_synchronizer.hh" +/* -------------------------------------------------------------------------- */ +#include "dumpable_inline_impl.hh" +//#include "dumper_element_partition.hh" +#include "dumper_iohelper_paraview.hh" +/* -------------------------------------------------------------------------- */ +#include "solid_mechanics_model_clip.hh" + + +using namespace akantu; + +class init +{ + public: + init(Real lc_, Real xmid_):lc(lc_),xmid(xmid_) {} + + Real operator()(const Vector<Real> & coords) + { + Real d = std::max(0.,1.-std::abs(coords[0])/lc); + return d; + } + private: + Real lc; + Real xmid; +}; + +int main(int argc, char ** argv) { + initialize("material.dat", argc, argv); + + Real lc = 1.; + Real xmid = 0.; + init initializer(lc,xmid); + + constexpr Int dim = 2; + + Mesh mesh(dim); + mesh.read("square_fine.msh"); + std::cout << "Initiate SolidMechanicsModelCLIP ... " << std::endl ; + SolidMechanicsModelCLIP model(mesh,dim); + model.getElementInserter().setLimit(_x, -1., 1.); + model.getElementInserter().setLimit(_y, -1., 1.); + // model.getMaterial(1).setReal("lc", lc); + auto start = std::chrono::high_resolution_clock::now(); + std::cout << "done initiate SolidMechanicsModelCLIP ! " << std::endl ; + + /// model initialization + model.initFull(_analysis_method = _explicit_lumped_mass + ,_is_extrinsic = false); + + model.setBaseName("cohesive"); + model.addDumpFieldVector("displacement"); + model.addDumpField("damage"); + model.setBaseNameToDumper("cohesive elements", "cohesive_elements"); + model.addDumpFieldToDumper("cohesive elements", "czm_damage"); + + model.setBaseNameToDumper("clip", "clip"); + model.addDumpFieldToDumper("clip", "clip_bulk_damage"); + model.addDumpFieldToDumper("clip", "clip_czm_damage"); + + + model.initializeCZMDamage(initializer); + model.dump(); + model.dump("cohesive elements"); + + std::cout << "test computeBulkDamage ... " << std::endl ; + // Start timing + + model.initialize(); + model.computeBulkDamage(); + // model.solveStep(); + // model.computeDamage(); + auto end = std::chrono::high_resolution_clock::now(); + std::chrono::duration<double> elapsed = end - start; + std::cout << "Elapsed time: " << elapsed.count() << " seconds" << std::endl; + + std::cout << "done computeBulkDamage ! " << std::endl ; + + model.dump(); + model.dump("cohesive elements"); + model.dump("clip"); + + finalize(); + return EXIT_SUCCESS; + +} diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/material.dat b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/material.dat new file mode 100644 index 0000000000000000000000000000000000000000..70ca9ae3dba48f97d414ca1142bb8a07d3f07b6b --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/material.dat @@ -0,0 +1,20 @@ +material bulk_damage [ + name = bulk + rho = 275 # density + E = 3e9 # young's modulus + nu = 0.001 # poisson's ratio + sigma_c = 3e6 + G_c = 120 + lc = 0.0125 + Dm = 0.1 +] + +material cohesive_damage_extrinsic [ + name = cohesive + sigma_c = 3e6 + E = 3e9 + k = 75000000000.0 + G_c = 120 + lc = 0.0125 + Dm = 0.1 +] \ No newline at end of file diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/square.geo b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/square.geo new file mode 100644 index 0000000000000000000000000000000000000000..7aa44974a3d67e104832ed16d6bf826d9b4c27f6 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/square.geo @@ -0,0 +1,27 @@ +h = 0.01; +L = 1; + +Point(1) = { L, 0.1*L, 0, h}; +Point(2) = {0., 0.1*L, 0, h}; +Point(3) = {0.,0., 0, h}; +Point(4) = {L,0., 0, h}; + +Line(1) = {1, 2}; +Line(2) = {2, 3}; +Line(3) = {3, 4}; +Line(4) = {4, 1}; + +Line Loop(5) = {1, 2, 3, 4}; + +Plane Surface(6) = {5}; +Physical Surface(7) = {6}; + +Transfinite Line {2, 4} = 2; +Transfinite Line {1, 3} = 51; +Transfinite Surface "*"; +Physical Curve("left", 8) = {2}; +Physical Curve("right", 9) = {4}; +Physical Point("point", 10) = {3}; +Physical Curve("bottom", 11) = {3}; +Physical Curve("top", 12) = {1}; + diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/square.msh b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/square.msh new file mode 100644 index 0000000000000000000000000000000000000000..05c846b87358d88e45407c688ec12f514c9112c7 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/clip_compute_damage/square.msh @@ -0,0 +1,34 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$PhysicalNames +3 +0 10 "point" +1 8 "left" +1 9 "right" +$EndPhysicalNames +$Nodes +8 +1 1 1 0 +2 -1 1 0 +3 -1 -1 0 +4 1 -1 0 +5 2.750244476601438e-12 1 0 +6 -2.750244476601438e-12 -1 0 +7 -0.2845299461618773 0 0 +8 0.3430940107676245 -2.220446049250313e-17 0 +$EndNodes +$Elements +11 +1 15 2 10 3 3 +2 1 2 8 2 2 3 +3 1 2 9 4 4 1 +4 2 2 7 6 3 6 7 +5 2 2 7 6 7 6 8 +6 2 2 7 6 6 4 8 +7 2 2 7 6 5 7 8 +8 2 2 7 6 1 5 8 +9 2 2 7 6 5 2 7 +10 2 2 7 6 4 1 8 +11 2 2 7 6 2 3 7 +$EndElements diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_mesh/CMakeLists.txt b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..38f887790a8b9c057ad085ecbf535c8ac60de19e --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/CMakeLists.txt @@ -0,0 +1,28 @@ +#=============================================================================== +# Copyright (©) 2018-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) +# Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) +# +# This file is part of Akantu +# +# 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/>. +# +#=============================================================================== + +add_mesh(square square.geo DIM 2 ORDER 1) + +register_test(clip_mesh + SOURCES clip_mesh.cc + DEPENDS square + PACKAGE core + UNSTABLE) diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_mesh/clip_mesh.cc b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/clip_mesh.cc new file mode 100644 index 0000000000000000000000000000000000000000..8e7753da8d4554f52bdafbdbc76c0a51eeb20027 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/clip_mesh.cc @@ -0,0 +1,129 @@ +/** + * Copyright (©) 2013-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * 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 "data_accessor.hh" +#include "mesh.hh" +#include "mesh_accessor.hh" +//#include "mesh_partition_scotch.hh" +#include "periodic_node_synchronizer.hh" +/* -------------------------------------------------------------------------- */ +#include "dumpable_inline_impl.hh" +//#include "dumper_element_partition.hh" +#include "dumper_iohelper_paraview.hh" +/* -------------------------------------------------------------------------- */ +#include "gmsh.h" + + +using namespace akantu; + +int main(int argc, char ** argv) { + initialize(argc, argv); + + constexpr Int dim = 2; + + Mesh mesh(dim); + mesh.read("square.msh"); + Mesh clip_mesh(dim); + + MeshAccessor mesh_accessor(mesh); + MeshAccessor mesh_accessor_clip(clip_mesh); + + auto & clip_nodes = mesh_accessor_clip.getNodes(); + auto & clip_connectivities = mesh_accessor_clip.getConnectivities(); + + Mesh & mesh_facets = mesh.initMeshFacets(); + MeshAccessor mesh_accessor_facets(mesh_facets); + // auto & facet_connectivities = mesh_accessor_facets.getConnectivities(); + + ElementTypeMapArray<Real> barycenters; + Int nb_clip_nodes(0); + barycenters.initialize(mesh_facets, _nb_component = dim, + _spatial_dimension = dim-1, + _with_nb_element = true); + + for (auto && ghost_type : ghost_types) { + for (auto && type : + barycenters.elementTypes(dim-1,ghost_type)) { + mesh_facets.getBarycenters(barycenters(type, ghost_type),type, + ghost_type); + nb_clip_nodes+=mesh_facets.getNbElement(type, ghost_type); + } + } + + mesh_accessor_clip.resizeNodes(nb_clip_nodes); + + auto && view_clip_nodes = make_view(clip_nodes,dim); + auto clip_nodes_it = view_clip_nodes.begin(); + + std::vector<double> coord; + for (auto && ghost_type : ghost_types) { + for (auto && type : + barycenters.elementTypes(dim-1,ghost_type)) { + auto & barycenter = barycenters(type,ghost_type); + auto && view_bar = + make_view(barycenter, barycenter.getNbComponent()); + for(auto && bar : view_bar) { + *clip_nodes_it=bar; + ++clip_nodes_it; + for(Int i=0; i<dim;++i) + { + coord.push_back(bar[i]); + } + } + } + } + // for(auto it=view_clip_nodes.begin();it!=view_clip_nodes.end();++it) + // { + // std::cout << "node = " << *it << std::endl; + // } + std::cout << "n_nodes = " << coord.size() << std::endl; + + std::vector<std::size_t> tri; + gmsh::initialize(); + gmsh::model::mesh::triangulate(coord,tri); + int n_tri = tri.size()/3; + std::cout << "n_tri = " << n_tri << std::endl ; + + for (auto && ghost_type : ghost_types) { + clip_mesh.addConnectivityType(_triangle_3, ghost_type); + mesh_accessor_clip.resizeConnectivity(n_tri,_triangle_3, ghost_type); + auto & clip_conn = clip_connectivities(_triangle_3, ghost_type); + auto && view_conn_it = make_view(clip_conn, clip_conn.getNbComponent()).begin(); + for(int i = 0 ; i<n_tri; ++i, ++view_conn_it) + { + for(int j = 0; j<3;++j) { + (*view_conn_it)[j]=tri[3*i+j]-1; + // std::cout << tri[i+3*j] << " " << std::endl; + } + // std::cout << std::endl; + } + } + + + // auto * dumper = new DumperParaview("clip_mesh", "./paraview"); + // mesh.registerExternalDumper(*dumper, "clip_mesh", true); + // mesh.addDumpMesh(clip_mesh); + // mesh.dump(); + + mesh_accessor_clip.makeReady(); + clip_mesh.write("clip_mesh.msh"); + +} diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_mesh/square.geo b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/square.geo new file mode 100644 index 0000000000000000000000000000000000000000..3f21d3ffc8c9abbabd401ecc62d05ba8f6cb6b17 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/square.geo @@ -0,0 +1,21 @@ +h = .1; + +Point(1) = { 1, 1, 0, h}; +Point(2) = {-1, 1, 0, h}; +Point(3) = {-1,-1, 0, h}; +Point(4) = { 1,-1, 0, h}; +Line(1) = {1, 2}; +Line(2) = {2, 3}; +Line(3) = {3, 4}; +Line(4) = {4, 1}; +Line Loop(5) = {1, 2, 3, 4}; +Plane Surface(6) = {5}; +// Transfinite Surface {7} = 6; +Physical Surface(7) = {6}; + +Transfinite Line {2, 4} = 1; +Transfinite Line {1, 3} = 3; + +Physical Curve("left", 8) = {2}; +Physical Curve("right", 9) = {4}; +Physical Point("point", 10) = {3}; diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_mesh/square.msh b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/square.msh new file mode 100644 index 0000000000000000000000000000000000000000..05c846b87358d88e45407c688ec12f514c9112c7 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/clip_mesh/square.msh @@ -0,0 +1,34 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$PhysicalNames +3 +0 10 "point" +1 8 "left" +1 9 "right" +$EndPhysicalNames +$Nodes +8 +1 1 1 0 +2 -1 1 0 +3 -1 -1 0 +4 1 -1 0 +5 2.750244476601438e-12 1 0 +6 -2.750244476601438e-12 -1 0 +7 -0.2845299461618773 0 0 +8 0.3430940107676245 -2.220446049250313e-17 0 +$EndNodes +$Elements +11 +1 15 2 10 3 3 +2 1 2 8 2 2 3 +3 1 2 9 4 4 1 +4 2 2 7 6 3 6 7 +5 2 2 7 6 7 6 8 +6 2 2 7 6 6 4 8 +7 2 2 7 6 5 7 8 +8 2 2 7 6 1 5 8 +9 2 2 7 6 5 2 7 +10 2 2 7 6 4 1 8 +11 2 2 7 6 2 3 7 +$EndElements diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_non_local/CMakeLists.txt b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6cb8ab9312bde21bfd8538d1bb27fa2ad03f7107 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/CMakeLists.txt @@ -0,0 +1,28 @@ +#=============================================================================== +# Copyright (©) 2018-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) +# Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) +# +# This file is part of Akantu +# +# 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/>. +# +#=============================================================================== + +add_mesh(square square.geo DIM 2 ORDER 1) + +register_test(clip_compute_damage + SOURCES clip_compute_damage.cc + DEPENDS square + PACKAGE core + UNSTABLE) diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_non_local/clip_non_local.cc b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/clip_non_local.cc new file mode 100644 index 0000000000000000000000000000000000000000..6a4c31a18b8126b6164b53790963e0f1becc58f6 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/clip_non_local.cc @@ -0,0 +1,97 @@ +/** + * Copyright (©) 2013-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * 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 "data_accessor.hh" +#include "mesh.hh" +#include "mesh_accessor.hh" +/* -------------------------------------------------------------------------- */ +#include "solid_mechanics_model_clip.hh" + + +using namespace akantu; + +class init +{ + public: + init(Real lc_, Real xmid_):lc(lc_),xmid(xmid_) {} + Real operator()(const Vector<Real> & coords) + { + if(std::abs(coords[0]) < 0.1*lc) + { + return 1.; + } + else + { + return 0.; + } + } + private: + Real lc; + Real xmid; +}; + +int main(int argc, char ** argv) { + initialize("material.dat", argc, argv); + + Real lc = 1.; + Real xmid = 0.; + init initializer(lc,xmid); + + constexpr Int dim = 2; + + Mesh mesh(dim); + mesh.read("square.msh"); + std::cout << "Initiate SolidMechanicsModelCLIP ... " << std::endl ; + SolidMechanicsModelCLIP model(mesh,dim); + model.getElementInserter().setLimit(_x, -1., 1.); + model.getElementInserter().setLimit(_y, -1., 1.); + + std::cout << "done initiate SolidMechanicsModelCLIP ! " << std::endl ; + + /// model initialization + model.initFull(_analysis_method = _explicit_lumped_mass + ,_is_extrinsic = false); + + model.setBaseName("cohesive"); + model.addDumpFieldVector("displacement"); + model.addDumpField("damage"); + model.setBaseNameToDumper("cohesive elements", "cohesive_elements"); + model.addDumpFieldToDumper("cohesive elements", "czm_damage"); + + model.setBaseNameToDumper("clip", "clip"); + model.addDumpFieldToDumper("clip", "clip_bulk_damage"); + model.addDumpFieldToDumper("clip", "clip_czm_damage"); + + model.initializeCZMDamage(initializer); + + model.assembleInternalForces(); + + // model.dump(); + // model.dump("cohesive elements"); + + // model.dump(); + // model.dump("cohesive elements"); + // model.dump("clip"); + + finalize(); + return EXIT_SUCCESS; + +} diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_non_local/material.dat b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/material.dat new file mode 100644 index 0000000000000000000000000000000000000000..2eb2461b92e451dca4e841460a2656e819bae72a --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/material.dat @@ -0,0 +1,20 @@ +material bulk_damage_non_local [ + name = bulk + rho = 1e3 # density + E = 1e3 # young's modulus + nu = 0.001 # poisson's ratio +] + +material cohesive_damage_non_local [ + name = cohesive + sigma_c = 3e6 + k = 75e9 + G_c = 120 +] + +non_local clip base_dist [ + radius = 0.01 + Dm = 0.8 + distance_function distance_parameter [] +] + diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_non_local/square.geo b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/square.geo new file mode 100644 index 0000000000000000000000000000000000000000..6a9251b7df87bc9d93906feb857764da79b69b1e --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/square.geo @@ -0,0 +1,21 @@ +h = .2; + +Point(1) = { 1, 1, 0, h}; +Point(2) = {-1, 1, 0, h}; +Point(3) = {-1,-1, 0, h}; +Point(4) = { 1,-1, 0, h}; +Line(1) = {1, 2}; +Line(2) = {2, 3}; +Line(3) = {3, 4}; +Line(4) = {4, 1}; +Line Loop(5) = {1, 2, 3, 4}; +Plane Surface(6) = {5}; +// Transfinite Surface {7} = 6; +Physical Surface(7) = {6}; + +//Transfinite Line {2, 4} = 1; +//Transfinite Line {1, 3} = 3; + +Physical Curve("left", 8) = {2}; +Physical Curve("right", 9) = {4}; +Physical Point("point", 10) = {3}; diff --git a/examples/c++/solid_mechanics_cohesive_model/clip_non_local/square.msh b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/square.msh new file mode 100644 index 0000000000000000000000000000000000000000..d608af215b65228be190ac0cab469aa0778432df --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/clip_non_local/square.msh @@ -0,0 +1,426 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$PhysicalNames +3 +0 10 "point" +1 8 "left" +1 9 "right" +$EndPhysicalNames +$Nodes +144 +1 1 1 0 +2 -1 1 0 +3 -1 -1 0 +4 1 -1 0 +5 0.8000000000005548 1 0 +6 0.6000000000011096 1 0 +7 0.4000000000016644 1 0 +8 0.2000000000022192 1 0 +9 2.752242878045763e-12 1 0 +10 -0.1999999999977808 1 0 +11 -0.3999999999983355 1 0 +12 -0.5999999999988903 1 0 +13 -0.7999999999994454 1 0 +14 -1 0.8000000000005548 0 +15 -1 0.6000000000011096 0 +16 -1 0.4000000000016644 0 +17 -1 0.2000000000022192 0 +18 -1 2.752242878045763e-12 0 +19 -1 -0.1999999999977808 0 +20 -1 -0.3999999999983355 0 +21 -1 -0.5999999999988903 0 +22 -1 -0.7999999999994454 0 +23 -0.8000000000005548 -1 0 +24 -0.6000000000011096 -1 0 +25 -0.4000000000016644 -1 0 +26 -0.2000000000022192 -1 0 +27 -2.752242878045763e-12 -1 0 +28 0.1999999999977808 -1 0 +29 0.3999999999983355 -1 0 +30 0.5999999999988903 -1 0 +31 0.7999999999994454 -1 0 +32 1 -0.8000000000005548 0 +33 1 -0.6000000000011096 0 +34 1 -0.4000000000016644 0 +35 1 -0.2000000000022192 0 +36 1 -2.752242878045763e-12 0 +37 1 0.1999999999977808 0 +38 1 0.3999999999983355 0 +39 1 0.5999999999988903 0 +40 1 0.7999999999994454 0 +41 0.09999999999751429 -0.8267949192431123 0 +42 -0.0999999999975143 0.8267949192431123 0 +43 -0.8152641451785186 -0.07885143852468808 0 +44 0.8304434373555855 0.09368058125465918 0 +45 0.3000000000017492 0.8267949192434423 0 +46 -0.8222913958556177 0.301840399804423 0 +47 -0.3000000000019418 -0.8267949192435928 0 +48 0.8267949192435928 -0.3000000000019418 0 +49 -0.4983653964756185 0.8277386580263953 0 +50 -0.8474033730928048 -0.4965246177615327 0 +51 0.4919576064632172 -0.840815486206938 0 +52 0.820740775008972 0.5173451309406248 0 +53 0.6991525261446221 0.8306455909891675 0 +54 -0.6891118908206922 -0.8090094343789862 0 +55 -0.81886055051106 0.6816348761887513 0 +56 0.8341005191704839 -0.698813536602138 0 +57 -0.2997275660773219 0.8269522090402291 0 +58 -0.1999545943440471 0.6536160534525139 0 +59 7.567611085503948e-06 0.6535942076475989 0 +60 -0.09999117112044205 0.4803898550844917 0 +61 0.1000027327496564 0.4803863354826932 0 +62 1.926939795782179e-06 0.3071807894914093 0 +63 -0.2006679354644429 0.3079248201300853 0 +64 -0.1014219475707913 0.1348264734253454 0 +65 0.09976332989618426 0.1341167611715012 0 +66 -0.0002764362773821823 -0.03906481084559155 0 +67 0.1999144822710444 -0.03917917809790765 0 +68 -0.201594010124382 -0.03833339145989768 0 +69 -0.1003117410650043 -0.2122584375003307 0 +70 -0.2983971709787789 -0.211147753724287 0 +71 0.2999463020288573 0.1340068414498632 0 +72 0.4089084371318499 -0.03267814517071942 0 +73 0.3014704865684335 -0.2113349576607175 0 +74 -0.4021165753759368 -0.03843604351766587 0 +75 -0.1997848186717709 -0.3853964894912181 0 +76 -0.3947386321509533 -0.3860304825270545 0 +77 -1.609328773086172e-05 -0.3855704319928288 0 +78 -0.09999999999686258 -0.558845726808855 0 +79 0.5032249595933229 0.1402606472768321 0 +80 0.4005285436045737 0.308232726355823 0 +81 0.5070716218789619 -0.2025490658234078 0 +82 0.4000000000016977 -0.3856406460521801 0 +83 0.6000000000009191 0.3071796769738866 0 +84 0.4942868204123083 0.4772109010552537 0 +85 0.1000000000026652 -0.5588457268086711 0 +86 0.62196210851684 -0.3904927803711393 0 +87 0.4975474734247751 -0.5568744827875467 0 +88 -0.3996745928146653 0.6537777124103196 0 +89 -0.6011821531096809 0.6593963523377666 0 +90 -0.5001427909848405 0.482115766704055 0 +91 -0.7010121778846208 0.4863202964944682 0 +92 -0.6065140164046823 0.3069727224290131 0 +93 -0.7049870583211724 0.1193783134563418 0 +94 -0.5077207049162372 0.1295170451519014 0 +95 -0.598774899089267 -0.0522329575172658 0 +96 -0.6740836360500956 -0.2392227049285593 0 +97 -0.302253528907891 0.1345117077962618 0 +98 0.2999999999981645 -0.8267949192426931 0 +99 0.7988367911987242 0.3057967778574708 0 +100 0.20000171672785 0.6535908296389998 0 +101 -0.1000000000021191 -0.8267949192431698 0 +102 0.8315481940282681 -0.1010532364594917 0 +103 0.6335912237475191 -0.02003653305503406 0 +104 0.100001547391357 0.8267958126288588 0 +105 -0.2999999999963751 -0.5588457268090072 0 +106 -0.4999999999960433 -0.5588457268092286 0 +107 0.4998587543585607 0.8274366978677389 0 +108 -0.491800230084482 -0.8369074999460275 0 +109 0.8264939634898354 -0.4982177194965171 0 +110 0.6302412295336577 0.6366727295001388 0 +111 0.1001301163685956 -0.2121747436915847 0 +112 0.2000404725367574 0.3073847019469172 0 +113 0.299143381005376 0.480065888827752 0 +114 0.4039219836732503 0.6502953276888875 0 +115 0.2002640849426297 -0.3854020388357766 0 +116 0.3000000000021172 -0.5588457268086774 0 +117 -0.300071847453999 0.4815659251382113 0 +118 -0.4028951373553488 0.3071013312249213 0 +119 -0.6938642437921219 0.8357449249653118 0 +120 -0.8443586096716835 -0.6931320786098996 0 +121 0.6881867797212334 -0.8122913120462014 0 +122 0.8335264302193998 0.7017517856175469 0 +123 -0.4900946041198567 -0.2133115496794405 0 +124 -0.8467162638363354 -0.2999999999980582 0 +125 -0.5773605825153454 -0.3977276319424348 0 +126 0.6761062340080962 -0.6000000000011095 0 +127 -0.6784462875602467 -0.5767637941719381 0 +128 0.6813857876547964 -0.2014420016043129 0 +129 -0.8684328248502595 0.4939591144980833 0 +130 0.1999999999975585 -0.6928203230278142 0 +131 0.3999999999983475 -0.6928203230271605 0 +132 -2.340797873689592e-12 -0.692820323027974 0 +133 -0.200000000001768 -0.6928203230279757 0 +134 -0.4000000000016648 -0.6928203230284052 0 +135 0.665192378864661 0.4602885682977754 0 +136 -0.8694874729372553 0.1000000000024857 0 +137 0.6732192823792142 0.1653762300615629 0 +138 0.8535898384868191 0.8535898384865219 0 +139 -0.8535898384865219 0.8535898384868191 0 +140 -0.8535898384868191 -0.8535898384865219 0 +141 0.8535898384865219 -0.8535898384868191 0 +142 -0.7292000671453386 -0.389286746676304 0 +143 -0.5518716816926258 -0.6948693556669171 0 +144 0.5507596187231338 -0.7005603208137912 0 +$EndNodes +$Elements +267 +1 15 2 10 3 3 +2 1 2 8 2 2 14 +3 1 2 8 2 14 15 +4 1 2 8 2 15 16 +5 1 2 8 2 16 17 +6 1 2 8 2 17 18 +7 1 2 8 2 18 19 +8 1 2 8 2 19 20 +9 1 2 8 2 20 21 +10 1 2 8 2 21 22 +11 1 2 8 2 22 3 +12 1 2 9 4 4 32 +13 1 2 9 4 32 33 +14 1 2 9 4 33 34 +15 1 2 9 4 34 35 +16 1 2 9 4 35 36 +17 1 2 9 4 36 37 +18 1 2 9 4 37 38 +19 1 2 9 4 38 39 +20 1 2 9 4 39 40 +21 1 2 9 4 40 1 +22 2 2 7 6 72 81 103 +23 2 2 7 6 110 52 122 +24 2 2 7 6 52 110 135 +25 2 2 7 6 48 86 109 +26 2 2 7 6 93 43 95 +27 2 2 7 6 89 55 91 +28 2 2 7 6 103 81 128 +29 2 2 7 6 109 86 126 +30 2 2 7 6 79 72 103 +31 2 2 7 6 43 93 136 +32 2 2 7 6 91 55 129 +33 2 2 7 6 91 46 92 +34 2 2 7 6 92 46 93 +35 2 2 7 6 86 48 128 +36 2 2 7 6 95 43 96 +37 2 2 7 6 53 110 122 +38 2 2 7 6 83 99 135 +39 2 2 7 6 55 89 119 +40 2 2 7 6 121 56 126 +41 2 2 7 6 86 87 126 +42 2 2 7 6 68 64 97 +43 2 2 7 6 92 94 118 +44 2 2 7 6 120 54 127 +45 2 2 7 6 99 83 137 +46 2 2 7 6 74 94 95 +47 2 2 7 6 99 52 135 +48 2 2 7 6 127 125 142 +49 2 2 7 6 94 97 118 +50 2 2 7 6 64 63 97 +51 2 2 7 6 74 68 97 +52 2 2 7 6 92 93 94 +53 2 2 7 6 121 126 144 +54 2 2 7 6 46 91 129 +55 2 2 7 6 74 95 123 +56 2 2 7 6 94 93 95 +57 2 2 7 6 94 74 97 +58 2 2 7 6 42 57 58 +59 2 2 7 6 44 37 99 +60 2 2 7 6 41 28 98 +61 2 2 7 6 42 10 57 +62 2 2 7 6 88 49 89 +63 2 2 7 6 9 10 42 +64 2 2 7 6 18 19 43 +65 2 2 7 6 27 28 41 +66 2 2 7 6 36 37 44 +67 2 2 7 6 100 45 104 +68 2 2 7 6 27 41 101 +69 2 2 7 6 36 44 102 +70 2 2 7 6 45 8 104 +71 2 2 7 6 47 26 101 +72 2 2 7 6 48 35 102 +73 2 2 7 6 57 49 88 +74 2 2 7 6 88 89 90 +75 2 2 7 6 9 42 104 +76 2 2 7 6 11 49 57 +77 2 2 7 6 38 52 99 +78 2 2 7 6 29 51 98 +79 2 2 7 6 110 107 114 +80 2 2 7 6 26 27 101 +81 2 2 7 6 35 36 102 +82 2 2 7 6 42 58 59 +83 2 2 7 6 10 11 57 +84 2 2 7 6 28 29 98 +85 2 2 7 6 37 38 99 +86 2 2 7 6 45 100 114 +87 2 2 7 6 8 9 104 +88 2 2 7 6 42 59 104 +89 2 2 7 6 90 89 91 +90 2 2 7 6 59 100 104 +91 2 2 7 6 90 91 92 +92 2 2 7 6 107 45 114 +93 2 2 7 6 20 21 50 +94 2 2 7 6 38 39 52 +95 2 2 7 6 11 12 49 +96 2 2 7 6 29 30 51 +97 2 2 7 6 102 44 103 +98 2 2 7 6 84 110 114 +99 2 2 7 6 59 58 60 +100 2 2 7 6 62 60 63 +101 2 2 7 6 65 64 66 +102 2 2 7 6 69 75 77 +103 2 2 7 6 65 66 67 +104 2 2 7 6 66 68 69 +105 2 2 7 6 58 57 88 +106 2 2 7 6 66 64 68 +107 2 2 7 6 62 64 65 +108 2 2 7 6 77 75 78 +109 2 2 7 6 71 67 72 +110 2 2 7 6 65 67 71 +111 2 2 7 6 7 8 45 +112 2 2 7 6 16 17 46 +113 2 2 7 6 25 26 47 +114 2 2 7 6 34 35 48 +115 2 2 7 6 62 63 64 +116 2 2 7 6 71 72 79 +117 2 2 7 6 66 69 111 +118 2 2 7 6 67 66 111 +119 2 2 7 6 77 78 85 +120 2 2 7 6 70 68 74 +121 2 2 7 6 69 77 111 +122 2 2 7 6 78 75 105 +123 2 2 7 6 69 70 75 +124 2 2 7 6 65 71 112 +125 2 2 7 6 61 60 62 +126 2 2 7 6 62 65 112 +127 2 2 7 6 59 61 100 +128 2 2 7 6 72 73 81 +129 2 2 7 6 81 82 86 +130 2 2 7 6 59 60 61 +131 2 2 7 6 61 62 112 +132 2 2 7 6 100 113 114 +133 2 2 7 6 6 7 107 +134 2 2 7 6 24 25 108 +135 2 2 7 6 33 34 109 +136 2 2 7 6 105 76 106 +137 2 2 7 6 7 45 107 +138 2 2 7 6 25 47 108 +139 2 2 7 6 72 67 73 +140 2 2 7 6 34 48 109 +141 2 2 7 6 69 68 70 +142 2 2 7 6 80 84 113 +143 2 2 7 6 71 79 80 +144 2 2 7 6 75 76 105 +145 2 2 7 6 61 112 113 +146 2 2 7 6 73 67 111 +147 2 2 7 6 100 61 113 +148 2 2 7 6 80 83 84 +149 2 2 7 6 75 70 76 +150 2 2 7 6 71 80 112 +151 2 2 7 6 77 85 115 +152 2 2 7 6 111 77 115 +153 2 2 7 6 112 80 113 +154 2 2 7 6 81 73 82 +155 2 2 7 6 5 6 53 +156 2 2 7 6 14 15 55 +157 2 2 7 6 23 24 54 +158 2 2 7 6 32 33 56 +159 2 2 7 6 88 90 117 +160 2 2 7 6 113 84 114 +161 2 2 7 6 86 82 87 +162 2 2 7 6 115 85 116 +163 2 2 7 6 80 79 83 +164 2 2 7 6 73 111 115 +165 2 2 7 6 53 107 110 +166 2 2 7 6 53 6 107 +167 2 2 7 6 54 24 108 +168 2 2 7 6 56 33 109 +169 2 2 7 6 60 58 117 +170 2 2 7 6 82 73 115 +171 2 2 7 6 82 115 116 +172 2 2 7 6 63 60 117 +173 2 2 7 6 58 88 117 +174 2 2 7 6 87 82 116 +175 2 2 7 6 106 125 127 +176 2 2 7 6 95 96 123 +177 2 2 7 6 76 123 125 +178 2 2 7 6 127 54 143 +179 2 2 7 6 97 63 118 +180 2 2 7 6 90 92 118 +181 2 2 7 6 63 117 118 +182 2 2 7 6 96 43 124 +183 2 2 7 6 117 90 118 +184 2 2 7 6 89 49 119 +185 2 2 7 6 12 13 119 +186 2 2 7 6 21 22 120 +187 2 2 7 6 30 31 121 +188 2 2 7 6 39 40 122 +189 2 2 7 6 76 70 123 +190 2 2 7 6 123 96 125 +191 2 2 7 6 43 19 124 +192 2 2 7 6 20 50 124 +193 2 2 7 6 93 46 136 +194 2 2 7 6 102 103 128 +195 2 2 7 6 81 86 128 +196 2 2 7 6 50 21 120 +197 2 2 7 6 52 39 122 +198 2 2 7 6 49 12 119 +199 2 2 7 6 51 30 121 +200 2 2 7 6 70 74 123 +201 2 2 7 6 16 46 129 +202 2 2 7 6 55 15 129 +203 2 2 7 6 110 84 135 +204 2 2 7 6 18 43 136 +205 2 2 7 6 46 17 136 +206 2 2 7 6 44 99 137 +207 2 2 7 6 40 1 138 +208 2 2 7 6 13 2 139 +209 2 2 7 6 22 3 140 +210 2 2 7 6 31 4 141 +211 2 2 7 6 1 5 138 +212 2 2 7 6 2 14 139 +213 2 2 7 6 3 23 140 +214 2 2 7 6 4 32 141 +215 2 2 7 6 50 127 142 +216 2 2 7 6 19 20 124 +217 2 2 7 6 106 76 125 +218 2 2 7 6 56 109 126 +219 2 2 7 6 48 102 128 +220 2 2 7 6 79 103 137 +221 2 2 7 6 50 120 127 +222 2 2 7 6 54 108 143 +223 2 2 7 6 83 79 137 +224 2 2 7 6 116 130 131 +225 2 2 7 6 132 78 133 +226 2 2 7 6 130 85 132 +227 2 2 7 6 78 105 133 +228 2 2 7 6 85 78 132 +229 2 2 7 6 105 106 134 +230 2 2 7 6 133 105 134 +231 2 2 7 6 116 85 130 +232 2 2 7 6 15 16 129 +233 2 2 7 6 87 116 131 +234 2 2 7 6 41 98 130 +235 2 2 7 6 130 98 131 +236 2 2 7 6 101 132 133 +237 2 2 7 6 98 51 131 +238 2 2 7 6 41 130 132 +239 2 2 7 6 47 101 133 +240 2 2 7 6 101 41 132 +241 2 2 7 6 108 47 134 +242 2 2 7 6 47 133 134 +243 2 2 7 6 84 83 135 +244 2 2 7 6 17 18 136 +245 2 2 7 6 103 44 137 +246 2 2 7 6 51 121 144 +247 2 2 7 6 119 13 139 +248 2 2 7 6 120 22 140 +249 2 2 7 6 121 31 141 +250 2 2 7 6 122 40 138 +251 2 2 7 6 5 53 138 +252 2 2 7 6 14 55 139 +253 2 2 7 6 23 54 140 +254 2 2 7 6 32 56 141 +255 2 2 7 6 124 50 142 +256 2 2 7 6 53 122 138 +257 2 2 7 6 54 120 140 +258 2 2 7 6 55 119 139 +259 2 2 7 6 56 121 141 +260 2 2 7 6 96 124 142 +261 2 2 7 6 125 96 142 +262 2 2 7 6 126 87 144 +263 2 2 7 6 106 127 143 +264 2 2 7 6 108 134 143 +265 2 2 7 6 134 106 143 +266 2 2 7 6 87 131 144 +267 2 2 7 6 131 51 144 +$EndElements diff --git a/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/CMakeLists.txt b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..37b7ff0b39a468d3931930869479d38f1aa28b7f --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/CMakeLists.txt @@ -0,0 +1,6 @@ +project(cohesive_damage_extrinsic) +cmake_minimum_required(VERSION 3.0.0) + +find_package(Akantu REQUIRED) + +add_akantu_simulation(cohesive_damage_extrinsic cohesive_damage_extrinsic.cc material.dat triangle.msh) diff --git a/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/cohesive_damage_extrinsic.cc b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/cohesive_damage_extrinsic.cc new file mode 100644 index 0000000000000000000000000000000000000000..4dfaa7ae2f61321835a35639cd628c31b1c8ecfc --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/cohesive_damage_extrinsic.cc @@ -0,0 +1,113 @@ +/** + * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * 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 "element_group.hh" +#include "mesh_iterators.hh" +#include "non_linear_solver.hh" +#include "solid_mechanics_model_cohesive_damage.hh" +/* -------------------------------------------------------------------------- */ +#include <iostream> +/* -------------------------------------------------------------------------- */ + +using namespace akantu; + +/* -------------------------------------------------------------------------- */ +int main(int argc, char * argv[]) { + initialize("material.dat", argc, argv); + + const Int spatial_dimension = 2; + const Int max_steps = 1; + + Real L = 0.4; + Real eps0 = 1e-1; + + Mesh mesh(spatial_dimension); + mesh.read("triangle.msh"); + + SolidMechanicsModelCohesiveDamage model(mesh); + + /// model initialization + model.initFull(_analysis_method = _explicit_lumped_mass + ,_is_extrinsic = true); + + Real time_step = model.getStableTimeStep() * 0.05; + model.setTimeStep(time_step); + std::cout << "Time step: " << time_step << std::endl; + + model.getElementInserter().setLimit(_x, 0.5*L-0.1, 0.5*L+0.1); + model.updateAutomaticInsertion(); + + + + model.applyBC(BC::Dirichlet::FixedValue(0., _x), "left"); + model.applyBC(BC::Dirichlet::FixedValue(0., _y), "point"); + + Int nb_nodes = mesh.getNbNodes(); + + Array<Real> & position = mesh.getNodes(); + Array<Real> & velocity = model.getVelocity(); + + for (Int n = 0; n < nb_nodes; ++n) { + velocity(n,0) = eps0*position(n,0); + } + + model.setBaseName("cohesive"); + model.addDumpFieldVector("displacement"); +// model.addDumpField("velocity"); +// model.addDumpField("acceleration"); + model.addDumpField("stress"); + model.addDumpField("grad_u"); + model.addDumpField("external_force"); + model.addDumpField("internal_force"); + model.dump(); + + /// Main loop + for (Int s = 1; s <= max_steps; ++s) { + model.applyBC(BC::Dirichlet::IncrementValue(time_step*eps0*L, _x), "right"); + // debug::setDebugLevel(dblDump); + debug::setDebugLevel(dblInfo); + model.checkCohesiveInsertion(); /// TODO : replace by a function which does not interpolate stress + model.solveStep(); + model.computeLagrangeMultiplier(); + model.computeDamage(); + model.checkCohesiveStress(); + debug::setDebugLevel(dblWarning); + + if (s % 1 == 0) { + model.dump(); + std::cout << "passing step " << s << "/" << max_steps << std::endl; + } + } + + Real E = model.getEnergy("potential"); + + std::cout << "Elastic energy : " << E << std::endl; + +// if (Ed < Edt * 0.999 || Ed > Edt * 1.001 || std::isnan(Ed)) { +// std::cout << "The dissipated energy is incorrect" << std::endl; +// return EXIT_FAILURE; +// } + + finalize(); + + return EXIT_SUCCESS; +} + diff --git a/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/cohesive_damage_extrinsic.py b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/cohesive_damage_extrinsic.py new file mode 100644 index 0000000000000000000000000000000000000000..4ef34df3d915e445f55e60163fef2993c15c5f8e --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/cohesive_damage_extrinsic.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python3 +__copyright__ = ( + "Copyright (©) 2019-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)" + "Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)" +) +__license__ = "LGPLv3" + + +import sys +sys.path.insert(0,"/home/ble/developpement/akantu/build/buildCZMDamageDebug/python") +print(sys.path) + +import akantu as aka +import numpy as np +import matplotlib.pyplot as plt + +from czm_damage import * + +def set_dumpers(model): + model.setBaseName("cohesive") + model.addDumpFieldVector("displacement") + model.addDumpFieldVector("external_force") + model.addDumpField("strain") + model.addDumpField("stress") + model.addDumpField("blocked_dofs") + + model.setBaseNameToDumper("cohesive elements", "cohesive") + model.addDumpFieldVectorToDumper("cohesive elements", "displacement") + model.addDumpFieldToDumper("cohesive elements", "damage") + model.addDumpFieldVectorToDumper("cohesive elements", "tractions") + model.addDumpFieldVectorToDumper("cohesive elements", "opening") + + +class FixedDisplacement (aka.DirichletFunctor): + ''' + Fix the displacement at its current value + ''' + + def __init__(self, axis, vel): + super().__init__(axis) + self.axis = axis + self.time = 0 + self.vel = vel + + def set_time(self, t): + self.time = t + + def get_imposed_disp(self): + return self.vel*self.time + + def __call__(self, node, flags, disp, coord): + # sets the blocked dofs vector to true in the desired axis + flags[int(self.axis)] = True + disp[int(self.axis)] = self.get_imposed_disp() + +def solve(material_file, mesh_file): + aka.parseInput(material_file) + spatial_dimension = 2 + L = 0.4 + + # ------------------------------------------------------------------------- + # Initialization + # ------------------------------------------------------------------------- + mesh = aka.Mesh(spatial_dimension) + mesh.read(mesh_file) + + model = aka.SolidMechanicsModelCohesiveDamage(mesh) + model.getElementInserter().setLimit(aka._x, 0.5*L-0.1, 0.5*L+0.1); + + model.initFull(_analysis_method=aka._static, _is_extrinsic=True) + + # Initilize a new solver (explicit Newmark with lumped mass) + model.initNewSolver(aka._explicit_lumped_mass) + # Dynamic insertion of cohesive elements + model.updateAutomaticInsertion() + + set_dumpers(model) + + + E = model.getMaterial("steel").getReal("E") + Gc = model.getMaterial("cohesive").getReal("G_c") + sigc = model.getMaterial("cohesive").getReal("sigma_c") + wc = 2.*Gc/sigc + w0 = (sigc/E)*L + k = model.getMaterial("cohesive").getReal("k") + g = degradation_function_linear_czm() + h = softening_function_linear_czm(k,sigc,Gc) + updater = damage_updater(Gc,sigc,k,g,h) + + imposed_disp = [0.] + reaction_force = [0.] + E_pot = [] + E_kin = [] + E_dis = [] + E_rev = [] + E_con = [] + + U = 0. + F = 0. + + # ------------------------------------------------------------------------- + # Initial and boundary conditions + # ------------------------------------------------------------------------- + eps0dot = 5e-1 + tc = w0/(eps0dot*L) + functor_r = FixedDisplacement(aka._x, L*eps0dot) + functor_r.set_time(tc) + model.applyBC(functor_r, 'right') + + model.applyBC(aka.FixedValue(0.0, aka._x), "left") + model.applyBC(aka.FixedValue(0.0, aka._y), "point") + + nodes = model.getMesh().getNodes() + disp_field = np.zeros(nodes.shape) + disp_field[:, 0] = nodes[:, 0]*(w0/L) + model.getDisplacement()[:] = disp_field + vel_field = np.zeros(nodes.shape) + vel_field[:, 0] = nodes[:, 0]*eps0dot + model.getVelocity()[:] = vel_field + + model.getExternalForce()[:] = 0 + model.assembleInternalForces() + + d = model.getMaterial("cohesive").getInternalReal("czm_damage")(aka._segment_2) + lda = model.getMaterial("cohesive").getInternalReal("lambda")(aka._segment_2) + Fint = model.getInternalForce() + + nodes_right = mesh.getElementGroup("right").getNodeGroup().getNodes() + + U = functor_r.get_imposed_disp() + imposed_disp.append(U) + F = -np.sum(Fint[nodes_right,0]) + reaction_force.append(F) + + Ep = model.getEnergy("potential") + Ek = model.getEnergy("kinetic") + Ed = model.getEnergy("dissipated") + Er = model.getEnergy("reversible") + + E_pot.append(Ep) + E_kin.append(Ek) + E_dis.append(Ed) + E_rev.append(Er) + + model.dump() + #model.dump("cohesive elements") + + maxsteps = 1 + dt = model.getStableTimeStep()*0.1 + # choose the timestep + model.setTimeStep(dt) + + time = tc + for i in range(0, maxsteps): + print("---- step {0}/{1}".format(i, maxsteps)) + time+=dt + functor_r.set_time(time) + # fix displacements of the right boundary + model.applyBC(functor_r, 'right') + d_previous = model.getMaterial("cohesive").getInternalReal("czm_damage")(aka._segment_2).copy() + #print("lda = ",lda) + model.solveStep('explicit_lumped') + model.computeLagrangeMultiplier() + #d[:] = updater.update_d(d_previous,lda) + model.computeDamage() + # print("d = ",d) + + model.checkCohesiveInsertion() + + U = functor_r.get_imposed_disp() + imposed_disp.append(U) + F = -np.sum(Fint[nodes_right,0]) + reaction_force.append(F) + + Ep = model.getEnergy("potential") + Ek = model.getEnergy("kinetic") + Ed = model.getEnergy("dissipated") + Er = model.getEnergy("reversible") + + E_pot.append(Ep) + E_kin.append(Ek) + E_dis.append(Ed) + E_rev.append(Er) + + model.dump() + #model.dump("cohesive elements") + + plt.plot(imposed_disp,reaction_force,'-o') + plt.plot([0., w0, wc], [0., sigc*L, 0.], 'k-o') + plt.show() + + +# ----------------------------------------------------------------------------- +# main +# ----------------------------------------------------------------------------- +def main(): + mesh_file = "triangle.msh" + material_file = "material.dat" + solve(material_file, mesh_file) + + +# ----------------------------------------------------------------------------- +if __name__ == "__main__": + main() diff --git a/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/czm_damage.py b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/czm_damage.py new file mode 100644 index 0000000000000000000000000000000000000000..3bce7d71269530f57b68ab4992efa8a84af27d1f --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/czm_damage.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 + +import numpy as np +import scipy.optimize + +import matplotlib.pyplot as plt + +class degradation_function: + # g(d) + def val(self,d): + return + # dg_dd(d) + def deriv(self,d): + return + # 1+g(d) + def augmented_stiffness(self,d): + return + def augmented_compliance(self,d): + # 1/(1+g(d)) + return + def augmented_compliance_deriv(self,d): + # d()1/(1+g(d))_dd + return + +class degradation_function_linear_czm(degradation_function): + def val(self,d): + return 1./d-1. + def deriv(self,d): + return -1./d**2 + def augmented_stiffness(self,d): + return 1./d + def augmented_compliance(self,d): + return d + def augmented_compliance_deriv(self,d): + return 1. + +class softening_function: + def val(self,d): + return + def deriv(self,d): + return + +class softening_function_linear_czm: + def __init__(self,k,tc,Gc): + wc = 2.*Gc/tc + self.a = k*wc/tc + def val(self,d): + return d/(d+self.a*(1.-d)) + def deriv(self,d): + return self.a/(d+self.a*(1.-d))**2 + +class damage_updater: + def __init__(self,Gc, sigc, k, g, h): + self.Gc = Gc + self.sigc = sigc + self.k = k + self.g = g + self.h = h + def update_d(self,d_previous,lda): + dz = d_previous.flatten() + shape_d = d_previous.shape + lda_lda_on_k = (lda[:,0]**2 + lda[:,1]**2)/self.k + + def F(d): + return -0.5*np.dot(lda_lda_on_k,self.g.augmented_compliance(d))+self.Gc*np.sum(self.h.val(d)) + def dF(d): + return -0.5*self.g.augmented_compliance_deriv(d)*lda_lda_on_k+self.Gc*self.h.deriv(d) + + #dd = np.linspace(0.,1.,100) + #D = dz.copy() + #FF = [] + #for i in range(len(dd)): + # D[0] = dd[i] + # FF.append(F(D)) + #plt.plot(dd,FF) + #plt.show() + #print("dz = ",dz) + #print("lda_lda_on_k = ",lda_lda_on_k) + #print("F1 = ",-0.5*np.dot(lda_lda_on_k,self.g.augmented_compliance(dz))) + #print("F2 = ",self.Gc*np.sum(self.h.val(dz))) + #print("F(dz) = ",F(dz)) + #print("self.k = ",self.k) + + boundd = scipy.optimize.Bounds(dz, np.ones(len(dz))) + options = {'verbose':1} + resd = scipy.optimize.minimize(F, dz, bounds=boundd + , jac =dF + #, method = 'trust-constr' + #, options = options + #, tol = 1e-10 + ) + if not resd.success: + print("resd.message = ",resd.message) + #print("niterd = ",resd.nit) + return np.resize(resd.x,shape_d) + +def energy(model): + return model.getEnergy("potential") + model.getEnergy("dissipated") diff --git a/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/material.dat b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/material.dat new file mode 100644 index 0000000000000000000000000000000000000000..58628a0714ca1e1d788e5f367e6ed3f92511ea78 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/material.dat @@ -0,0 +1,13 @@ +material elastic [ + name = steel + rho = 3800 # density + E = 3e10 # young's modulus + nu = 0. # poisson's ratio +] + +material cohesive_damage_extrinsic [ + name = cohesive + sigma_c = 3e6 + k = 75e9 + G_c = 120 +] diff --git a/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/triangle.geo b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/triangle.geo new file mode 100644 index 0000000000000000000000000000000000000000..e3d5073b5fdcb78a4f83d1dcce9e9dd63428b8f4 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/triangle.geo @@ -0,0 +1,23 @@ +h = .1; +L = 0.4; + +Point(1) = { L, L, 0, h}; +Point(2) = {0., L, 0, h}; +Point(3) = {0.,0., 0, h}; +Point(4) = {L,0., 0, h}; +Line(1) = {1, 2}; +Line(2) = {2, 3}; +Line(3) = {3, 4}; +Line(4) = {4, 1}; +Line Loop(5) = {1, 2, 3, 4}; +Plane Surface(6) = {5}; +Physical Surface(7) = {6}; + +Transfinite Line {2, 4} = 2; +Transfinite Line {1, 3} = 3; +Transfinite Surface {6} = {1, 2, 3, 4}; + + +Physical Curve("left", 8) = {2}; +Physical Curve("right", 9) = {4}; +Physical Point("point", 10) = {3}; diff --git a/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/triangle.msh b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/triangle.msh new file mode 100644 index 0000000000000000000000000000000000000000..4bb857aa493be251ed6cdb4a8da93c071d9858f2 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/cohesive_damage_extrinsic/triangle.msh @@ -0,0 +1,28 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$PhysicalNames +3 +0 10 "point" +1 8 "left" +1 9 "right" +$EndPhysicalNames +$Nodes +6 +1 0.4 0.4 0 +2 0 0.4 0 +3 0 0 0 +4 0.4 0 0 +5 0.2000000000005479 0.4 0 +6 0.1999999999994742 0 0 +$EndNodes +$Elements +7 +1 15 2 10 3 3 +2 1 2 8 2 2 3 +3 1 2 9 4 4 1 +4 2 2 7 6 1 5 4 +5 2 2 7 6 4 5 6 +6 2 2 7 6 5 2 6 +7 2 2 7 6 6 2 3 +$EndElements diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/CMakeLists.txt b/examples/c++/solid_mechanics_cohesive_model/my_first_test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..67ef4310bc692c719f839a4c1b6632c2f53b7ccb --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/CMakeLists.txt @@ -0,0 +1,6 @@ +project(my_first_test) +cmake_minimum_required(VERSION 3.0.0) + +find_package(Akantu REQUIRED) + +add_akantu_simulation(my_first_test my_first_test.cc material.dat triangle.msh) diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/czm_damage.py b/examples/c++/solid_mechanics_cohesive_model/my_first_test/czm_damage.py new file mode 100644 index 0000000000000000000000000000000000000000..3bce7d71269530f57b68ab4992efa8a84af27d1f --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/czm_damage.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 + +import numpy as np +import scipy.optimize + +import matplotlib.pyplot as plt + +class degradation_function: + # g(d) + def val(self,d): + return + # dg_dd(d) + def deriv(self,d): + return + # 1+g(d) + def augmented_stiffness(self,d): + return + def augmented_compliance(self,d): + # 1/(1+g(d)) + return + def augmented_compliance_deriv(self,d): + # d()1/(1+g(d))_dd + return + +class degradation_function_linear_czm(degradation_function): + def val(self,d): + return 1./d-1. + def deriv(self,d): + return -1./d**2 + def augmented_stiffness(self,d): + return 1./d + def augmented_compliance(self,d): + return d + def augmented_compliance_deriv(self,d): + return 1. + +class softening_function: + def val(self,d): + return + def deriv(self,d): + return + +class softening_function_linear_czm: + def __init__(self,k,tc,Gc): + wc = 2.*Gc/tc + self.a = k*wc/tc + def val(self,d): + return d/(d+self.a*(1.-d)) + def deriv(self,d): + return self.a/(d+self.a*(1.-d))**2 + +class damage_updater: + def __init__(self,Gc, sigc, k, g, h): + self.Gc = Gc + self.sigc = sigc + self.k = k + self.g = g + self.h = h + def update_d(self,d_previous,lda): + dz = d_previous.flatten() + shape_d = d_previous.shape + lda_lda_on_k = (lda[:,0]**2 + lda[:,1]**2)/self.k + + def F(d): + return -0.5*np.dot(lda_lda_on_k,self.g.augmented_compliance(d))+self.Gc*np.sum(self.h.val(d)) + def dF(d): + return -0.5*self.g.augmented_compliance_deriv(d)*lda_lda_on_k+self.Gc*self.h.deriv(d) + + #dd = np.linspace(0.,1.,100) + #D = dz.copy() + #FF = [] + #for i in range(len(dd)): + # D[0] = dd[i] + # FF.append(F(D)) + #plt.plot(dd,FF) + #plt.show() + #print("dz = ",dz) + #print("lda_lda_on_k = ",lda_lda_on_k) + #print("F1 = ",-0.5*np.dot(lda_lda_on_k,self.g.augmented_compliance(dz))) + #print("F2 = ",self.Gc*np.sum(self.h.val(dz))) + #print("F(dz) = ",F(dz)) + #print("self.k = ",self.k) + + boundd = scipy.optimize.Bounds(dz, np.ones(len(dz))) + options = {'verbose':1} + resd = scipy.optimize.minimize(F, dz, bounds=boundd + , jac =dF + #, method = 'trust-constr' + #, options = options + #, tol = 1e-10 + ) + if not resd.success: + print("resd.message = ",resd.message) + #print("niterd = ",resd.nit) + return np.resize(resd.x,shape_d) + +def energy(model): + return model.getEnergy("potential") + model.getEnergy("dissipated") diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/material.dat b/examples/c++/solid_mechanics_cohesive_model/my_first_test/material.dat new file mode 100644 index 0000000000000000000000000000000000000000..2f627470cac6f3b6dbebe6833d42b4fac47c8182 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/material.dat @@ -0,0 +1,13 @@ +material elastic [ + name = steel + rho = 1 # density + E = 3e10 # young's modulus + nu = 0. # poisson's ratio +] + +material cohesive_damage_intrinsic [ + name = cohesive + sigma_c = 3e6 + k = 75e9 + G_c = 120 +] diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/my_first_test.cc b/examples/c++/solid_mechanics_cohesive_model/my_first_test/my_first_test.cc new file mode 100644 index 0000000000000000000000000000000000000000..ae3bf49d97ab8bf7ba1e7dcd0c7955c3e3fe3738 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/my_first_test.cc @@ -0,0 +1,98 @@ +/** + * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * 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 "element_group.hh" +#include "mesh_iterators.hh" +#include "non_linear_solver.hh" +#include "solid_mechanics_model_cohesive.hh" +/* -------------------------------------------------------------------------- */ +#include <iostream> +/* -------------------------------------------------------------------------- */ + +using namespace akantu; + +/* -------------------------------------------------------------------------- */ +int main(int argc, char * argv[]) { + initialize("material.dat", argc, argv); + + const Int spatial_dimension = 2; + const Int max_steps = 1; + + Mesh mesh(spatial_dimension); + mesh.read("triangle.msh"); + + SolidMechanicsModelCohesive model(mesh); + model.getElementInserter().setLimit(_x, -0.05, 0.05); + + /// model initialization + model.initFull(_analysis_method = _static + ,_is_extrinsic = false + ); + + auto & solver = model.getNonLinearSolver(); +// solver.set("convergence_type", SolveConvergenceCriteria::_residual); + solver.set("convergence_type", SolveConvergenceCriteria::_solution); + solver.set("max_iterations", 2); + + model.applyBC(BC::Dirichlet::FixedValue(0., _x), "left"); + model.applyBC(BC::Dirichlet::FixedValue(0., _y), "point"); + + model.setBaseName("cohesive"); + model.addDumpFieldVector("displacement"); +// model.addDumpField("velocity"); +// model.addDumpField("acceleration"); + model.addDumpField("stress"); + model.addDumpField("grad_u"); + model.addDumpField("external_force"); + model.addDumpField("internal_force"); + model.dump(); + + + Real increment = 0.01; + + /// Main loop + for (Int s = 1; s <= max_steps; ++s) { + model.applyBC(BC::Dirichlet::IncrementValue(increment, _x), "right"); + // debug::setDebugLevel(dblDump); + debug::setDebugLevel(dblInfo); + model.solveStep(); + debug::setDebugLevel(dblWarning); + + if (s % 1 == 0) { + model.dump(); + std::cout << "passing step " << s << "/" << max_steps << std::endl; + } + } + + Real E = model.getEnergy("potential"); + + std::cout << "Elastic energy : " << E << std::endl; + +// if (Ed < Edt * 0.999 || Ed > Edt * 1.001 || std::isnan(Ed)) { +// std::cout << "The dissipated energy is incorrect" << std::endl; +// return EXIT_FAILURE; +// } + + finalize(); + + return EXIT_SUCCESS; +} + diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/my_first_test.py b/examples/c++/solid_mechanics_cohesive_model/my_first_test/my_first_test.py new file mode 100644 index 0000000000000000000000000000000000000000..a0244473dcfeb64c0274a2d6d242a57cc7788237 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/my_first_test.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +__copyright__ = ( + "Copyright (©) 2019-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne)" + "Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides)" +) +__license__ = "LGPLv3" + + +import sys +sys.path.insert(0,"/home/ble/buildAkantu/buildDebug/python") +print(sys.path) + +import akantu as aka +import numpy as np +import matplotlib.pyplot as plt + +from czm_damage import * + +def set_dumpers(model): + model.setBaseName("cohesive") + model.addDumpFieldVector("displacement") + model.addDumpFieldVector("external_force") + model.addDumpField("strain") + model.addDumpField("stress") + model.addDumpField("blocked_dofs") + + model.setBaseNameToDumper("cohesive elements", "cohesive") + model.addDumpFieldVectorToDumper("cohesive elements", "displacement") + model.addDumpFieldToDumper("cohesive elements", "damage") + model.addDumpFieldVectorToDumper("cohesive elements", "tractions") + model.addDumpFieldVectorToDumper("cohesive elements", "opening") + + +def solve(material_file, mesh_file, increment): + aka.parseInput(material_file) + spatial_dimension = 2 + + # ------------------------------------------------------------------------- + # Initialization + # ------------------------------------------------------------------------- + mesh = aka.Mesh(spatial_dimension) + mesh.read(mesh_file) + + model = aka.SolidMechanicsModelCohesive(mesh) + model.getElementInserter().setLimit(aka._x, -0.1, 0.1); + + model.initFull(_analysis_method=aka._static, _is_extrinsic=False) + + set_dumpers(model) + + L = 0.4 + E = model.getMaterial("steel").getReal("E") + Gc = model.getMaterial("cohesive").getReal("G_c") + tc = model.getMaterial("cohesive").getReal("sigma_c") + wc = 2.*Gc/tc + k = model.getMaterial("cohesive").getReal("k") + g = degradation_function_linear_czm() + h = softening_function_linear_czm(k,tc,Gc) + updater = damage_updater(Gc,tc,k,g,h) + + imposed_disp = [0.] + reaction_force = [0.] + U = 0. + F = 0. + + # ------------------------------------------------------------------------- + # Boundary conditions + # ------------------------------------------------------------------------- + model.applyBC(aka.FixedValue(0.0, aka._x), "left") + model.applyBC(aka.FixedValue(0.0, aka._y), "point") + model.applyBC(aka.IncrementValue(increment, aka._x), "right") + U+=increment + imposed_disp.append(U) + + model.getExternalForce()[:] = 0 + + solver = model.getNonLinearSolver("static") + solver.set("max_iterations", 2) + solver.set("threshold", 1e-10) + solver.set("convergence_type", aka.SolveConvergenceCriteria.residual) + + model.getNewSolver("linear_static", aka.TimeStepSolverType.static, + aka.NonLinearSolverType.linear) + model.setIntegrationScheme("linear_static", "displacement", + aka.IntegrationSchemeType.pseudo_time) + model.setIntegrationScheme("linear_static", "lambda", + aka.IntegrationSchemeType.pseudo_time) + + d = model.getMaterial("cohesive").getInternalReal("czm_damage")(aka._cohesive_2d_4) + lda = model.getMaterial("cohesive").getInternalReal("lambda")(aka._cohesive_2d_4) + Fint = model.getInternalForce() + + nodes_right = mesh.getElementGroup("right").getNodeGroup().getNodes() + model.solveStep("linear_static") + F = -np.sum(Fint[nodes_right,0]) + reaction_force.append(F) + + model.dump() + #model.dump("cohesive elements") + + maxsteps = 8 + maxiter = 10 + tol = 1e-6 + + for i in range(0, maxsteps): + print("---- step {0}/{1}".format(i, maxsteps)) + model.applyBC(aka.IncrementValue(increment, aka._x), "right") + U+=increment + imposed_disp.append(U) + it = 0 + d_previous = model.getMaterial("cohesive").getInternalReal("czm_damage")(aka._cohesive_2d_4).copy() + W0 = energy(model) + while it < maxiter: + #aka.debug.setDebugLevel(aka.dblInfo); + model.solveStep("linear_static") + d[:] = updater.update_d(d_previous,lda) + W = energy(model) + err = abs(W-W0)/W + print("iter ",it,", err = ",err) + if err < tol: + break + else: + W0 = W + it+=1 + F = -np.sum(Fint[nodes_right,0]) + reaction_force.append(F) + + model.dump() + #model.dump("cohesive elements") + + plt.plot(imposed_disp,reaction_force,'-o') + plt.plot([0., (tc/E)*L, wc], [0., tc*L, 0.], 'k-o') + plt.show() + W = model.getEnergy("potential"); + D = model.getEnergy("dissipated"); + print("Elastic energy = ",W) + print("Dissipated energy = ",D) + +# ----------------------------------------------------------------------------- +# main +# ----------------------------------------------------------------------------- +def main(): + mesh_file = "triangle.msh" + material_file = "material.dat" + increment = 0.01e-3 + solve(material_file, mesh_file, increment) + + +# ----------------------------------------------------------------------------- +if __name__ == "__main__": + main() diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle.geo b/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle.geo new file mode 100644 index 0000000000000000000000000000000000000000..43289bc469f191c43f77f0850c645fc9d9d54626 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle.geo @@ -0,0 +1,20 @@ +h = .1; + +Point(1) = { 1, 1, 0, h}; +Point(2) = {-1, 1, 0, h}; +Point(3) = {-1,-1, 0, h}; +Point(4) = { 1,-1, 0, h}; +Line(1) = {1, 2}; +Line(2) = {2, 3}; +Line(3) = {3, 4}; +Line(4) = {4, 1}; +Line Loop(5) = {1, 2, 3, 4}; +Plane Surface(6) = {5}; +Physical Surface(7) = {6}; + +Transfinite Line {1, 2, 3, 4} = 3; + + +Physical Curve("left", 8) = {2}; +Physical Curve("right", 9) = {4}; +Physical Point("point", 10) = {3}; diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle.msh b/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle.msh new file mode 100644 index 0000000000000000000000000000000000000000..8cff65b22fa2618249c9950a99588549901f74ab --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle.msh @@ -0,0 +1,37 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$PhysicalNames +3 +0 10 "point" +1 8 "left" +1 9 "right" +$EndPhysicalNames +$Nodes +9 +1 1 1 0 +2 -1 1 0 +3 -1 -1 0 +4 1 -1 0 +5 2.750244476601438e-12 1 0 +6 -1 2.750244476601438e-12 0 +7 -2.750244476601438e-12 -1 0 +8 1 -2.750244476601438e-12 0 +9 7.564178960885304e-24 0 0 +$EndNodes +$Elements +13 +1 15 2 10 3 3 +2 1 2 8 2 2 6 +3 1 2 8 2 6 3 +4 1 2 9 4 4 8 +5 1 2 9 4 8 1 +6 2 2 7 6 1 5 8 +7 2 2 7 6 8 5 9 +8 2 2 7 6 8 9 4 +9 2 2 7 6 4 9 7 +10 2 2 7 6 5 2 9 +11 2 2 7 6 9 2 6 +12 2 2 7 6 9 6 7 +13 2 2 7 6 7 6 3 +$EndElements diff --git a/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle_small.msh b/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle_small.msh new file mode 100644 index 0000000000000000000000000000000000000000..abf034048728dd554f1db12e8e476bb55088ebf6 --- /dev/null +++ b/examples/c++/solid_mechanics_cohesive_model/my_first_test/triangle_small.msh @@ -0,0 +1,28 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$PhysicalNames +3 +0 10 "point" +1 8 "left" +1 9 "right" +$EndPhysicalNames +$Nodes +6 +1 1 1 0 +2 -1 1 0 +3 -1 -1 0 +4 1 -1 0 +5 2.750244476601438e-12 1 0 +6 -2.750244476601438e-12 -1 0 +$EndNodes +$Elements +7 +1 15 2 10 3 3 +2 1 2 8 2 2 3 +3 1 2 9 4 4 1 +4 2 2 7 6 1 5 4 +5 2 2 7 6 4 5 6 +6 2 2 7 6 5 2 6 +7 2 2 7 6 6 2 3 +$EndElements diff --git a/packages/cohesive_element.cmake b/packages/cohesive_element.cmake index 86c8a49d8004095732ede94b63299190c001b14e..cc93d32a121398587bf29e362a46a0d6601c3fab 100644 --- a/packages/cohesive_element.cmake +++ b/packages/cohesive_element.cmake @@ -1,4 +1,4 @@ -#=============================================================================== + #=============================================================================== # Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) # Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) # @@ -62,9 +62,36 @@ package_declare_sources(cohesive_element model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_inline_impl.hh + model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.cc + model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.hh + model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_inline_impl.hh + + model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.cc + model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.hh + model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic_inline_impl.hh + model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.cc + model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.hh + model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_inline_impl.hh + + model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.cc + model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.hh + model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local_tmpl.hh + model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.cc + model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.hh + model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local_tmpl.hh + + model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_inline_impl.hh model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc + + model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.cc + model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.hh + + model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.cc + model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.hh + model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip_inline_impl.hh + ) diff --git a/packages/core.cmake b/packages/core.cmake index e70c826c8af828f40dd8ffc5f3d54e5897627f90..90b948f1c758748baa44380905bbd6d30cbf8082 100644 --- a/packages/core.cmake +++ b/packages/core.cmake @@ -237,6 +237,14 @@ package_declare_sources(core model/common/non_local_toolbox/base_weight_function.hh model/common/non_local_toolbox/base_weight_function.cc model/common/non_local_toolbox/base_weight_function_inline_impl.hh + + model/common/non_local_toolbox/clip_neighborhood.hh + model/common/non_local_toolbox/clip_neighborhood_tmpl.hh + model/common/non_local_toolbox/clip_neighborhood_inline_impl.hh + model/common/non_local_toolbox/base_distance_function.hh + model/common/non_local_toolbox/base_distance_function.cc + model/common/non_local_toolbox/base_distance_function_inline_impl.hh + model/common/model_solver.cc model/common/model_solver.hh @@ -247,7 +255,6 @@ package_declare_sources(core model/common/dof_manager/dof_manager.hh model/common/dof_manager/dof_manager_default.cc model/common/dof_manager/dof_manager_default.hh - model/common/dof_manager/dof_manager_default_inline_impl.hh model/common/dof_manager/dof_manager_inline_impl.hh model/common/non_linear_solver/non_linear_solver.cc diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 603658d7a1b0da8b488bc7d389725be9ef8bfa0e..e32b27a2b3133a77d106bd8ff15b4fb8b0662b2d 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -62,6 +62,7 @@ package_is_activated(cohesive_element _is_activated) if (_is_activated) list(APPEND PYAKANTU_SRCS py_solid_mechanics_model_cohesive.cc + py_solid_mechanics_model_cohesive_damage.cc py_fragment_manager.cc ) endif() diff --git a/python/py_akantu.cc b/python/py_akantu.cc index fc231c1b22a2f648b892b609445ebb66fd635222..6ffa5e4078dbd72d386e15c611e916cf6afcdd97 100644 --- a/python/py_akantu.cc +++ b/python/py_akantu.cc @@ -50,6 +50,7 @@ #if defined(AKANTU_COHESIVE_ELEMENT) #include "py_fragment_manager.hh" #include "py_solid_mechanics_model_cohesive.hh" +#include "py_solid_mechanics_model_cohesive_damage.hh" #endif #if defined(AKANTU_CONTACT_MECHANICS) @@ -109,6 +110,7 @@ void register_all(pybind11::module & mod) { #if defined(AKANTU_COHESIVE_ELEMENT) register_solid_mechanics_model_cohesive(mod); + register_solid_mechanics_model_cohesive_damage(mod); register_fragment_manager(mod); #endif diff --git a/python/py_material.cc b/python/py_material.cc index 2b56be2d44c26834c822be5f9b607c67570e07db..49e4946ddd92a6b9bb03c79cc42fd34f1dc01eab 100644 --- a/python/py_material.cc +++ b/python/py_material.cc @@ -217,6 +217,12 @@ void register_material(py::module & mod) { [](MaterialCohesive & self, ElementType type, GhostType ghost_type) -> decltype(auto) { return self.getTraction(type, ghost_type); }, py::arg("type"), py::arg("ghost_type") = _not_ghost, + py::return_value_policy::reference) + .def( + "getDamage", + [](MaterialCohesive & self, ElementType type, GhostType ghost_type) + -> decltype(auto) { return self.getDamage(type, ghost_type); }, + py::arg("type"), py::arg("ghost_type") = _not_ghost, py::return_value_policy::reference); register_material_cohesive_classes<MaterialCohesiveLinear<2>>( diff --git a/python/py_solid_mechanics_model_cohesive.cc b/python/py_solid_mechanics_model_cohesive.cc index d4d8c8db966557d0cb3dd47b4b37ca5a3c7f1958..68293f04258d3727d842e510b965275b78a35c3c 100644 --- a/python/py_solid_mechanics_model_cohesive.cc +++ b/python/py_solid_mechanics_model_cohesive.cc @@ -35,13 +35,13 @@ namespace akantu { #define def_function_nocopy(func_name) \ def( \ #func_name, \ - [](SolidMechanicsModel & self) -> decltype(auto) { \ + [](SolidMechanicsModelCohesive & self) -> decltype(auto) { \ return self.func_name(); \ }, \ py::return_value_policy::reference) #define def_function(func_name) \ - def(#func_name, [](SolidMechanicsModel & self) -> decltype(auto) { \ + def(#func_name, [](SolidMechanicsModelCohesive & self) -> decltype(auto) { \ return self.func_name(); \ }) diff --git a/python/py_solid_mechanics_model_cohesive_damage.cc b/python/py_solid_mechanics_model_cohesive_damage.cc new file mode 100644 index 0000000000000000000000000000000000000000..8fab3c850743399f5d7982eb024cccf4447c58c7 --- /dev/null +++ b/python/py_solid_mechanics_model_cohesive_damage.cc @@ -0,0 +1,87 @@ +/** + * Copyright (©) 2020-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * 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 "py_aka_array.hh" +/* -------------------------------------------------------------------------- */ +#include <element_synchronizer.hh> +#include <non_linear_solver.hh> +#include <solid_mechanics_model_cohesive_damage.hh> +/* -------------------------------------------------------------------------- */ +#include <pybind11/pybind11.h> +/* -------------------------------------------------------------------------- */ +namespace py = pybind11; +/* -------------------------------------------------------------------------- */ + +namespace akantu { + +#define def_function_nocopy(func_name) \ + def( \ + #func_name, \ + [](SolidMechanicsModelCohesiveDamage & self) -> decltype(auto) { \ + return self.func_name(); \ + }, \ + py::return_value_policy::reference) + +#define def_function(func_name) \ + def(#func_name, [](SolidMechanicsModelCohesiveDamage & self) -> decltype(auto) { \ + return self.func_name(); \ + }) + +void register_solid_mechanics_model_cohesive_damage(py::module & mod) { + + py::class_<SolidMechanicsModelCohesiveDamage, SolidMechanicsModel>( + mod, "SolidMechanicsModelCohesiveDamage") + .def(py::init<Mesh &, Int, const ID &>(), py::arg("mesh"), + py::arg("spatial_dimension") = _all_dimensions, + py::arg("id") = "solid_mechanics_model") + .def( + "initFull", + [](SolidMechanicsModel & self, const AnalysisMethod & analysis_method, + bool is_extrinsic) { + self.initFull(_analysis_method = analysis_method, + _is_extrinsic = is_extrinsic); + }, + py::arg("_analysis_method") = _explicit_lumped_mass, + py::arg("_is_extrinsic") = false) + + .def("checkCohesiveStress", + &SolidMechanicsModelCohesiveDamage::checkCohesiveStress) + .def("checkCohesiveInsertion", + &SolidMechanicsModelCohesiveDamage::checkCohesiveInsertion) + .def("computeLagrangeMultiplier", + &SolidMechanicsModelCohesiveDamage::computeLagrangeMultiplier) + .def("computeDamage", + &SolidMechanicsModelCohesiveDamage::computeDamage) + .def("getElementInserter", + &SolidMechanicsModelCohesiveDamage::getElementInserter, + py::return_value_policy::reference) + .def("getStressOnFacets", &SolidMechanicsModelCohesiveDamage::getStressOnFacets, + py::arg("type"), py::arg("ghost_type") = _not_ghost, + py::return_value_policy::reference) + .def("getTangents", &SolidMechanicsModelCohesiveDamage::getTangents, + py::arg("type"), py::arg("ghost_type") = _not_ghost, + py::return_value_policy::reference) + .def_function_nocopy(getLambda) + .def("updateAutomaticInsertion", + &SolidMechanicsModelCohesiveDamage::updateAutomaticInsertion); +} + +} // namespace akantu diff --git a/src/model/common/dof_manager/dof_manager_default_inline_impl.hh b/python/py_solid_mechanics_model_cohesive_damage.hh similarity index 68% rename from src/model/common/dof_manager/dof_manager_default_inline_impl.hh rename to python/py_solid_mechanics_model_cohesive_damage.hh index 2092bebf4c21a20a38c350d0339a6c3bae0b7331..83436997f20860cf6f181821de78daf197493cee 100644 --- a/src/model/common/dof_manager/dof_manager_default_inline_impl.hh +++ b/python/py_solid_mechanics_model_cohesive_damage.hh @@ -1,5 +1,5 @@ /** - * Copyright (©) 2015-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Copyright (©) 2020-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * This file is part of Akantu @@ -19,12 +19,15 @@ */ /* -------------------------------------------------------------------------- */ -#include "dof_manager_default.hh" -/* -------------------------------------------------------------------------- */ +#include <pybind11/pybind11.h> + +#ifndef AKANTU_PY_SOLID_MECHANICS_MODEL_COHESIVE_DAMAGE_HH_ +#define AKANTU_PY_SOLID_MECHANICS_MODEL_COHESIVE_DAMAGE_HH_ + +namespace akantu { -#ifndef AKANTU_DOF_MANAGER_DEFAULT_INLINE_IMPL_HH_ -#define AKANTU_DOF_MANAGER_DEFAULT_INLINE_IMPL_HH_ +void register_solid_mechanics_model_cohesive_damage(pybind11::module & mod); -namespace akantu {} // namespace akantu +} // namespace akantu -#endif /* AKANTU_DOF_MANAGER_DEFAULT_INLINE_IMPL_HH */ +#endif // AKANTU_PY_SOLID_MECHANICS_MODEL_COHESIVE_DAMAGE_HH_ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 69763527d64e6c6965fe437ba627f84275ef531c..fde7470d4b08d0ce04b9bdec3cdac12f9a913a7e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -53,6 +53,7 @@ set(AKANTU_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR} ${AKANTU_LIBRARY_INCLUDE_DIRS} CACHE INTERNAL "Internal include directories to link with Akantu as a subproject") + #=========================================================================== # configurations #=========================================================================== @@ -118,6 +119,16 @@ endif() #=============================================================================== add_library(akantu ${AKANTU_LIBRARY_SRCS}) + +#=============================================================================== +# Gmsh Management +#=============================================================================== +if(GMSH_INSTALL_DIR) + target_include_directories(akantu PUBLIC "${GMSH_INSTALL_DIR}/include/") + target_link_libraries(akantu PRIVATE ${GMSH_INSTALL_DIR}/lib/libgmsh.so) + add_definitions(-DWITH_GMSH) +endif() + target_include_directories(akantu PRIVATE $<BUILD_INTERFACE:${AKANTU_INCLUDE_DIRS}> INTERFACE $<INSTALL_INTERFACE:include/akantu> diff --git a/src/common/aka_common.hh b/src/common/aka_common.hh index 4433dfc1b1e7e36f70487cff3a3304005485389b..9bc405d5f12a664d7b5de5999d78863dde292f15 100644 --- a/src/common/aka_common.hh +++ b/src/common/aka_common.hh @@ -103,7 +103,8 @@ enum EventHandlerPriority { _ehp_mesh = 5, _ehp_fe_engine = 9, _ehp_synchronizer = 10, - _ehp_dof_manager = 20, + _ehp_dof_data = 21, + _ehp_dof_manager = 21, _ehp_model = 94, _ehp_non_local_manager = 100, _ehp_lowest = 100 @@ -516,7 +517,7 @@ namespace { inline void set##name(type variable) { this->variable = variable; } #define AKANTU_GET_MACRO(name, variable, type) \ - [[nodiscard]] inline auto get##name() const -> type { return variable; } + [[nodiscard]] inline auto get##name() const->type { return variable; } #define AKANTU_GET_MACRO_AUTO(name, variable) \ [[nodiscard]] inline decltype(auto) get##name() const { return (variable); } @@ -525,7 +526,7 @@ namespace { inline decltype(auto) get##name() { return (variable); } #define AKANTU_GET_MACRO_NOT_CONST(name, variable, type) \ - [[nodiscard]] inline auto get##name() -> type { return variable; } + [[nodiscard]] inline auto get##name()->type { return variable; } #define AKANTU_GET_MACRO_DEREF_PTR(name, ptr) \ [[nodiscard]] inline const auto & get##name() const { \ diff --git a/src/fe_engine/cohesive_element.hh b/src/fe_engine/cohesive_element.hh index c4e597394b7ad8f76f4a03e19eee7cdfabbc7223..a6efe6a09cfdf17451af9e92f863b9b392bf4cdf 100644 --- a/src/fe_engine/cohesive_element.hh +++ b/src/fe_engine/cohesive_element.hh @@ -33,7 +33,7 @@ AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_cohesive_1d_2, _gt_cohesive_1d_2, AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_cohesive_2d_4, _gt_cohesive_2d_4, _itp_lagrange_segment_2, _ek_cohesive, 2, - _git_segment, 2); + _git_segment, 1); AKANTU_DEFINE_ELEMENT_CLASS_PROPERTY(_cohesive_2d_6, _gt_cohesive_2d_6, _itp_lagrange_segment_3, _ek_cohesive, 2, diff --git a/src/io/parser/parser.hh b/src/io/parser/parser.hh index db8584720cdc1b133fad95ab5f5e368bfadf0eac..05681e510cb08e953f9e6343d0ef59ac73d1a6e6 100644 --- a/src/io/parser/parser.hh +++ b/src/io/parser/parser.hh @@ -50,11 +50,13 @@ namespace akantu { (neighborhoods) \ (non_linear_solver) \ (non_local) \ + (clip) \ (rules) \ (solver) \ (time_step_solver) \ (user) \ (weight_function) \ + (distance_function) \ (contact_detector) \ (contact_resolution) \ (not_defined) @@ -82,11 +84,13 @@ enum class ParserType { neighborhoods, non_linear_solver, non_local, + clip, rules, solver, time_step_solver, user, weight_function, + distance_function, not_defined }; #endif diff --git a/src/mesh/mesh.cc b/src/mesh/mesh.cc index 5b8cc6bcec69ec8465f8f42022401752661eb992..267f5ab032ef53731b3845583b41990177c7f0d3 100644 --- a/src/mesh/mesh.cc +++ b/src/mesh/mesh.cc @@ -563,7 +563,7 @@ void Mesh::distributeImpl( this->computeBoundingBox(); - MeshIsDistributedEvent event(AKANTU_CURRENT_FUNCTION); + MeshIsDistributedEvent event(mesh, AKANTU_CURRENT_FUNCTION); this->sendEvent(event); } @@ -621,6 +621,24 @@ void Mesh::fillNodesToElements(Int dimension) { } } +/* -------------------------------------------------------------------------- */ +void Mesh::copyNodes(const Mesh & mesh, std::vector<Idx> nodes) { + + auto && it = make_view(mesh.getNodes(), spatial_dimension).begin(); + + Idx new_node = this->nodes->size() - 1; + + for (auto node : nodes) { + auto && pos = it[node]; + this->nodes->push_back(pos); + this->nodes_flags->push_back(mesh.getNodeFlag(node)); + this->nodes_prank[new_node] = mesh.getNodePrank(node); + ++new_node; + } + + // TODO: need to regenerate global nodes ids and node synchronizer +} + /* -------------------------------------------------------------------------- */ std::tuple<Idx, Idx> Mesh::updateGlobalData(NewNodesEvent & nodes_event, NewElementsEvent & elements_event) { diff --git a/src/mesh/mesh.hh b/src/mesh/mesh.hh index 462081826296b92d5f7a35a3bc479b789b816820..8c03c7c17efdde6938562bff380e68e12f25df83 100644 --- a/src/mesh/mesh.hh +++ b/src/mesh/mesh.hh @@ -258,6 +258,9 @@ public: /// fills the nodes_to_elements for given dimension elements void fillNodesToElements(Int dimension = _all_dimensions); + /// copy the nodes `nodes` from `mesh` to *this + void copyNodes(const Mesh & mesh, std::vector<Idx> nodes); + private: /// update the global ids, nodes type, ... std::tuple<Int, Int> updateGlobalData(NewNodesEvent & nodes_event, @@ -265,6 +268,7 @@ private: void registerGlobalDataUpdater( std::unique_ptr<MeshGlobalDataUpdater> && global_data_updater); + /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ diff --git a/src/mesh/mesh_events.hh b/src/mesh/mesh_events.hh index 4158ff7ebcef6f1b14ff94091bd82341ea67ba9a..67827c74a2019dbdab3e0fd5ed3e5c08b562f37b 100644 --- a/src/mesh/mesh_events.hh +++ b/src/mesh/mesh_events.hh @@ -34,19 +34,24 @@ namespace akantu { /// akantu::MeshEvent is the base event for meshes template <class Entity> class MeshEvent { public: - MeshEvent(const std::string & origin = "") : origin_(origin) {} + MeshEvent(const Mesh & mesh, const std::string & origin = "") + : mesh(mesh), origin_(origin) {} virtual ~MeshEvent() = default; /// Get the list of entity modified by the event nodes or elements - const Array<Entity> & getList() const { return list; } + [[nodiscard]] const Array<Entity> & getList() const { return list; } /// Get the list of entity modified by the event nodes or elements Array<Entity> & getList() { return list; } - std::string origin() const { return origin_; } + [[nodiscard]] const ID & origin() const { return origin_; } + + AKANTU_GET_MACRO_AUTO(Mesh, mesh); protected: Array<Entity> list; + const Mesh & mesh; + private: std::string origin_; }; @@ -56,20 +61,19 @@ class Mesh; /// akantu::MeshEvent related to new nodes in the mesh class NewNodesEvent : public MeshEvent<Idx> { public: - NewNodesEvent(const std::string & origin = "") : MeshEvent(origin) {} - ~NewNodesEvent() override = default; + NewNodesEvent(const Mesh & mesh, const std::string & origin = "") + : MeshEvent(mesh, origin) {} }; /// akantu::MeshEvent related to nodes removed from the mesh class RemovedNodesEvent : public MeshEvent<Idx> { public: - inline RemovedNodesEvent(const Mesh & mesh, const std::string & origin = ""); + RemovedNodesEvent(const Mesh & mesh, const std::string & origin = ""); - ~RemovedNodesEvent() override = default; /// Get the new numbering following suppression of nodes from nodes arrays - AKANTU_GET_MACRO_NOT_CONST(NewNumbering, new_numbering, auto &); + AKANTU_GET_MACRO_AUTO_NOT_CONST(NewNumbering, new_numbering); /// Get the new numbering following suppression of nodes from nodes arrays - AKANTU_GET_MACRO(NewNumbering, new_numbering, const auto &); + AKANTU_GET_MACRO_AUTO(NewNumbering, new_numbering); private: Array<Idx> new_numbering; @@ -78,35 +82,31 @@ private: /// akantu::MeshEvent related to new elements in the mesh class NewElementsEvent : public MeshEvent<Element> { public: - NewElementsEvent(const std::string & origin = "") - : MeshEvent<Element>(origin) {} - ~NewElementsEvent() override = default; + NewElementsEvent(const Mesh & mesh, const std::string & origin = "") + : MeshEvent<Element>(mesh, origin) {} }; /// akantu::MeshEvent related to the case the mesh is made distributed. /// Note that the `list` has no meaning for this event. -class MeshIsDistributedEvent : public MeshEvent<UInt> { +class MeshIsDistributedEvent : public MeshEvent<Idx> { public: - MeshIsDistributedEvent(const std::string & origin = "") - : MeshEvent<UInt>(origin) {} - ~MeshIsDistributedEvent() override = default; + MeshIsDistributedEvent(const Mesh & mesh, const std::string & origin = "") + : MeshEvent<Idx>(mesh, origin) {} }; /// akantu::MeshEvent related to elements removed from the mesh class RemovedElementsEvent : public MeshEvent<Element> { public: - inline RemovedElementsEvent(const Mesh & mesh, - const ID & new_numbering_id = "new_numbering", - const std::string & origin = ""); - - ~RemovedElementsEvent() override = default; + RemovedElementsEvent(const Mesh & mesh, + const ID & new_numbering_id = "new_numbering", + const std::string & origin = ""); /// Get the new numbering following suppression of elements from elements /// arrays - AKANTU_GET_MACRO(NewNumbering, new_numbering, const auto &); + AKANTU_GET_MACRO_AUTO(NewNumbering, new_numbering); /// Get the new numbering following suppression of elements from elements /// arrays - AKANTU_GET_MACRO_NOT_CONST(NewNumbering, new_numbering, auto &); + AKANTU_GET_MACRO_AUTO_NOT_CONST(NewNumbering, new_numbering); /// Get the new numbering following suppression of elements from elements /// arrays AKANTU_GET_MACRO_BY_ELEMENT_TYPE(NewNumbering, new_numbering, Idx); @@ -128,11 +128,11 @@ public: const std::string & origin = "") : RemovedElementsEvent(mesh, new_numbering_id, origin) {} - ~ChangedElementsEvent() override = default; - AKANTU_GET_MACRO(ListOld, list, const Array<Element> &); - AKANTU_GET_MACRO_NOT_CONST(ListOld, list, Array<Element> &); - AKANTU_GET_MACRO(ListNew, new_list, const Array<Element> &); - AKANTU_GET_MACRO_NOT_CONST(ListNew, new_list, Array<Element> &); + AKANTU_GET_MACRO_AUTO(ListOld, list); + AKANTU_GET_MACRO_AUTO(ListNew, new_list); + + AKANTU_GET_MACRO_AUTO_NOT_CONST(ListOld, list); + AKANTU_GET_MACRO_AUTO_NOT_CONST(ListNew, new_list); protected: Array<Element> new_list; diff --git a/src/mesh/mesh_inline_impl.hh b/src/mesh/mesh_inline_impl.hh index 2ea6d6fbedfddd6c6b46f69456b512c4ac0ef8c7..e12b743ddcb7415effeb9dd946b30ef3e23f1045 100644 --- a/src/mesh/mesh_inline_impl.hh +++ b/src/mesh/mesh_inline_impl.hh @@ -59,14 +59,14 @@ inline decltype(auto) Mesh::getConnectivity(const Element & element) const { /* -------------------------------------------------------------------------- */ inline RemovedNodesEvent::RemovedNodesEvent(const Mesh & mesh, const std::string & origin) - : MeshEvent<Idx>(origin), + : MeshEvent<Idx>(mesh, origin), new_numbering(mesh.getNbNodes(), 1, "new_numbering") {} /* -------------------------------------------------------------------------- */ inline RemovedElementsEvent::RemovedElementsEvent(const Mesh & mesh, const ID & new_numbering_id, const std::string & origin) - : MeshEvent<Element>(origin), + : MeshEvent<Element>(mesh, origin), new_numbering(new_numbering_id, mesh.getID()) {} /* -------------------------------------------------------------------------- */ diff --git a/src/mesh/mesh_periodic.cc b/src/mesh/mesh_periodic.cc index 16cecb26488a737a1cf7a7c494851a6311c8dae2..1429e66f3b23c89acbd3ccfdbc17bcdc51878b33 100644 --- a/src/mesh/mesh_periodic.cc +++ b/src/mesh/mesh_periodic.cc @@ -136,7 +136,7 @@ void Mesh::makePeriodic(const SpatialDirection & direction, std::vector<Idx> new_nodes; if (is_distributed) { - NewNodesEvent event(AKANTU_CURRENT_FUNCTION); + NewNodesEvent event(mesh, AKANTU_CURRENT_FUNCTION); /* ---------------------------------------------------------------------- */ // function to send nodes in bboxes intersections @@ -203,8 +203,8 @@ void Mesh::makePeriodic(const SpatialDirection & direction, while (not buffer.empty()) { Vector<Real> pos(spatial_dimension); - Idx global_node; - NodeFlag flag; + Idx global_node{}; + NodeFlag flag{}; buffer >> global_node; buffer >> pos; buffer >> flag; @@ -214,7 +214,7 @@ void Mesh::makePeriodic(const SpatialDirection & direction, // get the master info of is slave if (flag == NodeFlag::_periodic_slave) { - Idx master_node; + Idx master_node{}; buffer >> master_node; // std::cout << " slave of " << master_node << std::endl; // auto local_master_node = getNodeLocalId(master_node); @@ -224,11 +224,11 @@ void Mesh::makePeriodic(const SpatialDirection & direction, // get the list of slaves if is master if ((flag & NodeFlag::_periodic_mask) == NodeFlag::_periodic_master) { - Int nb_slaves; + Int nb_slaves{}; buffer >> nb_slaves; // std::cout << " master of " << nb_slaves << " nodes : ["; for (auto ns [[gnu::unused]] : arange(nb_slaves)) { - Idx gslave_node; + Idx gslave_node{}; buffer >> gslave_node; // std::cout << (ns == 0 ? "" : ", ") << gslave_node; // auto lslave_node = getNodeLocalId(gslave_node); diff --git a/src/mesh_utils/cohesive_element_inserter.cc b/src/mesh_utils/cohesive_element_inserter.cc index 36ad226cb802cd638a6304319919d62d2d2fdc6d..8c687334e9993ebe485d9b2b6167233e732ec36f 100644 --- a/src/mesh_utils/cohesive_element_inserter.cc +++ b/src/mesh_utils/cohesive_element_inserter.cc @@ -226,8 +226,8 @@ void CohesiveElementInserter::limitCheckFacets( /* -------------------------------------------------------------------------- */ UInt CohesiveElementInserter::insertElements(bool only_double_facets) { - CohesiveNewNodesEvent node_event(AKANTU_CURRENT_FUNCTION); - NewElementsEvent element_event(AKANTU_CURRENT_FUNCTION); + CohesiveNewNodesEvent node_event(mesh, AKANTU_CURRENT_FUNCTION); + NewElementsEvent element_event(mesh, AKANTU_CURRENT_FUNCTION); if (mesh_facets.isDistributed()) { mesh_facets.getElementSynchronizer().synchronizeOnce( diff --git a/src/mesh_utils/cohesive_element_inserter.hh b/src/mesh_utils/cohesive_element_inserter.hh index ce0cb29b4a26836f09a3f6ed19a81fdedaa64a76..03de522945227ddedcfa42a818255937cf1e6a5b 100644 --- a/src/mesh_utils/cohesive_element_inserter.hh +++ b/src/mesh_utils/cohesive_element_inserter.hh @@ -82,7 +82,7 @@ protected: /// functions for parallel communications inline Int getNbData(const Array<Element> & elements, - const SynchronizationTag & tag) const override; + const SynchronizationTag & tag) const override; inline void packData(CommunicationBuffer & buffer, const Array<Element> & elements, @@ -151,8 +151,8 @@ private: class CohesiveNewNodesEvent : public NewNodesEvent { public: - CohesiveNewNodesEvent(const std::string & origin) : NewNodesEvent(origin) {} - ~CohesiveNewNodesEvent() override = default; + CohesiveNewNodesEvent(const Mesh & mesh, const std::string & origin) + : NewNodesEvent(mesh, origin) {} AKANTU_GET_MACRO_NOT_CONST(OldNodesList, old_nodes, Array<Idx> &); AKANTU_GET_MACRO(OldNodesList, old_nodes, const Array<Idx> &); diff --git a/src/mesh_utils/cohesive_element_inserter_helper.cc b/src/mesh_utils/cohesive_element_inserter_helper.cc index 43a3bdd75576a4de7380e2e31104614d2c5898b7..ccb87d3d1191c52039ae21eb7d8f71641cabd6ff 100644 --- a/src/mesh_utils/cohesive_element_inserter_helper.cc +++ b/src/mesh_utils/cohesive_element_inserter_helper.cc @@ -431,7 +431,7 @@ Int CohesiveElementInserterHelper::insertFacetsOnly() { /* -------------------------------------------------------------------------- */ template <Int dim> void CohesiveElementInserterHelper::doubleFacets() { AKANTU_DEBUG_IN(); - NewElementsEvent new_facets; + NewElementsEvent new_facets(mesh); auto spatial_dimension = mesh_facets.getSpatialDimension(); auto & facets_to_double = *facets_to_double_by_dim[dim]; @@ -798,7 +798,7 @@ void CohesiveElementInserterHelper::doublePointFacet() { return; } - NewElementsEvent new_facets_event; + NewElementsEvent new_facets_event(mesh); auto & facets_to_double = *facets_to_double_by_dim[spatial_dimension - 1]; const auto & element_to_facet = mesh_facets.getElementToSubelement(); @@ -852,7 +852,7 @@ void CohesiveElementInserterHelper::doubleSubfacet() { return; } - NewElementsEvent new_facets_event; + NewElementsEvent new_facets_event(mesh); std::vector<Idx> nodes_to_double; MeshAccessor mesh_accessor(mesh_facets); diff --git a/src/mesh_utils/mesh_utils.cc b/src/mesh_utils/mesh_utils.cc index 0d7ccaa563e00d2949cfddfe3d52114bc71b3882..2c1b4ed58667899a68059ff4ef53b5d7a8988c5c 100644 --- a/src/mesh_utils/mesh_utils.cc +++ b/src/mesh_utils/mesh_utils.cc @@ -206,7 +206,7 @@ void MeshUtils::buildFacetsDimension(const Mesh & mesh, Mesh & mesh_facets, Array<Int> counter; std::vector<Element> connected_elements; - NewElementsEvent event(AKANTU_CURRENT_FUNCTION); + NewElementsEvent event(mesh, AKANTU_CURRENT_FUNCTION); // init the SubelementToElement data to improve performance for (auto && ghost_type : ghost_types) { diff --git a/src/model/common/boundary_condition/boundary_condition.hh b/src/model/common/boundary_condition/boundary_condition.hh index 69205decd8cb3c12b0929bdbb42d0ec852538d1a..3229150184f6300e04b1823a8c33585a2eef9b26 100644 --- a/src/model/common/boundary_condition/boundary_condition.hh +++ b/src/model/common/boundary_condition/boundary_condition.hh @@ -40,7 +40,7 @@ private: /* Constructors / Destructors / Initializers */ /* ------------------------------------------------------------------------ */ public: - BoundaryCondition() : model(nullptr) {} + BoundaryCondition(const ID & dof_name) : model(nullptr), dof_name(dof_name) {} /// Initialize the boundary conditions void initBC(ModelType & model, Array<Real> & primal, Array<Real> & dual); void initBC(ModelType & model, Array<Real> & primal, @@ -73,6 +73,8 @@ public: private: ModelType * model; + ID dof_name; + Array<Real> * primal{nullptr}; Array<Real> * dual{nullptr}; Array<Real> * primal_increment{nullptr}; diff --git a/src/model/common/boundary_condition/boundary_condition_tmpl.hh b/src/model/common/boundary_condition/boundary_condition_tmpl.hh index 3fd02e64a8e7a0de2593c8a14c20dff8925ba43b..070191b10ab0c2353a5bef8668785225cd7fb339 100644 --- a/src/model/common/boundary_condition/boundary_condition_tmpl.hh +++ b/src/model/common/boundary_condition/boundary_condition_tmpl.hh @@ -166,7 +166,8 @@ struct BoundaryCondition<ModelType>::TemplateFunctionWrapper< // assemble the result into force vector model.getDOFManager().assembleElementalArrayLocalArray( - dual_by_shapes_integ, dual, type, ghost_type, 1., element_ids); + bc_instance.dof_name, dual_by_shapes_integ, dual, type, ghost_type, + 1., element_ids); } } }; diff --git a/src/model/common/dof_manager/dof_manager.cc b/src/model/common/dof_manager/dof_manager.cc index d5a47ba38b6ef0e1f27eb3caa56ad5db74122375..e956111094a6c0b97815c63d4112e06865dbfb78 100644 --- a/src/model/common/dof_manager/dof_manager.cc +++ b/src/model/common/dof_manager/dof_manager.cc @@ -40,17 +40,6 @@ DOFManager::DOFManager(const ID & id) global_equation_number(0, 1, "global_equation_number"), communicator(Communicator::getStaticCommunicator()) {} -/* -------------------------------------------------------------------------- */ -DOFManager::DOFManager(Mesh & mesh, const ID & id) - : id(id), mesh(&mesh), dofs_flag(0, 1, std::string(id + ":dofs_type")), - global_equation_number(0, 1, "global_equation_number"), - communicator(mesh.getCommunicator()) { - this->mesh->registerEventHandler(*this, _ehp_dof_manager); -} - -/* -------------------------------------------------------------------------- */ -DOFManager::~DOFManager() = default; - /* -------------------------------------------------------------------------- */ std::vector<ID> DOFManager::getDOFIDs() const { std::vector<ID> keys; @@ -63,57 +52,50 @@ std::vector<ID> DOFManager::getDOFIDs() const { /* -------------------------------------------------------------------------- */ void DOFManager::assembleElementalArrayLocalArray( - const Array<Real> & elementary_vect, Array<Real> & array_assembeled, - ElementType type, GhostType ghost_type, Real scale_factor, - const Array<Int> & filter_elements) { + const ID & dof_id, const Array<Real> & elementary_vect, + Array<Real> & array_assembeled, ElementType type, GhostType ghost_type, + Real scale_factor, const Array<Int> & filter_elements) { AKANTU_DEBUG_IN(); + auto & dof_data = this->getDOFData(dof_id); - Int nb_element; - auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); + auto && connectivity = dof_data.mesh->getConnectivity(type, ghost_type); + + auto nb_nodes_per_element = connectivity.getNbComponent(); auto nb_degree_of_freedom = elementary_vect.getNbComponent() / nb_nodes_per_element; - const Idx * filter_it = nullptr; - if (filter_elements != empty_filter) { - nb_element = filter_elements.size(); - filter_it = filter_elements.data(); - } else { - nb_element = this->mesh->getNbElement(type, ghost_type); - } - - AKANTU_DEBUG_ASSERT(elementary_vect.size() == nb_element, + AKANTU_DEBUG_ASSERT((filter_elements != empty_filter and + elementary_vect.size() == filter_elements.size()) or + (elementary_vect.size() == connectivity.size()), "The vector elementary_vect(" << elementary_vect.getID() << ") has not the good size."); - const auto & connectivity = this->mesh->getConnectivity(type, ghost_type); - - auto elem_it = - make_view(elementary_vect, nb_degree_of_freedom, nb_nodes_per_element) - .begin(); auto assemble_it = make_view(array_assembeled, nb_degree_of_freedom).begin(); - for (Int el = 0; el < nb_element; ++el, ++elem_it) { - auto element = el; - if (filter_it != nullptr) { - - element = *filter_it; - } - - // const Vector<UInt> & conn = *conn_it; - const auto & elemental_val = *elem_it; - for (Int n = 0; n < nb_nodes_per_element; ++n) { - auto node = connectivity(element, n); - + auto per_element_assemble = [&assemble_it, scale_factor](auto & conn, + auto & vals) { + for (auto && [node, val] : zip(conn, vals)) { auto && assemble = assemble_it[node]; - assemble += scale_factor * elemental_val(n); + assemble += scale_factor * val; } + }; - if (filter_it != nullptr) { - ++filter_it; + if (filter_elements != empty_filter) { + for (auto && [conn, vals] : + zip(filter(filter_elements, + make_view(connectivity, nb_nodes_per_element)), + make_view(elementary_vect, nb_degree_of_freedom, + nb_nodes_per_element))) { + per_element_assemble(conn, vals); + } + } else { + for (auto && [conn, vals] : + zip(make_view(connectivity, nb_nodes_per_element), + make_view(elementary_vect, nb_degree_of_freedom, + nb_nodes_per_element))) { + per_element_assemble(conn, vals); } - // else - // ++conn_it; } AKANTU_DEBUG_OUT(); @@ -125,18 +107,22 @@ void DOFManager::assembleElementalArrayToResidual( GhostType ghost_type, Real scale_factor, const Array<Int> & filter_elements) { AKANTU_DEBUG_IN(); + auto & dof_data = this->getDOFData(dof_id); + + auto && connectivity = dof_data.mesh->getConnectivity(type, ghost_type); - auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); + // auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); + auto nb_nodes_per_element = connectivity.getNbComponent(); auto nb_degree_of_freedom = elementary_vect.getNbComponent() / nb_nodes_per_element; - Array<Real> array_localy_assembeled(this->mesh->getNbNodes(), - nb_degree_of_freedom); + Array<Real> array_localy_assembeled(dof_data.dof->size(), + nb_degree_of_freedom); array_localy_assembeled.zero(); this->assembleElementalArrayLocalArray( - elementary_vect, array_localy_assembeled, type, ghost_type, scale_factor, - filter_elements); + dof_id, elementary_vect, array_localy_assembeled, type, ghost_type, + scale_factor, filter_elements); this->assembleToResidual(dof_id, array_localy_assembeled, 1); @@ -149,24 +135,39 @@ void DOFManager::assembleElementalArrayToLumpedMatrix( const ID & lumped_mtx, ElementType type, GhostType ghost_type, Real scale_factor, const Array<Int> & filter_elements) { AKANTU_DEBUG_IN(); + auto & dof_data = this->getDOFData(dof_id); - auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); + auto && connectivity = dof_data.mesh->getConnectivity(type, ghost_type); + + auto nb_nodes_per_element = connectivity.getNbComponent(); auto nb_degree_of_freedom = elementary_vect.getNbComponent() / nb_nodes_per_element; - Array<Real> array_localy_assembeled(this->mesh->getNbNodes(), + + Array<Real> array_localy_assembeled(dof_data.dof->size(), nb_degree_of_freedom); array_localy_assembeled.zero(); this->assembleElementalArrayLocalArray( - elementary_vect, array_localy_assembeled, type, ghost_type, scale_factor, - filter_elements); + dof_id, elementary_vect, array_localy_assembeled, type, ghost_type, + scale_factor, filter_elements); this->assembleToLumpedMatrix(dof_id, array_localy_assembeled, lumped_mtx, 1); AKANTU_DEBUG_OUT(); } +/* -------------------------------------------------------------------------- */ +void DOFManager::assembleElementalMatricesToMatrix( + const ID & matrix_id, const ID & dof_id, const Array<Real> & elementary_mat, + ElementType type, GhostType ghost_type, + const MatrixType & elemental_matrix_type, + const Array<Int> & filter_elements) { + assembleElementalMatricesToMatrix(matrix_id, dof_id, elementary_mat, type, + ghost_type, elemental_matrix_type, + filter_elements); +} + /* -------------------------------------------------------------------------- */ void DOFManager::assembleMatMulDOFsToResidual(const ID & A_id, Real scale_factor) { @@ -241,29 +242,50 @@ DOFManager::DOFData::DOFData(const ID & dof_id) associated_nodes(0, 1, dof_id + "associated_nodes") {} /* -------------------------------------------------------------------------- */ -DOFManager::DOFData::~DOFData() = default; +void DOFManager::DOFData::onNodesAdded(const Array<Idx> & nodes_list, + const NewNodesEvent & event) { + if (this->mesh != nullptr and this->mesh != &(event.getMesh())) { + return; + } + + const auto & group = group_support; + + if (group == "__mesh__") { + dof_manager->updateNodalDOFs(dof_id, nodes_list); + } else { + const auto & node_group = this->mesh->getElementGroup(group).getNodeGroup(); + Array<Idx> new_nodes_list; + for (const auto & node : nodes_list) { + if (node_group.find(node) != Int(-1)) { + new_nodes_list.push_back(node); + } + } + + dof_manager->updateNodalDOFs(dof_id, new_nodes_list); + } +} /* -------------------------------------------------------------------------- */ template <typename Func> -auto DOFManager::countDOFsForNodes(const DOFData & dof_data, Int nb_nodes, - Func && getNode) { +auto DOFManager::DOFData::countDOFsForNodes(Int nb_nodes, + Func && get_node) const { auto nb_local_dofs = nb_nodes; decltype(nb_local_dofs) nb_pure_local = 0; for (auto n : arange(nb_nodes)) { - UInt node = getNode(n); + auto node = get_node(n); // http://www.open-std.org/jtc1/sc22/open/n2356/conv.html // bool are by convention casted to 0 and 1 when promoted to int - nb_pure_local += this->mesh->isLocalOrMasterNode(node); - nb_local_dofs -= this->mesh->isPeriodicSlave(node); + nb_pure_local += mesh->isLocalOrMasterNode(node); + nb_local_dofs -= mesh->isPeriodicSlave(node); } - const auto & dofs_array = *dof_data.dof; - nb_pure_local *= dofs_array.getNbComponent(); - nb_local_dofs *= dofs_array.getNbComponent(); + nb_pure_local *= dof->getNbComponent(); + nb_local_dofs *= dof->getNbComponent(); return std::make_pair(nb_local_dofs, nb_pure_local); } +/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ auto DOFManager::getNewDOFDataInternal(const ID & dof_id) -> DOFData & { auto it = this->dofs.find(dof_id); @@ -275,15 +297,21 @@ auto DOFManager::getNewDOFDataInternal(const ID & dof_id) -> DOFData & { DOFData & dof_data = *dof_data_ptr; this->dofs[dof_id] = std::move(dof_data_ptr); + + dof_data.dof_manager = this; + dof_data.dof_id = dof_id; + return dof_data; } /* -------------------------------------------------------------------------- */ void DOFManager::registerDOFs(const ID & dof_id, Array<Real> & dofs_array, DOFSupportType support_type) { + AKANTU_DEBUG_ASSERT(support_type != _dst_nodal, + "Nodal DOFs need to be registered with a mesh"); + auto & dofs_storage = this->getNewDOFDataInternal(dof_id); dofs_storage.support_type = support_type; - this->registerDOFsInternal(dof_id, dofs_array); resizeGlobalArrays(); @@ -291,10 +319,17 @@ void DOFManager::registerDOFs(const ID & dof_id, Array<Real> & dofs_array, /* -------------------------------------------------------------------------- */ void DOFManager::registerDOFs(const ID & dof_id, Array<Real> & dofs_array, - const ID & support_group) { + Mesh & mesh, const ID & support_group) { auto & dofs_storage = this->getNewDOFDataInternal(dof_id); dofs_storage.support_type = _dst_nodal; dofs_storage.group_support = support_group; + dofs_storage.mesh = &mesh; + + if (registered_meshes.find(&mesh) == registered_meshes.end()) { + mesh.registerEventHandler(*this, _ehp_dof_manager); + registered_meshes.insert(&mesh); + } + mesh.registerEventHandler(dofs_storage, _ehp_dof_data); this->registerDOFsInternal(dof_id, dofs_array); @@ -319,22 +354,22 @@ DOFManager::registerDOFsInternal(const ID & dof_id, Array<Real> & dofs_array) { std::function<Idx(Idx)> getNode; if (group == "__mesh__") { AKANTU_DEBUG_ASSERT( - dofs_array.size() == this->mesh->getNbNodes(), + dofs_array.size() == dof_data.mesh->getNbNodes(), "The array of dof is too short to be associated to nodes."); - std::tie(nb_local_dofs, nb_pure_local) = countDOFsForNodes( - dof_data, this->mesh->getNbNodes(), [](auto && n) { return n; }); + std::tie(nb_local_dofs, nb_pure_local) = dof_data.countDOFsForNodes( + dof_data.mesh->getNbNodes(), [](auto && n) { return n; }); } else { const auto & node_group = - this->mesh->getElementGroup(group).getNodeGroup().getNodes(); + dof_data.mesh->getElementGroup(group).getNodeGroup().getNodes(); AKANTU_DEBUG_ASSERT( dofs_array.size() == node_group.size(), - "The array of dof is too shot to be associated to nodes."); + "The array of dof is too short to be associated to nodes."); - std::tie(nb_local_dofs, nb_pure_local) = - countDOFsForNodes(dof_data, node_group.size(), - [&node_group](auto && n) { return node_group(n); }); + std::tie(nb_local_dofs, nb_pure_local) = dof_data.countDOFsForNodes( + node_group.size(), + [&node_group](auto && n) { return node_group(n); }); } break; @@ -367,13 +402,13 @@ DOFManager::registerDOFsInternal(const ID & dof_id, Array<Real> & dofs_array) { const auto & group = dof_data.group_support; if (group != "__mesh__") { auto & support_nodes = - this->mesh->getElementGroup(group).getNodeGroup().getNodes(); + dof_data.mesh->getElementGroup(group).getNodeGroup().getNodes(); this->updateDOFsData( dof_data, nb_local_dofs, nb_pure_local, support_nodes.size(), [&support_nodes](Idx node) -> Idx { return support_nodes[node]; }); } else { this->updateDOFsData(dof_data, nb_local_dofs, nb_pure_local, - mesh->getNbNodes(), + dof_data.mesh->getNbNodes(), [](Idx node) -> Idx { return node; }); } break; @@ -624,11 +659,9 @@ void DOFManager::zeroLumpedMatrix(const ID & mtx) { std::pair<Int, Int> DOFManager::updateNodalDOFs(const ID & dof_id, const Array<Idx> & nodes_list) { auto & dof_data = this->getDOFData(dof_id); - Int nb_new_local_dofs, nb_new_pure_local; - std::tie(nb_new_local_dofs, nb_new_pure_local) = - countDOFsForNodes(dof_data, nodes_list.size(), - [&nodes_list](auto && n) { return nodes_list(n); }); + auto && [nb_new_local_dofs, nb_new_pure_local] = dof_data.countDOFsForNodes( + nodes_list.size(), [&nodes_list](auto && n) { return nodes_list(n); }); this->pure_local_system_size += nb_new_pure_local; this->local_system_size += nb_new_local_dofs; @@ -664,42 +697,21 @@ void DOFManager::resizeGlobalArrays() { } /* -------------------------------------------------------------------------- */ -void DOFManager::onNodesAdded(const Array<Idx> & nodes_list, - const NewNodesEvent &) { - for (auto & pair : this->dofs) { - const auto & dof_id = pair.first; - auto & dof_data = this->getDOFData(dof_id); - if (dof_data.support_type != _dst_nodal) { - continue; - } - - const auto & group = dof_data.group_support; - - if (group == "__mesh__") { - this->updateNodalDOFs(dof_id, nodes_list); - } else { - const auto & node_group = - this->mesh->getElementGroup(group).getNodeGroup(); - Array<Idx> new_nodes_list; - for (const auto & node : nodes_list) { - if (node_group.find(node) != Int(-1)) { - new_nodes_list.push_back(node); - } - } - - this->updateNodalDOFs(dof_id, new_nodes_list); - } - } - +void DOFManager::onNodesAdded(const Array<Idx> & /*nodes_list*/, + const NewNodesEvent & /*event*/) { this->resizeGlobalArrays(); } /* -------------------------------------------------------------------------- */ -void DOFManager::onMeshIsDistributed(const MeshIsDistributedEvent & /*event*/) { - AKANTU_DEBUG_ASSERT(this->mesh != nullptr, "The `Mesh` pointer is not set."); +void DOFManager::onMeshIsDistributed(const MeshIsDistributedEvent & event) { + const Mesh * mesh = &event.getMesh(); + + AKANTU_DEBUG_ASSERT(this->registered_meshes.find(mesh) != + this->registered_meshes.end(), + "The `Mesh` pointer is not set."); // check if the distributed state of the residual and the mesh are the same. - if (this->mesh->isDistributed() != this->residual->isDistributed()) { + if (mesh->isDistributed() != this->residual->isDistributed()) { // TODO: Allow to reallocate the internals, in that case one could actually // react on that event. auto is_or_is_not = [](bool q) { @@ -708,7 +720,7 @@ void DOFManager::onMeshIsDistributed(const MeshIsDistributedEvent & /*event*/) { AKANTU_EXCEPTION("There is an inconsistency about the distribution state " "of the `DOFManager`." " It seams that the `Mesh` " - << is_or_is_not(this->mesh->isDistributed()) + << is_or_is_not(mesh->isDistributed()) << " distributed, but the `DOFManager`'s residual " << is_or_is_not(this->residual->isDistributed()) << ", which is of type " @@ -723,11 +735,8 @@ public: GlobalDOFInfoDataAccessor(DOFManager::DOFData & dof_data, DOFManager & dof_manager) : dof_data(dof_data), dof_manager(dof_manager) { - for (auto && pair : + for (auto && [dof, node] : zip(dof_data.local_equation_number, dof_data.associated_nodes)) { - Idx node; - Idx dof; - std::tie(dof, node) = pair; dofs_per_node[node].push_back(dof); } @@ -806,7 +815,7 @@ auto DOFManager::computeFirstDOFIDs(Int nb_new_local_dofs, /* -------------------------------------------------------------------------- */ void DOFManager::updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs, Int nb_new_pure_local, Int nb_node, - const std::function<Idx(Idx)> & getNode) { + const std::function<Idx(Idx)> & get_node) { auto nb_local_dofs_added = nb_node * dof_data.dof->getNbComponent(); auto first_dof_pos = dof_data.local_equation_number.size(); @@ -821,17 +830,17 @@ void DOFManager::updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs, std::unordered_map<std::pair<Idx, Idx>, Idx> masters_dofs; // update per dof info - Int local_eq_num, first_global_dof_id; - std::tie(local_eq_num, first_global_dof_id) = + auto && [local_eq_num, first_global_dof_id] = computeFirstDOFIDs(nb_new_local_dofs, nb_new_pure_local); + for (auto d : arange(nb_local_dofs_added)) { - auto node = getNode(d / dof_data.dof->getNbComponent()); - auto dof_flag = this->mesh->getNodeFlag(node); + auto node = get_node(d / dof_data.dof->getNbComponent()); + auto dof_flag = dof_data.mesh->getNodeFlag(node); dof_data.associated_nodes.push_back(node); - auto is_local_dof = this->mesh->isLocalOrMasterNode(node); - auto is_periodic_slave = this->mesh->isPeriodicSlave(node); - auto is_periodic_master = this->mesh->isPeriodicMaster(node); + auto is_local_dof = dof_data.mesh->isLocalOrMasterNode(node); + auto is_periodic_slave = dof_data.mesh->isPeriodicSlave(node); + auto is_periodic_master = dof_data.mesh->isPeriodicMaster(node); if (is_periodic_slave) { dof_data.local_equation_number.push_back(-1); @@ -851,7 +860,7 @@ void DOFManager::updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs, } if (is_periodic_master) { - auto node = getNode(d / dof_data.dof->getNbComponent()); + auto node = get_node(d / dof_data.dof->getNbComponent()); auto dof = d % dof_data.dof->getNbComponent(); masters_dofs.insert( std::make_pair(std::make_pair(node, dof), local_eq_num)); @@ -861,15 +870,15 @@ void DOFManager::updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs, } // correct periodic slave equation numbers - if (this->mesh->isPeriodic()) { + if (dof_data.mesh->isPeriodic()) { auto assoc_begin = dof_data.associated_nodes.begin(); for (auto d : arange(nb_local_dofs_added)) { auto node = dof_data.associated_nodes(first_dof_pos + d); - if (not this->mesh->isPeriodicSlave(node)) { + if (not dof_data.mesh->isPeriodicSlave(node)) { continue; } - auto master_node = this->mesh->getPeriodicMaster(node); + auto master_node = dof_data.mesh->getPeriodicMaster(node); auto dof = d % dof_data.dof->getNbComponent(); dof_data.local_equation_number(first_dof_pos + d) = masters_dofs[std::make_pair(master_node, dof)]; @@ -877,15 +886,15 @@ void DOFManager::updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs, } // synchronize the global numbering for slaves nodes - if (this->mesh->isDistributed()) { + if (dof_data.mesh->isDistributed()) { GlobalDOFInfoDataAccessor data_accessor(dof_data, *this); - if (this->mesh->isPeriodic()) { - mesh->getPeriodicNodeSynchronizer().synchronizeOnce( + if (dof_data.mesh->isPeriodic()) { + dof_data.mesh->getPeriodicNodeSynchronizer().synchronizeOnce( data_accessor, SynchronizationTag::_giu_global_conn); } - auto & node_synchronizer = this->mesh->getNodeSynchronizer(); + auto & node_synchronizer = dof_data.mesh->getNodeSynchronizer(); node_synchronizer.synchronizeOnce(data_accessor, SynchronizationTag::_ask_nodes); } @@ -897,8 +906,7 @@ void DOFManager::updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs, dof_data.local_equation_number.reserve(dof_data.local_equation_number.size() + nb_new_local_dofs); - Int first_local_dof_id, first_global_dof_id; - std::tie(first_local_dof_id, first_global_dof_id) = + auto [first_local_dof_id, first_global_dof_id] = computeFirstDOFIDs(nb_new_local_dofs, nb_new_pure_local); this->dofs_flag.resize(this->local_system_size, NodeFlag::_normal); @@ -919,25 +927,6 @@ void DOFManager::updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs, } } -/* -------------------------------------------------------------------------- */ -void DOFManager::onNodesRemoved(const Array<Idx> &, const Array<Idx> &, - const RemovedNodesEvent &) {} - -/* -------------------------------------------------------------------------- */ -void DOFManager::onElementsAdded(const Array<Element> & /*unused*/, - const NewElementsEvent & /*unused*/) {} - -/* -------------------------------------------------------------------------- */ -void DOFManager::onElementsRemoved(const Array<Element> &, - const ElementTypeMapArray<Idx> &, - const RemovedElementsEvent &) {} - -/* -------------------------------------------------------------------------- */ -void DOFManager::onElementsChanged(const Array<Element> &, - const Array<Element> &, - const ElementTypeMapArray<Idx> &, - const ChangedElementsEvent &) {} - /* -------------------------------------------------------------------------- */ void DOFManager::updateGlobalBlockedDofs() { this->previous_global_blocked_dofs.copy(this->global_blocked_dofs); diff --git a/src/model/common/dof_manager/dof_manager.hh b/src/model/common/dof_manager/dof_manager.hh index 8b14df5cc45bfacd43181bdc50e83b1398702478..a715dba6a95c7a75bbba15b05a3f27c9a575aa3d 100644 --- a/src/model/common/dof_manager/dof_manager.hh +++ b/src/model/common/dof_manager/dof_manager.hh @@ -21,6 +21,8 @@ /* -------------------------------------------------------------------------- */ #include "aka_factory.hh" #include "mesh.hh" +#include "non_linear_solver.hh" +#include "time_step_solver.hh" /* -------------------------------------------------------------------------- */ #include <map> #include <set> @@ -49,8 +51,7 @@ protected: public: DOFManager(const ID & id = "dof_manager"); - DOFManager(Mesh & mesh, const ID & id = "dof_manager"); - ~DOFManager() override; + ~DOFManager() = default; /* ------------------------------------------------------------------------ */ /* Methods */ @@ -63,7 +64,7 @@ public: /// the dof as an implied type of _dst_nodal and is defined only on a subset /// of nodes virtual void registerDOFs(const ID & dof_id, Array<Real> & dofs_array, - const ID & support_group); + Mesh & mesh, const ID & support_group = "__mesh__"); /// register an array of previous values of the degree of freedom virtual void registerDOFsPrevious(const ID & dof_id, @@ -99,8 +100,9 @@ public: * With 0 < n < nb_nodes_per_element and 0 < d < nb_dof_per_node **/ virtual void assembleElementalArrayLocalArray( - const Array<Real> & elementary_vect, Array<Real> & array_assembeled, - ElementType type, GhostType ghost_type, Real scale_factor = 1., + const ID & dof_id, const Array<Real> & elementary_vect, + Array<Real> & array_assembeled, ElementType type, GhostType ghost_type, + Real scale_factor = 1., const Array<Int> & filter_elements = empty_filter); /** @@ -133,7 +135,7 @@ public: const Array<Real> & elementary_mat, ElementType type, GhostType ghost_type = _not_ghost, const MatrixType & elemental_matrix_type = _symmetric, - const Array<Int> & filter_elements = empty_filter) = 0; + const Array<Int> & filter_elements = empty_filter); /// multiply a vector by a matrix and assemble the result to the residual virtual void assembleMatMulVectToArray(const ID & dof_id, const ID & A_id, @@ -469,12 +471,7 @@ public: bool hasTimeStepSolver(const ID & solver_id) const; /* ------------------------------------------------------------------------ */ - const Mesh & getMesh() { - if (mesh != nullptr) { - return *mesh; - } - AKANTU_EXCEPTION("No mesh registered in this dof manager"); - } + const Mesh & getMesh(const ID & dof_id) const; /* ------------------------------------------------------------------------ */ AKANTU_GET_MACRO_AUTO(Communicator, communicator); @@ -496,10 +493,6 @@ protected: virtual std::pair<Int, Int> updateNodalDOFs(const ID & dof_id, const Array<Idx> & nodes_list); - template <typename Func> - auto countDOFsForNodes(const DOFData & dof_data, Int nb_nodes, - Func && getNode); - void updateDOFsData(DOFData & dof_data, Int nb_new_local_dofs, Int nb_new_pure_local, Int nb_nodes, const std::function<Idx(Idx)> & getNode); @@ -513,30 +506,6 @@ protected: /// cleaning matrices profiles virtual void resizeGlobalArrays(); -public: - /// function to implement to react on akantu::NewNodesEvent - void onNodesAdded(const Array<Idx> & nodes_list, - const NewNodesEvent & event) override; - /// function to implement to react on akantu::RemovedNodesEvent - void onNodesRemoved(const Array<Idx> & nodes_list, - const Array<Idx> & new_numbering, - const RemovedNodesEvent & event) override; - /// function to implement to react on akantu::NewElementsEvent - void onElementsAdded(const Array<Element> & elements_list, - const NewElementsEvent & event) override; - /// function to implement to react on akantu::RemovedElementsEvent - void onElementsRemoved(const Array<Element> & elements_list, - const ElementTypeMapArray<Idx> & new_numbering, - const RemovedElementsEvent & event) override; - /// function to implement to react on akantu::ChangedElementsEvent - void onElementsChanged(const Array<Element> & old_elements_list, - const Array<Element> & new_elements_list, - const ElementTypeMapArray<Idx> & new_numbering, - const ChangedElementsEvent & event) override; - - /// function to implement to react on akantu::MeshIsDistributedEvent - void onMeshIsDistributed(const MeshIsDistributedEvent & event) override; - protected: inline DOFData & getDOFData(const ID & dof_id); inline const DOFData & getDOFData(const ID & dof_id) const; @@ -547,16 +516,36 @@ protected: virtual std::unique_ptr<DOFData> getNewDOFData(const ID & dof_id) = 0; +public: + /// function to implement to react on akantu::NewNodesEvent + void onNodesAdded(const Array<Idx> & nodes_list, + const NewNodesEvent & event) override; + + /// function to implement to react on akantu::MeshIsDistributedEvent + void onMeshIsDistributed(const MeshIsDistributedEvent & event) override; + /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// dof representations in the dof manager - struct DOFData { + struct DOFData : public MeshEventHandler { DOFData() = delete; explicit DOFData(const ID & dof_id); - virtual ~DOFData(); + template <typename Func> + [[nodiscard]] auto countDOFsForNodes(Int nb_nodes, Func && get_node) const; + + virtual Array<Idx> & getLocalEquationsNumbers() { + return local_equation_number; + } + + /// function to implement to react on akantu::NewNodesEvent + void onNodesAdded(const Array<Idx> & nodes_list, + const NewNodesEvent & event) override; + + public: + ID dof_id; /// DOF support type (nodal, general) this is needed to determine how the /// dof are shared among processors DOFSupportType support_type; @@ -597,12 +586,13 @@ protected: /// local numbering equation numbers Array<Idx> local_equation_number; + /// reference to the underlying mesh + const Mesh * mesh{nullptr}; + + DOFManager * dof_manager{nullptr}; + /// associated node for _dst_nodal dofs only Array<Idx> associated_nodes; - - virtual Array<Idx> & getLocalEquationsNumbers() { - return local_equation_number; - } }; /// type to store dofs information @@ -637,9 +627,6 @@ protected: /// time step solvers storage TimeStepSolversMap time_step_solvers; - /// reference to the underlying mesh - Mesh * mesh{nullptr}; - /// Total number of degrees of freedom (size with the ghosts) Int local_system_size{0}; @@ -695,10 +682,12 @@ protected: private: /// This is for unit testing friend class DOFManagerTester; + + std::set<const Mesh *> registered_meshes; }; using DefaultDOFManagerFactory = Factory<DOFManager, ID, const ID &>; -using DOFManagerFactory = Factory<DOFManager, ID, Mesh &, const ID &>; +using DOFManagerFactory = Factory<DOFManager, ID, const ID &>; } // namespace akantu diff --git a/src/model/common/dof_manager/dof_manager_default.cc b/src/model/common/dof_manager/dof_manager_default.cc index 361cc8c867605a95b7fe262d64d22297b8dbf239..eac4ab08cfb3dbda4643bc839a6db8a935da90fa 100644 --- a/src/model/common/dof_manager/dof_manager_default.cc +++ b/src/model/common/dof_manager/dof_manager_default.cc @@ -41,40 +41,31 @@ namespace akantu { /* -------------------------------------------------------------------------- */ DOFManagerDefault::DOFManagerDefault(const ID & id) - : DOFManager(id), synchronizer(nullptr) { - residual = std::make_unique<SolverVectorDefault>( - *this, std::string(id + ":residual")); - solution = std::make_unique<SolverVectorDefault>( - *this, std::string(id + ":solution")); - data_cache = std::make_unique<SolverVectorDefault>( - *this, std::string(id + ":data_cache")); -} - -/* -------------------------------------------------------------------------- */ -DOFManagerDefault::DOFManagerDefault(Mesh & mesh, const ID & id) - : DOFManager(mesh, id), synchronizer(nullptr) { - if (this->mesh->isDistributed()) { - this->synchronizer = std::make_unique<DOFSynchronizer>( - *this, this->id + ":dof_synchronizer"); - residual = std::make_unique<SolverVectorDistributed>( - *this, std::string(id + ":residual")); - solution = std::make_unique<SolverVectorDistributed>( - *this, std::string(id + ":solution")); - data_cache = std::make_unique<SolverVectorDistributed>( - *this, std::string(id + ":data_cache")); - - } else { - residual = std::make_unique<SolverVectorDefault>( - *this, std::string(id + ":residual")); - solution = std::make_unique<SolverVectorDefault>( - *this, std::string(id + ":solution")); - data_cache = std::make_unique<SolverVectorDefault>( - *this, std::string(id + ":data_cache")); - } -} + : DOFManager(id), synchronizer(nullptr) {} -/* -------------------------------------------------------------------------- */ DOFManagerDefault::~DOFManagerDefault() = default; +/* -------------------------------------------------------------------------- */ +// DOFManagerDefault::DOFManagerDefault(Mesh & mesh, const ID & id) +// : DOFManager(mesh, id), synchronizer(nullptr) { +// if (this->mesh->isDistributed()) { +// this->synchronizer = std::make_unique<DOFSynchronizer>( +// *this, this->id + ":dof_synchronizer"); +// residual = std::make_unique<SolverVectorDistributed>( +// *this, std::string(id + ":residual")); +// solution = std::make_unique<SolverVectorDistributed>( +// *this, std::string(id + ":solution")); +// data_cache = std::make_unique<SolverVectorDistributed>( +// *this, std::string(id + ":data_cache")); + +// } else { +// residual = std::make_unique<SolverVectorDefault>( +// *this, std::string(id + ":residual")); +// solution = std::make_unique<SolverVectorDefault>( +// *this, std::string(id + ":solution")); +// data_cache = std::make_unique<SolverVectorDefault>( +// *this, std::string(id + ":data_cache")); +// } +// } /* -------------------------------------------------------------------------- */ void DOFManagerDefault::makeConsistentForPeriodicity(const ID & dof_id, @@ -84,11 +75,11 @@ void DOFManagerDefault::makeConsistentForPeriodicity(const ID & dof_id, return; } - if (not mesh->isPeriodic()) { + if (not dof_data.mesh->isPeriodic()) { return; } - this->mesh->getPeriodicNodeSynchronizer() + dof_data.mesh->getPeriodicNodeSynchronizer() .reduceSynchronizeWithPBCSlaves<AddOperation>( aka::as_type<SolverVectorDefault>(array).getVector()); } @@ -107,7 +98,7 @@ void DOFManagerDefault::assembleToGlobalArray( "The array to assemble does not have a correct size." << " (" << array_to_assemble.getID() << ")"); - if (dof_data.support_type == _dst_nodal and mesh->isPeriodic()) { + if (dof_data.support_type == _dst_nodal and dof_data.mesh->isPeriodic()) { for (auto && data : zip(dof_data.local_equation_number, dof_data.associated_nodes, make_view(array_to_assemble))) { @@ -162,11 +153,37 @@ DOFManagerDefault::registerDOFsInternal(const ID & dof_id, Array<Real> & dofs_array) { auto ret = DOFManager::registerDOFsInternal(dof_id, dofs_array); - // update the synchronizer if needed - if (this->synchronizer) { - this->synchronizer->registerDOFs(dof_id); + auto & dof_data = aka::as_type<DOFDataDefault>(this->getDOFData(dof_id)); + + if (residual == nullptr) { + if (dof_data.mesh != nullptr and dof_data.mesh->isDistributed()) { + residual = std::make_unique<SolverVectorDistributed>( + *this, std::string(id + ":residual")); + solution = std::make_unique<SolverVectorDistributed>( + *this, std::string(id + ":solution")); + data_cache = std::make_unique<SolverVectorDistributed>( + *this, std::string(id + ":data_cache")); + } else { + residual = std::make_unique<SolverVectorDefault>( + *this, std::string(id + ":residual")); + solution = std::make_unique<SolverVectorDefault>( + *this, std::string(id + ":solution")); + data_cache = std::make_unique<SolverVectorDefault>( + *this, std::string(id + ":data_cache")); + } + } + + if (dof_data.mesh == nullptr) { + return ret; } + if (not hasSynchronizer()) { + synchronizer = std::make_unique<DOFSynchronizer>( + *this, this->id + ":dof_synchronizer"); + } + + synchronizer->registerDOFs(dof_id); + return ret; } @@ -302,7 +319,8 @@ void DOFManagerDefault::assembleMatMulVectToArray(const ID & dof_id, const Array<Real> & x, Array<Real> & array, Real scale_factor) { - if (mesh->isDistributed()) { + auto & dof_data = this->getDOFData(dof_id); + if (dof_data.mesh->isDistributed()) { DOFManager::assembleMatMulVectToArray_<SolverVectorDistributed>( dof_id, A_id, x, array, scale_factor); } else { @@ -326,7 +344,7 @@ void DOFManagerDefault::addToProfile(const ID & matrix_id, const ID & dof_id, auto type_pair = std::make_pair(type, ghost_type); auto prof_it = this->matrix_profiled_dofs.find(mat_dof); - if (prof_it != this->matrix_profiled_dofs.end() && + if (prof_it != this->matrix_profiled_dofs.end() and std::find(prof_it->second.begin(), prof_it->second.end(), type_pair) != prof_it->second.end()) { return; @@ -342,7 +360,7 @@ void DOFManagerDefault::addToProfile(const ID & matrix_id, const ID & dof_id, auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); - const auto & connectivity = this->mesh->getConnectivity(type, ghost_type); + const auto & connectivity = dof_data.mesh->getConnectivity(type, ghost_type); auto cbegin = connectivity.begin(nb_nodes_per_element); auto cit = cbegin; @@ -350,7 +368,7 @@ void DOFManagerDefault::addToProfile(const ID & matrix_id, const ID & dof_id, const Int * ge_it = nullptr; if (dof_data.group_support != "__mesh__") { const auto & group_elements = - this->mesh->getElementGroup(dof_data.group_support) + dof_data.mesh->getElementGroup(dof_data.group_support) .getElements(type, ghost_type); ge_it = group_elements.data(); nb_elements = group_elements.size(); @@ -376,15 +394,15 @@ void DOFManagerDefault::addToProfile(const ID & matrix_id, const ID & dof_id, ++cit; } - for (Int i = 0; i < size_mat; ++i) { - auto c_irn = element_eq_nb(i); - if (c_irn < size) { - for (Int j = 0; j < size_mat; ++j) { - auto c_jcn = element_eq_nb(j); - if (c_jcn < size) { - A.add(c_irn, c_jcn); - } + for (auto c_irn : element_eq_nb) { + if (c_irn >= size) { + continue; + } + for (auto c_jcn : element_eq_nb) { + if (c_jcn >= size) { + continue; } + A.add(c_irn, c_jcn); } } } @@ -414,8 +432,8 @@ void DOFManagerDefault::onNodesAdded(const Array<Idx> & nodes_list, const NewNodesEvent & event) { DOFManager::onNodesAdded(nodes_list, event); - if (this->synchronizer) { - this->synchronizer->onNodesAdded(nodes_list); + if (synchronizer) { + synchronizer->onNodesAdded(nodes_list); } } @@ -456,17 +474,16 @@ const Array<bool> & DOFManagerDefault::getBlockedDOFs() const { } /* -------------------------------------------------------------------------- */ -static bool dof_manager_is_registered = +static const bool dof_manager_is_registered = DOFManagerFactory::getInstance().registerAllocator( - "default", - [](Mesh & mesh, const ID & id) -> std::unique_ptr<DOFManager> { - return std::make_unique<DOFManagerDefault>(mesh, id); + "default", [](const ID & id) -> std::unique_ptr<DOFManager> { + return std::make_unique<DOFManagerDefault>(id); }); -static bool dof_manager_is_registered_mumps = +static const bool dof_manager_is_registered_mumps = DOFManagerFactory::getInstance().registerAllocator( - "mumps", [](Mesh & mesh, const ID & id) -> std::unique_ptr<DOFManager> { - return std::make_unique<DOFManagerDefault>(mesh, id); + "mumps", [](const ID & id) -> std::unique_ptr<DOFManager> { + return std::make_unique<DOFManagerDefault>(id); }); } // namespace akantu diff --git a/src/model/common/dof_manager/dof_manager_default.hh b/src/model/common/dof_manager/dof_manager_default.hh index fa26f3845ced19fade05cc7c73dee301f986ea1e..4e8cd9453e94950e85c7fffdd19afe4041ffd988 100644 --- a/src/model/common/dof_manager/dof_manager_default.hh +++ b/src/model/common/dof_manager/dof_manager_default.hh @@ -43,12 +43,15 @@ class DOFManagerDefault : public DOFManager { /* ------------------------------------------------------------------------ */ public: DOFManagerDefault(const ID & id = "dof_manager_default"); - DOFManagerDefault(Mesh & mesh, const ID & id = "dof_manager_default"); ~DOFManagerDefault() override; protected: struct DOFDataDefault : public DOFData { explicit DOFDataDefault(const ID & dof_id); + + public: + /// synchronizer to maintain coherency in dof fields + std::shared_ptr<DOFSynchronizer> synchronizer; }; /* ------------------------------------------------------------------------ */ @@ -114,9 +117,6 @@ public: /// update the global dofs vector void updateGlobalBlockedDofs() override; - // /// apply boundary conditions to jacobian matrix - // void applyBoundary(const ID & matrix_id = "J") override; - private: /// Add a symmetric matrices to a symmetric sparse matrix void addSymmetricElementalMatrixToSymmetric( @@ -139,23 +139,14 @@ private: GhostType ghost_type); /* ------------------------------------------------------------------------ */ - /* MeshEventHandler interface */ + /* MeOAshEventHandler interface */ /* ------------------------------------------------------------------------ */ protected: std::tuple<Int, Int, Int> registerDOFsInternal(const ID & dof_id, Array<Real> & dofs_array) override; - // std::pair<UInt, UInt> - // updateNodalDOFs(const ID & dof_id, const Array<UInt> & nodes_list) - // override; - void resizeGlobalArrays() override; -public: - /// function to implement to react on akantu::NewNodesEvent - void onNodesAdded(const Array<Idx> & nodes_list, - const NewNodesEvent & event) override; - /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ @@ -192,6 +183,9 @@ public: NonLinearSolver & non_linear_solver, SolverCallback & solver_callback) override; + /* ------------------------------------------------------------------------ */ + void onNodesAdded(const Array<Idx> & nodes_list, const NewNodesEvent & event); + /* ------------------------------------------------------------------------ */ private: /// Get the solution array @@ -205,10 +199,15 @@ private: public: /// access the internal dof_synchronizer - AKANTU_GET_MACRO_NOT_CONST(Synchronizer, *synchronizer, DOFSynchronizer &); + DOFSynchronizer & getSynchronizer() { + AKANTU_DEBUG_ASSERT(synchronizer != nullptr, "DOFSynchronizer is not set"); + return *synchronizer; + } /// access the internal dof_synchronizer - bool hasSynchronizer() const { return synchronizer != nullptr; } + [[nodiscard]] bool hasSynchronizer() const { + return (synchronizer != nullptr); + } Array<bool> & getBlockedDOFs(); const Array<bool> & getBlockedDOFs() const; @@ -227,17 +226,14 @@ protected: /// contains the the dofs that where added to the profile of a given matrix. DOFToMatrixProfile matrix_profiled_dofs; - /// synchronizer to maintain coherency in dof fields - std::unique_ptr<DOFSynchronizer> synchronizer; - friend class DOFSynchronizer; /// Array containing the true or false if the node is in global_blocked_dofs Array<bool> global_blocked_dofs_uint; + + std::unique_ptr<DOFSynchronizer> synchronizer; }; } // namespace akantu -#include "dof_manager_default_inline_impl.hh" - #endif /* AKANTU_DOF_MANAGER_DEFAULT_HH_ */ diff --git a/src/model/common/dof_manager/dof_manager_inline_impl.hh b/src/model/common/dof_manager/dof_manager_inline_impl.hh index 7aeedf31ecdfe335ae4b4f3ab2b72c96989794d0..1492a61f4427d4d1ab85cd977b0fc6624e952193 100644 --- a/src/model/common/dof_manager/dof_manager_inline_impl.hh +++ b/src/model/common/dof_manager/dof_manager_inline_impl.hh @@ -57,6 +57,14 @@ const DOFManager::DOFData & DOFManager::getDOFData(const ID & dof_id) const { return *it->second; } +/* -------------------------------------------------------------------------- */ +inline const Mesh & DOFManager::getMesh(const ID & dof_id) const { + auto && dof_data = getDOFData(dof_id); + if (not dof_data.mesh) { + AKANTU_EXCEPTION("No mesh was associated to the dof " << dof_id); + } + return *(dof_data.mesh); +} /* -------------------------------------------------------------------------- */ inline void DOFManager::extractElementEquationNumber( const Array<Idx> & equation_numbers, const Vector<Idx> & connectivity, @@ -244,20 +252,23 @@ void DOFManager::assembleElementalMatricesToMatrix_( const auto & equation_number = this->getLocalEquationsNumbers(dof_id); - Int nb_element; + Int nb_element{}; const Idx * filter_it = nullptr; + + const auto & connectivity = dof_data.mesh->getConnectivity(type, ghost_type); + if (filter_elements != empty_filter) { nb_element = filter_elements.size(); filter_it = filter_elements.data(); } else { if (dof_data.group_support != "__mesh__") { const auto & group_elements = - this->mesh->getElementGroup(dof_data.group_support) + dof_data.mesh->getElementGroup(dof_data.group_support) .getElements(type, ghost_type); nb_element = group_elements.size(); filter_it = group_elements.data(); } else { - nb_element = this->mesh->getNbElement(type, ghost_type); + nb_element = connectivity.size(); } } @@ -266,11 +277,10 @@ void DOFManager::assembleElementalMatricesToMatrix_( << elementary_mat.getID() << ") has not the good size."); - auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); + auto nb_nodes_per_element = connectivity.getNbComponent(); auto nb_degree_of_freedom = dof_data.dof->getNbComponent(); - const auto & connectivity = this->mesh->getConnectivity(type, ghost_type); auto conn_begin = connectivity.begin(nb_nodes_per_element); auto conn_it = conn_begin; auto size_mat = nb_nodes_per_element * nb_degree_of_freedom; @@ -323,4 +333,4 @@ void DOFManager::assemblePreassembledMatrix_(Mat & A, } // namespace akantu -//#endif /* __AKANTU_DOF_MANAGER_INLINE_IMPL_CC__ */ +// #endif /* __AKANTU_DOF_MANAGER_INLINE_IMPL_CC__ */ diff --git a/src/model/common/dof_manager/dof_manager_petsc.cc b/src/model/common/dof_manager/dof_manager_petsc.cc index e2bdd3addd4c9721943adeba609b164bf2787e4d..d7f3ccd6d32a4392431a30663a51a7d7ff2d32d0 100644 --- a/src/model/common/dof_manager/dof_manager_petsc.cc +++ b/src/model/common/dof_manager/dof_manager_petsc.cc @@ -190,13 +190,13 @@ void DOFManagerPETSc::getArrayPerDOFs(const ID & dof_id, /* -------------------------------------------------------------------------- */ void DOFManagerPETSc::assembleElementalMatricesToMatrix( const ID & matrix_id, const ID & dof_id, const Array<Real> & elementary_mat, - ElementType type, GhostType ghost_type, + const Array<Idx> & connectivity, ElementType type, GhostType ghost_type, const MatrixType & elemental_matrix_type, const Array<Int> & filter_elements) { auto & A = getMatrix(matrix_id); DOFManager::assembleElementalMatricesToMatrix_( - A, dof_id, elementary_mat, type, ghost_type, elemental_matrix_type, - filter_elements); + A, dof_id, elementary_mat, connectivity, type, ghost_type, + elemental_matrix_type, filter_elements); A.applyModifications(); } diff --git a/src/model/common/dof_manager/dof_manager_petsc.hh b/src/model/common/dof_manager/dof_manager_petsc.hh index 88370ea029542ff4d5a430fe6bbe0eb7972d578a..4411cefb1229ff617e8d94e1bbb1f4bd255c7558 100644 --- a/src/model/common/dof_manager/dof_manager_petsc.hh +++ b/src/model/common/dof_manager/dof_manager_petsc.hh @@ -82,29 +82,27 @@ protected: /* Methods */ /* ------------------------------------------------------------------------ */ public: - void assembleToLumpedMatrix(const ID & /*dof_id*/, - Array<Real> & /*array_to_assemble*/, - const ID & /*lumped_mtx*/, - Real /*scale_factor*/ = 1.) override { + void assembleToLumpedMatrix(const ID & dof_id, + Array<Real> & array_to_assemble, + const ID & lumped_mtx, + Real scale_factor = 1.) override { AKANTU_TO_IMPLEMENT(); } void assembleElementalMatricesToMatrix( - const ID & /*matrix_id*/, const ID & /*dof_id*/, - const Array<Real> & /*elementary_mat*/, ElementType /*type*/, - GhostType /*ghost_type*/, - const MatrixType & /*elemental_matrix_type*/, - const Array<Idx> & /*filter_elements*/) override; - - void assembleMatMulVectToArray(const ID & /*dof_id*/, const ID & /*A_id*/, - const Array<Real> & /*x*/, - Array<Real> & /*array*/, - Real /*scale_factor*/ = 1.) override; - - void assembleLumpedMatMulVectToResidual(const ID & /*dof_id*/, - const ID & /*A_id*/, - const Array<Real> & /*x*/, - Real /*scale_factor*/ = 1) override { + const ID & matrix_id, const ID & dof_id, + const Array<Real> & elementary_mat, const Array<Idx> & connectivity, + ElementType type, GhostType ghost_type, + const MatrixType & elemental_matrix_type, + const Array<Idx> & filter_elements) override; + + void assembleMatMulVectToArray(const ID & dof_id, const ID & A_id, + const Array<Real> & x, Array<Real> & array, + Real scale_factor = 1.) override; + + void assembleLumpedMatMulVectToResidual(const ID & dof_id, const ID & A_id, + const Array<Real> & x, + Real scale_factor = 1) override { AKANTU_TO_IMPLEMENT(); } diff --git a/src/model/common/model_solver.cc b/src/model/common/model_solver.cc index 8d1b7258dc8aebca5205a97a0b2511eb2e779f30..92f4a9f556bc542a84b68e5595a27cfb7d0b7e78 100644 --- a/src/model/common/model_solver.cc +++ b/src/model/common/model_solver.cc @@ -80,7 +80,7 @@ ModelSolver::initDOFManager(const std::shared_ptr<DOFManager> & dof_manager) { ID solver_type = "default"; #if defined(AKANTU_USE_MUMPS) - solver_type = "default"; + solver_type = "mumps"; #elif defined(AKANTU_USE_PETSC) solver_type = "petsc"; #endif @@ -103,7 +103,7 @@ ModelSolver::initDOFManager(const ID & solver_type) { try { this->dof_manager = DOFManagerFactory::getInstance().allocate( - solver_type, mesh, this->id + ":dof_manager_" + solver_type); + solver_type, this->id + ":dof_manager_" + solver_type); } catch (...) { AKANTU_EXCEPTION( "To use the solver " diff --git a/src/model/common/non_local_toolbox/base_distance_function.cc b/src/model/common/non_local_toolbox/base_distance_function.cc new file mode 100644 index 0000000000000000000000000000000000000000..a96c5c1ea14b11d2dc5fa19ff35ff6c066abc51e --- /dev/null +++ b/src/model/common/non_local_toolbox/base_distance_function.cc @@ -0,0 +1,28 @@ +/** + * Copyright (©) 2022-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * 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 "base_distance_function.hh" + +namespace akantu { + +// TODO : MODIFY THIS ??? +INSTANTIATE_CLIP_NEIGHBORHOOD(base_dist, BaseDistanceFunction); + +} // namespace akantu diff --git a/src/model/common/non_local_toolbox/base_distance_function.hh b/src/model/common/non_local_toolbox/base_distance_function.hh new file mode 100644 index 0000000000000000000000000000000000000000..15bacdf36616bb3787634c9814900b293db11f08 --- /dev/null +++ b/src/model/common/non_local_toolbox/base_distance_function.hh @@ -0,0 +1,170 @@ +/** + * Copyright (©) 2015-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "aka_factory.hh" +#include "data_accessor.hh" +#include "model.hh" +#include "non_local_manager.hh" +#include "clip_neighborhood.hh" +#include "parsable.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef AKANTU_BASE_DISTANCE_FUNCTION_HH_ +#define AKANTU_BASE_DISTANCE_FUNCTION_HH_ + +namespace akantu { + +/* -------------------------------------------------------------------------- */ +/* Normal weight function */ +/* -------------------------------------------------------------------------- */ +class BaseDistanceFunction : public Parsable, public DataAccessor<Element> { +public: + /* ------------------------------------------------------------------------ */ + /* Constructors/Destructors */ + /* ------------------------------------------------------------------------ */ + BaseDistanceFunction(NonLocalManager & manager, + const std::string & type = "base") + : Parsable(ParserType::_distance_function, "distance_function:" + type), + manager(manager), type(type), + spatial_dimension(manager.getModel().getMesh().getSpatialDimension()) { + this->registerParam("update_rate", update_rate, Int(1), _pat_parsmod, + "Update frequency"); + } + + ~BaseDistanceFunction() override = default; + + /* ------------------------------------------------------------------------ */ + /* Methods */ + /* ------------------------------------------------------------------------ */ + /// initialize the weight function + virtual inline void init(); + + /// update the internal parameters + virtual void updateInternals(){}; + + /* ------------------------------------------------------------------------ */ + /// set the non-local radius + inline void setRadius(Real radius); + + /* ------------------------------------------------------------------------ */ + /// compute the weight for a given distance between two quadrature points + inline Real operator()(Real r, const IntegrationPoint & q1, + const IntegrationPoint & q2) const; + + /// print function + void printself(std::ostream & stream, int indent = 0) const override { + std::string space; + for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) { + ; + } + stream << space << "WeightFunction " << type << " [" << std::endl; + Parsable::printself(stream, indent); + stream << space << "]" << std::endl; + } + + /* -------------------------------------------------------------------------- + */ + /* Accessors */ + /* -------------------------------------------------------------------------- + */ + +public: + /// get the radius + Real getRadius() const { return R; } + /// get the update rate + Int getUpdateRate() const { return update_rate; } + +public: + /* ------------------------------------------------------------------------ */ + /* Data Accessor inherited members */ + /* ------------------------------------------------------------------------ */ + + Int getNbData(const Array<Element> &, + const SynchronizationTag &) const override { + return 0; + } + + inline void packData(CommunicationBuffer & /*buffer*/, + const Array<Element> & /*element*/, + const SynchronizationTag & /*tag*/) const override {} + + inline void unpackData(CommunicationBuffer & /*buffer*/, + const Array<Element> & /*element*/, + const SynchronizationTag & /*tag*/) override {} + + /* ------------------------------------------------------------------------ */ + /* Accessors */ + /* ------------------------------------------------------------------------ */ +public: + AKANTU_GET_MACRO(Type, type, const ID &); + +protected: + /* ------------------------------------------------------------------------ */ + /* Class Members */ + /* ------------------------------------------------------------------------ */ + /// reference to the non-local manager + NonLocalManager & manager; + + /// the non-local radius + Real R; + + /// the non-local radius squared + Real R2; + + /// the update rate + Int update_rate; + + /// name of the type of weight function + const std::string type; + + /// the spatial dimension + Int spatial_dimension; +}; + +inline std::ostream & operator<<(std::ostream & stream, + const BaseDistanceFunction & _this) { + _this.printself(stream); + return stream; +} + +#define INSTANTIATE_CLIP_NEIGHBORHOOD(id, distance_fun_name) \ + static bool distance_is_alocated_##id [[gnu::unused]] = \ + NonLocalNeighborhoodFactory::getInstance().registerAllocator( \ + #id, \ + [](const ID & /*name*/, NonLocalManager & non_local_manager, \ + const ElementTypeMapReal & quad_point_positions, const ID & id) { \ + return std::make_unique<CLIPNeighborhood<distance_fun_name>>( \ + non_local_manager, quad_point_positions, id); \ + }) + +} // namespace akantu + +#include "base_distance_function_inline_impl.hh" + +/* -------------------------------------------------------------------------- */ +/* Include all other distance function types */ +/* -------------------------------------------------------------------------- */ +#if defined(AKANTU_DAMAGE_NON_LOCAL) +// in case other distance functions are defined +#endif +/* -------------------------------------------------------------------------- */ + +#endif /* AKANTU_BASE_DISTANCE_FUNCTION_HH_ */ diff --git a/src/model/common/non_local_toolbox/base_distance_function_inline_impl.hh b/src/model/common/non_local_toolbox/base_distance_function_inline_impl.hh new file mode 100644 index 0000000000000000000000000000000000000000..144a7efb25cf1a3848b42db9438adcdd3b9fa28e --- /dev/null +++ b/src/model/common/non_local_toolbox/base_distance_function_inline_impl.hh @@ -0,0 +1,53 @@ +/** + * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * 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 "base_distance_function.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef AKANTU_BASE_DISTANCE_FUNCTION_INLINE_IMPL_HH_ +#define AKANTU_BASE_DISTANCE_FUNCTION_INLINE_IMPL_HH_ + +namespace akantu { + +/* -------------------------------------------------------------------------- */ +inline void BaseDistanceFunction::init() { + /// compute R^2 for a given non-local radius + this->R2 = this->R * this->R; +} + +/* -------------------------------------------------------------------------- */ +inline void BaseDistanceFunction::setRadius(Real radius) { + /// set the non-local radius and update R^2 accordingly + this->R = radius; + this->R2 = this->R * this->R; +} + +/* -------------------------------------------------------------------------- */ +inline Real +BaseDistanceFunction::operator()(Real r, const IntegrationPoint & /* q1 */, + const IntegrationPoint & /* q2 */) const { + + return r; +} + +} // namespace akantu + +#endif /* AKANTU_BASE_DISTANCE_FUNCTION_INLINE_IMPL_HH_ */ diff --git a/src/model/common/non_local_toolbox/base_weight_function.hh b/src/model/common/non_local_toolbox/base_weight_function.hh index 9a77266dbfaeeff84c5fe56fbc3a0f0a50cb9b6a..0ca6376b4d26fd58bb14c282e0585dc0a96c03da 100644 --- a/src/model/common/non_local_toolbox/base_weight_function.hh +++ b/src/model/common/non_local_toolbox/base_weight_function.hh @@ -145,10 +145,6 @@ inline std::ostream & operator<<(std::ostream & stream, return stream; } -using NonLocalNeighborhoodFactory = - Factory<NonLocalNeighborhoodBase, ID, ID, NonLocalManager &, - const ElementTypeMapReal &, const ID &>; - #define INSTANTIATE_NL_NEIGHBORHOOD(id, weight_fun_name) \ static bool weigth_is_alocated_##id [[gnu::unused]] = \ NonLocalNeighborhoodFactory::getInstance().registerAllocator( \ diff --git a/src/model/common/non_local_toolbox/clip_neighborhood.hh b/src/model/common/non_local_toolbox/clip_neighborhood.hh new file mode 100644 index 0000000000000000000000000000000000000000..a2e2e6ba5349d8b2e41dfbb701e6619ce2552954 --- /dev/null +++ b/src/model/common/non_local_toolbox/clip_neighborhood.hh @@ -0,0 +1,138 @@ +/** + * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "non_local_neighborhood_base.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef AKANTU_CLIPNEIGHBORHOOD_HH_ +#define AKANTU_CLIPNEIGHBORHOOD_HH_ + +namespace akantu { +class BaseDistanceFunction; +class NonLocalManager; +} // namespace akantu + +namespace akantu { + +template <class DistanceFunction = BaseDistanceFunction> +class CLIPNeighborhood : public NonLocalNeighborhoodBase { + /* ------------------------------------------------------------------------ */ + /* Constructors/Destructors */ + /* ------------------------------------------------------------------------ */ +public: + CLIPNeighborhood(NonLocalManager & manager, + const ElementTypeMapReal & quad_coordinates, + const ID & id = "neighborhood"); + + /* ------------------------------------------------------------------------ */ + /* Methods */ + /* ------------------------------------------------------------------------ */ +public: + + /// create the pairs of quadrature points + void updatePairList() override; + + /// compute the weights for non-local averaging + void computeWeights() override; + + /// compute the weights for non-local averaging of function derivative + void computeDerivativeWeights(); + + /// save the pair of weights in a file + void saveWeights(const std::string & filename) const override; + + /// compute the non-local counter part for a given element type map + void weightedAverageOnNeighbours(const ElementTypeMapReal & to_accumulate, + ElementTypeMapReal & accumulated, + Int nb_degree_of_freedom, + GhostType ghost_type2) const override; + + /// compute the non-local part of clip functional derivative for a given element type map + void weightedDerivativeAverageOnNeighbours(const ElementTypeMapReal & to_accumulate, + ElementTypeMapReal & accumulated, + Int nb_degree_of_freedom, + GhostType ghost_type2) const; + + /// update the weights based on the weight function + void updateWeights() override; + + /// register a new non-local variable in the neighborhood + // void registerNonLocalVariable(const ID & id); +protected: + template <class Func> + inline void foreach_distance(GhostType ghost_type, Func && func); + + template <class Func> + inline void foreach_distance(GhostType ghost_type, Func && func) const; + + template <class Func> + inline void foreach_derivative_weight(GhostType ghost_type, Func && func); + + template <class Func> + inline void foreach_derivative_weight(GhostType ghost_type, Func && func) const; + + [[nodiscard]] inline Int + getNbData(const Array<Element> & elements, + const SynchronizationTag & tag) const override; + + inline void packData(CommunicationBuffer & buffer, + const Array<Element> & elements, + const SynchronizationTag & tag) const override; + + inline void unpackData(CommunicationBuffer & buffer, + const Array<Element> & elements, + const SynchronizationTag & tag) override; + + /* ------------------------------------------------------------------------ */ + /* Accessor */ + /* ------------------------------------------------------------------------ */ +public: + AKANTU_GET_MACRO_AUTO(NonLocalManager, non_local_manager); + AKANTU_GET_MACRO_AUTO_NOT_CONST(NonLocalManager, non_local_manager); + + /* ------------------------------------------------------------------------ */ + /* Class Members */ + /* ------------------------------------------------------------------------ */ +private: + + /// Damage limiter value + Real Dm{0.}; + + /// Pointer to non-local manager class + NonLocalManager & non_local_manager; + + /// the distances associated to the pairs + std::map<GhostType, std::unique_ptr<Array<Real>>> pair_distance; + + /// the derivative weights associated to the pairs + std::map<GhostType, std::unique_ptr<Array<Real>>> pair_derivative_weights; + + /// weight function + std::shared_ptr<DistanceFunction> distance_function; + +}; + +} // namespace akantu + +#include "clip_neighborhood_inline_impl.hh" +#include "clip_neighborhood_tmpl.hh" + +#endif /* AKANTU_CLIPNEIGHBORHOOD_HH_ */ diff --git a/src/model/common/non_local_toolbox/clip_neighborhood_inline_impl.hh b/src/model/common/non_local_toolbox/clip_neighborhood_inline_impl.hh new file mode 100644 index 0000000000000000000000000000000000000000..cadf551a697973797153ade6062f5a17e104df2c --- /dev/null +++ b/src/model/common/non_local_toolbox/clip_neighborhood_inline_impl.hh @@ -0,0 +1,77 @@ +/** + * Copyright (©) 2015-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +//#include "non_local_neighborhood.hh" +#include "non_local_manager.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef AKANTU_CLIP_NEIGHBORHOOD_INLINE_IMPL_HH_ +#define AKANTU_CLIP_NEIGHBORHOOD_INLINE_IMPL_HH_ + +namespace akantu { +/* -------------------------------------------------------------------------- */ +template <class DistanceFunction> +inline Int CLIPNeighborhood<DistanceFunction>::getNbData( + const Array<Element> & elements, const SynchronizationTag & tag) const { + Int size = 0; + + if (tag == SynchronizationTag::_mnl_for_average) { + for (auto && variable_id : non_local_variables) { + size += this->non_local_manager.getNbData(elements, variable_id); + } + } + + size += this->distance_function->getNbData(elements, tag); + + return size; +} + +/* -------------------------------------------------------------------------- */ +template <class DistanceFunction> +inline void CLIPNeighborhood<DistanceFunction>::packData( + CommunicationBuffer & buffer, const Array<Element> & elements, + const SynchronizationTag & tag) const { + if (tag == SynchronizationTag::_mnl_for_average) { + for (auto && variable_id : non_local_variables) { + this->non_local_manager.packData(buffer, elements, variable_id); + } + } + + this->distance_function->packData(buffer, elements, tag); +} + +/* -------------------------------------------------------------------------- */ +template <class DistanceFunction> +inline void CLIPNeighborhood<DistanceFunction>::unpackData( + CommunicationBuffer & buffer, const Array<Element> & elements, + const SynchronizationTag & tag) { + if (tag == SynchronizationTag::_mnl_for_average) { + for (auto & variable_id : non_local_variables) { + this->non_local_manager.unpackData(buffer, elements, variable_id); + } + } + + this->distance_function->unpackData(buffer, elements, tag); +} + +} // namespace akantu + +#endif /* AKANTU_CLIP_NEIGHBORHOOD_INLINE_IMPL_HH_ */ diff --git a/src/model/common/non_local_toolbox/clip_neighborhood_tmpl.hh b/src/model/common/non_local_toolbox/clip_neighborhood_tmpl.hh new file mode 100644 index 0000000000000000000000000000000000000000..8372fe64a969a4e80a9374a0919a189e5cd51b26 --- /dev/null +++ b/src/model/common/non_local_toolbox/clip_neighborhood_tmpl.hh @@ -0,0 +1,351 @@ +/** + * Copyright (©) 2015-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * 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 "communicator.hh" +#include "model.hh" +#include "non_local_manager.hh" +#include "clip_neighborhood.hh" +/* -------------------------------------------------------------------------- */ +#include <fstream> +/* -------------------------------------------------------------------------- */ + +#ifndef AKANTU_CLIP_NEIGHBORHOOD_TMPL_HH_ +#define AKANTU_CLIP_NEIGHBORHOOD_TMPL_HH_ + +namespace akantu { + +/* -------------------------------------------------------------------------- */ +template <class DistanceFunction> +template <class Func> +inline void +CLIPNeighborhood<DistanceFunction>::foreach_distance(GhostType ghost_type, + Func && func) { + auto && weight_vect = *pair_distance[ghost_type]; + + for (auto && [pair, weight] : + zip(pair_list[ghost_type], + make_view(weight_vect, weight_vect.getNbComponent()))) { + auto && [q1, q2] = pair; + std::forward<decltype(func)>(func)(q1, q2, weight); + } +} + +/* -------------------------------------------------------------------------- */ +template <class DistanceFunction> +template <class Func> +inline void +CLIPNeighborhood<DistanceFunction>::foreach_distance(GhostType ghost_type, + Func && func) const { + auto && weight_vect = *pair_distance.at(ghost_type); + + for (auto && [pair, weight] : + zip(pair_list.at(ghost_type), + make_view(weight_vect, weight_vect.getNbComponent()))) { + auto && [q1, q2] = pair; + std::forward<decltype(func)>(func)(q1, q2, weight); + } +} + +/* -------------------------------------------------------------------------- */ +template <class DistanceFunction> +template <class Func> +inline void +CLIPNeighborhood<DistanceFunction>::foreach_derivative_weight(GhostType ghost_type, + Func && func) { + auto && weight_vect = *pair_derivative_weights[ghost_type]; + + for (auto && [pair, weight] : + zip(pair_list[ghost_type], + make_view(weight_vect, weight_vect.getNbComponent()))) { + auto && [q1, q2] = pair; + std::forward<decltype(func)>(func)(q1, q2, weight); + } +} + +/* -------------------------------------------------------------------------- */ +template <class DistanceFunction> +template <class Func> +inline void +CLIPNeighborhood<DistanceFunction>::foreach_derivative_weight(GhostType ghost_type, + Func && func) const { + auto && weight_vect = *pair_derivative_weights.at(ghost_type); + + for (auto && [pair, weight] : + zip(pair_list.at(ghost_type), + make_view(weight_vect, weight_vect.getNbComponent()))) { + auto && [q1, q2] = pair; + std::forward<decltype(func)>(func)(q1, q2, weight); + } +} + +/* -------------------------------------------------------------------------- */ +template <class DistanceFunction> +CLIPNeighborhood<DistanceFunction>::CLIPNeighborhood( + NonLocalManager & manager, const ElementTypeMapReal & quad_coordinates, + const ID & id) + : NonLocalNeighborhoodBase(manager.getModel(), quad_coordinates, id), + non_local_manager(manager) { + AKANTU_DEBUG_IN(); + + this->distance_function = std::make_unique<DistanceFunction>(manager); + + this->registerSubSection(ParserType::_distance_function, "distance_parameter", + *distance_function); + this->registerParam("Dm", Dm, 0., + _pat_parsable | _pat_readable, "Dm"); + + for (auto ghost_type : ghost_types) { + if (pair_distance.find(ghost_type) == pair_distance.end()) { + pair_distance[ghost_type] = std::make_unique<Array<Real>>(0, 1); + pair_list[ghost_type].resize(0); + } + if (pair_derivative_weights.find(ghost_type) == pair_derivative_weights.end()) { + pair_derivative_weights[ghost_type] = std::make_unique<Array<Real>>(0, 1); + } + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template <class DistanceFunction> +void CLIPNeighborhood<DistanceFunction>::updatePairList() { + AKANTU_DEBUG_IN(); + + //// loop over all quads -> all cells + for (auto && cell_id : *spatial_grid) { + AKANTU_DEBUG_INFO("Looping on next cell"); + + for (auto && q1 : spatial_grid->getCell(cell_id)) { + if (q1.ghost_type == _ghost || q1.kind() == _ek_regular) { + break; + } + auto q1_coords = this->quad_coordinates.get(q1); + + AKANTU_DEBUG_INFO("Current quadrature point in this cell: " << q1); + auto cell_id = spatial_grid->getCellID(q1_coords); + + /// loop over all the neighboring cells of the current quad + for (auto && neighbor_cell : cell_id.neighbors()) { + // loop over the quadrature point in the current neighboring cell + for (auto && q2 : spatial_grid->getCell(neighbor_cell)) { + auto q2_coords = this->quad_coordinates.get(q2); + + Real distance = q1_coords.distance(q2_coords); + + if (distance <= this->neighborhood_radius + Math::getTolerance() && + q2.kind() == _ek_regular) { + // Not sure if we still need these conditions + // (q2.ghost_type == _ghost || + // (q2.ghost_type == _not_ghost && + // q1.global_num <= q2.global_num))) { // storing only half lists + pair_list[q1.ghost_type].emplace_back(q1, q2); + } + } + } + } + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template <class DistanceFunction> +void CLIPNeighborhood<DistanceFunction>::computeWeights() { + AKANTU_DEBUG_IN(); + + std::cout << "CLIPNeighborhood::In computeWeights " << std::endl; + this->distance_function->setRadius(this->neighborhood_radius); + + /// update the internals of the weight function if applicable (not + /// all the weight functions have internals and do noting in that + /// case) + distance_function->updateInternals(); + + for (auto ghost_type : ghost_types) { + /// allocate the array to store the weight, if it doesn't exist already + if (not pair_distance[ghost_type]) { + pair_distance[ghost_type] = + std::make_unique<Array<Real>>(0, 1); + } + + auto && pair_lists = pair_list[ghost_type]; + auto && pair_distances = *pair_distance[ghost_type]; + + pair_distances.resize(pair_lists.size()); + pair_distances.zero(); + + /// loop over all pairs in the current pair list array and their + /// corresponding weights + // Compute the distances + for (auto && [dist, pairs] : + zip(make_view(pair_distances, 1), pair_lists)) { + const auto & [q1, q2] = pairs; + + /// get the coordinates for the given pair of quads + auto && q1_coord = this->quad_coordinates.get(q1); + auto && q2_coord = this->quad_coordinates.get(q2); + + /// compute distance between the two quadrature points + auto r = q1_coord.distance(q2_coord); + + /// compute the weight for averaging on q1 based on the distance + dist(0) = (*this->distance_function)(r, q1, q2); + } + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template <class DistanceFunction> +void CLIPNeighborhood<DistanceFunction>::computeDerivativeWeights() { + AKANTU_DEBUG_IN(); + + for (auto ghost_type : ghost_types) { + /// allocate the array to store the weight, if it doesn't exist already + if (not pair_derivative_weights[ghost_type]) { + pair_derivative_weights[ghost_type] = + std::make_unique<Array<Real>>(0, 1); + } + + auto && pair_lists = pair_list[ghost_type]; + auto && pair_derivative_weights = *pair_derivative_weights[ghost_type]; + + pair_derivative_weights.resize(pair_lists.size()); + pair_derivative_weights.zero(); + + /// loop over all pairs in the current pair list array and their + /// corresponding weights + // Compute the distances + for (auto && [weight, pairs] : + zip(make_view(pair_derivative_weights, 1), pair_lists)) { + const auto & [q1, q2] = pairs; + + /// get the coordinates for the given pair of quads + auto && q1_coord = this->quad_coordinates.get(q1); + auto && q2_coord = this->quad_coordinates.get(q2); + + /// TODO : compute the weight for averaging on q1 + weight(0) = 0.; + } + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template <class DistanceFunction> +void CLIPNeighborhood<DistanceFunction>::saveWeights( + const std::string & filename) const { + std::ofstream pout; + + std::stringstream sstr; + + const Communicator & comm = model.getMesh().getCommunicator(); + + auto prank = comm.whoAmI(); + sstr << filename << "." << prank; + + pout.open(sstr.str().c_str()); + + for (auto ghost_type : ghost_types) { + AKANTU_DEBUG_ASSERT((pair_distance.at(ghost_type)), + "the weights have not been computed yet"); + + const auto & weights = *pair_distance.at(ghost_type); + for (auto && weight : make_view(weights, 2)) { + pout << "w1: " << weight(0) << " w2: " << weight(1) << "\n"; + } + } +} + +/* -------------------------------------------------------------------------- */ +template <class DistanceFunction> +void CLIPNeighborhood<DistanceFunction>::weightedAverageOnNeighbours( + const ElementTypeMapReal & to_accumulate, ElementTypeMapReal & accumulated, + Int /*nb_degree_of_freedom*/, GhostType ghost_type2) const { + + std::cout << "CLIPNeighborhood::In weightedAverageOnNeighbours " << std::endl; + + auto it = non_local_variables.find(accumulated.getName()); + // do averaging only for variables registered in the neighborhood + if (it == non_local_variables.end()) { + return; + } + + std::cout << "to_accumulate.getName() " << to_accumulate.getName() << std::endl; + std::cout << "accumulated.getName() " << accumulated.getName() << std::endl; + + foreach_distance( + ghost_type2, + [this,ghost_type2, &to_accumulate, + &accumulated](const auto & q1, const auto & q2, auto & weight) { + auto && to_acc_1 = to_accumulate.get(q1); + auto && acc_2 = accumulated.get(q2); + acc_2(0) =std::max(acc_2(0),this->Dm*(to_acc_1(0)-weight(0)/this->neighborhood_radius)); + // acc_1 =this->Dm*(to_acc_2+weight(0)/this->neighborhood_radius); + }); +} + +/* -------------------------------------------------------------------------- */ +template <class DistanceFunction> +void CLIPNeighborhood<DistanceFunction>::weightedDerivativeAverageOnNeighbours( + const ElementTypeMapReal & to_accumulate, ElementTypeMapReal & accumulated, + Int /*nb_degree_of_freedom*/, GhostType ghost_type2) const { + + std::cout << "CLIPNeighborhood::In weightedDerivativeAverageOnNeighbours " << std::endl; + + // auto it = non_local_variables.find(accumulated.getName()); + // // do averaging only for variables registered in the neighborhood + // if (it == non_local_variables.end()) { + // return; + // } + + std::cout << "to_accumulate.getName() " << to_accumulate.getName() << std::endl; + std::cout << "accumulated.getName() " << accumulated.getName() << std::endl; + + foreach_derivative_weight( + ghost_type2, + [this,ghost_type2, &to_accumulate, + &accumulated](const auto & q1, const auto & q2, auto & weight) { + auto && acc_1 = accumulated.get(q1); + auto && to_acc_2 = to_accumulate.get(q2); + acc_1 += weight(0) * to_acc_2; + }); +} + +/* -------------------------------------------------------------------------- */ +template <class DistanceFunction> +void CLIPNeighborhood<DistanceFunction>::updateWeights() { + // Update the weights for the non local variable averaging + if (this->distance_function->getUpdateRate() and + (this->non_local_manager.getNbStressCalls() % + this->distance_function->getUpdateRate() == + 0)) { + SynchronizerRegistry::synchronize(SynchronizationTag::_mnl_weight); + this->computeWeights(); + } +} + +} // namespace akantu + +#endif /* __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL__ */ diff --git a/src/model/common/non_local_toolbox/neighborhood_base.hh b/src/model/common/non_local_toolbox/neighborhood_base.hh index 061c2fdfd22513923fcdfb0bc294ac538fa691cc..4a74b9f19eabdf490f3f918154b23e3278f6bc66 100644 --- a/src/model/common/non_local_toolbox/neighborhood_base.hh +++ b/src/model/common/non_local_toolbox/neighborhood_base.hh @@ -61,7 +61,7 @@ public: const VectorProxy<const Real> & coords); /// create the pairs of quadrature points - void updatePairList(); + virtual void updatePairList(); /// save the pairs of quadrature points in a file void savePairs(const std::string & filename) const; diff --git a/src/model/common/non_local_toolbox/non_local_manager.cc b/src/model/common/non_local_toolbox/non_local_manager.cc index acfa9b7e033a987311c586c8f67d34d471825683..c0df1ca0b47faca73f714d469284c4a667e0edb4 100644 --- a/src/model/common/non_local_toolbox/non_local_manager.cc +++ b/src/model/common/non_local_toolbox/non_local_manager.cc @@ -21,10 +21,12 @@ /* -------------------------------------------------------------------------- */ #include "non_local_manager.hh" #include "base_weight_function.hh" +#include "base_distance_function.hh" #include "grid_synchronizer.hh" #include "integrator.hh" #include "model.hh" #include "non_local_neighborhood.hh" +#include "clip_neighborhood.hh" /* -------------------------------------------------------------------------- */ #include <numeric> /* -------------------------------------------------------------------------- */ @@ -102,6 +104,7 @@ void NonLocalManager::setJacobians(const FEEngine & fe_engine, /* -------------------------------------------------------------------------- */ void NonLocalManager::createNeighborhood(const ID & weight_func, const ID & neighborhood_id) { + auto weight_func_it = this->weight_function_types.find(weight_func); AKANTU_DEBUG_ASSERT(weight_func_it != weight_function_types.end(), "No info found in the input file for the weight_function " @@ -111,7 +114,6 @@ void NonLocalManager::createNeighborhood(const ID & weight_func, const ParserSection & section = weight_func_it->second; const ID weight_func_type = section.getOption(); - /// create new neighborhood for given ID neighborhoods[neighborhood_id] = NonLocalNeighborhoodFactory::getInstance().allocate( weight_func_type, neighborhood_id, *this, diff --git a/src/model/common/non_local_toolbox/non_local_manager.hh b/src/model/common/non_local_toolbox/non_local_manager.hh index 065010de7dfcd2a9262d69ccc0a6f4430d58a517..f434b62472c050a3ac50fdda95e20721c7d922b4 100644 --- a/src/model/common/non_local_toolbox/non_local_manager.hh +++ b/src/model/common/non_local_toolbox/non_local_manager.hh @@ -180,6 +180,7 @@ private: ID id; protected: + /// the non-local neighborhoods present NeighborhoodMap neighborhoods; diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh b/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh index 178e0c29f45fc5d934b2d0b4e68ae17c26c79059..4458a6b1ba42cc8311ab661ea2a90a37fa856344 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh +++ b/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh @@ -20,6 +20,7 @@ /* -------------------------------------------------------------------------- */ #include "neighborhood_base.hh" +#include "non_local_manager.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ @@ -118,6 +119,10 @@ protected: std::set<ID> non_local_variables; }; +using NonLocalNeighborhoodFactory = + Factory<NonLocalNeighborhoodBase, ID, ID, NonLocalManager &, + const ElementTypeMapReal &, const ID &>; + } // namespace akantu #endif /* AKANTU_NON_LOCAL_NEIGHBORHOOD_BASE_HH_ */ diff --git a/src/model/contact_mechanics/contact_mechanics_model.cc b/src/model/contact_mechanics/contact_mechanics_model.cc index e260c669384e4a0e8d16d66f5cbef07814ca28a6..f12f2f9de52208efce57f032a4932adb6446c591 100644 --- a/src/model/contact_mechanics/contact_mechanics_model.cc +++ b/src/model/contact_mechanics/contact_mechanics_model.cc @@ -37,7 +37,8 @@ namespace akantu { ContactMechanicsModel::ContactMechanicsModel( Mesh & mesh, Int dim, const ID & id, std::shared_ptr<DOFManager> dof_manager, const ModelType model_type) - : Model(mesh, model_type, dim, id) { + : Model(mesh, model_type, dim, id), + BoundaryCondition<ContactMechanicsModel>("displacement") { AKANTU_DEBUG_IN(); @@ -484,8 +485,8 @@ void ContactMechanicsModel::computeNodalAreas(GhostType ghost_type) { ghost_type, element_ids); this->getDOFManager().assembleElementalArrayLocalArray( - dual_by_shapes_integ, *external_force, type, ghost_type, 1., - element_ids); + "displacement", dual_by_shapes_integ, *external_force, type, ghost_type, + 1., element_ids); } for (auto && tuple : diff --git a/src/model/diffusion_model/diffusion_law.cc b/src/model/diffusion_model/diffusion_law.cc index 7b5ad1a4de74922400f2515e9adb99cba4cee352..ebe76e7c56caa1cfae09b358b31e9407231e62f7 100644 --- a/src/model/diffusion_model/diffusion_law.cc +++ b/src/model/diffusion_model/diffusion_law.cc @@ -66,8 +66,8 @@ void DiffusionLaw::assembleInternalFlow(GhostType ghost_type) { elem_filter); model.getDOFManager().assembleElementalArrayLocalArray( - int_bt_d_gu, model.getInternalFlow(), type, ghost_type, -1, - elem_filter); + model.getDOFName(), int_bt_d_gu, model.getInternalFlow(), type, + ghost_type, -1, elem_filter); } } diff --git a/src/model/diffusion_model/diffusion_model.cc b/src/model/diffusion_model/diffusion_model.cc index 27338c55fba863459d0a5c25429e99c802d3d72c..6e308c33db6d8d1424be7a27c6fe06f0a4d33590 100644 --- a/src/model/diffusion_model/diffusion_model.cc +++ b/src/model/diffusion_model/diffusion_model.cc @@ -135,7 +135,7 @@ void DiffusionModel::initSolver(TimeStepSolverType time_step_solver_type, this->allocNodalField(this->blocked_dofs, 1, "blocked_dofs"); if (not dof_manager.hasDOFs(dof_name)) { - dof_manager.registerDOFs(dof_name, *this->diffusion, _dst_nodal); + dof_manager.registerDOFs(dof_name, *this->diffusion, this->mesh); dof_manager.registerBlockedDOFs(dof_name, *this->blocked_dofs); } diff --git a/src/model/model_couplers/coupler_solid_phasefield.cc b/src/model/model_couplers/coupler_solid_phasefield.cc index 6a259cfd8593d23d64b0e90dbe9d4242743abb8b..7a626ffa95eb135da8891204eaaa6f396724810e 100644 --- a/src/model/model_couplers/coupler_solid_phasefield.cc +++ b/src/model/model_couplers/coupler_solid_phasefield.cc @@ -33,7 +33,8 @@ namespace akantu { CouplerSolidPhaseField::CouplerSolidPhaseField(Mesh & mesh, Int dim, const ID & id, const ModelType model_type) - : Model(mesh, model_type, dim, id) { + : Model(mesh, model_type, dim, id), + BoundaryCondition<CouplerSolidPhaseField>("displacement") { this->registerFEEngineObject<MyFEEngineType>("CouplerSolidPhaseField", mesh, Model::spatial_dimension); diff --git a/src/model/phase_field/phase_field_model.cc b/src/model/phase_field/phase_field_model.cc index b3f3618a9fcf217b8c74c20b54e9c09f052e5115..6f3fefbf5e49aa6a44824aa3f09aac03e9b131e4 100644 --- a/src/model/phase_field/phase_field_model.cc +++ b/src/model/phase_field/phase_field_model.cc @@ -39,7 +39,8 @@ namespace akantu { PhaseFieldModel::PhaseFieldModel(Mesh & mesh, Int dim, const ID & id, std::shared_ptr<DOFManager> dof_manager, ModelType model_type) - : Parent(mesh, model_type, dim, id) { + : Parent(mesh, model_type, dim, id), BoundaryCondition<PhaseFieldModel>( + "damage") { AKANTU_DEBUG_IN(); this->initDOFManager(std::move(dof_manager)); @@ -109,7 +110,7 @@ void PhaseFieldModel::initSolver(TimeStepSolverType time_step_solver_type, this->allocNodalField(this->previous_damage, 1, "previous_damage"); if (!dof_manager.hasDOFs("damage")) { - dof_manager.registerDOFs("damage", *this->damage, _dst_nodal); + dof_manager.registerDOFs("damage", *this->damage, mesh); dof_manager.registerBlockedDOFs("damage", *this->blocked_dofs); dof_manager.registerDOFsPrevious("damage", *this->previous_damage); } diff --git a/src/model/phase_field/phasefield.cc b/src/model/phase_field/phasefield.cc index cbce39571501dc48aecafd394d8778f5dc009f8e..0025044ca59687067198ae889b9b698b83b007e1 100644 --- a/src/model/phase_field/phasefield.cc +++ b/src/model/phase_field/phasefield.cc @@ -121,7 +121,7 @@ void PhaseField::assembleInternalForces(GhostType ghost_type) { type, ghost_type, elem_filter); handler.getDOFManager().assembleElementalArrayLocalArray( - int_nt_driving_force, internal_force, type, ghost_type, -1, + "damage", int_nt_driving_force, internal_force, type, ghost_type, -1, elem_filter); // damage_energy_on_qpoints = gc*l0 = scalar @@ -136,7 +136,7 @@ void PhaseField::assembleInternalForces(GhostType ghost_type) { nb_nodes_per_element, type, ghost_type, elem_filter); handler.getDOFManager().assembleElementalArrayLocalArray( - int_bt_driving_energy, internal_force, type, ghost_type, -1, + "damage", int_bt_driving_energy, internal_force, type, ghost_type, -1, elem_filter); } } diff --git a/src/model/solid_mechanics/material.cc b/src/model/solid_mechanics/material.cc index 5fd5737aafdae3dee6f78a344cec628910870e15..54d87409641a7c34567451e00571946b8a2b214a 100644 --- a/src/model/solid_mechanics/material.cc +++ b/src/model/solid_mechanics/material.cc @@ -127,7 +127,6 @@ void Material::assembleInternalForces(GhostType ghost_type) { */ void Material::computeAllStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); - auto spatial_dimension = getModel().getSpatialDimension(); auto & fem = getFEEngine(); for (const auto & type : @@ -506,7 +505,8 @@ void Material::assembleInternalForces(GhostType ghost_type) { /// assemble getModel().getDOFManager().assembleElementalArrayLocalArray( - *int_sigma_dphi_dx, internal_force, type, ghost_type, -1, elem_filter); + "displacement", *int_sigma_dphi_dx, internal_force, type, ghost_type, -1, + elem_filter); } /* -------------------------------------------------------------------------- */ template <Int dim> @@ -578,7 +578,7 @@ void Material::assembleInternalForcesFiniteDeformation(GhostType ghost_type) { fem.integrate(*bt_s, *r_e, bt_s_size, type, ghost_type, elem_filter); getModel().getDOFManager().assembleElementalArrayLocalArray( - *r_e, internal_force, type, ghost_type, -1., elem_filter); + "displacement", *r_e, internal_force, type, ghost_type, -1., elem_filter); AKANTU_DEBUG_OUT(); } diff --git a/src/model/solid_mechanics/materials/material_elastic_inline_impl.hh b/src/model/solid_mechanics/materials/material_elastic_inline_impl.hh index 5a6f6191a43a13dae8c778449608e1b45f863bf5..5a0423c83edeebe77898e3a6157d578271ad365b 100644 --- a/src/model/solid_mechanics/materials/material_elastic_inline_impl.hh +++ b/src/model/solid_mechanics/materials/material_elastic_inline_impl.hh @@ -113,6 +113,8 @@ template <class Args> inline void MaterialElastic<dim>::computePotentialEnergyOnQuad(Args && args, Real & epot) { epot = .5 * args["sigma"_n].doubleDot(args["grad_u"_n]); + // std::cout << "epot "<< epot << std::endl ; + } } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model.cc b/src/model/solid_mechanics/solid_mechanics_model.cc index 21737ca8dbd46d38d3c20ec9b00f9611267ca984..c58504f17e9ad219cf56382adb8bea12746aa13b 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.cc +++ b/src/model/solid_mechanics/solid_mechanics_model.cc @@ -52,7 +52,8 @@ namespace akantu { SolidMechanicsModel::SolidMechanicsModel( Mesh & mesh, Int dim, const ID & id, const std::shared_ptr<DOFManager> & dof_manager, const ModelType model_type) - : CLHParent(mesh, model_type, dim, id) { + : CLHParent(mesh, model_type, dim, id), + BoundaryCondition<SolidMechanicsModel>("displacement") { AKANTU_DEBUG_IN(); this->initDOFManager(dof_manager); @@ -207,7 +208,7 @@ void SolidMechanicsModel::initSolver(TimeStepSolverType time_step_solver_type, /* ------------------------------------------------------------------------ */ if (!dof_manager.hasDOFs("displacement")) { - dof_manager.registerDOFs("displacement", *this->displacement, _dst_nodal); + dof_manager.registerDOFs("displacement", *this->displacement, this->mesh); dof_manager.registerBlockedDOFs("displacement", *this->blocked_dofs); dof_manager.registerDOFsIncrement("displacement", *this->displacement_increment); @@ -336,7 +337,7 @@ void SolidMechanicsModel::assembleInternalForces() { AKANTU_DEBUG_INFO("Assemble the internal forces"); this->internal_force->zero(); - + // compute the stresses of local elements AKANTU_DEBUG_INFO("Compute local stresses"); for_each_constitutive_law( @@ -521,9 +522,11 @@ Real SolidMechanicsModel::getKineticEnergy() { } mesh.getCommunicator().allReduce(ekin, SynchronizerOperation::_sum); + Real kinetic_energy = ekin / 2.; + AKANTU_DEBUG_OUT(); - return ekin / 2.; + return kinetic_energy; } /* -------------------------------------------------------------------------- */ @@ -661,38 +664,22 @@ void SolidMechanicsModel::onNodesAdded(const Array<Idx> & nodes_list, AKANTU_DEBUG_IN(); auto nb_nodes = mesh.getNbNodes(); + for (auto && ptr : + {displacement.get(), velocity.get(), acceleration.get(), mass.get(), + external_force.get(), internal_force.get(), current_position.get(), + previous_displacement.get(), displacement_increment.get()}) { + if (ptr != nullptr) { + ptr->resize(nb_nodes, 0.); + } + } + if (displacement) { - displacement->resize(nb_nodes, 0.); ++displacement_release; } - if (mass) { - mass->resize(nb_nodes, 0.); - } - if (velocity) { - velocity->resize(nb_nodes, 0.); - } - if (acceleration) { - acceleration->resize(nb_nodes, 0.); - } - if (external_force) { - external_force->resize(nb_nodes, 0.); - } - if (internal_force) { - internal_force->resize(nb_nodes, 0.); - } + if (blocked_dofs) { blocked_dofs->resize(nb_nodes, false); } - if (current_position) { - current_position->resize(nb_nodes, 0.); - } - - if (previous_displacement) { - previous_displacement->resize(nb_nodes, 0.); - } - if (displacement_increment) { - displacement_increment->resize(nb_nodes, 0.); - } for_each_constitutive_law( [&](auto && material) { material.onNodesAdded(nodes_list, event); }); @@ -707,35 +694,21 @@ void SolidMechanicsModel::onNodesAdded(const Array<Idx> & nodes_list, void SolidMechanicsModel::onNodesRemoved(const Array<Idx> & /*element_list*/, const Array<Idx> & new_numbering, const RemovedNodesEvent & /*event*/) { - if (displacement) { - mesh.removeNodesFromArray(*displacement, new_numbering); - ++displacement_release; - } - if (mass) { - mesh.removeNodesFromArray(*mass, new_numbering); - } - if (velocity) { - mesh.removeNodesFromArray(*velocity, new_numbering); - } - if (acceleration) { - mesh.removeNodesFromArray(*acceleration, new_numbering); - } - if (internal_force) { - mesh.removeNodesFromArray(*internal_force, new_numbering); - } - if (external_force) { - mesh.removeNodesFromArray(*external_force, new_numbering); + for (auto && ptr : + {displacement.get(), velocity.get(), acceleration.get(), mass.get(), + external_force.get(), internal_force.get(), previous_displacement.get(), + displacement_increment.get()}) { + if (ptr != nullptr) { + mesh.removeNodesFromArray(*ptr, new_numbering); + } } + if (blocked_dofs) { mesh.removeNodesFromArray(*blocked_dofs, new_numbering); } - if (displacement_increment) { - mesh.removeNodesFromArray(*displacement_increment, new_numbering); - } - - if (previous_displacement) { - mesh.removeNodesFromArray(*previous_displacement, new_numbering); + if (displacement) { + ++displacement_release; } } diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.cc new file mode 100644 index 0000000000000000000000000000000000000000..7fdac579533135b81e1697564e9a191477f4992c --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.cc @@ -0,0 +1,127 @@ +/** + * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "material_bulk_damage.hh" +#include "aka_common.hh" +#include "solid_mechanics_model.hh" + +namespace akantu { + +/* -------------------------------------------------------------------------- */ +template <Int dim> +MaterialBulkDamage<dim>::MaterialBulkDamage(SolidMechanicsModel & model, + const ID & id) + : Parent(model, id), + objective_functional(this->registerInternal("objective_functional", 1)) { + AKANTU_DEBUG_IN(); + this->registerParam("Dm", Dm, _pat_parsable | _pat_readable, + "Clip Parameter"); + + this->registerParam("sigma_c", sigc, _pat_parsable | _pat_readable, + "Critical stress"); + + this->registerParam("G_c", G_c, _pat_parsable | _pat_readable, + "Fracture energy"); + + this->registerParam("lc", lc, _pat_parsable | _pat_readable, + "Regularising length"); + + AKANTU_DEBUG_OUT(); +} +/* -------------------------------------------------------------------------- */ +template <Int dim> +void MaterialBulkDamage<dim>::initMaterial() { + AKANTU_DEBUG_IN(); + + Parent::initMaterial(); + + // This is a quick fix : sigc and wc should be CohesiveInternalField<Real>/FacetInternalField<Real> + + lch = (this->E * G_c)/(pow(sigc, 2)); + gamma = lc/lch; + Yc = (sigc*sigc)/(2*this->E); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +void MaterialBulkDamage<dim>::computeStress(ElementType el_type, + GhostType ghost_type) { + for (auto && args : getArguments(el_type, ghost_type)) { + computeStressOnQuad(args); + } +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +void MaterialBulkDamage<dim>::computeTangentModuli(ElementType el_type, + Array<Real> & tangent_matrix, + GhostType ghost_type) { + for (auto && args : + getArgumentsTangent(tangent_matrix, el_type, ghost_type)) { + computeTangentModuliOnQuad(args); + } +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +Real MaterialBulkDamage<dim>::computeObjectiveFunctional() { + Real val(0.); + for (auto && type : this->getElementFilter().elementTypes(dim, _not_ghost)) { + for (auto && args : getArgumentsObjective(type)) { + computeObjectiveFunctionalOnQuad(args); + } + val += this->getFEEngine().integrate( + this->objective_functional(type, _not_ghost), type, _not_ghost, + this->getElementFilter(type, _not_ghost)); + } + return val; +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +Real MaterialBulkDamage<dim>::GD_clip_function(const Real D) +{ + Real num = gamma*pow((pow(D,2) - 1),2); + Real den = (2*D*Dm + gamma*pow((pow(D,2) - 1), 2)); + + return num/den; +} + +template <Int dim> +Real MaterialBulkDamage<dim>::HD_clip_function(const Real D) +{ + Real num = 2*D*Dm ; + Real den = (gamma*pow((pow(D,2) * Dm - pow(D,2) + 1),2)); + + return num/den; +} + +/* -------------------------------------------------------------------------- */ +template class MaterialBulkDamage<1>; +template class MaterialBulkDamage<2>; +template class MaterialBulkDamage<3>; + +const bool material_is_allocated_bulk [[maybe_unused]] = + instantiateMaterial<MaterialBulkDamage>("bulk_damage"); + +} // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.hh new file mode 100644 index 0000000000000000000000000000000000000000..c19485adbc52cddff49166b9cc7560c5d766fd79 --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage.hh @@ -0,0 +1,114 @@ +/** + * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "aka_common.hh" +#include "material.hh" +#include "material_damage.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef AKANTU_MATERIAL_BULK_DAMAGE_HH_ +#define AKANTU_MATERIAL_BULK_DAMAGE_HH_ + +namespace akantu { + +template <Int dim> class MaterialBulkDamage : public MaterialDamage<dim> { + using Parent = MaterialDamage<dim>; + /* ------------------------------------------------------------------------ */ + /* Constructors/Destructors */ + /* ------------------------------------------------------------------------ */ +public: + MaterialBulkDamage(SolidMechanicsModel & model, const ID & id = ""); + + /* ------------------------------------------------------------------------ */ + /* Methods */ + /* ------------------------------------------------------------------------ */ +public: + + /// initialize the material parameters + void initMaterial() override; + + /// constitutive law for all element of a type + void computeStress(ElementType el_type, + GhostType ghost_type = _not_ghost) override; + + /// compute the tangent stiffness matrix for an element type + void computeTangentModuli(ElementType el_type, Array<Real> & tangent_matrix, + GhostType ghost_type = _not_ghost) override; + + /// objective function for all element of a type + Real computeObjectiveFunctional(); + + /* ------------------------------------------------------------------------ */ + decltype(auto) getArguments(ElementType el_type, + GhostType ghost_type = _not_ghost) { + return zip_append(Parent::getArguments(el_type, ghost_type), + "damage"_n = make_view(this->damage(el_type, ghost_type))); + } + + decltype(auto) getArgumentsTangent(Array<Real> & tangent_matrix, + ElementType el_type, + GhostType ghost_type) { + return zip_append( + Parent::getArgumentsTangent(tangent_matrix, el_type, ghost_type), + "damage"_n = make_view(this->damage(el_type, ghost_type))); + } + + decltype(auto) getArgumentsObjective(ElementType el_type) { + return zip_append(Parent::getArguments(el_type, _not_ghost), + "damage"_n = make_view(this->damage(el_type, _not_ghost)), + "objective"_n = make_view(this->objective_functional(el_type, _not_ghost))); + } + +protected: + /// constitutive law for a given quadrature point + template <class Args> inline void computeStressOnQuad(Args && args); + + /// compute the tangent stiffness matrix for a given quadrature point + template <class Args> inline void computeTangentModuliOnQuad(Args && args); + + /// compute the objective function for a given quadrature point + template <class Args> inline void computeObjectiveFunctionalOnQuad(Args && args); + + /* ------------------------------------------------------------------------ */ + /* Class Members */ + /* ------------------------------------------------------------------------ */ +protected: + + Real GD_clip_function(const Real D); + // Real GD_clip_function_first_derivative(const Real D, const Real gamma); + + Real HD_clip_function(const Real D); + // Real HD_clip_function_first_derivative(const Real D, const Real gamma); + + Real lc, Dm, lch, gamma, sigc, G_c, Yc; + /// objective functional at quadrature points + InternalField<Real> & objective_functional; +}; + +} // namespace akantu + +/* -------------------------------------------------------------------------- */ +/* inline functions */ +/* -------------------------------------------------------------------------- */ + +#include "material_bulk_damage_inline_impl.hh" + +#endif /* AKANTU_MATERIAL_BULK_DAMAGE_HH_ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_inline_impl.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_inline_impl.hh new file mode 100644 index 0000000000000000000000000000000000000000..ba25535265ced738f93283946f2c6ee4e2d1ac8c --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_inline_impl.hh @@ -0,0 +1,58 @@ +/** + * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "material_bulk_damage.hh" + +#ifndef AKANTU_MATERIAL_BULK_DAMAGE_INLINE_IMPL_HH_ +#define AKANTU_MATERIAL_BULK_DAMAGE_INLINE_IMPL_HH_ +/* -------------------------------------------------------------------------- */ +namespace akantu { +template <Int dim> +template <class Args> +inline void MaterialBulkDamage<dim>::computeStressOnQuad(Args && args) { + MaterialElastic<dim>::computeStressOnQuad(args); + auto && dam = args["damage"_n]; + args["sigma"_n] *= GD_clip_function(dam); +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +template <class Args> +void MaterialBulkDamage<dim>::computeTangentModuliOnQuad(Args && args) { + MaterialElastic<dim>::computeTangentModuliOnQuad(args); + + auto dam = args["damage"_n]; + /// TODO : replace (1 - dam) by G(D) + args["tangent_moduli"_n] *= (1 - dam); +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +template <class Args> +void MaterialBulkDamage<dim>::computeObjectiveFunctionalOnQuad(Args && args) { + auto && obj = args["objective"_n]; + auto && sigma = args["sigma"_n]; + auto && eps = Material::gradUToEpsilon<dim>(args["grad_u"_n]); + auto && dam = args["damage"_n]; + obj = 0.5*sigma.doubleDot(eps)*GD_clip_function(dam) + Yc*HD_clip_function(dam); +} + +} // namespace akantu +#endif diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.cc new file mode 100644 index 0000000000000000000000000000000000000000..223291a7ac8ba2b778cb92a2f924876a13c33db8 --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.cc @@ -0,0 +1,35 @@ +/** + * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "material_bulk_damage_non_local.hh" + +namespace akantu { + +template class MaterialBulkDamageNonLocal<1>; +template class MaterialBulkDamageNonLocal<2>; +template class MaterialBulkDamageNonLocal<3>; + +template <Int dim> using MaterialBulkDamageNonLocal_ = MaterialBulkDamageNonLocal<dim>; + +static bool material_is_alocated_bulk_damage_non_local = + instantiateMaterial<MaterialBulkDamageNonLocal_>("bulk_damage_non_local"); + +} // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.hh new file mode 100644 index 0000000000000000000000000000000000000000..e9740e0d8a081374b9b41b12d5ce2ec96c2dadba --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local.hh @@ -0,0 +1,79 @@ +/** + * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "aka_common.hh" +#include "material_damage_non_local.hh" +#include "material_bulk_damage.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_HH_ +#define AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_HH_ + +namespace akantu { + +/** + * Material bulk damage Non local + * + * parameters in the material files : + */ +template <Int dim> +class MaterialBulkDamageNonLocal + : public MaterialDamageNonLocal<dim, MaterialBulkDamage<dim>> { + /* ------------------------------------------------------------------------ */ + /* Constructors/Destructors */ + /* ------------------------------------------------------------------------ */ +public: + using parent = MaterialDamageNonLocal<dim, MaterialBulkDamage<dim>>; + + MaterialBulkDamageNonLocal(SolidMechanicsModel & model, const ID & id = ""); + + /* ------------------------------------------------------------------------ */ + /* Methods */ + /* ------------------------------------------------------------------------ */ +protected: + /// constitutive law for all element of a type + void computeStress(ElementType el_type, + GhostType ghost_type = _not_ghost) override; + + void computeNonLocalStress(ElementType el_type, + GhostType ghost_type = _not_ghost) override; + + void registerNonLocalVariables() override; + + ID getNeighborhoodName() override {return "clip"; }; + + /* ------------------------------------------------------------------------ */ + /* Accessors */ + /* ------------------------------------------------------------------------ */ +public: + + /* ------------------------------------------------------------------------ */ + /* Class Members */ + /* ------------------------------------------------------------------------ */ +private: + +}; + +} // namespace akantu + +#include "material_bulk_damage_non_local_tmpl.hh" + +#endif /* AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_HH_ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local_tmpl.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local_tmpl.hh new file mode 100644 index 0000000000000000000000000000000000000000..a0d836a6e5bdfa4397d9fdad9ceb3c77a944af84 --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_bulk_damage_non_local_tmpl.hh @@ -0,0 +1,67 @@ +/** + * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "solid_mechanics_model.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_TMPL_HH_ +#define AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_TMPL_HH_ + +namespace akantu { + +/* -------------------------------------------------------------------------- */ +template <Int dim> +MaterialBulkDamageNonLocal<dim>::MaterialBulkDamageNonLocal( + SolidMechanicsModel & model, const ID & id):parent(model,id) + { + AKANTU_DEBUG_IN(); + + this->is_non_local = true; + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +void MaterialBulkDamageNonLocal<dim>::registerNonLocalVariables() { + this->getModel() + .getNonLocalManager() + .getNeighborhood(this->getNeighborhoodName()) + .registerNonLocalVariable(this->damage.getName()); +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +void MaterialBulkDamageNonLocal<dim>::computeStress(ElementType el_type, + GhostType ghost_type) { + parent::MaterialParent::computeStress(el_type,ghost_type); +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +void MaterialBulkDamageNonLocal<dim>::computeNonLocalStress( + ElementType /*el_type*/, GhostType /*ghost_type*/) { +/// TODO +} + +} // namespace akantu + +#endif // AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_TMPL_HH_ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc index 7e8776ea854a5912fd3bbb79022307fc04799957..8b5a58f4ff463d6ad8120ffee23affc355117829 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc @@ -165,7 +165,8 @@ void MaterialCohesive::assembleInternalForces(GhostType ghost_type) { /// assemble model->getDOFManager().assembleElementalArrayLocalArray( - *int_t_N, internal_force, type, ghost_type, 1, elem_filter); + "displacement", *int_t_N, internal_force, type, ghost_type, 1, + elem_filter); } AKANTU_DEBUG_OUT(); @@ -283,11 +284,13 @@ void MaterialCohesive::assembleStiffnessMatrix(GhostType ghost_type) { */ void MaterialCohesive::computeTraction(GhostType ghost_type) { AKANTU_DEBUG_IN(); - + for (const auto & type : getElementFilter().elementTypes( spatial_dimension, ghost_type, _ek_cohesive)) { + auto & elem_filter = getElementFilter(type, ghost_type); auto nb_element = elem_filter.size(); + if (nb_element == 0) { continue; } @@ -299,7 +302,7 @@ void MaterialCohesive::computeTraction(GhostType ghost_type) { /// compute openings @f$\mathbf{\delta}@f$ computeOpening(model->getDisplacement(), opening(type, ghost_type), type, ghost_type); - + /// compute traction @f$\mathbf{t}@f$ computeTraction(type, ghost_type); } diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh index a7bc0bec294b08a5249d06e27282dbbaeb85ac17..05eff0e60a111b099a11ec435b00f9be45dab5d3 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh @@ -40,8 +40,8 @@ class MaterialCohesive : public Material { /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: - using MyFEEngineCohesiveType = - FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive>; + using MyFEEngineCohesiveType = + FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive>; public: MaterialCohesive(SolidMechanicsModel & model, const ID & id = ""); @@ -62,6 +62,15 @@ public: AKANTU_TO_IMPLEMENT(); } + /// compute Lagrange multiplier + virtual void computeLambda(GhostType /*ghost_type*/ = _not_ghost) { + AKANTU_TO_IMPLEMENT(); + } + + virtual void computeDamage(GhostType /*ghost_type*/ = _not_ghost){ + AKANTU_TO_IMPLEMENT(); + } + /// interpolate stress on given positions for each element (empty /// implemantation to avoid the generic call to be done on cohesive elements) virtual void interpolateStress(const ElementType /*type*/, @@ -121,6 +130,8 @@ protected: AKANTU_TO_IMPLEMENT(); } + + /// parallelism functions [[nodiscard]] inline Int getNbData(const Array<Element> & elements, @@ -176,6 +187,8 @@ public: // return Material::getEnergy(energy_id, element); // } + [[nodiscard]] virtual bool needLambda() const { return false; } + /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.cc new file mode 100644 index 0000000000000000000000000000000000000000..444c3e6422a483f0ab7121298000449c08b00a9b --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.cc @@ -0,0 +1,188 @@ +/** + * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "material_cohesive_damage.hh" +//#include "solid_mechanics_model_cohesive.hh" +/* -------------------------------------------------------------------------- */ +#include <algorithm> +#include <numeric> +/* -------------------------------------------------------------------------- */ + +namespace akantu { + +/* -------------------------------------------------------------------------- */ +MaterialCohesiveDamage::MaterialCohesiveDamage(SolidMechanicsModel & model, + const ID & id) + : MaterialCohesive(model, id) +{ + AKANTU_DEBUG_IN(); + + this->registerParam("k", k, _pat_parsable | _pat_readable, + "Cohesive stiffness parameter"); + + this->registerParam("G_c", G_c, _pat_parsable | _pat_readable, + "Mode I fracture energy"); + + this->registerParam("E", E_coh, _pat_parsable | _pat_readable, + "Youngs Modulus Cohesive"); + + this->registerParam("lc", lc, _pat_parsable | _pat_readable |_pat_modifiable, + "Regularising length"); + + this->registerParam("Dm", Dm, _pat_parsable | _pat_readable, + "Clip Parameter"); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void MaterialCohesiveDamage::initMaterial() { + AKANTU_DEBUG_IN(); + + MaterialCohesive::initMaterial(); + + // This is a quick fix : sigc and wc should be CohesiveInternalField<Real>/FacetInternalField<Real> + sigc = sigma_c; + wc = 2.*G_c/sigc; + a = k*wc/sigc; + + lch = (E_coh * G_c)/(pow(sigc, 2)); + gamma = lc/lch; + + yc = (sigc*sigc)/(2*k); + Yc = (sigc*sigc)/(2*E_coh); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +Real MaterialCohesiveDamage::stiffness(const Real d) +{ + return k*(1./d-1.); +} + +Real MaterialCohesiveDamage::augmented_stiffness(const Real d) +{ + return k*1./d; +} + +Real MaterialCohesiveDamage::augmented_compliance(const Real d) +{ + return d/k; +} + +Real MaterialCohesiveDamage::augmented_compliance_first_derivative(const Real /*d*/) +{ + return 1./k; +} + +Real MaterialCohesiveDamage::augmented_compliance_second_derivative(const Real /*d*/) +{ + return 0.; +} + +Real MaterialCohesiveDamage::softening(const Real d) +{ + return d/(d+a*(1.-d)); +} + +Real MaterialCohesiveDamage::softening_first_derivative(const Real d) +{ + return a/pow(d+a*(1.-d),2); +} + +Real MaterialCohesiveDamage::softening_second_derivative(const Real d) +{ + return -2.*(1.-a)*a/pow(d+a*(1.-d),3); +} + +Real MaterialCohesiveDamage::gd_clip_function(const Real d) +{ + return (1-d)/((1 - Dm)*d); +} + +Real MaterialCohesiveDamage::gd_clip_function_first_derivative(const Real d) +{ + return 1./(pow(d,2)*(Dm -1)); +} + +Real MaterialCohesiveDamage::hd_clip_function(const Real d) +{ + Real num = 2 * d * (pow(Dm, 6) * pow(d, 4) + - 5 * pow(Dm, 5) * pow(d, 4) + + 2 * pow(Dm, 5) * pow(d, 3) + + 4 * pow(Dm, 4) * pow(d, 4) + - 2 * pow(Dm, 4) *pow(d, 3) + - pow(Dm, 4) * pow(d, 2) + + 4 * pow(Dm, 3) * pow(d, 2) + - 3 * pow(Dm, 2) * pow(d, 2) + - Dm + 1 + ); + + Real den = ( + std::pow(Dm, 6) * std::pow(d, 5) + - 2 * std::pow(Dm, 5) * std::pow(d, 5) + + std::pow(Dm, 4) * std::pow(d, 5) + - std::pow(Dm, 4) * std::pow(d, 3) + + std::pow(Dm, 3) * std::pow(d, 3) + + 2 * std::pow(Dm, 3) * std::pow(d, 2) + - 2 * std::pow(Dm, 2) * std::pow(d, 2) + - Dm * d - d + 2 + ); + + if (den == 0){ + throw std::runtime_error("Divison by zero in h(d) function"); + } + return num/den; +} + +Real MaterialCohesiveDamage::hd_clip_function_first_derivative(const Real d) +{ + + + Real numerator = 2*((8*pow(Dm,4)*pow(d,3)*(pow(Dm,2) - 2*Dm + 1) + 9*pow(Dm,2)*pow(d,2)*(1 - Dm) - 4*pow(Dm,2)*d*(pow(Dm,2) - 5*Dm + 4) - Dm - 5)*pow((pow(Dm,4)*pow(d,5)*(pow(Dm,3) - 3*pow(Dm,2) + 3*Dm - 1) - pow(Dm,3)*pow(d,3)*(pow(Dm,2) - 2*Dm + 1) + 2*pow(Dm,2)*pow(d,2)*(pow(Dm,2) - 2*Dm + 1) + 2*Dm - d*(pow(Dm,2) - 1) - 2),2) + (5*pow(Dm,4)*pow(d,4)*(pow(Dm,3) - 3*pow(Dm,2) + 3*Dm - 1) + 3*pow(Dm,3)*pow(d,2)*(-pow(Dm,2) + 2*Dm - 1) + 4*pow(Dm,2)*d*(pow(Dm,2) - 2*Dm + 1) - pow(Dm,2) + 1)*(2*pow(Dm,4)*pow(d,4)*(-pow(Dm,2) + 2*Dm - 1) + 3*pow(Dm,2)*pow(d,3)*(Dm - 1) + 2*pow(Dm,2)*pow(d,2)*(pow(Dm,2)- 5*Dm + 4) + 2*Dm + d*(Dm + 5) - 8)*(pow(Dm,4)*pow(d,5)*(pow(Dm,3) - 3*pow(Dm,2) + 3*Dm - 1) + pow(Dm,3)*pow(d,3)*(-pow(Dm,2) + 2*Dm - 1) + 2*pow(Dm,2)*pow(d,2)*(pow(Dm,2) - 2*Dm + 1) + 2*Dm - d*(pow(Dm,2) - 1) - 2)); + + Real denominator = pow((pow(Dm,4)*pow(d,5)*(pow(Dm,3) - 3*pow(Dm,2) + 3*Dm - 1) - pow(Dm,3)*pow(d,3)*(pow(Dm,2) - 2*Dm + 1) + 2*pow(Dm,2)*pow(d,2)*(pow(Dm,2) - 2*Dm + 1) + 2*Dm - d*(pow(Dm,2) - 1) - 2),3); + + if (denominator == 0) { + throw std::runtime_error("Division by zero in h'(d) function"); + } + + return numerator / denominator; +} + +Real MaterialCohesiveDamage::GD_clip_function(const Real D) +{ + Real num = gamma*pow((pow(D,2) - 1),2); + Real den = (2*D*Dm + gamma*pow((pow(D,2) - 1), 2)); + + return num/den; +} + +Real MaterialCohesiveDamage::HD_clip_function(const Real D) +{ + Real num = 2*D*Dm ; + Real den = (gamma*pow((pow(D,2) * Dm - pow(D,2) + 1),2)); + + return num/den; +} + +} diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.hh new file mode 100644 index 0000000000000000000000000000000000000000..419205a8fa6c0240a9ec9f90476453ce677732f1 --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage.hh @@ -0,0 +1,148 @@ +/** + * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "material_cohesive.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef AKANTU_MATERIAL_COHESIVE_DAMAGE_HH_ +#define AKANTU_MATERIAL_COHESIVE_DAMAGE_HH_ + +namespace akantu { + +/** + * Cohesive material linear damage + * + * parameters in the material files : + * - sigma_c : critical stress sigma_c (default: 0) + * - G_c : fracture energy for mode I (default: 0) + * - k : cohesive stiffness + */ +class MaterialCohesiveDamage : public MaterialCohesive { + /* ------------------------------------------------------------------------ */ + /* Constructors/Destructors */ + /* ------------------------------------------------------------------------ */ +public: + MaterialCohesiveDamage(SolidMechanicsModel & model, const ID & id = ""); + + /* ------------------------------------------------------------------------ */ + /* Methods */ + /* ------------------------------------------------------------------------ */ +public: + /// initialize the material parameters + void initMaterial() override; + + virtual void computeDamage(GhostType /*ghost_type*/ = _not_ghost) + { + AKANTU_TO_IMPLEMENT(); + } + + virtual void readDamage(const Array<Element> &, const Array<Real> &) + { + AKANTU_TO_IMPLEMENT(); + } + + virtual void writeDamage(const Array<Element> &, Array<Real> &) const + { + AKANTU_TO_IMPLEMENT(); + } + + /// compute the objective function + virtual Real computeObjectiveFunctional() = 0; + + /// accessors + AKANTU_GET_MACRO(Lc, lc, Real); + AKANTU_GET_MACRO(Dm, Dm, Real); + + /* ------------------------------------------------------------------------ */ + /* Class Members */ + /* ------------------------------------------------------------------------ */ +protected: + + virtual void getArgumentsDamage(ElementType /*el_type*/, + GhostType /*ghost_type*/ = _not_ghost) { + AKANTU_TO_IMPLEMENT(); + } + /// compute the damage for a given quadrature point + template <typename Args> inline void computeDamageOnQuad(Args && args); + + inline Real computeResidual(Real d, Real target_omega2); + inline Real solveForDamageUsingLeastSquares(Real target_omega2, Real lower_bound, Real upper_bound, + Real tol, int max_iter); + /// these functions should be put in a separate class + Real stiffness(const Real d); + Real augmented_stiffness(const Real d); + + Real augmented_compliance(const Real d); + Real augmented_compliance_first_derivative(const Real d); + Real augmented_compliance_second_derivative(const Real d); + + Real softening(const Real d); + Real softening_first_derivative(const Real d); + Real softening_second_derivative(const Real d); + + Real gd_clip_function(const Real d); + Real gd_clip_function_first_derivative(const Real d); + + Real hd_clip_function(const Real d); + Real hd_clip_function_first_derivative(const Real d); + + /// WARNING : These functions should be in MaterialBulkDamage + /// They are necessary in MaterialCohesiveDamage only because + /// cohesive damage is computed using 1D stress/opening curve. + /// Once computation of d by (TAO) optimisation is implemented, + /// these functions should be removed from MaterialCohesiveDamage + Real GD_clip_function(const Real D); + // Real GD_clip_function_first_derivative(const Real D, const Real gamma); + + Real HD_clip_function(const Real D); + // Real HD_clip_function_first_derivative(const Real D, const Real gamma); + + /// cohesive stiffness + Real k; + + /// mode I fracture energy + Real G_c; + + /// CLIP regularization parameters + Real lc, Dm; + + /// critical stress and opening + Real sigc, wc; + + Real E_coh; + + /// parameter for softening function + Real a; + + Real lch, gamma; + + Real yc,Yc ; +}; + +/* -------------------------------------------------------------------------- */ +/* inline functions */ +/* -------------------------------------------------------------------------- */ + +} // namespace akantu + +#include "material_cohesive_damage_inline_impl.hh" + +#endif /* AKANTU_MATERIAL_COHESIVE_DAMAGE_HH_ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.cc new file mode 100644 index 0000000000000000000000000000000000000000..602303cbd3c560dd3b51e48d23c889a6ad929c01 --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.cc @@ -0,0 +1,392 @@ +/** + * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "material_cohesive_damage_extrinsic.hh" +#include "dof_synchronizer.hh" +#include "fe_engine_template.hh" +#include "integrator_gauss.hh" +#include "shape_cohesive.hh" +#include "solid_mechanics_model_cohesive_damage.hh" +#include "sparse_matrix.hh" +/* -------------------------------------------------------------------------- */ +#include <algorithm> +#include <numeric> +/* -------------------------------------------------------------------------- */ + +namespace akantu { + +/* -------------------------------------------------------------------------- */ +template <Int dim> +MaterialCohesiveDamageExtrinsic<dim>::MaterialCohesiveDamageExtrinsic(SolidMechanicsModel & model, + const ID & id) + : MaterialCohesiveDamage(model, id), + lambda(registerInternal<Real, CohesiveInternalField>("lambda", + spatial_dimension)), + czm_damage( + registerInternal<Real, CohesiveInternalField>("czm_damage", 1)), + insertion_stress(registerInternal<Real, CohesiveInternalField>( + "insertion_stress", dim)), + sigma_c_eff(registerInternal<Real, CohesiveRandomInternalField>( + "sigma_c_eff", 1)), + delta_c_eff( + registerInternal<Real, CohesiveInternalField>("delta_c_eff", 1)), + is_new_crack(registerInternal<Real, CohesiveInternalField>( + "is_new_crack", 1)), + objective_functional(registerInternal<Real, CohesiveInternalField>( + "objective_functional", 1)) +{ + + this->registerParam("max_quad_stress_insertion", max_quad_stress_insertion, + false, _pat_parsable | _pat_readable, + "Insertion of cohesive element when stress is high " + "enough just on one quadrature point"); + +// czm_damage.setDefaultValue(0.1); + is_new_crack.setDefaultValue(0.); +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> // NOLINTNEXTLINE(readability-function-cognitive-complexity) +void MaterialCohesiveDamageExtrinsic<dim>::checkInsertion(bool check_only) { + AKANTU_DEBUG_IN(); + + const auto & mesh_facets = model->getMeshFacets(); + auto & inserter = model->getElementInserter(); + + for (const auto & type_facet : mesh_facets.elementTypes(dim - 1)) { + auto type_cohesive = FEEngine::getCohesiveElementType(type_facet); + + const auto & facets_check = inserter.getCheckFacets(type_facet); + auto & f_insertion = inserter.getInsertionFacets(type_facet); + auto & sig_c_eff = sigma_c_eff(type_cohesive); + auto & del_c = delta_c_eff(type_cohesive); + auto & ins_stress = insertion_stress(type_cohesive); + auto & trac_old = tractions.previous(type_cohesive); + const auto & f_stress = model->getStressOnFacets(type_facet); + + const auto & facet_filter_array = getFacetFilter(type_facet); + const auto & sigma_limit_array = sigma_c(type_facet); + + auto nb_quad_facet = + model->getFEEngine("FacetsFEEngine").getNbIntegrationPoints(type_facet); + +#ifndef AKANTU_NDEBUG + auto nb_quad_cohesive = model->getFEEngine("CohesiveFEEngine") + .getNbIntegrationPoints(type_cohesive); + + AKANTU_DEBUG_ASSERT(nb_quad_cohesive == nb_quad_facet, + "The cohesive element and the corresponding facet do " + "not have the same numbers of integration points"); +#endif + + Matrix<Real, dim, dim> stress_tmp; + Matrix<Real> normal_traction(dim, nb_quad_facet); + Vector<Real> stress_check(nb_quad_facet); + + const auto & tangents = model->getTangents(type_facet); + const auto & normals = model->getFEEngine("FacetsFEEngine") + .getNormalsOnIntegrationPoints(type_facet); + auto normal_begin = make_view<dim>(normals).begin(); + auto tangent_begin = make_view<dim, (dim == 3 ? 2 : 1)>(tangents).begin(); + auto facet_stress_begin = make_view(f_stress, dim, dim, 2).begin(); + + std::vector<Real> new_sigmas; + std::vector<Vector<Real>> new_normal_traction; + std::vector<Real> new_delta_c; + + // loop over each facet belonging to this material + for (auto && [facet, sigma_limit] : + zip(facet_filter_array, sigma_limit_array)) { + // skip facets where check shouldn't be realized + if (!facets_check(facet)) { + continue; + } + + // compute the effective norm on each quadrature point of the facet + for (Int q = 0; q < nb_quad_facet; ++q) { + auto current_quad = facet * nb_quad_facet + q; + auto && normal = normal_begin[current_quad]; + auto && tangent = tangent_begin[current_quad]; + auto && facet_stress = facet_stress_begin[current_quad]; + + // compute average stress on the current quadrature point + auto && stress_1 = facet_stress(0); + auto && stress_2 = facet_stress(1); + + auto && stress_avg = (stress_1 + stress_2) / 2.; + + // compute normal and effective stress + stress_check(q) = computeEffectiveNorm(stress_avg, normal, tangent, + normal_traction(q)); + } + + // verify if the effective stress overcomes the threshold + auto final_stress = stress_check.mean(); + if (max_quad_stress_insertion) { + final_stress = + *std::max_element(stress_check.begin(), stress_check.end()); + } + + if (final_stress > sigma_limit) { + f_insertion(facet) = true; + + if (check_only) { + continue; + } + + // store the new cohesive material parameters for each quadrature + // point + for (Int q = 0; q < nb_quad_facet; ++q) { + auto new_sigma = stress_check(q); + auto && normal_traction_vec = normal_traction(q); + + if (dim != 3) { + normal_traction_vec *= -1.; + } + + new_sigmas.push_back(new_sigma); + new_normal_traction.emplace_back(normal_traction_vec); + + Real new_delta{}; + + // set delta_c in function of G_c or a given delta_c value + if (Math::are_float_equal(delta_c, 0.)) { + new_delta = 2 * G_c / new_sigma; + } else { + new_delta = sigma_limit / new_sigma * delta_c; + } + + new_delta_c.push_back(new_delta); + } + } + } + + // update material data for the new elements + auto old_nb_quad_points = sig_c_eff.size(); + Int new_nb_quad_points = Int(new_sigmas.size()); + sig_c_eff.resize(old_nb_quad_points + new_nb_quad_points); + ins_stress.resize(old_nb_quad_points + new_nb_quad_points); + trac_old.resize(old_nb_quad_points + new_nb_quad_points); + del_c.resize(old_nb_quad_points + new_nb_quad_points); + + for (Int q = 0; q < new_nb_quad_points; ++q) { + sig_c_eff(old_nb_quad_points + q) = new_sigmas[q]; + del_c(old_nb_quad_points + q) = new_delta_c[q]; + for (Int d = 0; d < dim; ++d) { + ins_stress(old_nb_quad_points + q, d) = new_normal_traction[q](d); + trac_old(old_nb_quad_points + q, d) = new_normal_traction[q](d); + } + } + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +void MaterialCohesiveDamageExtrinsic<dim>::computeLambdaOnQuad(ElementType type, + GhostType ghost_type) { + SolidMechanicsModelCohesiveDamage * model_lambda = &aka::as_type<SolidMechanicsModelCohesiveDamage>(*model); + auto & fem_lambda = model->getFEEngine("LambdaFEEngine"); + const auto & lambda = model_lambda->getLambda(); + auto & lambda_on_quad = this->lambda(type, ghost_type); + + auto underlying_type = Mesh::getFacetType(type); + fem_lambda.interpolateOnIntegrationPoints( + lambda, lambda_on_quad, dim, underlying_type, ghost_type, + this->getElementFilter(type, ghost_type)); +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +void MaterialCohesiveDamageExtrinsic<dim>::computeTraction(ElementType el_type, + GhostType ghost_type) { + +// std::cout << "In MaterialCohesiveDamageExtrinsic<dim>::computeTraction " << std::endl ; + + auto & elem_filter = getElementFilter(el_type, ghost_type); + auto nb_element = elem_filter.size(); + if (nb_element > 0) { + // computeLambdaOnQuad(el_type, ghost_type); // not used + // it iterates over the elements of type _ek_cohesive to computeTraction + for (auto && args : getArguments(el_type, ghost_type)) { + + computeTractionOnQuad(args); + } + } +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +Real MaterialCohesiveDamageExtrinsic<dim>::computeObjectiveFunctional() { + + Real val(0.); + + /// integrate the dissipated energy for each type of elements + for (auto && type : this->getElementFilter().elementTypes(dim, _not_ghost)) { + auto & elem_filter = getElementFilter(type, _not_ghost); + auto nb_element = elem_filter.size(); + if (nb_element > 0) { + for (auto && args : getArgumentsObjective(type)) { + computeObjectiveFunctionalOnQuad(args); + } + val += this->getFEEngine().integrate( + this->objective_functional(type, _not_ghost), type, _not_ghost, + this->getElementFilter(type, _not_ghost)); + } + } + return val; +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +void MaterialCohesiveDamageExtrinsic<dim>::computeLambda(GhostType ghost_type) +{ + std::cout << " In MaterialCohesiveDamageExtrinsic<dim>::computeLambda " << std::endl ; + const auto & mesh_facets = model->getMeshFacets(); + for (const auto & type_facet : mesh_facets.elementTypes(dim - 1)) { + auto type_cohesive = FEEngine::getCohesiveElementType(type_facet); + auto nb_quad_facet = + model->getFEEngine("FacetsFEEngine").getNbIntegrationPoints(type_facet); + + #ifndef AKANTU_NDEBUG + auto nb_quad_cohesive = model->getFEEngine("CohesiveFEEngine") + .getNbIntegrationPoints(type_cohesive); + + AKANTU_DEBUG_ASSERT(nb_quad_cohesive == nb_quad_facet, + "The cohesive element and the corresponding facet do " + "not have the same numbers of integration points"); + #endif + + const auto & element_to_subelement = + mesh_facets.getElementToSubelement(type_facet, ghost_type); + + const auto & normals = model->getFEEngine("FacetsFEEngine") + .getNormalsOnIntegrationPoints(type_facet); + const auto & f_stress = model->getStressOnFacets(type_facet); + + auto facet_stress_begin = make_view(f_stress, dim, dim, 2).begin(); + auto normal_begin = make_view<dim>(normals).begin(); + + auto damage_begin = czm_damage(type_facet,ghost_type).begin(); + auto opening_begin = make_view<dim>(opening(type_cohesive,ghost_type)).begin(); + + for (auto data : + enumerate(make_view(lambda(type_facet), dim,nb_quad_facet))) { + auto && f = std::get<0>(data); + auto && lda = std::get<1>(data); + auto && elem = element_to_subelement(f); + + auto && e = -1; + for(auto ec : elem) + { + if(ec!=ElementNull) + { + if(ec.kind() == _ek_cohesive) + { + e = ec.element; + continue; + } + } + } + + if(e < 0) + { + for (Int q = 0; q < nb_quad_facet; ++q) { + auto current_quad = f * nb_quad_facet + q; + auto && normal = normal_begin[current_quad]; + auto && facet_stress = facet_stress_begin[current_quad]; + + auto && stress_1 = facet_stress(0); + auto && stress_2 = facet_stress(1); + + auto && stress_avg = (stress_1 + stress_2) / 2.; + lda(q) = stress_avg*normal; + } + } + else + { + for (Int q = 0; q < nb_quad_facet; ++q) { + auto current_quad = f * nb_quad_facet + q; + auto current_elem_quad = e * nb_quad_facet + q; + auto && w = opening_begin[current_elem_quad]; + auto && d = damage_begin[current_quad]; + lda(q) = k*augmented_stiffness(d)*w; + std::cout << "f = " << f << std::endl ; + std::cout << " w = " << w << std::endl ; + std::cout << " d = " << d << std::endl ; + std::cout << " lda = " << lda(q) << std::endl ; + } + } + } + } +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +void MaterialCohesiveDamageExtrinsic<dim>::computeDamage(GhostType ghost_type) +{ + + for (const auto & type : getElementFilter().elementTypes( + spatial_dimension, ghost_type, _ek_cohesive)) { + + auto & elem_filter = getElementFilter(type, ghost_type); + // retrives the a filter that selects elments based on their type, more specifically like triangle, quad etc + auto nb_element = elem_filter.size(); + + if (nb_element == 0) { + continue; + } + + // iterating over the elements of type _ek_cohesive + for (auto && args : getArguments(type, ghost_type)) { + computeDamageOnQuad(args); + } + } + +} +/* -------------------------------------------------------------------------- */ +template <Int dim> +void MaterialCohesiveDamageExtrinsic<dim>::readDamage(const Array<Element> &, const Array<Real> &) +{ + /// TODO +} +/* -------------------------------------------------------------------------- */ +template <Int dim> +void MaterialCohesiveDamageExtrinsic<dim>::writeDamage(const Array<Element> & clip_to_mesh, Array<Real> & to) const +{ + Int n_nodes = to.size(); + auto clip_nodes_it = clip_to_mesh.begin(); + for(int i = 0 ; i<n_nodes; ++i, ++clip_nodes_it) { + Element elem=*clip_nodes_it; + if(elem!=ElementNull) { + to[i]=czm_damage(elem); + } + } +} +/* -------------------------------------------------------------------------- */ +template class MaterialCohesiveDamageExtrinsic<1>; +template class MaterialCohesiveDamageExtrinsic<2>; +template class MaterialCohesiveDamageExtrinsic<3>; +const bool material_is_alocated_cohesive_damage [[maybe_unused]] = + instantiateMaterial<MaterialCohesiveDamageExtrinsic>("cohesive_damage_extrinsic"); + +} // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.hh new file mode 100644 index 0000000000000000000000000000000000000000..f6c78d2097bb4d228c90401bb8723c770ff647eb --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic.hh @@ -0,0 +1,142 @@ +/** + * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "material_cohesive_damage.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef AKANTU_MATERIAL_COHESIVE_DAMAGE_EXTRINSIC_HH_ +#define AKANTU_MATERIAL_COHESIVE_DAMAGE_EXTRINSIC_HH_ + +namespace akantu { + +/** + * Cohesive material linear damage for extrinsinc case + * + * parameters in the material files : + * - sigma_c : critical stress sigma_c (default: 0) + * - G_c : fracture energy for mode I (default: 0) + * - k : cohesive stiffness + */ +template <Int dim> class MaterialCohesiveDamageExtrinsic : public MaterialCohesiveDamage { + /* ------------------------------------------------------------------------ */ + /* Constructors/Destructors */ + /* ------------------------------------------------------------------------ */ +public: + MaterialCohesiveDamageExtrinsic(SolidMechanicsModel & model, const ID & id = ""); + + /* ------------------------------------------------------------------------ */ + /* Methods */ + /* ------------------------------------------------------------------------ */ + + /// check stress for cohesive elements' insertion + void checkInsertion(bool check_only = false) override; + + void computeLambda(GhostType ghost_type = _not_ghost) override; + + void computeDamage(GhostType /*ghost_type*/ = _not_ghost) override; + + void readDamage(const Array<Element> &, const Array<Real> &) override; + void writeDamage(const Array<Element> &, Array<Real> &) const override; + + template <class D1, class D2, class D3, class D4> + Real + computeEffectiveNorm(const Eigen::MatrixBase<D1> & stress, + const Eigen::MatrixBase<D2> & normal, + const Eigen::MatrixBase<D3> & tangent, + const Eigen::MatrixBase<D4> & normal_traction_) const; + + /// compute the value of the objective function + Real computeObjectiveFunctional(); + +protected: + void computeLambdaOnQuad(ElementType type, GhostType ghost_type); + + inline decltype(auto) getArguments(ElementType element_type, + GhostType ghost_type) { + using namespace tuple; + return zip_append( + MaterialCohesive::getArguments<dim>(element_type, ghost_type), + "lambda"_n = make_view<dim>(this->lambda(element_type, ghost_type)), + "czm_damage"_n = this->czm_damage(element_type, ghost_type)); + } + + /// constitutive law + void computeTraction(ElementType el_type, + GhostType ghost_type = _not_ghost) override; + + template <typename Args> inline void computeTractionOnQuad(Args && args); + + /// compute the objective function for a given quadrature point + template <typename Args> inline void computeObjectiveFunctionalOnQuad(Args && args); + + inline decltype(auto) getArgumentsObjective(ElementType element_type) { + using namespace tuple; + return zip_append( + MaterialCohesive::getArguments<dim>(element_type, _not_ghost), + "lambda"_n = make_view<dim>(this->lambda(element_type, _not_ghost)), + "czm_damage"_n = this->czm_damage(element_type, _not_ghost), + "objective"_n = this->czm_damage(element_type, _not_ghost)); + } + + [[nodiscard]] bool needLambda() const override { return false; } + + /* ------------------------------------------------------------------------ */ + /* Class Members */ + /* ------------------------------------------------------------------------ */ +protected: + + /// augmented lagrange multiplier + CohesiveInternalField<Real> & lambda; + + /// cohesive damage + CohesiveInternalField<Real> & czm_damage; + + /// stress at insertion + CohesiveInternalField<Real> & insertion_stress; + + CohesiveRandomInternalField<Real> & sigma_c_eff; + + /// effective critical displacement (each element can have a + /// different value) + CohesiveInternalField<Real> & delta_c_eff; + + /// stress at insertion + CohesiveInternalField<Real> & is_new_crack; + + /// objective_function + CohesiveInternalField<Real> & objective_functional; + + bool max_quad_stress_insertion{}; + + Real beta2_inv{}; + + +}; + +/* -------------------------------------------------------------------------- */ +/* inline functions */ +/* -------------------------------------------------------------------------- */ + +} // namespace akantu + +#include "material_cohesive_damage_extrinsic_inline_impl.hh" + +#endif /* AKANTU_MATERIAL_COHESIVE_DAMAGE_EXTRINSIC_HH_ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic_inline_impl.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic_inline_impl.hh new file mode 100644 index 0000000000000000000000000000000000000000..09cc2f4d5489a1cfa977413454b9e95b92b62969 --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_extrinsic_inline_impl.hh @@ -0,0 +1,96 @@ +/** + * Copyright (©) 2015-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "material_cohesive_damage_extrinsic.hh" + +/* -------------------------------------------------------------------------- */ +#ifndef AKANTU_MATERIAL_COHESIVE_DAMAGE_EXTRINSIC_INLINE_IMPL_HH_ +#define AKANTU_MATERIAL_COHESIVE_DAMAGE_EXTRINSIC_INLINE_IMPL_HH_ + +/* -------------------------------------------------------------------------- */ + +namespace akantu { + +///* -------------------------------------------------------------------------- */ + +template <Int dim> +template <typename Args> +inline void MaterialCohesiveDamageExtrinsic<dim>::computeTractionOnQuad(Args && args) { + + auto && d = args["czm_damage"_n]; + auto && opening = args["opening"_n]; + auto && traction = args["traction"_n]; + // auto && normal = args["normal"_n]; + if (d == 0.0) { + traction.setZero(); + + return; + } + + traction = k * opening * this->gd_clip_function(d); + +} +/* -------------------------------------------------------------------------------------- */ +template <Int dim> +template <class D1, class D2, class D3, class D4> +Real MaterialCohesiveDamageExtrinsic<dim>::computeEffectiveNorm( + const Eigen::MatrixBase<D1> & stress, const Eigen::MatrixBase<D2> & normal, + const Eigen::MatrixBase<D3> & tangent, + const Eigen::MatrixBase<D4> & normal_traction_) const { + Eigen::MatrixBase<D4> & normal_traction = + const_cast<Eigen::MatrixBase<D4> &>(normal_traction_); + normal_traction = stress * normal; + + Real normal_contrib = normal_traction.dot(normal); + + /// in 3D tangential components must be summed + Real tangent_contrib = 0; + + if constexpr (dim == 2) { + Real tangent_contrib_tmp = normal_traction.dot(tangent); + tangent_contrib += tangent_contrib_tmp * tangent_contrib_tmp; + } else if constexpr (dim == 3) { + for (auto && tangent_v : tangent) { + Real tangent_contrib_tmp = normal_traction.dot(tangent_v); + tangent_contrib += tangent_contrib_tmp * tangent_contrib_tmp; + } + } + + tangent_contrib = std::sqrt(tangent_contrib); + normal_contrib = std::max(Real(0.), normal_contrib); + + return std::sqrt(normal_contrib * normal_contrib + + tangent_contrib * tangent_contrib * beta2_inv); +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +template <typename Args> +inline void MaterialCohesiveDamageExtrinsic<dim>::computeObjectiveFunctionalOnQuad(Args && args) { + auto && d = args["czm_damage"_n]; + auto && opening = args["opening"_n]; + args["objective"_n] = 0.5*k*opening.dot(opening)*this->gd_clip_function(d) + yc*hd_clip_function(d); +} + +} // namespace akantu + +/* -------------------------------------------------------------------------- */ +#endif // AKANTU_MATERIAL_COHESIVE_DAMAGE_EXTRINSIC_INLINE_IMPL_HH_ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_inline_impl.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_inline_impl.hh new file mode 100644 index 0000000000000000000000000000000000000000..df7b0d230fbeeb0ccf1ed58623ff41267aef42a6 --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_inline_impl.hh @@ -0,0 +1,208 @@ +/** + * Copyright (©) 2015-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "material_cohesive_damage.hh" + +/* -------------------------------------------------------------------------- */ +#ifndef AKANTU_MATERIAL_COHESIVE_DAMAGE_INLINE_IMPL_HH_ +#define AKANTU_MATERIAL_COHESIVE_DAMAGE_INLINE_IMPL_HH_ + +/* -------------------------------------------------------------------------- */ + +namespace akantu { +///* -------------------------------------------------------------------------- */ +template <typename Args> +inline void MaterialCohesiveDamage::computeDamageOnQuad(Args && args) { + auto && d = args["czm_damage"_n]; + auto && open = args["opening"_n]; + auto && normal = args["normal"_n]; + + auto normal_opening = open.dot(normal); + auto normal_opening_squared = normal_opening * normal_opening; + + Real lower_bound = 1e-10; // Define lower bound of the damage + Real upper_bound = 1.; // Define upper bound of the damage + + if(normal_opening_squared == 0) { + d = 0.0; + return; + } + +try { + // Define the residual function for Brent's Method + auto residual = [&](Real d_val) { return computeResidual(d_val, normal_opening_squared); }; + + // Solve for d using Brent's Method + Real d_solution = brentsMethod(residual, lower_bound, upper_bound); + + d = d_solution; + // std::cout << "Solution for d found using Brent's Method: d = " << d_solution << std::endl; + } catch (const std::exception &e) { + std::cerr << "Error in Brent's method: " << e.what() << std::endl; + // Handle error (e.g., fallback to another method or log failure) + } + +// try { +// // Solve for d using Least Squares +// Real d_solution = solveForDamageUsingLeastSquares(normal_opening_squared, lower_bound, upper_bound, 1e-12, 1000); + +// d = d_solution; +// std::cout << "Solution for d found using Least Squares: d = " << d_solution << std::endl; +// } catch (const std::exception &e) { +// std::cerr << "Error in Least Squares method: " << e.what() << std::endl; +// // Handle error (e.g., fallback to another method or log failure) +// } + +} + +///* -------------------------------------------------------------------------- */ +/// Function to Define Residual for Brent's Method +inline Real MaterialCohesiveDamage::computeResidual(Real d, Real normal_opening_squared) { + + auto numerator = (yc * hd_clip_function_first_derivative(d) / 2.0) + + (Yc * lc * HD_clip_function(Dm * d)); + + auto denominator = ((k * k * gd_clip_function(d) * gd_clip_function(d) * lc) / (2.0 * E_coh)) * + (1.0 / GD_clip_function(Dm * d) - 1.0) - + (k * gd_clip_function_first_derivative(d) / 4.0); + + + auto f_d = numerator / denominator; + return f_d - normal_opening_squared; +} + + +///* -------------------------------------------------------------------------- */ +template <typename Func> +Real brentsMethod(Func func, Real lower, Real upper, Real tol = 1e-15, int max_iter = 1000) { + Real a = lower, b = upper, c = upper; + Real fa = func(a), fb = func(b), fc = fb; + + if (std::abs(fa) < tol) return a; + if (std::abs(fb) < tol) return b; + + Real s = b, fs = fb; // Approximation and function value + bool mflag = true; // Flag to indicate if bisection is used + Real d = 0; // Step size for the interval + + for (int iter = 0; iter < max_iter; ++iter) { + // Convergence check + if (std::abs(b - a) < tol || std::abs(fb) < tol) { + return b; + } + + if (fa != fc && fb != fc) { + // Inverse quadratic interpolation + s = a * fb * fc / ((fa - fb) * (fa - fc)) + + b * fa * fc / ((fb - fa) * (fb - fc)) + + c * fa * fb / ((fc - fa) * (fc - fb)); + } else { + // Secant method + s = b - fb * (b - a) / (fb - fa); + } + + // Condition for bisection fallback + if ((s < (3 * a + b) / 4 || s > b) || + (mflag && std::abs(s - b) >= std::abs(b - c) / 2) || + (!mflag && std::abs(s - b) >= std::abs(c - d) / 2) || + (mflag && std::abs(b - c) < tol) || + (!mflag && std::abs(c - d) < tol)) { + s = (a + b) / 2; // Bisection + mflag = true; + } else { + mflag = false; + } + + fs = func(s); + d = c; // Update previous step + c = b; // Update c to the current b + + if (fa * fs < 0) { + b = s; + fb = fs; + } else { + a = s; + fa = fs; + } + + // Ensure a and b are ordered with |f(a)| < |f(b)| + if (std::abs(fa) < std::abs(fb)) { + std::swap(a, b); + std::swap(fa, fb); + } + } + + throw std::runtime_error("Brent's method failed to converge."); +} + +/* -------------------------------------------------------------------------- */ +/// Least Squares Solver for the Problem +inline Real MaterialCohesiveDamage::solveForDamageUsingLeastSquares(Real normal_opening_squared, Real lower_bound, Real upper_bound, + Real tol, int max_iter) { + Real a = lower_bound, b = upper_bound; + Real best_d = a, best_residual = std::numeric_limits<Real>::max(); + + // Number of points for the grid search phase + const int num_points = 1000; + std::vector<Real> d_values(num_points); + + // Grid search to find a rough minimum + for (int i = 0; i < num_points; ++i) { + Real d = a + i * (b - a) / (num_points - 1); + Real residual = std::pow(computeResidual(d, normal_opening_squared), 2); + if (residual < best_residual) { + best_d = d; + best_residual = residual; + } + } + + // Refine solution using a gradient-descent-like approach + Real d = best_d; + for (int iter = 0; iter < max_iter; ++iter) { + Real f_d = computeResidual(d, normal_opening_squared); + Real f_d_prime = (computeResidual(d + tol, normal_opening_squared) - f_d) / tol; // Approximate derivative + + if (std::abs(f_d_prime) < tol) { + break; // Convergence achieved + } + + // Gradient descent update + Real step = -2.0 * f_d * f_d_prime; + d += step; + + // Keep d within bounds + if (d < a || d > b) { + throw std::runtime_error("Solution moved out of bounds."); + } + + // Check for convergence + if (std::abs(f_d) < tol) { + return d; + } + } + + return d; +} + +} + +/* -------------------------------------------------------------------------- */ +#endif // AKANTU_MATERIAL_COHESIVE_DAMAGE_INLINE_IMPL_HH_ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.cc new file mode 100644 index 0000000000000000000000000000000000000000..01abc4a34246c32821e145c1c8e42a1b66b45093 --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.cc @@ -0,0 +1,35 @@ +/** + * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "material_cohesive_damage_non_local.hh" + +namespace akantu { + +template class MaterialCohesiveDamageNonLocal<1>; +template class MaterialCohesiveDamageNonLocal<2>; +template class MaterialCohesiveDamageNonLocal<3>; + +template <Int dim> using MaterialCohesiveDamageNonLocal_ = MaterialCohesiveDamageNonLocal<dim>; + +static bool material_is_alocated_cohesive_damage_non_local = + instantiateMaterial<MaterialCohesiveDamageNonLocal_>("cohesive_damage_non_local"); + +} // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.hh new file mode 100644 index 0000000000000000000000000000000000000000..6ca13aa375ba010e8bd45ca8599a1004cff2e662 --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local.hh @@ -0,0 +1,80 @@ +/** + * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "aka_common.hh" +#include "material_damage_non_local.hh" +#include "material_cohesive_damage_extrinsic.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef AKANTU_MATERIAL_COHESIVE_DAMAGE_NON_LOCAL_HH_ +#define AKANTU_MATERIAL_COHESIVE_DAMAGE_NON_LOCAL_HH_ + +namespace akantu { + +/** + * Material bulk damage Non local + * + * parameters in the material files : + */ +template <Int dim> +class MaterialCohesiveDamageNonLocal + : public MaterialDamageNonLocal<dim, MaterialCohesiveDamageExtrinsic<dim>> { + /* ------------------------------------------------------------------------ */ + /* Constructors/Destructors */ + /* ------------------------------------------------------------------------ */ +public: + using parent = MaterialDamageNonLocal<dim, MaterialCohesiveDamageExtrinsic<dim>>; + + MaterialCohesiveDamageNonLocal(SolidMechanicsModel & model, const ID & id = ""); + + /* ------------------------------------------------------------------------ */ + /* Methods */ + /* ------------------------------------------------------------------------ */ + + void computeNonLocalStress(ElementType /*el_type*/, + GhostType /*ghost_type = _not_ghost*/) override {} + +protected: + + void registerNeighborhood() override {}; + + void registerNonLocalVariables() override; + + /* ------------------------------------------------------------------------ */ + /* Accessors */ + /* ------------------------------------------------------------------------ */ + + ID getNeighborhoodName() override {return "clip"; }; + +public: + + /* ------------------------------------------------------------------------ */ + /* Class Members */ + /* ------------------------------------------------------------------------ */ +private: + +}; + +} // namespace akantu + +#include "material_cohesive_damage_non_local_tmpl.hh" + +#endif /* AKANTU_MATERIAL_COHESIVE_DAMAGE_NON_LOCAL_HH_ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local_tmpl.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local_tmpl.hh new file mode 100644 index 0000000000000000000000000000000000000000..604ada62dfb2ed243f81d884c03b96f931bb10c2 --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive_damage_non_local_tmpl.hh @@ -0,0 +1,54 @@ +/** + * Copyright (©) 2010-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "solid_mechanics_model.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_TMPL_HH_ +#define AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_TMPL_HH_ + +namespace akantu { + +/* -------------------------------------------------------------------------- */ +template <Int dim> +MaterialCohesiveDamageNonLocal<dim>::MaterialCohesiveDamageNonLocal( + SolidMechanicsModel & model, const ID & id):parent(model,id) + { + AKANTU_DEBUG_IN(); + + //// MUST THIS REALLY BE SET TO TRUE ??? + this->is_non_local = true; + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template <Int dim> +void MaterialCohesiveDamageNonLocal<dim>::registerNonLocalVariables() { + // this->getModel() + // .getNonLocalManager() + // .getNeighborhood(this->name) + // .registerNonLocalVariable(this->czm_damage.getName()); +} + +} // namespace akantu + +#endif // AKANTU_MATERIAL_BULK_DAMAGE_NON_LOCAL_TMPL_HH_ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.cc new file mode 100644 index 0000000000000000000000000000000000000000..786b00fa40a7386df732d58b5a3d36ff5de4b09a --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.cc @@ -0,0 +1,446 @@ +/** + * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "solid_mechanics_model_clip.hh" +#include "aka_iterators.hh" +#include "fe_engine_template.hh" +#include "shape_lagrange.hh" +#include "integrator_gauss.hh" +#include "mesh_accessor.hh" +/* -------------------------------------------------------------------------- */ +#include "dumper_iohelper_paraview.hh" +/* -------------------------------------------------------------------------- */ +#include <algorithm> +/* -------------------------------------------------------------------------- */ +#if defined(WITH_GMSH) +#include "gmsh.h" +#endif + +namespace akantu { + +/* -------------------------------------------------------------------------- */ +SolidMechanicsModelCLIP::SolidMechanicsModelCLIP( + Mesh & mesh, Int dim, const ID & id, + const std::shared_ptr<DOFManager> & dof_manager) + : SolidMechanicsModelCohesiveDamage(mesh, dim, id, dof_manager) + ,czm_material(nullptr) + ,bulk_material(nullptr) +{ + czm_damage = + std::make_unique<Array<Real>>(0, 1, "cohesive damage"); + + bulk_damage = + std::make_unique<Array<Real>>(0, 1, "bulk damage"); + + clip_mesh = std::make_unique<Mesh>(spatial_dimension, + mesh.getCommunicator(), "clip_mesh"); + + this->mesh.registerDumper<DumperParaview>("clip", id); + this->mesh.addDumpMeshToDumper("clip", *clip_mesh, + Model::spatial_dimension, _not_ghost, + _ek_regular); + +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCLIP::initialize() { + // Precompute distances once before the time-stepping loop + precomputeDistances(); +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCLIP::initConstitutiveLaws() { + AKANTU_DEBUG_IN(); + #if defined(WITH_GMSH) + createCLIPMesh(); + #endif + this->for_each_constitutive_law([&](auto && material) { + try { + auto & mat = aka::as_type<MaterialCohesiveDamage>(material); + czm_material = &mat; + } catch (std::bad_cast & bce) { + Material * mat = &material; + if(mat->isInternal<Real>("damage",_ek_regular)) { + bulk_material = &material; + } + } + }); + SolidMechanicsModelCohesiveDamage::initConstitutiveLaws(); + if (this->isNonLocal()) { + this->getNonLocalManager().registerNonLocalVariable("czm_damage", "damage", 1); + } + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCLIP::createCLIPMesh() +{ + MeshAccessor mesh_accessor(mesh); + MeshAccessor mesh_accessor_clip(*clip_mesh); + + auto & clip_nodes = mesh_accessor_clip.getNodes(); + auto & clip_connectivities = mesh_accessor_clip.getConnectivities(); + + Mesh & mesh_facets = mesh.initMeshFacets(); + MeshAccessor mesh_accessor_facets(mesh_facets); + + // get facets barycenters + ElementTypeMapArray<Real> barycenters; + Int nb_clip_nodes(0); + barycenters.initialize(mesh_facets, _nb_component = spatial_dimension, + _spatial_dimension = spatial_dimension-1, + _with_nb_element = true); + + for (auto && ghost_type : ghost_types) { + for (auto && type : + barycenters.elementTypes(spatial_dimension-1,ghost_type)) { + mesh_facets.getBarycenters(barycenters(type, ghost_type),type, + ghost_type); + nb_clip_nodes+=mesh_facets.getNbElement(type, ghost_type); + } + } + + mesh_accessor_clip.resizeNodes(nb_clip_nodes); + + // create clip mesh nodes array and facets_to_clip element map + auto & clip_to_mesh = mesh.getNodalData<Element>("clip_to_mesh"); + clip_to_mesh.resize(clip_mesh->getNbNodes(),ElementNull); + + auto && view_clip_nodes = make_view(clip_nodes,spatial_dimension); + auto clip_nodes_begin = view_clip_nodes.begin(); + facets_to_clip.initialize(mesh_facets, _nb_component = 1,_spatial_dimension = spatial_dimension-1); + std::vector<double> coord; + Int i_node = 0; + + for (auto && ghost_type : ghost_types) { + for (auto && type : + barycenters.elementTypes(spatial_dimension-1,ghost_type)) { + auto & barycenter = barycenters(type,ghost_type); + auto && view_bar = + make_view(barycenter, barycenter.getNbComponent()); + facets_to_clip(type,ghost_type).resize(mesh_facets.getNbElement(type,ghost_type),-1); + for (auto && data : zip(view_bar,view_clip_nodes,facets_to_clip(type,ghost_type))) { + std::get<1>(data)=std::get<0>(data); + std::get<2>(data)=i_node; + for(Int i=0; i<spatial_dimension;++i) + { + coord.push_back(std::get<0>(data)[i]); + } + ++i_node; + } + } + } + + // call gmsh to create clip mesh + std::vector<std::size_t> tri; + #if defined(WITH_GMSH) + gmsh::initialize(); + gmsh::model::mesh::triangulate(coord,tri); + #else + std::cout << "WARNING : SolidMechanicsModelCLIP::createCLIPMesh requires to compile with WITH_GMSH=ON " << std::endl; + #endif + int n_tri = tri.size()/3; + + // create mesh connectivities + fix triangles orientations + for (auto && ghost_type : ghost_types) { + clip_mesh->addConnectivityType(_triangle_3, ghost_type); + mesh_accessor_clip.resizeConnectivity(n_tri,_triangle_3, ghost_type); + auto & clip_conn = clip_connectivities(_triangle_3, ghost_type); + auto && view_conn_it = make_view(clip_conn, clip_conn.getNbComponent()).begin(); + for(int i = 0 ; i<n_tri; ++i, ++view_conn_it) + { + int i1 = tri[3*i]-1; + int i2 = tri[3*i+1]-1; + int i3 = tri[3*i+2]-1; + auto x1 = clip_nodes_begin[i1]; + auto x2 = clip_nodes_begin[i2]; + auto x3 = clip_nodes_begin[i3]; + auto v12 = x2-x1; + auto v13 = x3-x1; + Real t = v12[1]*v13[0]-v12[0]*v13[1]; + (*view_conn_it)[0]=i1; + if(t < 0.) + { + (*view_conn_it)[1]=i2; + (*view_conn_it)[2]=i3; + } + else + { + (*view_conn_it)[1]=i3; + (*view_conn_it)[2]=i2; + } + } + } + + mesh_accessor_clip.makeReady(); + clip_mesh->write("clip_mesh.msh"); + + czm_damage->resize(clip_mesh->getNbNodes(),0.); + bulk_damage->resize(clip_mesh->getNbNodes(),0.); + + registerFEEngineObject<MyFEEngineType>("CLIPFEEngine", *clip_mesh, + Model::spatial_dimension); + // precompute clip shape functions at computation mesh integration points + computeShapeFunctionsOnIntegrationPoints(); + +} + + +/*----------------------------------------------------------------------------*/ +void SolidMechanicsModelCLIP::precomputeDistances() { + auto & clip_to_mesh = mesh.getNodalData<Element>("clip_to_mesh"); + Int n_nodes = clip_to_mesh.size(); + MeshAccessor mesh_accessor_clip(*clip_mesh); + auto & clip_nodes = mesh_accessor_clip.getNodes(); + auto && view_clip_nodes = make_view(clip_nodes, spatial_dimension); + auto clip_nodes_begin = view_clip_nodes.begin(); + + distances.resize(n_nodes, std::vector<Real>(n_nodes, 0.0)); + std::cout << "Distances are pre computed" << std::endl ; + for (Int i = 0; i < n_nodes; ++i) { + const auto& current_node = clip_nodes_begin[i]; + for (Int j = 0; j < n_nodes; ++j) { + const auto& other_node = clip_nodes_begin[j]; + Real dist = 0.0; + for (Int k = 0; k < spatial_dimension; ++k) { + Real diff = current_node[k] - other_node[k]; + dist += diff * diff; + } + distances[i][j] = std::sqrt(dist); + } + } +} + + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCLIP::computeBulkDamage() { + auto & clip_to_mesh = mesh.getNodalData<Element>("clip_to_mesh"); + + // Write czm damage from MaterialCohesiveDamage inside model czm damage + czm_material->writeDamage(clip_to_mesh, *czm_damage); + + Real lc = czm_material->getLc(); + Real Dm = czm_material->getDm(); + + // Get the number of nodes in the clip_to_mesh + Int n_nodes = clip_to_mesh.size(); + // std::cout << "Number of nodes of Clip mesh = " << n_nodes << std::endl ; + + // Initialize vectors to store damage values + std::vector<std::vector<Real>> all_Di(n_nodes, std::vector<Real>(n_nodes, 0.0)); + std::vector<Real> max_Di(n_nodes, 0.0); + + // Iterate over each node in the clip_to_mesh + for(Int i = 0; i < n_nodes; ++i) { + auto& di = (*czm_damage)[i]; + // Iterate over all other nodes to compute damage using precomputed distances + for (Int j = 0; j < n_nodes; ++j) { + Real dist = distances[i][j]; + Real Computed_Di = (di - (dist)/(lc))*Dm; + all_Di[i][j] = Computed_Di; + } + } + // Compute and print the maximum value of each column in all_Di + std::vector<Real> max_col_values(n_nodes, 0.0); + for (Int j = 0; j < n_nodes; ++j) { + Real max_col_value = all_Di[0][j]; + for (Int i = 1; i < n_nodes; ++i) { + if (all_Di[i][j] > max_col_value) { + max_col_value = all_Di[i][j]; + } + } + max_col_values[j] = max_col_value; + } + + for (Int i = 0; i < n_nodes; ++i) { + (*bulk_damage)[i] = max_col_values[i]; + } + + // czm_material->readDamage(clip_to_mesh, *czm_damage); + interpolateBulkDamageOnIntegrationPoints(); +} +/* -------------------------------------------------------------------------- */ +Real SolidMechanicsModelCLIP::computeObjectiveFunction() { + Real val_czm = czm_material->computeObjectiveFunctional(); + Real val_bulk; + // very dirty but no other choice for now + switch(spatial_dimension) { + case 1 : + val_bulk = aka::as_type<MaterialBulkDamage<1>>(*bulk_material).computeObjectiveFunctional(); + break; + case 2 : + val_bulk = aka::as_type<MaterialBulkDamage<2>>(*bulk_material).computeObjectiveFunctional(); + break; + case 3 : + val_bulk = aka::as_type<MaterialBulkDamage<3>>(*bulk_material).computeObjectiveFunctional(); + break; + default: + break; + } + return val_czm + val_bulk; +} + + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCLIP::computeShapeFunctionsOnIntegrationPoints() { + auto & fem_clip = this->getFEEngine("CLIPFEEngine"); + auto & fem = this->getFEEngine("SolidMechanicsFEEngine"); + + clip_shapes.initialize(mesh,_spatial_dimension = spatial_dimension); + gp_to_clip_elem.initialize(mesh,_spatial_dimension = spatial_dimension); + + for (auto && ghost_type : ghost_types) { + for (auto && type : mesh.elementTypes(spatial_dimension,ghost_type,_ek_regular)) { + Array<Real> quadrature_points(mesh.getNbElement(type,ghost_type),spatial_dimension*fem.getNbIntegrationPoints(type,ghost_type)); + fem.computeIntegrationPointsCoordinates(quadrature_points,type,ghost_type); + + auto nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); + auto size_of_shapes = fem_clip.getShapes(type, ghost_type).getNbComponent(); + clip_shapes(type,ghost_type).resize(mesh.getNbElement(type,ghost_type)*size_of_shapes*nb_quadrature_points); + gp_to_clip_elem(type,ghost_type).resize(mesh.getNbElement(type,ghost_type)*nb_quadrature_points); + auto quadrature_points_begin = make_view(quadrature_points,spatial_dimension).begin(); + auto shapes_begin = make_view(clip_shapes(type,ghost_type),size_of_shapes).begin(); + auto gp_to_clip_elem_begin = make_view(gp_to_clip_elem(type,ghost_type),nb_quadrature_points).begin(); + for(int e =0; e<mesh.getNbElement(type,ghost_type);++e) { + auto && gp_to_clip_elem_e = gp_to_clip_elem_begin[e]; + for(int i = 0; i < nb_quadrature_points; ++i) + { + const auto & xgi = quadrature_points_begin[e*nb_quadrature_points+i]; + auto && Ngi = shapes_begin[e*nb_quadrature_points+i]; + // WARNING : very CPU inefficient, try to find something else !!! + for (auto && ghost_typei : ghost_types) { + for (auto && typei : clip_mesh->elementTypes(spatial_dimension,ghost_type,_ek_regular)) { + Int j=0; + for(; j<clip_mesh->getNbElement(typei,ghost_typei);++j) { + if(aka::as_type<MyFEEngineType>(fem_clip).contains(xgi,j,typei,ghost_typei)) { + /// NOTE : THIS WORKS ONLY IF CLIP MESH IS MADE ONLY OF TRI/TET (WHICH IS THE CASE AT THE MOMENT) + /// (normally should also store type and chost_type) + gp_to_clip_elem_e[i]=j; + break; + } + } + fem_clip.computeShapes(xgi,j,typei,Ngi,ghost_typei); + } + } + } + } + } + } +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCLIP::interpolateBulkDamageOnIntegrationPoints() +{ + InternalField<Real> & bulk_damage_internal = bulk_material->getInternal<Real>("damage"); + + auto & connectivities = clip_mesh->getConnectivities(); + auto & fem_clip = this->getFEEngine("CLIPFEEngine"); + auto & fem = this->getFEEngine("SolidMechanicsFEEngine"); + + for (auto && ghost_type : ghost_types) { + for (auto && type : mesh.elementTypes(spatial_dimension,ghost_type,_ek_regular)) { + auto nb_nodes_per_element = Mesh::getNbNodesPerElement(type); + auto nb_quadrature_points_per_element = fem.getNbIntegrationPoints(type, ghost_type); + auto size_of_shapes = fem_clip.getShapes(type, ghost_type).getNbComponent(); + + auto connectivities_begin = make_view(connectivities(type,ghost_type),nb_nodes_per_element).begin(); + auto shapes_begin = make_view(clip_shapes(type,ghost_type),size_of_shapes*nb_quadrature_points_per_element).begin(); + auto bulk_damage_begin = make_view(bulk_damage_internal(type,ghost_type),nb_quadrature_points_per_element).begin(); + auto gp_to_clip_elem_begin = make_view(gp_to_clip_elem(type,ghost_type),nb_quadrature_points_per_element).begin(); + for(int e =0; e<mesh.getNbElement(type,ghost_type);++e) { + auto && gp_to_clip_elem_e = gp_to_clip_elem_begin[e]; + auto && dam = bulk_damage_begin[e]; + for(int i = 0; i < nb_quadrature_points_per_element; ++i) + { + auto e_clip = gp_to_clip_elem_e[i]; + const auto & shape = shapes_begin[e]; + const auto & conn = connectivities_begin[e_clip]; + auto && Di = dam[i]; + Di=0.; + for(int j=0;j<size_of_shapes;++j) + { + Di+=(*this->bulk_damage)[conn[j]]*shape[i*nb_quadrature_points_per_element+j]; + } + } + } + } + } +} + +/* -------------------------------------------------------------------------- */ +std::shared_ptr<dumpers::Field> +SolidMechanicsModelCLIP::createNodalFieldReal(const std::string & field_name, + const std::string & group_name, + bool padding_flag) +{ + if(field_name == "clip_bulk_damage" || field_name == "clip_czm_damage") + { + + std::map<std::string, Array<Real> *> real_nodal_fields; + real_nodal_fields["clip_bulk_damage"] = this->bulk_damage.get(); + real_nodal_fields["clip_czm_damage"] = this->czm_damage.get(); + + std::shared_ptr<dumpers::Field> field; + if (padding_flag) { + field = clip_mesh->createNodalField(real_nodal_fields[field_name], + group_name, 3); + } else { + field = + clip_mesh->createNodalField(real_nodal_fields[field_name], group_name); + } + return field; + } + else + { + return SolidMechanicsModel::createNodalFieldReal(field_name,group_name,padding_flag); + } +} + +/* -------------------------------------------------------------------------- */ +std::shared_ptr<dumpers::Field> +SolidMechanicsModelCLIP::createElementalField(const std::string & field_name, + const std::string & group_name, bool padding_flag, + Int spatial_dimension, ElementKind kind) +{ + return SolidMechanicsModel::createElementalField(field_name,group_name,padding_flag,spatial_dimension,kind); +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCLIP::onElementsAdded(const Array<Element> & element_list, + const NewElementsEvent & event) + +{ + auto & clip_to_mesh = mesh.getNodalData<Element>("clip_to_mesh"); + const auto & mesh_facets = this->getMeshFacets(); + for(auto & element : element_list) + { + auto type = element.type; + auto ghost_type = element.ghost_type; + const auto & element_to_facet = mesh_facets.getSubelementToElement(type,ghost_type); + auto && facet_1 = element_to_facet(element.element,0); + auto && facet_2 = element_to_facet(element.element,1); + auto && facet = facet_1<facet_2?facet_1:facet_2; + clip_to_mesh[facets_to_clip(facet)]=element; + } + SolidMechanicsModelCohesiveDamage::onElementsAdded(element_list,event); +} + +} // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.hh new file mode 100644 index 0000000000000000000000000000000000000000..3eefb0422e62fe3dd54b9a6e0416e09ac2516afc --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip.hh @@ -0,0 +1,114 @@ +/** + * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "solid_mechanics_model_cohesive_damage.hh" +#include "material_cohesive_damage.hh" +#include "material_bulk_damage.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef AKANTU_SOLID_MECHANICS_MODEL_CLIP_HH_ +#define AKANTU_SOLID_MECHANICS_MODEL_CLIP_HH_ + +/* -------------------------------------------------------------------------- */ +namespace akantu { + +/* -------------------------------------------------------------------------- */ +/* Solid Mechanics Model for CLIP formulation */ +/* -------------------------------------------------------------------------- */ +class SolidMechanicsModelCLIP : public SolidMechanicsModelCohesiveDamage { + + /* ------------------------------------------------------------------------ */ + /* Constructors/Destructors */ + /* ------------------------------------------------------------------------ */ +public: + SolidMechanicsModelCLIP( + Mesh & mesh, Int dim = _all_dimensions, + const ID & id = "solid_mechanics_model_cohesive_clip", + const std::shared_ptr<DOFManager> & dof_manager = nullptr); + + /* ------------------------------------------------------------------------ */ + /* Methods */ + /* ------------------------------------------------------------------------ */ + +public: + void initialize(); + void createCLIPMesh(); + + template<class func> + void initializeCZMDamage(func); + + void precomputeDistances(); + void computeBulkDamage() override; + + Real computeObjectiveFunction(); + + std::shared_ptr<dumpers::Field> + createNodalFieldReal(const std::string & field_name, + const std::string & group_name, + bool padding_flag) override; + + std::shared_ptr<dumpers::Field> + createElementalField(const std::string & field_name, + const std::string & group_name, bool padding_flag, + Int spatial_dimension, ElementKind kind) override; + + +protected: + + /// initialize cohesive material and clip mesh + void initConstitutiveLaws() override; + + void onElementsAdded(const Array<Element> & element_list, + const NewElementsEvent & event) override; + + void computeShapeFunctionsOnIntegrationPoints(); + + void interpolateBulkDamageOnIntegrationPoints(); + +private: + + MaterialCohesiveDamage * czm_material; + + Material * bulk_material; + + std::unique_ptr<Mesh> clip_mesh; + + ElementTypeMapInt facets_to_clip; + + ElementTypeMapReal clip_shapes; + + ElementTypeMapInt gp_to_clip_elem; + + + /// cohesive damage + std::unique_ptr<Array<Real>> czm_damage; + + /// bulk damage + std::unique_ptr<Array<Real>> bulk_damage; + + std::vector<std::vector<Real>> distances; +}; + +} // namespace akantu + +#include "solid_mechanics_model_clip_inline_impl.hh" + +#endif /* AKANTU_SOLID_MECHANICS_MODEL_CLIP_HH_ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip_inline_impl.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip_inline_impl.hh new file mode 100644 index 0000000000000000000000000000000000000000..e2b7bfbb70d3c006e68c0f59fef473e5e8fdde53 --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_clip_inline_impl.hh @@ -0,0 +1,51 @@ +/** + * Copyright (©) 2013-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "solid_mechanics_model_clip.hh" + +#ifndef AKANTU_SOLID_MECHANICS_MODEL_CLIP_INLINE_IMPL_HH_ +#define AKANTU_SOLID_MECHANICS_MODEL_CLIP_INLINE_IMPL_HH_ + +namespace akantu { + +template<class func> +void SolidMechanicsModelCLIP::initializeCZMDamage(func init){ + InternalField<Real> & czm_damage_internal = czm_material->getInternal<Real>("czm_damage"); + auto & fem = this->getFEEngine("CohesiveFEEngine"); + ElementTypeMapReal integration_points_positions("integration_points_positions", id); + integration_points_positions.initialize(fem, _nb_component = spatial_dimension, + _spatial_dimension = spatial_dimension); + fem.computeIntegrationPointsCoordinates(integration_points_positions); + + for (auto ghost_type : ghost_types) { + for (auto type : mesh.elementTypes(_element_kind = _ek_cohesive, + _ghost_type = ghost_type)) { + for (auto && data : + zip((czm_damage_internal)(type,ghost_type) + ,make_view(integration_points_positions(type,ghost_type),spatial_dimension))) { + std::get<0>(data) = init(std::get<1>(data)); + } + } + } +} + +} // namespace akantu + +#endif /* AKANTU_SOLID_MECHANICS_MODEL_CLIP_INLINE_IMPL_HH_ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc index 0d0b906907eefaa59e3d2112a7b6e470940d9cff..38d31c135d2f11cb1d59bd707859650959975ab3 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc @@ -397,20 +397,28 @@ void SolidMechanicsModelCohesive::initStressInterpolation() { /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::assembleInternalForces() { AKANTU_DEBUG_IN(); - + // std::cout << "Assemble Internal forces" << std::endl; // f_int += f_int_cohe + // iterates over each constiute law defined in the solidMEchanicsModel + this->for_each_constitutive_law([&](auto && material) { try { + //it tries to cast the generic material to the type MaterialCohesive.If its a different type + // it throws a std::bad_cast + auto & mat = aka::as_type<MaterialCohesive>(material); + mat.computeDamage(_not_ghost); + mat.computeTraction(_not_ghost); } catch (std::bad_cast & bce) { } }); - + computeBulkDamage(); + // need to compute Bulk G(D) SolidMechanicsModel::assembleInternalForces(); AKANTU_DEBUG_OUT(); -} + } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::computeNormals() { @@ -490,7 +498,6 @@ UInt SolidMechanicsModelCohesive::checkCohesiveStress() { void SolidMechanicsModelCohesive::onElementsAdded( const Array<Element> & element_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); - SolidMechanicsModel::onElementsAdded(element_list, event); if (is_extrinsic) { @@ -500,6 +507,7 @@ void SolidMechanicsModelCohesive::onElementsAdded( AKANTU_DEBUG_OUT(); } +/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onNodesAdded(const Array<Idx> & new_nodes, const NewNodesEvent & event) { @@ -552,8 +560,6 @@ void SolidMechanicsModelCohesive::onNodesAdded(const Array<Idx> & new_nodes, /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::afterSolveStep(bool converged) { - AKANTU_DEBUG_IN(); - /* * This is required because the Cauchy stress is the stress measure that * is used to check the insertion of cohesive elements @@ -567,8 +573,6 @@ void SolidMechanicsModelCohesive::afterSolveStep(bool converged) { } SolidMechanicsModel::afterSolveStep(converged); - - AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh index c4c96d4d9d257b204674d1da9b73f0e790d6002b..08806b6a31ba21053f3694d26c33be6f5dfdfe8c 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh @@ -44,14 +44,15 @@ struct FacetsCohesiveIntegrationOrderFunctor { CohesiveFacetProperty<type>::cohesive_type> struct _helper { static constexpr int get() { - return ElementClassProperty<cohesive_type>::polynomial_degree; +// return 1; + return ElementClassProperty<cohesive_type>::polynomial_degree; } }; template <ElementType type> struct _helper<type, _not_defined> { static constexpr int get() { - return ElementClassProperty<type>::polynomial_degree; - } + // return 1; + return ElementClassProperty<type>::polynomial_degree; } }; template <ElementType type> static inline constexpr int getOrder() { @@ -115,7 +116,6 @@ public: /// insert intrinsic cohesive elements void insertIntrinsicElements(); - // template <SolveConvergenceMethod cmethod, SolveConvergenceCriteria // criteria> bool solveStepCohesive(Real tolerance, Real & error, UInt // max_iteration = 100, @@ -139,7 +139,7 @@ protected: /// function to print the contain of the class void printself(std::ostream & stream, int indent = 0) const override; -private: +protected: /// insert cohesive elements along a given physical surface of the mesh void insertElementsFromMeshData(const std::string & physical_name); @@ -155,6 +155,9 @@ private: /// init facets_check array void initFacetsCheck(); + virtual void computeBulkDamage(){ + // TODO: Implement bulk damage computation + } /* ------------------------------------------------------------------------ */ /* Mesh Event Handler inherited members */ /* ------------------------------------------------------------------------ */ @@ -183,13 +186,6 @@ public: ElementKind element_kind, bool padding_flag) override; -public: - /// register the tags associated with the parallel synchronizer for - /// cohesive elements - // void initParallel(MeshPartition * partition, - // DataAccessor * data_accessor = NULL, - // bool extrinsic = false); - protected: // void synchronizeGhostFacetsConnectivity(); @@ -267,7 +263,7 @@ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ -private: +protected: friend class CohesiveMeshGlobalDataUpdater; /// @todo store tangents when normals are computed: diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.cc new file mode 100644 index 0000000000000000000000000000000000000000..648a1552f49c1e161204babe4fd9930380283bb1 --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.cc @@ -0,0 +1,502 @@ +/** + * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "solid_mechanics_model_cohesive_damage.hh" +#include "aka_iterators.hh" +#include "cohesive_element_inserter.hh" +#include "fe_engine_template.hh" +#include "integrator_gauss.hh" +#include "material_cohesive_damage.hh" +#include "mesh_accessor.hh" +#include "parser.hh" +#include "shape_cohesive.hh" +/* -------------------------------------------------------------------------- */ +#include "dumper_iohelper_paraview.hh" +/* -------------------------------------------------------------------------- */ +#include <algorithm> +/* -------------------------------------------------------------------------- */ + +namespace akantu { + +/* -------------------------------------------------------------------------- */ +SolidMechanicsModelCohesiveDamage::SolidMechanicsModelCohesiveDamage( + Mesh & mesh, Int dim, const ID & id, + const std::shared_ptr<DOFManager> & dof_manager) + : SolidMechanicsModelCohesive(mesh, dim, id, dof_manager) +{} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCohesiveDamage::initConstitutiveLaws() { + AKANTU_DEBUG_IN(); + + // make sure the material are instantiated + instantiateMaterials(); + + auto & material_selector = this->getConstitutiveLawSelector(); + + // set the facet information in the material in case of dynamic insertion + // to know what material to call for stress checks + const Mesh & mesh_facets = inserter->getMeshFacets(); + facet_material.initialize( + mesh_facets, _spatial_dimension = spatial_dimension - 1, + _with_nb_element = true, + _default_value = + DefaultMaterialCohesiveSelector::getDefaultCohesiveMaterial(*this)); + + for_each_element( + mesh_facets, + [&](auto && element) { + auto mat_index = material_selector(element); + if (not mat_index) { + return; + } + auto & mat = + aka::as_type<MaterialCohesive>(this->getConstitutiveLaw(mat_index)); + + facet_material(element) = mat_index; + if (is_extrinsic) { + mat.addFacet(element); + } + }, + _spatial_dimension = spatial_dimension - 1, _ghost_type = _not_ghost); + + SolidMechanicsModel::initConstitutiveLaws(); + + auto & initial_nodes = mesh.getNodalData<Idx>("initial_nodes_match"); + initial_nodes.resize(mesh.getNbNodes()); + for (auto && [node, init_node] : enumerate(initial_nodes)) { + init_node = node; + } + + auto need_lambda = false; + + this->for_each_constitutive_law([&need_lambda](auto && material) { + if (aka::is_of_type<MaterialCohesive>(material)) { + need_lambda |= aka::as_type<MaterialCohesive>(material).needLambda(); + } + }); + + if (need_lambda) { + lambda = + std::make_unique<Array<Real>>(0, spatial_dimension, "cohesive lambda"); + previous_lambda = + std::make_unique<Array<Real>>(0, spatial_dimension, "previous lambda"); + lambda_increment = + std::make_unique<Array<Real>>(0, spatial_dimension, "lambda increment"); + lambda_blocked_dofs = std::make_unique<Array<bool>>(0, spatial_dimension, + "lambda_blocked_dofs"); + + lambda_mesh = std::make_unique<Mesh>(spatial_dimension, + mesh.getCommunicator(), "lambda_mesh"); + registerFEEngineObject<MyFEEngineLambdaType>("LambdaFEEngine", *lambda_mesh, + Model::spatial_dimension - 1); + + auto & nodes_to_lambda = mesh.getNodalData<Idx>("nodes_to_lambda"); + nodes_to_lambda.resize(mesh.getNbNodes(), -1); + } + + if (is_extrinsic) { + this->initAutomaticInsertion(); + } else { + this->insertIntrinsicElements(); + } + + if (lambda) { + auto & dof_manager = this->getDOFManager(); + if (!dof_manager.hasDOFs("lambda")) { + dof_manager.registerDOFs("lambda", *this->lambda, *lambda_mesh); + dof_manager.registerDOFsIncrement("lambda", *this->lambda_increment); + dof_manager.registerDOFsPrevious("lambda", *this->previous_lambda); + dof_manager.registerBlockedDOFs("lambda", *this->lambda_blocked_dofs); + } + } + + AKANTU_DEBUG_OUT(); +} // namespace akantu + +/* -------------------------------------------------------------------------- */ +UInt SolidMechanicsModelCohesiveDamage::checkCohesiveInsertion() { + AKANTU_DEBUG_IN(); + + if (not is_extrinsic) { + AKANTU_EXCEPTION( + "This function can only be used for extrinsic cohesive elements"); + } + + this->for_each_constitutive_law([&](auto && material) { + std::cout << "check insertion " << std::endl ; + if (aka::is_of_type<MaterialCohesive>(material)) { + /// check which not ghost cohesive elements are to be created + auto & mat_cohesive = aka::as_type<MaterialCohesive>(material); + mat_cohesive.checkInsertion(); + } + }); + + /// insert cohesive elements + auto nb_new_elements = inserter->insertElements(); + + AKANTU_DEBUG_OUT(); + + return nb_new_elements; +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCohesiveDamage::computeLagrangeMultiplier() { + AKANTU_DEBUG_IN(); + + if (not is_extrinsic) { + AKANTU_EXCEPTION( + "This function can only be used for extrinsic cohesive elements"); + } + + interpolateStress(); + + this->for_each_constitutive_law([&](auto && material) { + if (aka::is_of_type<MaterialCohesive>(material)) { + /// check which not ghost cohesive elements are to be created + auto & mat_cohesive = aka::as_type<MaterialCohesive>(material); + mat_cohesive.computeLambda(); + } + }); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCohesiveDamage::computeDamage() { + AKANTU_DEBUG_IN(); + + this->for_each_constitutive_law([&](auto && material) { + if (aka::is_of_type<MaterialCohesiveDamage>(material)) { + /// check which not ghost cohesive elements are to be created + auto & mat_cohesive = aka::as_type<MaterialCohesiveDamage>(material); + mat_cohesive.computeDamage(); + } + }); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCohesiveDamage::updateLambdaMesh() { +// std::cout << " SolidMechanicsModelCohesiveDamage::updateLambdaMesh " << std::endl; + + const auto & connectivities = mesh.getConnectivities(); + const auto & initial_nodes = mesh.getNodalData<Idx>("initial_nodes_match"); + auto & nodes_to_lambda = mesh.getNodalData<Idx>("nodes_to_lambda"); + nodes_to_lambda.resize(mesh.getNbNodes(), -1); + + auto & lambda_connectivities = MeshAccessor(*lambda_mesh).getConnectivities(); + + auto lambda_id = lambda->size(); + + std::vector<Idx> new_nodes; + + NewNodesEvent node_event(*lambda_mesh, AKANTU_CURRENT_FUNCTION); + auto & node_list = node_event.getList(); +// std::cout << "node_list before = " << std::endl ; +// ArrayPrintHelper<true>::print_content(node_list,std::cout,0); + + NewElementsEvent element_event(*lambda_mesh, AKANTU_CURRENT_FUNCTION); + auto & element_list = element_event.getList(); +// std::cout << "element_list before = " << std::endl ; +// ArrayPrintHelper<true>::print_content(element_list,std::cout,0); + + for (auto ghost_type : ghost_types) { + for (auto type : connectivities.elementTypes(_element_kind = _ek_cohesive, + _ghost_type = ghost_type)) { + auto underlying_type = Mesh::getFacetType(type); + + auto & connectivity = connectivities(type, ghost_type); + auto & lambda_connectivity = + lambda_connectivities(underlying_type, ghost_type); + +// std::cout << "connectivity = " << std::endl ; +// ArrayPrintHelper<true>::print_content(connectivity,std::cout,0); + +// std::cout << "lambda_connectivity = " << std::endl ; +// ArrayPrintHelper<true>::print_content(lambda_connectivity,std::cout,0); + + + auto nb_new_elements = connectivity.size() - lambda_connectivity.size(); + auto nb_old_elements = lambda_connectivity.size(); + + lambda_connectivity.resize(connectivity.size()); + + auto && view_iconn = + make_view(connectivity, connectivity.getNbComponent()); + auto && view_conn = + make_view(lambda_connectivity, lambda_connectivity.getNbComponent()); + +// std::cout << " connectivity.getNbComponent() " << connectivity.getNbComponent() << std::endl ; +// std::cout << " lambda_connectivity.getNbComponent() " << lambda_connectivity.getNbComponent() << std::endl ; + +// for (auto && [conn, lambda_conn] : +// zip(range(view_iconn.begin() + nb_old_elements, view_iconn.end()), +// range(view_conn.begin() + nb_old_elements, view_conn.end()))) { +// std::cout << "conn = " << conn << std::endl ; +// std::cout << "lambda_conn = " << lambda_conn << std::endl ; + +// for (auto && [n, lambda_node] : enumerate(lambda_conn)) { +// std::cout << "n = " << n << std::endl ; +// auto node = conn[n]; +// std::cout << "node conn= " << node << std::endl ; + +// node = initial_nodes(node); +// std::cout << "node initial_nodes = " << node << std::endl ; + +// auto & ntl = nodes_to_lambda(node); +// std::cout << "ntl = " << ntl << std::endl ; + +// if (ntl == -1) { +// ntl = lambda_id; +// new_nodes.push_back(node); +// node_list.push_back(lambda_id); +// ++lambda_id; +// } + +// lambda_node = ntl; +// } +// } + + for (auto && [conn, lambda_conn] : + zip(range(view_iconn.begin() + nb_old_elements, view_iconn.end()), + range(view_conn.begin() + nb_old_elements, view_conn.end()))) { +// std::cout << "conn = " << conn << std::endl ; +// std::cout << "lambda_conn = " << lambda_conn << std::endl ; + + for (auto && [n, lambda_node] : enumerate(lambda_conn)) { +// std::cout << "n = " << n << std::endl ; + auto node = conn[n]; +// std::cout << "node conn= " << node << std::endl ; + + node = initial_nodes(node); +// std::cout << "node initial_nodes = " << node << std::endl ; + + auto & ntl = nodes_to_lambda(node); +// std::cout << "ntl = " << ntl << std::endl ; + + if (ntl == -1) { + ntl = lambda_id; + new_nodes.push_back(node); + node_list.push_back(lambda_id); + ++lambda_id; + } + + lambda_node = ntl; + } + } + + for (auto && el : arange(nb_old_elements, nb_new_elements)) { +// std::cout << "el = " << el << std::endl ; + element_list.push_back({underlying_type, el, ghost_type}); + } + } + } + +// std::cout << "node_list after = " << std::endl ; +// ArrayPrintHelper<true>::print_content(node_list,std::cout,0); + +// std::cout << "element_list after = " << std::endl ; +// ArrayPrintHelper<true>::print_content(element_list,std::cout,0); + + lambda_mesh->copyNodes(mesh, new_nodes); + + lambda->resize(lambda_id, 0.); + lambda_increment->resize(lambda_id, 0.); + previous_lambda->resize(lambda_id, 0.); + + lambda_mesh->sendEvent(element_event); + lambda_mesh->sendEvent(node_event); +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCohesiveDamage::onElementsAdded( + const Array<Element> & element_list, const NewElementsEvent & event) { + AKANTU_DEBUG_IN(); + +// std::cout << " SolidMechanicsModelCohesiveDamage::onElementsAdded " << std::endl; + + SolidMechanicsModel::onElementsAdded(element_list, event); + + if (lambda) { + auto & lambda_connectivities = + MeshAccessor(*lambda_mesh).getConnectivities(); + + for (auto ghost_type : ghost_types) { + for (auto type : mesh.elementTypes(_element_kind = _ek_cohesive, + _ghost_type = ghost_type)) { + auto underlying_type = Mesh::getFacetType(type); + if (not lambda_connectivities.exists(underlying_type, ghost_type)) { + auto nb_nodes_per_element = + Mesh::getNbNodesPerElement(underlying_type); + lambda_connectivities.alloc(0, nb_nodes_per_element, underlying_type, + ghost_type, -1); + } + } + } + } + + if (is_extrinsic) { + resizeFacetStress(); + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCohesiveDamage::onNodesAdded(const Array<Idx> & new_nodes, + const NewNodesEvent & event) { + SolidMechanicsModel::onNodesAdded(new_nodes, event); + + auto & initial_nodes = mesh.getNodalData<Idx>("initial_nodes_match"); + + auto old_max_nodes = initial_nodes.size(); + initial_nodes.resize(mesh.getNbNodes(), -1); + + const auto * cohesive_event = + dynamic_cast<const CohesiveNewNodesEvent *>(&event); + if (cohesive_event == nullptr) { + for (auto && node : new_nodes) { + initial_nodes(node) = node; + } + return; + } + + auto old_nodes = cohesive_event->getOldNodesList(); + + // getting a corrected old_nodes for multiple doubling + for (auto & onode : old_nodes) { + while (onode >= old_max_nodes) { + auto nnode = new_nodes.find(onode); + AKANTU_DEBUG_ASSERT(nnode != -1, + "If the old node is bigger than old_max_nodes it " + "should also be a new node"); + onode = nnode; + } + } + + auto copy = [&new_nodes, &old_nodes](auto & arr) { + auto it = make_view(arr, arr.getNbComponent()).begin(); + for (auto [new_node, old_node] : zip(new_nodes, old_nodes)) { + it[new_node] = it[old_node]; + } + }; + + for (auto && ptr : {displacement.get(), velocity.get(), acceleration.get(), + current_position.get(), previous_displacement.get(), + displacement_increment.get()}) { + if (ptr != nullptr) { + copy(*ptr); + } + } + + copy(*displacement); + copy(*blocked_dofs); + + if (velocity) { + copy(*velocity); + } + + if (acceleration) { + copy(*acceleration); + } + + if (current_position) { + copy(*current_position); + } + + if (previous_displacement) { + copy(*previous_displacement); + } + + if (displacement_increment) { + copy(*displacement_increment); + } + + copy(getDOFManager().getSolution("displacement")); + + // correct connectivities + if (lambda) { + lambda_blocked_dofs->resize(mesh.getNbNodes(), false); + copy(*lambda_blocked_dofs); + updateLambdaMesh(); + } +} + +/* -------------------------------------------------------------------------- */ +ModelSolverOptions SolidMechanicsModelCohesiveDamage::getDefaultSolverOptions( + const TimeStepSolverType & type) const { + ModelSolverOptions options = + SolidMechanicsModel::getDefaultSolverOptions(type); + + if (lambda) { +// if (true) { + switch (type) { + case TimeStepSolverType::_dynamic_lumped: { + options.non_linear_solver_type = NonLinearSolverType::_lumped; + options.integration_scheme_type["lambda"] = + IntegrationSchemeType::_central_difference; + options.solution_type["lambda"] = IntegrationScheme::_acceleration; + break; + } + case TimeStepSolverType::_static: { + options.non_linear_solver_type = NonLinearSolverType::_newton_raphson; + options.integration_scheme_type["lambda"] = + IntegrationSchemeType::_pseudo_time; + options.solution_type["lambda"] = IntegrationScheme::_not_defined; + break; + } + case TimeStepSolverType::_dynamic: { + if (this->method == _explicit_consistent_mass) { + options.non_linear_solver_type = NonLinearSolverType::_newton_raphson; + options.integration_scheme_type["lambda"] = + IntegrationSchemeType::_central_difference; + options.solution_type["lambda"] = IntegrationScheme::_acceleration; + } else { + options.non_linear_solver_type = NonLinearSolverType::_newton_raphson; + options.integration_scheme_type["lambda"] = + IntegrationSchemeType::_trapezoidal_rule_2; + options.solution_type["lambda"] = IntegrationScheme::_displacement; + } + break; + } + default: + AKANTU_EXCEPTION(type << " is not a valid time step solver type"); + } + } + return options; +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCohesiveDamage::printself(std::ostream & stream, + int indent) const { + std::string space(indent, AKANTU_INDENT); + + stream << space << "SolidMechanicsModelCohesiveDamage [" + << "\n"; + SolidMechanicsModelCohesive::printself(stream, indent + 2); + stream << space << "]\n"; +} + +/* -------------------------------------------------------------------------- */ + +} // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.hh new file mode 100644 index 0000000000000000000000000000000000000000..5ccf6b678f4c06187b9cb3e96a0c9bb66547d2fc --- /dev/null +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_damage.hh @@ -0,0 +1,151 @@ +/** + * Copyright (©) 2012-2023 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * This file is part of Akantu + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see <http://www.gnu.org/licenses/>. + */ + +/* -------------------------------------------------------------------------- */ +#include "solid_mechanics_model_cohesive.hh" +/* -------------------------------------------------------------------------- */ + +#ifndef AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_DAMAGE_HH_ +#define AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_DAMAGE_HH_ + +/* -------------------------------------------------------------------------- */ +namespace akantu { + +/* -------------------------------------------------------------------------- */ +struct CohesiveIntegrationOrderFunctor { + template <ElementType type, ElementType cohesive_type = + CohesiveFacetProperty<type>::cohesive_type> + struct _helper { + static constexpr int get() { + // return 1; + return ElementClassProperty<cohesive_type>::polynomial_degree; } + }; + + template <ElementType type> struct _helper<type, _not_defined> { + static constexpr int get() { + // return 1; + return ElementClassProperty<type>::polynomial_degree; } + }; + + template <ElementType type> static inline constexpr int getOrder() { + return _helper<type>::get(); + } +}; + +/* -------------------------------------------------------------------------- */ +/* Solid Mechanics Model for Cohesive damage elements */ +/* -------------------------------------------------------------------------- */ +class SolidMechanicsModelCohesiveDamage : public SolidMechanicsModelCohesive { + + using MyFEEngineLambdaType = + FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_regular, + FacetsCohesiveIntegrationOrderFunctor>; + + /* ------------------------------------------------------------------------ */ + /* Constructors/Destructors */ + /* ------------------------------------------------------------------------ */ +public: + SolidMechanicsModelCohesiveDamage( + Mesh & mesh, Int dim = _all_dimensions, + const ID & id = "solid_mechanics_model_cohesive_damage", + const std::shared_ptr<DOFManager> & dof_manager = nullptr); + + /* ------------------------------------------------------------------------ */ + /* Methods */ + /* ------------------------------------------------------------------------ */ + +public: + + /// function to perform an insertion check on each facet and insert + /// cohesive elements if needed (returns the number of new cohesive + /// elements) + UInt checkCohesiveInsertion(); + + /// compute Lagrange multiplier + void computeLagrangeMultiplier(); + + /// compute damage variable + void computeDamage(); + +protected: + + /// initialize cohesive material + void initConstitutiveLaws() override; + + /// function to print the contain of the class + void printself(std::ostream & stream, int indent = 0) const override; + + /* ------------------------------------------------------------------------ */ + /* SolidMechanicsModelEventHandler inherited members */ + /* ------------------------------------------------------------------------ */ +public: + + [[nodiscard]] ModelSolverOptions + getDefaultSolverOptions(const TimeStepSolverType & type) const override; + + void updateLambdaMesh(); + + /* ------------------------------------------------------------------------ */ + /* Accessors */ + /* ------------------------------------------------------------------------ */ +public: + + /// get the SolidMechanicsModel::lambda array + AKANTU_GET_MACRO_DEREF_PTR_NOT_CONST(Lambda, lambda); + /// get the SolidMechanicsModel::displacement array + AKANTU_GET_MACRO_DEREF_PTR(Lambda, lambda); + + /// get lambda mesh + const Mesh & getLambdaMesh() { + if (not lambda_mesh) { + AKANTU_EXCEPTION("This model does not have a lambda mesh"); + } + return *lambda_mesh; + } + +protected: + void onNodesAdded(const Array<Idx> & new_nodes, + const NewNodesEvent & event) override; + void onElementsAdded(const Array<Element> & element_list, + const NewElementsEvent & event) override; + + /* ------------------------------------------------------------------------ */ + /* Class Members */ + /* ------------------------------------------------------------------------ */ +private: + + /// lambda array + std::unique_ptr<Array<Real>> lambda; + + /// lambda array at the previous time step + std::unique_ptr<Array<Real>> previous_lambda; + + /// increment of lambda + std::unique_ptr<Array<Real>> lambda_increment; + + /// array specifing if a lambda degree of freedom is blocked or not + std::unique_ptr<Array<bool>> lambda_blocked_dofs; + + std::unique_ptr<Mesh> lambda_mesh; +}; + +} // namespace akantu + +#endif /* AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_DAMAGE_HH_ */ diff --git a/src/model/structural_mechanics/structural_mechanics_model.cc b/src/model/structural_mechanics/structural_mechanics_model.cc index 49a48cfdcd4ec4b6de5f36e1a9fb31303a992ad1..92eba2052a3a677748f3b283e6b3123e1defcf52 100644 --- a/src/model/structural_mechanics/structural_mechanics_model.cc +++ b/src/model/structural_mechanics/structural_mechanics_model.cc @@ -149,8 +149,7 @@ void StructuralMechanicsModel::initSolver( auto & dof_manager = this->getDOFManager(); if (not dof_manager.hasDOFs("displacement")) { - dof_manager.registerDOFs("displacement", *displacement_rotation, - _dst_nodal); + dof_manager.registerDOFs("displacement", *displacement_rotation, mesh); dof_manager.registerBlockedDOFs("displacement", *this->blocked_dofs); } @@ -525,8 +524,8 @@ void StructuralMechanicsModel::assembleInternalForce(ElementType type, Array<Real> intBtSigma(0, ndof_per_elem, "intBtSigma"); fem.integrate(BtSigma, intBtSigma, ndof_per_elem, type, gt); - getDOFManager().assembleElementalArrayLocalArray(intBtSigma, *internal_force, - type, gt, -1.); + getDOFManager().assembleElementalArrayLocalArray( + "displacement", intBtSigma, *internal_force, type, gt, -1.); } /* -------------------------------------------------------------------------- */ @@ -687,8 +686,8 @@ void StructuralMechanicsModel::computeForcesByLocalTractionArray( nb_degree_of_freedom * nb_nodes_per_element, type); // assemble the result into force vector - getDOFManager().assembleElementalArrayLocalArray(int_funct, *external_force, - type, _not_ghost, 1); + getDOFManager().assembleElementalArrayLocalArray( + "displacement", int_funct, *external_force, type, _not_ghost, 1); AKANTU_DEBUG_OUT(); } diff --git a/src/synchronizer/dof_synchronizer.cc b/src/synchronizer/dof_synchronizer.cc index 4cdf8f55b5f5c51c78d8e54530800d848a57898f..d6497c76531d6528a2900025f7dee5e7781a7f17 100644 --- a/src/synchronizer/dof_synchronizer.cc +++ b/src/synchronizer/dof_synchronizer.cc @@ -56,9 +56,6 @@ DOFSynchronizer::DOFSynchronizer(DOFManagerDefault & dof_manager, const ID & id) } } -/* -------------------------------------------------------------------------- */ -DOFSynchronizer::~DOFSynchronizer() = default; - /* -------------------------------------------------------------------------- */ void DOFSynchronizer::registerDOFs(const ID & dof_id) { if (this->nb_proc == 1) { @@ -71,7 +68,8 @@ void DOFSynchronizer::registerDOFs(const ID & dof_id) { const auto & equation_numbers = dof_manager.getLocalEquationsNumbers(dof_id); const auto & associated_nodes = dof_manager.getDOFsAssociatedNodes(dof_id); - const auto & node_synchronizer = dof_manager.getMesh().getNodeSynchronizer(); + const auto & node_synchronizer = + dof_manager.getMesh(dof_id).getNodeSynchronizer(); const auto & node_communications = node_synchronizer.getCommunications(); auto transcode_node_to_global_dof_scheme = @@ -99,8 +97,7 @@ void DOFSynchronizer::registerDOFs(const ID & dof_id) { std::sort(global_dofs_per_node.begin(), global_dofs_per_node.end()); std::transform(global_dofs_per_node.begin(), global_dofs_per_node.end(), global_dofs_per_node.begin(), [this](Idx g) -> Idx { - auto l = dof_manager.globalToLocalEquationNumber(g); - return l; + return dof_manager.globalToLocalEquationNumber(g); }); for (auto & leqnum : global_dofs_per_node) { scheme.push_back(leqnum); @@ -145,8 +142,7 @@ void DOFSynchronizer::onNodesAdded(const Array<Idx> & /*nodes_list*/) { auto dof_ids = dof_manager.getDOFIDs(); for (auto sr : iterate_send_recv) { - for (auto && data : communications.iterateSchemes(sr)) { - auto & scheme = data.second; + for (auto && [_, scheme] : communications.iterateSchemes(sr)) { scheme.resize(0); } } diff --git a/src/synchronizer/dof_synchronizer.hh b/src/synchronizer/dof_synchronizer.hh index 93179dcaf8852e0b6bbebf3535313ea9f2a4685a..f3ea171aaf857c28b382b578182d5e98f55732d6 100644 --- a/src/synchronizer/dof_synchronizer.hh +++ b/src/synchronizer/dof_synchronizer.hh @@ -41,7 +41,6 @@ class DOFSynchronizer : public SynchronizerImpl<Idx> { public: DOFSynchronizer(DOFManagerDefault & dof_manager, const ID & id = "dof_synchronizer"); - ~DOFSynchronizer() override; virtual void registerDOFs(const ID & dof_id); /* ------------------------------------------------------------------------ */ diff --git a/src/synchronizer/grid_synchronizer.cc b/src/synchronizer/grid_synchronizer.cc index 25f00d184b9d971d6cf73d34fbafc986f69f14ca..19117fc3622d8c8ae9d2a9054cfe979fcc0baabc 100644 --- a/src/synchronizer/grid_synchronizer.cc +++ b/src/synchronizer/grid_synchronizer.cc @@ -27,7 +27,6 @@ #include "mesh.hh" #include "mesh_io.hh" #include <iostream> - /* -------------------------------------------------------------------------- */ namespace akantu { @@ -232,8 +231,8 @@ void GridSynchronizer::createGridSynchronizer(const SpatialGrid<E> & grid) { Int nb_total_nodes_to_recv = 0; Int nb_current_nodes = global_nodes_ids.size(); - NewNodesEvent new_nodes; - NewElementsEvent new_elements; + NewNodesEvent new_nodes(mesh); + NewElementsEvent new_elements(mesh); std::map<Int, std::vector<Int>> ask_nodes_per_proc; diff --git a/test/test_model/test_common/test_dof_manager.cc b/test/test_model/test_common/test_dof_manager.cc index acde4ea0669bdd02fb7151bab5082ebb21855ca1..64251a74eeddda4a96a9955929c08672e2692f3e 100644 --- a/test/test_model/test_common/test_dof_manager.cc +++ b/test/test_model/test_common/test_dof_manager.cc @@ -121,7 +121,7 @@ public: {_dmt_default, "default"}, {_dmt_petsc, "petsc"}}; return DOFManagerTester(DOFManagerFactory::getInstance().allocate( - types[T::value], *mesh, "dof_manager")); + types[T::value], "dof_manager")); } decltype(auto) registerDOFs(DOFSupportType dst1, DOFSupportType dst2) { @@ -130,14 +130,22 @@ public: auto n1 = dst1 == _dst_nodal ? nb_nodes : nb_pure_local; this->dof1 = std::make_unique<Array<Real>>(n1, 3); - dof_manager->registerDOFs("dofs1", *this->dof1, dst1); + if (dst1 == _dst_nodal) { + dof_manager->registerDOFs("dofs1", *this->dof1, *mesh); + } else { + dof_manager->registerDOFs("dofs1", *this->dof1, dst1); + } EXPECT_EQ(dof_manager.residual().size(), nb_total_nodes * 3); auto n2 = dst2 == _dst_nodal ? nb_nodes : nb_pure_local; this->dof2 = std::make_unique<Array<Real>>(n2, 5); - dof_manager->registerDOFs("dofs2", *this->dof2, dst2); + if (dst2 == _dst_nodal) { + dof_manager->registerDOFs("dofs2", *this->dof2, *mesh); + } else { + dof_manager->registerDOFs("dofs2", *this->dof2, dst2); + } EXPECT_EQ(dof_manager.residual().size(), nb_total_nodes * 8); return dof_manager; @@ -176,23 +184,32 @@ TYPED_TEST(DOFManagerFixture, RegisterGenericDOF1) { EXPECT_GE(dof_manager.residual().size(), this->nb_total_nodes * 3); } +/* -------------------------------------------------------------------------- */ +TYPED_TEST(DOFManagerFixture, RegisterGenericDOF2) { + this->registerDOFs(_dst_generic, _dst_generic); +} + /* -------------------------------------------------------------------------- */ TYPED_TEST(DOFManagerFixture, RegisterNodalDOF1) { auto dof_manager = this->alloc(); Array<Real> dofs(this->nb_nodes, 3); - dof_manager->registerDOFs("dofs1", dofs, _dst_nodal); + dof_manager->registerDOFs("dofs1", dofs, *this->mesh); EXPECT_GE(dof_manager.residual().size(), this->nb_total_nodes * 3); } /* -------------------------------------------------------------------------- */ -TYPED_TEST(DOFManagerFixture, RegisterGenericDOF2) { - this->registerDOFs(_dst_generic, _dst_generic); +TYPED_TEST(DOFManagerFixture, RegisterNodalDOF2) { + this->registerDOFs(_dst_nodal, _dst_nodal); } /* -------------------------------------------------------------------------- */ -TYPED_TEST(DOFManagerFixture, RegisterNodalDOF2) { - this->registerDOFs(_dst_nodal, _dst_nodal); +TYPED_TEST(DOFManagerFixture, RegisterNodalDOF3) { + auto dof_manager = this->alloc(); + + Array<Real> dofs(this->nb_nodes, 3); + EXPECT_THROW(dof_manager->registerDOFs("dofs1", dofs, _dst_nodal), + debug::Exception); } /* -------------------------------------------------------------------------- */ diff --git a/test/test_model/test_common/test_dof_mesh_distribute.cc b/test/test_model/test_common/test_dof_mesh_distribute.cc index 1514cb254698d43951080a653814e9663b127331..ea2b89db6c51cc3971a00cbc1ea8c1bcb7356237 100644 --- a/test/test_model/test_common/test_dof_mesh_distribute.cc +++ b/test/test_model/test_common/test_dof_mesh_distribute.cc @@ -53,16 +53,19 @@ TEST(TestMesh, TestMeshDistribute) { mesh2.read("mesh.msh"); } + Array<Real> dofs(mesh1.getNbNodes(), 1); + /* This should fail since the mesh is distributed after the * DOFManager is created. */ - DOFManagerDefault dof_manager(mesh1, "test_dof_manager_1__failing"); + DOFManagerDefault dof_manager("test_dof_manager_1__failing"); + dof_manager.registerDOFs("u", dofs, mesh1); EXPECT_THROW(mesh1.distribute(), debug::Exception); /* This will succeed since the mesh is distributed before the manager is * created. */ mesh2.distribute(); - EXPECT_NO_THROW( - DOFManagerDefault dof_manager2(mesh2, "test_dof_manager_2__succeeding")); + DOFManagerDefault dof_manager2("test_dof_manager_2__succeeding"); + EXPECT_NO_THROW(dof_manager2.registerDOFs("u", dofs, mesh2)); finalize(); } diff --git a/test/test_model/test_common/test_model_solver/test_model_solver_my_model.hh b/test/test_model/test_common/test_model_solver/test_model_solver_my_model.hh index b8ce549a4c5293ada414f9b1083143935dc0e5b1..9d25bd39f997eaa3bca280270b797337e387aa6e 100644 --- a/test/test_model/test_common/test_model_solver/test_model_solver_my_model.hh +++ b/test/test_model/test_common/test_model_solver/test_model_solver_my_model.hh @@ -50,11 +50,11 @@ public: MyModel(Real F, Mesh & mesh, bool lumped, const ID & dof_manager_type = "default") : ModelSolver(mesh, ModelType::_model, "model_solver"), - nb_dofs(mesh.getNbNodes()), nb_elements(mesh.getNbElement(_segment_2)), - lumped(lumped), E(1.), A(1.), rho(1.), mesh(mesh), - displacement(nb_dofs, 1, "disp"), velocity(nb_dofs, 1, "velo"), - acceleration(nb_dofs, 1, "accel"), blocked(nb_dofs, 1, "blocked"), - forces(nb_dofs, 1, "force_ext"), + BoundaryCondition<MyModel>("disp"), nb_dofs(mesh.getNbNodes()), + nb_elements(mesh.getNbElement(_segment_2)), lumped(lumped), E(1.), + A(1.), rho(1.), mesh(mesh), displacement(nb_dofs, 1, "disp"), + velocity(nb_dofs, 1, "velo"), acceleration(nb_dofs, 1, "accel"), + blocked(nb_dofs, 1, "blocked"), forces(nb_dofs, 1, "force_ext"), internal_forces(nb_dofs, 1, "force_int"), stresses(nb_elements, 1, "stress"), strains(nb_elements, 1, "strain"), initial_lengths(nb_elements, 1, "L0") { @@ -63,7 +63,7 @@ public: this->initBC(*this, displacement, forces); - this->getDOFManager().registerDOFs("disp", displacement, _dst_nodal); + this->getDOFManager().registerDOFs("disp", displacement, mesh); this->getDOFManager().registerDOFsDerivative("disp", 1, velocity); this->getDOFManager().registerDOFsDerivative("disp", 2, acceleration); this->getDOFManager().registerBlockedDOFs("disp", blocked); @@ -140,7 +140,7 @@ public: } this->getDOFManager().assembleElementalArrayLocalArray( - m_all_el, M, _segment_2, ghost_type); + "disp", m_all_el, M, _segment_2, ghost_type); this->getDOFManager().assembleToLumpedMatrix("disp", M, "M"); } @@ -295,7 +295,7 @@ public: } this->getDOFManager().assembleElementalArrayLocalArray( - forces_internal_el, internal_forces, _segment_2, ghost_type); + "disp", forces_internal_el, internal_forces, _segment_2, ghost_type); } Real getPotentialEnergy() { diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo index 9cae112da0a2518e00a7ee8fdb48f0acfc0b23cd..8656cdfcfa044acfd52ba723498f36d9c5faa058 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.geo @@ -10,23 +10,39 @@ Point(4) = { x/2.,-y/2, 0, h}; Point(5) = {-x/2., 0, 0, h}; Point(6) = { x/2., 0, 0, h}; -Line(1) = {1, 2}; +Point(7) = { 0, 0, 0, h}; +Point(8) = { 0, y/2, 0, h}; +Point(9) = { 0,-y/2, 0, h}; + + +Line(11) = {1, 8}; +Line(12) = {8, 2}; Line(2) = {2, 5}; -Line(3) = {5, 6}; +Line(31) = {5, 7}; +Line(32) = {7, 6}; Line(4) = {6, 1}; Line(5) = {5, 3}; -Line(6) = {3, 4}; +Line(61) = {3, 9}; +Line(62) = {9, 4}; Line(7) = {4, 6}; -Line Loop(1) = {1, 2, 3, 4}; -Line Loop(2) = {-3, 5, 6, 7}; -Plane Surface(1) = {1}; -Plane Surface(2) = {2}; +Line(8) = {7, 8}; +Line(9) = {7, 9}; + +Line Loop(11) = {11, -8, 32, 4}; +Line Loop(12) = {12, 2, 31, 8}; +Line Loop(21) = {-32, 9, 62, 7}; +Line Loop(22) = {-31, 5, 61, -9}; +Plane Surface(11) = {11}; +Plane Surface(12) = {12}; +Plane Surface(21) = {21}; +Plane Surface(22) = {22}; -Physical Line("fixed") = {6}; -Physical Line("loading") = {1}; -Physical Line("insertion") = {3}; +Physical Line("fixed") = {61, 62}; +Physical Line("loading") = {11, 12}; +Physical Line("insertion") = {31, 32}; Physical Line("sides") = {2, 5, 7, 4}; +Physical Line("middle") = {8, 9}; -Physical Surface("body") = {1, 2}; +Physical Surface("body") = {11, 12, 21, 22}; diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.msh b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.msh index f9a6e5773bdc6681f4e2e194cbfef15d42c8b481..dbe5b77db2ee982a15298b492fd2621a6cfa034e 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.msh +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D.msh @@ -1,51 +1,205 @@ $MeshFormat -2.2 0 8 +4.1 0 8 $EndMeshFormat $PhysicalNames -4 +6 1 1 "fixed" 1 2 "loading" 1 3 "insertion" -2 4 "body" +1 4 "sides" +1 5 "middle" +2 6 "body" $EndPhysicalNames +$Entities +9 12 2 0 +1 1 0.5 0 0 +2 -1 0.5 0 0 +3 -1 -0.5 0 0 +4 1 -0.5 0 0 +5 -1 0 0 0 +6 1 0 0 0 +7 0 0 0 0 +8 0 0.5 0 0 +9 0 -0.5 0 0 +2 -1 0 0 -1 0.5 0 1 4 2 2 -5 +4 1 0 0 1 0.5 0 1 4 2 6 -1 +5 -1 -0.5 0 -1 0 0 1 4 2 5 -3 +7 1 -0.5 0 1 0 0 1 4 2 4 -6 +8 0 0 0 0 0.5 0 1 5 2 7 -8 +9 0 -0.5 0 0 0 0 1 5 2 7 -9 +11 0 0.5 0 1 0.5 0 1 2 2 1 -8 +12 -1 0.5 0 0 0.5 0 1 2 2 8 -2 +31 -1 0 0 0 0 0 1 3 2 5 -7 +32 0 0 0 1 0 0 1 3 2 7 -6 +61 -1 -0.5 0 0 -0.5 0 1 1 2 3 -9 +62 0 -0.5 0 1 -0.5 0 1 1 2 9 -4 +1 -1 0 0 1 0.5 0 1 6 8 12 2 31 8 -4 -32 8 -11 +2 -1 -0.5 0 1 0 0 1 6 8 -32 9 62 7 -31 5 61 -9 +$EndEntities $Nodes +23 33 1 33 +0 1 0 1 +1 +1 0.5 0 +0 2 0 1 +2 +-1 0.5 0 +0 3 0 1 +3 +-1 -0.5 0 +0 4 0 1 +4 +1 -0.5 0 +0 5 0 1 +5 +-1 0 0 +0 6 0 1 +6 +1 0 0 +0 7 0 1 +7 +0 0 0 +0 8 0 1 +8 +0 0.5 0 +0 9 0 1 +9 +0 -0.5 0 +1 2 0 1 +10 +-1 0.2500000000010293 0 +1 4 0 1 +11 +1 0.2499999999993471 0 +1 5 0 1 +12 +-1 -0.2499999999993471 0 +1 7 0 1 13 -1 1 1 0 -2 -1 1 0 -3 -1 -1 0 -4 1 -1 0 -5 -1 0 0 -6 1 0 0 -7 2.752797989558076e-12 1 0 -8 -2.752797989558076e-12 0 0 -9 -2.752797989558076e-12 -1 0 -10 -0.4999999999986235 0.5000000000027528 0 -11 0.5000000000013765 0.5 0 -12 0.4999999999986235 -0.5 0 -13 -0.5000000000013765 -0.5 0 +1 -0.2500000000010293 0 +1 8 0 1 +14 +0 0.2499999999993471 0 +1 9 0 1 +15 +0 -0.2499999999993471 0 +1 11 0 2 +16 +17 +0.6666666666675911 0.5 0 +0.3333333333347203 0.5 0 +1 12 0 2 +18 +19 +-0.3333333333325025 0.5 0 +-0.6666666666657889 0.5 0 +1 31 0 2 +20 +21 +-0.6666666666675911 0 0 +-0.3333333333347203 0 0 +1 32 0 2 +22 +23 +0.3333333333325025 0 0 +0.6666666666657889 0 0 +1 61 0 2 +24 +25 +-0.6666666666675911 -0.5 0 +-0.3333333333347203 -0.5 0 +1 62 0 2 +26 +27 +0.3333333333325025 -0.5 0 +0.6666666666657889 -0.5 0 +2 1 0 3 +28 +29 +30 +-0.5000000000003003 0.2499999999997421 0 +-0.2500000000005764 0.263888888887807 0 +-0.7500000000006232 0.2361111111106458 0 +2 2 0 3 +31 +32 +33 +-0.5000000000011557 -0.25 0 +-0.2500000000005597 -0.2638888888885687 0 +-0.7500000000005961 -0.2638888888893391 0 $EndNodes $Elements -22 -1 1 4 2 1 1 1 1 7 -2 1 4 2 1 1 1 7 2 -3 1 2 3 3 5 8 -4 1 2 3 3 8 6 -5 1 4 1 6 1 3 3 9 -6 1 4 1 6 1 3 9 4 -7 2 5 4 1 2 1 -2 11 7 10 -8 2 5 4 1 2 2 -1 8 11 10 -9 2 5 4 1 2 1 -2 2 10 7 -10 2 6 4 1 3 2 -1 -3 6 11 8 -11 2 6 4 1 3 1 -2 -3 1 11 6 -12 2 6 4 1 3 1 -2 -3 2 5 10 -13 2 6 4 1 3 2 -1 -3 5 8 10 -14 2 5 4 1 2 1 -2 1 7 11 -15 2 5 4 2 2 2 -3 12 8 13 -16 2 5 4 2 2 3 -2 9 12 13 -17 2 5 4 2 2 3 -2 4 12 9 -18 2 6 4 2 3 2 -1 -3 6 8 12 -19 2 6 4 2 3 3 -1 -2 3 13 5 -20 2 6 4 2 3 3 -1 -2 4 6 12 -21 2 5 4 2 2 3 -2 3 9 13 -22 2 6 4 2 3 2 -1 -3 5 13 8 +14 58 1 58 +1 2 1 2 +1 2 10 +2 10 5 +1 4 1 2 +3 6 11 +4 11 1 +1 5 1 2 +5 5 12 +6 12 3 +1 7 1 2 +7 4 13 +8 13 6 +1 8 1 2 +9 7 14 +10 14 8 +1 9 1 2 +11 7 15 +12 15 9 +1 11 1 3 +13 1 16 +14 16 17 +15 17 8 +1 12 1 3 +16 8 18 +17 18 19 +18 19 2 +1 31 1 3 +19 5 20 +20 20 21 +21 21 7 +1 32 1 3 +22 7 22 +23 22 23 +24 23 6 +1 61 1 3 +25 3 24 +26 24 25 +27 25 9 +1 62 1 3 +28 9 26 +29 26 27 +30 27 4 +2 1 2 14 +31 2 10 30 +32 7 14 29 +33 19 2 30 +34 21 7 29 +35 14 8 29 +36 10 5 30 +37 8 18 29 +38 5 20 30 +39 18 19 28 +40 20 21 28 +41 28 19 30 +42 28 21 29 +43 18 28 29 +44 20 28 30 +2 2 2 14 +45 7 32 15 +46 12 33 5 +47 21 32 7 +48 5 33 20 +49 15 32 9 +50 3 33 12 +51 9 32 25 +52 24 33 3 +53 25 31 24 +54 20 31 21 +55 31 32 21 +56 20 33 31 +57 25 32 31 +58 31 33 24 $EndElements diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_mixte.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_mixte.geo index 5d78488e4400f78609adfa30e4a2b6b317d51721..4d3fec0ea0707460156ebf9b21b9100886c7e049 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_mixte.geo +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_mixte.geo @@ -1,4 +1,4 @@ -h = 0.5; +h = 0.4; y = 1; x = 2; @@ -10,27 +10,43 @@ Point(4) = { x/2.,-y/2, 0, h}; Point(5) = {-x/2., 0, 0, h}; Point(6) = { x/2., 0, 0, h}; -Line(1) = {1, 2}; +Point(7) = { 0, 0, 0, h}; +Point(8) = { 0, y/2, 0, h}; +Point(9) = { 0,-y/2, 0, h}; + + +Line(11) = {1, 8}; +Line(12) = {8, 2}; Line(2) = {2, 5}; -Line(3) = {5, 6}; +Line(31) = {5, 7}; +Line(32) = {7, 6}; Line(4) = {6, 1}; Line(5) = {5, 3}; -Line(6) = {3, 4}; +Line(61) = {3, 9}; +Line(62) = {9, 4}; Line(7) = {4, 6}; -Line Loop(1) = {1, 2, 3, 4}; -Line Loop(2) = {-3, 5, 6, 7}; -Plane Surface(1) = {1}; -Plane Surface(2) = {2}; - -Physical Line("fixed") = {6}; -Physical Line("loading") = {1}; -Physical Line("insertion") = {3}; +Line(8) = {7, 8}; +Line(9) = {7, 9}; + +Line Loop(11) = {11, -8, 32, 4}; +Line Loop(12) = {12, 2, 31, 8}; +Line Loop(21) = {-32, 9, 62, 7}; +Line Loop(22) = {-31, 5, 61, -9}; +Plane Surface(11) = {11}; +Plane Surface(12) = {12}; +Plane Surface(21) = {21}; +Plane Surface(22) = {22}; + +Physical Line("fixed") = {61, 62}; +Physical Line("loading") = {11, 12}; +Physical Line("insertion") = {31, 32}; Physical Line("sides") = {2, 5, 7, 4}; +Physical Line("middle") = {8, 9}; -Physical Surface("body") = {1, 2}; +Physical Surface("body") = {11, 12, 21, 22}; -Recombine Surface {2}; -Transfinite Surface {2}; +Recombine Surface {21, 22}; +Transfinite Surface {21, 22}; Mesh.SecondOrderIncomplete = 1; diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_structured.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_structured.geo index 07eadacae310dd5f164b6aed0ab4104f2c6e241f..2fbd9855413fb4dba06a69797ca96760537709c1 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_structured.geo +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_2D_structured.geo @@ -1,4 +1,4 @@ -h = 0.2; +h = 0.4; y = 1; x = 2; @@ -10,26 +10,42 @@ Point(4) = { x/2.,-y/2, 0, h}; Point(5) = {-x/2., 0, 0, h}; Point(6) = { x/2., 0, 0, h}; -Line(1) = {1, 2}; +Point(7) = { 0, 0, 0, h}; +Point(8) = { 0, y/2, 0, h}; +Point(9) = { 0,-y/2, 0, h}; + + +Line(11) = {1, 8}; +Line(12) = {8, 2}; Line(2) = {2, 5}; -Line(3) = {5, 6}; +Line(31) = {5, 7}; +Line(32) = {7, 6}; Line(4) = {6, 1}; Line(5) = {5, 3}; -Line(6) = {3, 4}; +Line(61) = {3, 9}; +Line(62) = {9, 4}; Line(7) = {4, 6}; -Line Loop(1) = {1, 2, 3, 4}; -Line Loop(2) = {-3, 5, 6, 7}; -Plane Surface(1) = {1}; -Plane Surface(2) = {2}; - -Physical Line("fixed") = {6}; -Physical Line("loading") = {1}; -Physical Line("insertion") = {3}; +Line(8) = {7, 8}; +Line(9) = {7, 9}; + +Line Loop(11) = {11, -8, 32, 4}; +Line Loop(12) = {12, 2, 31, 8}; +Line Loop(21) = {-32, 9, 62, 7}; +Line Loop(22) = {-31, 5, 61, -9}; +Plane Surface(11) = {11}; +Plane Surface(12) = {12}; +Plane Surface(21) = {21}; +Plane Surface(22) = {22}; + +Physical Line("fixed") = {61, 62}; +Physical Line("loading") = {11, 12}; +Physical Line("insertion") = {31, 32}; Physical Line("sides") = {2, 5, 7, 4}; +Physical Line("middle") = {8, 9}; -Physical Surface("body") = {1, 2}; +Physical Surface("body") = {11, 12, 21, 22}; Recombine Surface "*"; Transfinite Surface "*"; diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo index 3242a10d2e9e2dbc5a86a1e41bee981edef703e4..1831c5086e40528bcbb85f155376cd3b0eac0615 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D.geo @@ -1,4 +1,4 @@ -h = 0.7; +h = 0.4; z = 1; y = 2; @@ -12,26 +12,43 @@ Point(4) = { x/2,-y/2, -z/2, h}; Point(5) = {-x/2, 0, -z/2, h}; Point(6) = { x/2, 0, -z/2, h}; -Line(1) = {1, 2}; -Line(2) = {2, 5}; -Line(3) = {5, 6}; -Line(4) = {6, 1}; +Point(7) = { 0, 0, -z/2, h}; +Point(8) = { 0, y/2, -z/2, h}; +Point(9) = { 0,-y/2, -z/2, h}; -Line(5) = {5, 3}; -Line(6) = {3, 4}; -Line(7) = {4, 6}; -Line Loop(1) = {1, 2, 3, 4}; -Line Loop(2) = {-3, 5, 6, 7}; -Plane Surface(1) = {1}; -Plane Surface(2) = {2}; +Line(11) = {1, 8}; +Line(12) = {8, 2}; +Line(2) = {2, 5}; +Line(31) = {5, 7}; +Line(32) = {7, 6}; +Line(4) = {6, 1}; + +Line(5) = {5, 3}; +Line(61) = {3, 9}; +Line(62) = {9, 4}; +Line(7) = {4, 6}; + +Line(8) = {7, 8}; +Line(9) = {7, 9}; + +Line Loop(11) = {11, -8, 32, 4}; +Line Loop(12) = {12, 2, 31, 8}; +Line Loop(21) = {-32, 9, 62, 7}; +Line Loop(22) = {-31, 5, 61, -9}; +Plane Surface(11) = {11}; +Plane Surface(12) = {12}; +Plane Surface(21) = {21}; +Plane Surface(22) = {22}; + Extrude {0, 0, z} { - Surface{1}; Surface{2}; + Surface{11}; Surface{12}; Surface{21}; Surface{22}; } -Physical Surface("fixed") = {46}; -Physical Surface("insertion") = {24}; -Physical Surface("loading") = {16}; -Physical Surface("sides") = {1, 20, 29, 28, 50, 2, 51, 42}; +Physical Surface("fixed") = {145, 123}; +Physical Surface("loading") = {93, 71}; +Physical Surface("insertion") = {101, 79}; +Physical Surface("sides") = {97, 141, 83, 127}; +Physical Surface("middle") = {75, 119}; -Physical Volume("body") = {1, 2}; +Physical Volume("body") = {1, 2, 3, 4}; diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D_structured.geo b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D_structured.geo index c54ed87057536e0dd07ae5439520908a191ef64e..a3224b5e6c98b6d0de84a91f61ec39d54be8cccf 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D_structured.geo +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/data/cohesive_strait_3D_structured.geo @@ -1,36 +1,57 @@ -h = 0.5; - -Point(1) = { 1, 1, -.5, h}; -Point(2) = {-1, 1, -.5, h}; -Point(3) = {-1,-1, -.5, h}; -Point(4) = { 1,-1, -.5, h}; - -Point(5) = {-1, 0, -.5, h}; -Point(6) = { 1, 0, -.5, h}; - -Line(1) = {1, 2}; -Line(2) = {2, 5}; -Line(3) = {5, 6}; -Line(4) = {6, 1}; - -Line(5) = {5, 3}; -Line(6) = {3, 4}; -Line(7) = {4, 6}; - -Line Loop(1) = {1, 2, 3, 4}; -Line Loop(2) = {-3, 5, 6, 7}; -Plane Surface(1) = {1}; -Plane Surface(2) = {2}; -Extrude {0, 0, 1} { - Surface{1}; Surface{2}; +h = 0.4; + +z = 1; +y = 2; +x = 2; + +Point(1) = { x/2, y/2, -z/2, h}; +Point(2) = {-x/2, y/2, -z/2, h}; +Point(3) = {-x/2,-y/2, -z/2, h}; +Point(4) = { x/2,-y/2, -z/2, h}; + +Point(5) = {-x/2, 0, -z/2, h}; +Point(6) = { x/2, 0, -z/2, h}; + +Point(7) = { 0, 0, -z/2, h}; +Point(8) = { 0, y/2, -z/2, h}; +Point(9) = { 0,-y/2, -z/2, h}; + + +Line(11) = {1, 8}; +Line(12) = {8, 2}; +Line(2) = {2, 5}; +Line(31) = {5, 7}; +Line(32) = {7, 6}; +Line(4) = {6, 1}; + +Line(5) = {5, 3}; +Line(61) = {3, 9}; +Line(62) = {9, 4}; +Line(7) = {4, 6}; + +Line(8) = {7, 8}; +Line(9) = {7, 9}; + +Line Loop(11) = {11, -8, 32, 4}; +Line Loop(12) = {12, 2, 31, 8}; +Line Loop(21) = {-32, 9, 62, 7}; +Line Loop(22) = {-31, 5, 61, -9}; +Plane Surface(11) = {11}; +Plane Surface(12) = {12}; +Plane Surface(21) = {21}; +Plane Surface(22) = {22}; + +Extrude {0, 0, z} { + Surface{11}; Surface{12}; Surface{21}; Surface{22}; } -Physical Surface("fixed") = {46}; -Physical Surface("insertion") = {24}; -Physical Surface("loading") = {16}; -Physical Surface("sides") = {1, 20, 29, 28, 50, 2, 51, 42}; +Physical Line("fixed") = {145, 123}; +Physical Line("loading") = {93, 71}; +Physical Line("insertion") = {101, 79}; +Physical Line("sides") = {97, 141, 83, 127}; +Physical Line("middle") = {75, 119}; -Physical Volume("body") = {1, 2}; +Physical Surface("body") = {1, 2, 3, 4}; Transfinite Surface "*"; Transfinite Volume "*"; diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive.cc index aa532806ccc2d0e296aee73bcd9fa87702770b1c..bf75e5c6c77e765d133db2a7a16e3bd704e9fac1 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive.cc @@ -121,3 +121,23 @@ TYPED_TEST(TestSMMCFixture, IntrinsicModeII) { // if (this->dim != 3) this->checkDissipated(G_c); } + +TYPED_TEST(TestSMMCFixture, IntrinsicImplicitModeI) { + if (this->mesh->getCommunicator().getNbProc() > 1 and this->dim == 1) { + SUCCEED(); + return; + } + getStaticParser().parse("material_1.dat"); + this->is_extrinsic = false; + this->analysis_method = _implicit_dynamic; + + this->testModeI(); + + this->checkInsertion(); + + auto & mat_co = this->model->getMaterial("insertion"); + Real G_c = mat_co.get("G_c"); + + // if (this->dim != 3) + this->checkDissipated(G_c); +} diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_fixture.hh b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_fixture.hh index 199a2cc28d9d171e1d91441592b2d0625af25fc9..6dfc991774b8e5ce2a7cdf9cce65de729c233921 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_fixture.hh +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_fixture.hh @@ -19,7 +19,7 @@ */ /* -------------------------------------------------------------------------- */ -#include "communicator.hh" +#include "non_linear_solver.hh" #include "solid_mechanics_model_cohesive.hh" #include "test_gtest_utils.hh" /* -------------------------------------------------------------------------- */ @@ -86,6 +86,13 @@ public: model->initFull(_analysis_method = this->analysis_method, _is_extrinsic = this->is_extrinsic); + if (this->analysis_method == _implicit_dynamic) { + auto & solver = model->getNonLinearSolver(); + solver.set("max_iterations", 100); + solver.set("threshold", 1e-7); + solver.set("convergence_type", SolveConvergenceCriteria::_residual); + } + auto time_step = this->model->getStableTimeStep() * 0.01; this->model->setTimeStep(time_step); @@ -109,7 +116,7 @@ public: mesh->getCommunicator().allReduce(group_size, SynchronizerOperation::_sum); -#define debug_ 0 +#define debug_ 1 #if debug_ auto size = mesh->getCommunicator().getNbProc(); @@ -137,11 +144,9 @@ public: } void setInitialCondition(const Matrix<Real> & strain) { - for (auto && data : + for (auto && [pos, disp] : zip(make_view(this->mesh->getNodes(), this->dim), make_view(this->model->getDisplacement(), this->dim))) { - const auto & pos = std::get<0>(data); - auto & disp = std::get<1>(data); disp = strain * pos; } } @@ -165,16 +170,20 @@ public: for (auto _ [[gnu::unused]] : arange(nb_steps)) { this->model->applyBC(functor, "loading"); this->model->applyBC(functor, "fixed"); +#if debug_ + this->model->dump(); + this->model->dump("cohesive elements"); +#endif if (this->is_extrinsic) { this->model->checkCohesiveStress(); } this->model->solveStep(); + } #if debug_ - this->model->dump(); - this->model->dump("cohesive elements"); + this->model->dump(); + this->model->dump("cohesive elements"); #endif - } } void checkInsertion() { @@ -201,10 +210,18 @@ public: if (dim == 1) { direction = _x; } + auto length = mesh->getUpperBounds()(direction) - mesh->getLowerBounds()(direction); nb_steps = length / speed / model->getTimeStep(); + if (this->dim > 1) { + this->model->applyBC(BC::Dirichlet::FlagOnly(_x), "middle"); + } + if (this->dim > 2) { + this->model->applyBC(BC::Dirichlet::FlagOnly(_z), "middle"); + } + SCOPED_TRACE(std::to_string(this->dim) + "D - " + std::to_string(type_1) + ":" + std::to_string(type_2)); @@ -227,6 +244,12 @@ public: strain *= sigma_c / E; this->setInitialCondition((1 - 1e-5) * strain); + +#if debug_ + this->model->dump(); + this->model->dump("cohesive elements"); +#endif + this->steps(2e-2 * strain); } @@ -251,10 +274,12 @@ public: SCOPED_TRACE(std::to_string(this->dim) + "D - " + std::to_string(type_1) + ":" + std::to_string(type_2)); - if (this->dim > 1) + if (this->dim > 1) { this->model->applyBC(BC::Dirichlet::FlagOnly(_y), "sides"); - if (this->dim > 2) + } + if (this->dim > 2) { this->model->applyBC(BC::Dirichlet::FlagOnly(_z), "sides"); + } auto & mat_co = this->model->getMaterial("insertion"); Real sigma_c = mat_co.get("sigma_c"); @@ -279,6 +304,12 @@ public: // nb_steps *= 5; this->setInitialCondition((1. - 1e-5) * strain); + +#if debug_ + this->model->dump(); + this->model->dump("cohesive elements"); +#endif + this->steps(0.005 * strain); } diff --git a/test/test_solver/test_sparse_matrix_assemble.cc b/test/test_solver/test_sparse_matrix_assemble.cc index 0ed5de244b6b734bddd30db5ef2c37b093e68eff..a9582d324d6ce55e8d0dd498747faab30439cded 100644 --- a/test/test_solver/test_sparse_matrix_assemble.cc +++ b/test/test_solver/test_sparse_matrix_assemble.cc @@ -38,35 +38,15 @@ int main(int argc, char * argv[]) { Mesh mesh(spatial_dimension); mesh.read("triangle.msh"); - UInt nb_nodes = mesh.getNbNodes(); + auto nb_nodes = mesh.getNbNodes(); - DOFManagerDefault dof_manager(mesh, "test_dof_manager"); + DOFManagerDefault dof_manager("test_dof_manager"); Array<Real> test_synchronize(nb_nodes, spatial_dimension, "Test vector"); - dof_manager.registerDOFs("test_synchronize", test_synchronize, _dst_nodal); + dof_manager.registerDOFs("test_synchronize", test_synchronize, mesh); auto & A = dof_manager.getNewMatrix("A", _symmetric); - // const akantu::Mesh::ConnectivityTypeList & type_list = - // mesh.getConnectivityTypeList(); - // akantu::Mesh::ConnectivityTypeList::const_iterator it; - - // for(it = type_list.begin(); it != type_list.end(); ++it) { - // if(mesh.getSpatialDimension(*it) != spatial_dimension) continue; - // akantu::UInt nb_element = mesh.getNbElement(*it); - // akantu::UInt nb_nodes_per_element = mesh.getNbNodesPerElement(*it); - // akantu::Element element(*it); - - // akantu::UInt m = nb_nodes_per_element * spatial_dimension; - // akantu::Array<akantu::Real> local_mat(m, m, 1, "local_mat"); - - // for(akantu::UInt e = 0; e < nb_element; ++e) { - // element.element = e; - // sparse_matrix.addToMatrix(local_mat.data(), element, - // nb_nodes_per_element); - // } - // } - A.saveMatrix("matrix.mtx"); finalize(); diff --git a/test/test_solver/test_sparse_matrix_product.cc b/test/test_solver/test_sparse_matrix_product.cc index 4c2f53fa6e2e5aacef0321382f94568f146eea8b..5c03ba24110dce81023159d0aa07721fb42d4eeb 100644 --- a/test/test_solver/test_sparse_matrix_product.cc +++ b/test/test_solver/test_sparse_matrix_product.cc @@ -46,10 +46,10 @@ int main(int argc, char * argv[]) { mesh.distribute(); Int nb_nodes = mesh.getNbNodes(); - DOFManagerDefault dof_manager(mesh, "test_dof_manager"); + DOFManagerDefault dof_manager("test_dof_manager"); Array<Real> test_synchronize(nb_nodes, nb_dof, "Test vector"); - dof_manager.registerDOFs("test_synchronize", test_synchronize, _dst_nodal); + dof_manager.registerDOFs("test_synchronize", test_synchronize, mesh); if (prank == 0) std::cout << "Creating a SparseMatrix" << std::endl; diff --git a/test/test_solver/test_sparse_matrix_profile.cc b/test/test_solver/test_sparse_matrix_profile.cc index 4d45b25ddb653d89d5d2805c34b37deeb20bbad8..4d69e35447a7087d42230b1d63c0fab5799bcd27 100644 --- a/test/test_solver/test_sparse_matrix_profile.cc +++ b/test/test_solver/test_sparse_matrix_profile.cc @@ -38,9 +38,9 @@ int main(int argc, char * argv[]) { Int nb_nodes = mesh.getNbNodes(); - DOFManagerDefault dof_manager(mesh, "test_dof_manager"); + DOFManagerDefault dof_manager("test_dof_manager"); Array<Real> test_synchronize(nb_nodes, spatial_dimension, "Test vector"); - dof_manager.registerDOFs("test_synchronize", test_synchronize, _dst_nodal); + dof_manager.registerDOFs("test_synchronize", test_synchronize, mesh); auto & A = dof_manager.getNewMatrix("A", _symmetric); diff --git a/test/test_solver/test_sparse_solver_mumps.cc b/test/test_solver/test_sparse_solver_mumps.cc index b4ef93d8e0b0b6cd2cecb6898c274060e763372a..d45b443b8ce0cfd400e1e8c9527e59056f17c3ca 100644 --- a/test/test_solver/test_sparse_solver_mumps.cc +++ b/test/test_solver/test_sparse_solver_mumps.cc @@ -66,10 +66,10 @@ int main(int argc, char * argv[]) { } Int nb_nodes = mesh.getNbNodes(); - DOFManagerDefault dof_manager(mesh, "test_dof_manager"); + DOFManagerDefault dof_manager("test_dof_manager"); Array<Real> x(nb_nodes); - dof_manager.registerDOFs("x", x, _dst_nodal); + dof_manager.registerDOFs("x", x, mesh); const auto & local_equation_number = dof_manager.getLocalEquationsNumbers("x"); diff --git a/test/test_synchronizer/test_dof_synchronizer.cc b/test/test_synchronizer/test_dof_synchronizer.cc index 896f1c1bb7d0e6a64d0f4d7ad7156c97410eb122..c30b9bb7fd1ff549decfb89964c7f2e33d9d0bbd 100644 --- a/test/test_synchronizer/test_dof_synchronizer.cc +++ b/test/test_synchronizer/test_dof_synchronizer.cc @@ -45,7 +45,7 @@ int main(int argc, char * argv[]) { mesh.read("bar.msh"); mesh.distribute(); - DOFManagerDefault dof_manager(mesh, "test_dof_manager"); + DOFManagerDefault dof_manager("test_dof_manager"); UInt nb_nodes = mesh.getNbNodes(); @@ -53,7 +53,7 @@ int main(int argc, char * argv[]) { /* test the synchronization */ /* ------------------------------------------------------------------------ */ Array<Real> test_synchronize(nb_nodes, spatial_dimension, "Test vector"); - dof_manager.registerDOFs("test_synchronize", test_synchronize, _dst_nodal); + dof_manager.registerDOFs("test_synchronize", test_synchronize, mesh); const auto & equation_number = dof_manager.getLocalEquationsNumbers("test_synchronize");