diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..6989458f --- /dev/null +++ b/.clang-format @@ -0,0 +1,47 @@ +BasedOnStyle: LLVM +--- +Language: Cpp +Standard: Cpp11 +IndentWidth: 4 +TabWidth: 4 +UseTab: Never +ColumnLimit: 100 +AlwaysBreakTemplateDeclarations: Yes +BreakConstructorInitializers : BeforeColon +ConstructorInitializerAllOnOneLineOrOnePerLine: true +FixNamespaceComments : true +IncludeBlocks: Regroup +IncludeCategories: + # aster main header + - Regex: '^"aster[cx]*.h"$' + Priority: -1 + # Headers in "" with extension and without /. + - Regex: '"([a-z0-9\._])+"' + Priority: 3 + # Headers in "" with extension and with /. + - Regex: '"([a-z0-9\./\-_])+"' + Priority: 4 + # Headers in <> without extension. + - Regex: '<([a-z0-9/\-_])+>' + Priority: 5 + # Headers in <> with extension. + - Regex: '<([a-z0-9\./\-_])+>' + Priority: 6 + +# not properly applied by clang-format-11, will be set 'true' when updated +Cpp11BracedListStyle : false +SpaceBeforeCpp11BracedList: true + +SpacesInAngles: true +SpacesInSquareBrackets: false + +SpaceAfterCStyleCast: false +SpacesInParentheses: true +SpacesInCStyleCastParentheses: false + +# for clang-format>=17 +# SpacesInParens: Custom +# SpacesInParensOptions: +# InConditionalStatements: true +# InEmptyParentheses: false +# InCStyleCasts: false diff --git a/apps/acoustic_eigs/src/acoustic_eigs.cpp b/apps/acoustic_eigs/src/acoustic_eigs.cpp index bd9afb36..f43d0016 100644 --- a/apps/acoustic_eigs/src/acoustic_eigs.cpp +++ b/apps/acoustic_eigs/src/acoustic_eigs.cpp @@ -9,14 +9,13 @@ */ #include +#include +#include #include #include #include #include -#include -#include - - +#include #include "sol/sol.hpp" #include "diskpp/common/eigen.hpp" @@ -72,7 +71,7 @@ auto acoustic_eigs_dg(Mesh& msh, size_t degree, const typename Mesh::coordinate_type eta, disk::silo_database& silo) -{ +{ std::cout << "DG eigsolver" << std::endl; auto cvf = connectivity_via_faces(msh); using T = typename Mesh::coordinate_type; @@ -83,13 +82,13 @@ acoustic_eigs_dg(Mesh& msh, size_t degree, auto cbs = disk::scalar_basis_size(degree, Mesh::dimension); auto assm = make_discontinuous_galerkin_eigenvalue_assembler(msh, cbs); - + timecounter tc; tc.tic(); for (auto& tcl : msh) { auto tbasis = disk::basis::scaled_monomial_basis(msh, tcl, degree, basis_rescaling); - + matrix_type M = integrate(msh, tcl, tbasis, tbasis); matrix_type K = integrate(msh, tcl, grad(tbasis), grad(tbasis)); @@ -98,15 +97,15 @@ acoustic_eigs_dg(Mesh& msh, size_t degree, auto fcs = faces(msh, tcl); for (auto& fc : fcs) - { + { auto n = normal(msh, tcl, fc); auto eta_l = eta / diameter(msh, fc); - + auto nv = cvf.neighbour_via(msh, tcl, fc); if (nv) { matrix_type Att = matrix_type::Zero(tbasis.size(), tbasis.size()); matrix_type Atn = matrix_type::Zero(tbasis.size(), tbasis.size()); - + auto ncl = nv.value(); auto nbasis = disk::basis::scaled_monomial_basis(msh, ncl, degree, basis_rescaling); assert(tbasis.size() == nbasis.size()); @@ -128,7 +127,7 @@ acoustic_eigs_dg(Mesh& msh, size_t degree, //Att += - integrate(msh, fc, grad(tbasis).dot(n), tbasis); //Att += - integrate(msh, fc, tbasis, grad(tbasis).dot(n)); //assm.assemble(msh, tcl, tcl, Att); - } + } } } @@ -183,7 +182,7 @@ acoustic_eigs_dg(Mesh& msh, size_t degree, auto ofs = cbs * offset(msh, cl); u.push_back(eigvecs(ofs, col)); } - + std::string vname = "eigfun_" + std::to_string(col); silo.add_variable("mesh", vname, u, disk::zonal_variable_t); } @@ -194,7 +193,7 @@ void solve_feast_dense(auto assm, disk::dynamic_matrix& eigvecs, disk::dynamic_vector& eigvals) { timecounter tc; - +#ifdef HAVE_MUMPS std::cout << "MUMPS factorization..." << std::flush; tc.tic(); disk::solvers::mumps_solver AFF_lu_mumps; @@ -218,6 +217,9 @@ void solve_feast_dense(auto assm, disk::dynamic_matrix& eigvecs, disk::solvers::feast(params, KTT, assm.BTT, eigvecs, eigvals); std::cout << "Eigensolver time: " << tc.toc() << " seconds\n"; +#else + std::cerr << "MUMPS is needed" << std::endl; +#endif } template @@ -226,6 +228,7 @@ void solve_feast_mf(auto assm, disk::dynamic_matrix& eigvecs, { timecounter tc; +#ifdef HAVE_PARDISO Eigen::PardisoLDLT< Eigen::SparseMatrix > AFF_lu(assm.AFF); auto apply_A = [&]( @@ -234,7 +237,6 @@ void solve_feast_mf(auto assm, disk::dynamic_matrix& eigvecs, Eigen::Matrix z = assm.AFT*v; return assm.ATT*v - assm.ATF*AFF_lu.solve(z); }; - std::cout << "FEAST eigensolver (matrix-free)" << std::endl; tc.tic(); disk::solvers::feast_eigensolver_params params; @@ -247,6 +249,9 @@ void solve_feast_mf(auto assm, disk::dynamic_matrix& eigvecs, disk::solvers::feast_mf(params, apply_A, assm.BTT, eigvecs, eigvals); std::cout << "Eigensolver time: " << tc.toc() << " seconds\n"; +#else + std::cerr << "Pardiso is needed" << std::endl; +#endif } @@ -256,6 +261,7 @@ void solve_bjd_mf(auto assm, disk::dynamic_matrix& eigvecs, { timecounter tc; +#ifdef HAVE_MUMPS //Eigen::PardisoLDLT< Eigen::SparseMatrix > AFF_lu(assm.AFF); disk::solvers::mumps_solver AFF_lu; AFF_lu.symmetric(true); @@ -280,6 +286,9 @@ void solve_bjd_mf(auto assm, disk::dynamic_matrix& eigvecs, disk::solvers::block_jacobi_davidson(params, apply_A, assm.BTT, eigvecs, eigvals); std::cout << "Eigensolver time: " << tc.toc() << " seconds\n"; +#else + std::cerr << "MUMPS is needed" << std::endl; +#endif } #if 0 @@ -397,7 +406,7 @@ acoustic_eigs_hho(const Mesh& msh, const config& cfg, disk::silo_database& silo) auto ofs = cbasis_type::size_of_degree(di.cell) * offset(msh, cl); u.push_back(eigvecs(ofs, col)); } - + std::string vname = "hho_eigfun_" + std::to_string(col); silo.add_variable("hmesh", vname, u, disk::zonal_variable_t); } @@ -442,7 +451,7 @@ int main(int argc, char **argv) case 'f': cfg.mesh_filename = optarg; break; - + case 'k': cfg.order = std::stoul(optarg); break; @@ -475,30 +484,37 @@ int main(int argc, char **argv) if (cfg.mesh_filename != "") { - + if (std::regex_match(cfg.mesh_filename, std::regex(".*\\.geo2s$") )) { std::cout << "Guessed mesh format: GMSH 2D simplicials" << std::endl; using mesh_type = disk::triangular_mesh; mesh_type msh; +#ifdef HAVE_GMSH disk::gmsh_geometry_loader< mesh_type > loader; loader.read_mesh(cfg.mesh_filename); loader.populate_mesh(msh); - run_eigsolver(msh, cfg); +#else + std::cerr << "GMSH is needed" << std::endl; +#endif return 0; } - + if (std::regex_match(cfg.mesh_filename, std::regex(".*\\.geo3s$") )) { std::cout << "Guessed mesh format: GMSH 3D simplicials" << std::endl; using mesh_type = disk::tetrahedral_mesh; mesh_type msh; +#ifdef HAVE_GMSH disk::gmsh_geometry_loader< mesh_type > loader; loader.read_mesh(cfg.mesh_filename); loader.populate_mesh(msh); run_eigsolver(msh, cfg); +#else + std::cerr << "GMSH is needed" << std::endl; +#endif return 0; } } @@ -515,7 +531,7 @@ int main(int argc, char **argv) for (int i = 0; i < cfg.reflevels; i++) { mesher.refine(); - + std::cout << ">>>>>>>> DIAM: " << disk::average_diameter(msh) << std::endl; run_eigsolver(msh, cfg); } @@ -533,7 +549,7 @@ int main(int argc, char **argv) for (int i = 0; i < cfg.reflevels; i++) { mesher.refine(); - + std::cout << ">>>>>>>> DIAM: " << disk::average_diameter(msh) << std::endl; run_eigsolver(msh, cfg); } @@ -551,7 +567,7 @@ int main(int argc, char **argv) for (int i = 0; i < cfg.reflevels; i++) { mesher.refine(); - + std::cout << ">>>>>>>> DIAM: " << disk::average_diameter(msh) << std::endl; run_eigsolver(msh, cfg); } @@ -570,7 +586,7 @@ int main(int argc, char **argv) for (int i = 0; i < cfg.reflevels; i++) { mesher.refine(); - + std::cout << ">>>>>>>> DIAM: " << disk::average_diameter(msh) << std::endl; run_eigsolver(msh, cfg); } @@ -589,11 +605,11 @@ int main(int argc, char **argv) msh.transform( [&](const typename mesh_type::point_type& pt) { return typename mesh_type::point_type{pt.x(), 1.1*pt.y()}; } ); - + std::cout << ">>>>>>>> DIAM: " << disk::average_diameter(msh) << std::endl; run_eigsolver(msh, cfg); } } - + return 0; } diff --git a/apps/contact/src/common.hpp b/apps/contact/src/common.hpp index 7f5263d6..8c8dde1d 100644 --- a/apps/contact/src/common.hpp +++ b/apps/contact/src/common.hpp @@ -1903,7 +1903,7 @@ class diffusion_condensed_assembler_nitsche_cells { auto fb = make_scalar_monomial_basis(msh, fc, di.face_degree()); auto dirichlet_bf = m_bnd.dirichlet_boundary_func(face_id); - Matrix mass = make_mass_matrix(msh, fc, fb, di.face_degree()); + Matrix mass = make_mass_matrix(msh, fc, fb); Matrix rhs = make_rhs(msh, fc, fb, dirichlet_bf, di.face_degree()); //ret.block(face_i*fbs, 0, fbs, 1) = mass.llt().solve(rhs); } @@ -2249,7 +2249,7 @@ class diffusion_full_assembler if (m_bnd.is_dirichlet_face( face_id)) { auto fb = disk::make_scalar_monomial_basis(msh, fc, di.face_degree()); - Matrix mass = make_mass_matrix(msh, fc, fb, di.face_degree()); + Matrix mass = make_mass_matrix(msh, fc, fb); auto velocity = m_bnd.dirichlet_boundary_func(face_id); Matrix rhs = make_rhs(msh, fc, fb, velocity, di.face_degree()); svel.block(cbs + i * fbs, 0, fbs, 1) = mass.llt().solve(rhs); @@ -2569,7 +2569,7 @@ class diffusion_mix_full_assembler if (m_bnd.is_dirichlet_face( face_id)) { auto fb = disk::make_scalar_monomial_basis(msh, fc, di.face_degree()); - Matrix mass = make_mass_matrix(msh, fc, fb, di.face_degree()); + Matrix mass = make_mass_matrix(msh, fc, fb); auto velocity = m_bnd.dirichlet_boundary_func(face_id); Matrix rhs = make_rhs(msh, fc, fb, velocity, di.face_degree()); svel.block(cbs + i * fbs, 0, fbs, 1) = mass.llt().solve(rhs); @@ -2893,7 +2893,7 @@ class contact_full_assembler if (dirichlet) { auto fb = disk::make_scalar_monomial_basis(msh, fc, di.face_degree()); - Matrix mass = make_mass_matrix(msh, fc, fb, di.face_degree()); + Matrix mass = make_mass_matrix(msh, fc, fb); auto velocity = m_bnd.dirichlet_boundary_func(face_id); Matrix rhs = make_rhs(msh, fc, fb, velocity);//, di.face_degree()); svel.block(cbs + i * fbs, 0, fbs, 1) = mass.llt().solve(rhs); @@ -3119,7 +3119,7 @@ class contact_full_assembler_new auto fb = make_scalar_monomial_basis(msh, face, di.face_degree()); auto dirichlet_fun = m_bnd.dirichlet_boundary_func(face_id); - matrix_type mass = make_mass_matrix(msh, face, fb);// di.face_degree()); + matrix_type mass = make_mass_matrix(msh, face, fb); vector_type rhs = make_rhs(msh, face, fb, dirichlet_fun);// di.face_degree()); sol.block(face_ofs, 0, fbs, 1) = mass.llt().solve(rhs); @@ -3448,7 +3448,7 @@ class contact_face_assembler_new Matrix robin = make_rhs(msh,bfc,fb,bnd.robin_boundary_func(face_id), face_degree); assert (robin.size() == num_face_dofs); - Matrix mass = make_mass_matrix(msh, bfc, fb, face_degree); + Matrix mass = make_mass_matrix(msh, bfc, fb); for (size_t i = 0; i < num_face_dofs; i++) { @@ -3518,7 +3518,7 @@ class contact_face_assembler_new auto fb = make_scalar_monomial_basis(msh, face, di.face_degree()); auto dirichlet_fun = m_bnd.dirichlet_boundary_func(face_id); - Matrix mass = make_mass_matrix(msh, face, fb, di.face_degree()); + Matrix mass = make_mass_matrix(msh, face, fb); Matrix rhs = make_rhs(msh, face, fb, dirichlet_fun, di.face_degree()); sol.block(face_ofs, 0, fb.size(), 1) = mass.llt().solve(rhs); diff --git a/apps/contact/src/diffusion_nitsche_solver.hpp b/apps/contact/src/diffusion_nitsche_solver.hpp index 9337e0ba..f90d6a86 100644 --- a/apps/contact/src/diffusion_nitsche_solver.hpp +++ b/apps/contact/src/diffusion_nitsche_solver.hpp @@ -206,7 +206,7 @@ run_hho_diffusion_nitsche_faces(const Mesh& msh, auto diff = realsol - fullsol; H1_error += diff.dot(A*diff); - matrix_type mass = make_mass_matrix(msh, cl, cb, hdi.cell_degree()); + matrix_type mass = make_mass_matrix(msh, cl, cb); vector_type u_diff = diff.block(0, 0, cbs, 1); L2_error += u_diff.dot(mass * u_diff); @@ -370,7 +370,7 @@ run_hho_diffusion_nitsche_cells_full(const Mesh& msh, auto diff = realsol - fullsol; H1_error += diff.dot(A*diff); - matrix_type mass = make_mass_matrix(msh, cl, cb, hdi.cell_degree()); + matrix_type mass = make_mass_matrix(msh, cl, cb); vector_type u_diff = diff.block(0, 0, cbs, 1); L2_error += u_diff.dot(mass * u_diff); diff --git a/apps/contact/src/signorini_newton_solver.hpp b/apps/contact/src/signorini_newton_solver.hpp index 3f90b14e..b613ebe0 100644 --- a/apps/contact/src/signorini_newton_solver.hpp +++ b/apps/contact/src/signorini_newton_solver.hpp @@ -155,7 +155,7 @@ solve_faces(const Mesh& msh, const Function& rhs_fun, const Analytical& sol_fun H1_increment += du_full.dot(A * du_full); - matrix_type mass = make_mass_matrix(msh, cl, cb);//, hdi.cell_degree()); + matrix_type mass = make_mass_matrix(msh, cl, cb); vector_type u_diff = du_full.block(0, 0, cbs, 1); L2_increment += u_diff.dot(mass * u_diff); @@ -209,7 +209,7 @@ solve_faces(const Mesh& msh, const Function& rhs_fun, const Analytical& sol_fun H1_error += diff.dot(Ah*diff); auto cb = make_scalar_monomial_basis(msh, cl, hdi.cell_degree()); - matrix_type mass = make_mass_matrix(msh, cl, cb, hdi.cell_degree()); + matrix_type mass = make_mass_matrix(msh, cl, cb); vector_type u_diff = diff.block(0, 0, cbs, 1); L2_error += u_diff.dot(mass * u_diff); @@ -415,7 +415,7 @@ solve_faces_hier(const Mesh& msh, const Function& rhs_fun, const Analytical& so H1_increment += du_full.dot(A * du_full); - matrix_type mass = make_mass_matrix(msh, cl, cb);//, hdi.cell_degree()); + matrix_type mass = make_mass_matrix(msh, cl, cb); vector_type u_diff = du_full.block(0, 0, cbs, 1); L2_increment += u_diff.dot(mass * u_diff); @@ -469,7 +469,7 @@ solve_faces_hier(const Mesh& msh, const Function& rhs_fun, const Analytical& so H1_error += diff.dot(Ah*diff); auto cb = make_scalar_monomial_basis(msh, cl, hdi.cell_degree()); - matrix_type mass = make_mass_matrix(msh, cl, cb, hdi.cell_degree()); + matrix_type mass = make_mass_matrix(msh, cl, cb); vector_type u_diff = diff.block(0, 0, cbs, 1); L2_error += u_diff.dot(mass * u_diff); @@ -637,7 +637,7 @@ solve_cells_full(const Mesh& msh, const Function& rhs_fun, const Analytical& so diff_sol.block(cell_ofs, 0, num_total_dofs ,1) = du_full; auto cb = make_scalar_monomial_basis(msh, cl, hdi.cell_degree()); - matrix_type mass = make_mass_matrix(msh, cl, cb);//, hdi.cell_degree()); + matrix_type mass = make_mass_matrix(msh, cl, cb); vector_type u_diff = du_full.block(0, 0, cbs, 1); H1_increment += du_full.dot(Ah * du_full); @@ -715,7 +715,7 @@ solve_cells_full(const Mesh& msh, const Function& rhs_fun, const Analytical& so #endif auto cb = make_scalar_monomial_basis(msh, cl, hdi.cell_degree()); - matrix_type mass = make_mass_matrix(msh, cl, cb, hdi.cell_degree()); + matrix_type mass = make_mass_matrix(msh, cl, cb); vector_type u_diff = diff.block(0, 0, cbs, 1); L2_error += u_diff.dot(mass * u_diff); @@ -903,7 +903,7 @@ solve_cells_full_hier(const Mesh& msh, const Function& rhs_fun, const Analytica diff_sol.block(cell_ofs, 0, num_total_dofs ,1) = du_full; auto cb = make_scalar_monomial_basis(msh, cl, hdi.cell_degree()); - matrix_type mass = make_mass_matrix(msh, cl, cb);//, hdi.cell_degree()); + matrix_type mass = make_mass_matrix(msh, cl, cb); vector_type u_diff = du_full.block(0, 0, cbs, 1); H1_increment += du_full.dot(Ah * du_full); @@ -958,7 +958,7 @@ solve_cells_full_hier(const Mesh& msh, const Function& rhs_fun, const Analytica H1_error += diff.dot(Ah*diff); auto cb = make_scalar_monomial_basis(msh, cl, hdi.cell_degree()); - matrix_type mass = make_mass_matrix(msh, cl, cb, hdi.cell_degree()); + matrix_type mass = make_mass_matrix(msh, cl, cb); vector_type u_diff = diff.block(0, 0, cbs, 1); L2_error += u_diff.dot(mass * u_diff); diff --git a/apps/diffusion/src/consistency.cpp b/apps/diffusion/src/consistency.cpp index 10970533..3c4307d3 100644 --- a/apps/diffusion/src/consistency.cpp +++ b/apps/diffusion/src/consistency.cpp @@ -335,9 +335,11 @@ int main(int argc, char **argv) { std::cout << "Guessed mesh format: GMSH simplicial 3D" << std::endl; disk::simplicial_mesh msh; +#ifdef HAVE_GMSH disk::gmsh_geometry_loader< disk::simplicial_mesh > loader; loader.read_mesh(mesh_filename); loader.populate_mesh(msh); +#endif msh.transform(tr); test_consistency(msh, degree, increment, variant); return 0; diff --git a/apps/diffusion/src/diffusion_hho_test.cpp b/apps/diffusion/src/diffusion_hho_test.cpp index 25da32b8..7bf164eb 100644 --- a/apps/diffusion/src/diffusion_hho_test.cpp +++ b/apps/diffusion/src/diffusion_hho_test.cpp @@ -20,27 +20,25 @@ * DOI: 10.1016/j.cam.2017.09.017 */ +#include "diskpp/common/colormanip.h" +#include "diskpp/common/timecounter.hpp" +#include "diskpp/methods/implementation_hho/methods_hho.hpp" + +#include +#include #include +#include #include -#include #include -#include -#include - -#include "colormanip.h" - -#include "config.h" - -#include "timecounter.h" +#include #define _USE_MATH_DEFINES -#include - -#include "geometry/geometry.hpp" -#include "loaders/loader.hpp" -#include "methods/hho" -#include "solvers/solver.hpp" +#include "diskpp/geometry/geometry.hpp" +#include "diskpp/loaders/loader.hpp" +#include "diskpp/methods/hho" +#include "diskpp/output/silo.hpp" +#include "diskpp/solvers/direct_solvers.hpp" /***************************************************************************/ /* RHS definition */ @@ -146,11 +144,13 @@ run_hho_diffusion_solver(const Mesh& msh, const size_t degree) { auto cb = make_scalar_monomial_basis(msh, cl, hdi.cell_degree()); auto gr = make_scalar_hho_laplacian(msh, cl, hdi); - auto stab = make_scalar_hho_stabilization(msh, cl, gr.first, hdi); - auto rhs = make_rhs(msh, cl, cb, rhs_fun); + auto stab = make_scalar_hho_stabilization( msh, cl, gr.first, hdi ); Eigen::Matrix A = gr.second + stab; - auto sc = diffusion_static_condensation_compute(msh, cl, hdi, A, rhs); - assembler.assemble(msh, cl, sc.first, sc.second, sol_fun); + auto rhst = make_rhs( msh, cl, cb, rhs_fun ); + dynamic_vector< T > rhs = dynamic_vector< T >::Zero( A.cols() ); + rhs.head( cb.size() ) = rhst; + auto [lhsC, rhsC] = disk::static_condensation( A, rhs, cb.size() ); + assembler.assemble( msh, cl, lhsC, rhsC, sol_fun ); } assembler.finalize(); @@ -160,55 +160,58 @@ run_hho_diffusion_solver(const Mesh& msh, const size_t degree) disk::dynamic_vector sol = disk::dynamic_vector::Zero(systsz); - disk::solvers::pardiso_params pparams; - pparams.report_factorization_Mflops = true; - mkl_pardiso(pparams, assembler.LHS, assembler.RHS, sol); + disk::solvers::sparse_lu( assembler.LHS, assembler.RHS, sol ); - T error = 0.0; + T errorL2 = 0.0; + T errorEnergy = 0.0; - std::ofstream ofs("sol.dat"); + std::vector< T > u; for (auto& cl : msh) { auto cb = make_scalar_monomial_basis(msh, cl, hdi.cell_degree()); auto gr = make_scalar_hho_laplacian(msh, cl, hdi); - auto stab = make_scalar_hho_stabilization(msh, cl, gr.first, hdi); - auto rhs = make_rhs(msh, cl, cb, rhs_fun); + auto stab = make_scalar_hho_stabilization( msh, cl, gr.first, hdi ); Eigen::Matrix A = gr.second + stab; + auto rhst = make_rhs( msh, cl, cb, rhs_fun ); + dynamic_vector< T > rhs = dynamic_vector< T >::Zero( A.cols() ); + rhs.head( cb.size() ) = rhst; Eigen::Matrix locsol = assembler.take_local_data(msh, cl, sol, sol_fun); - Eigen::Matrix fullsol = - diffusion_static_condensation_recover(msh, cl, hdi, A, rhs, locsol); + Eigen::Matrix< T, Eigen::Dynamic, 1 > fullsol = static_decondensation( A, rhs, locsol ); - Eigen::Matrix realsol = project_function(msh, cl, hdi, sol_fun); + Eigen::Matrix< T, Eigen::Dynamic, 1 > realsol = + project_function( msh, cl, hdi, sol_fun, 2 ); - /// Just for residual typedef Eigen::Matrix matrix_type; typedef Eigen::Matrix vector_type; - matrix_type ATT = A.block(0,0, cbs, cbs); - vector_type u_cell = fullsol.block(0,0, cbs, 1); - vector_type res = ATT * u_cell - rhs; - matrix_type mm = make_mass_matrix(msh, cl, cb, hdi.cell_degree()); - error += res.dot(mm * res); + vector_type diffT = fullsol.head( cbs ) - realsol.head( cbs ); + matrix_type mm = make_mass_matrix( msh, cl, cb ); + errorL2 += diffT.dot( mm * diffT ); - //auto diff = realsol - fullsol; - //error += diff.dot(A*diff); + auto diff = realsol - fullsol; + errorEnergy += diff.dot( A * diff ); auto bar = barycenter(msh, cl); - for (size_t i = 0; i < Mesh::dimension; i++) - ofs << bar[i] << " "; - ofs << fullsol(0) << std::endl; - + u.push_back( fullsol( 0 ) ); } - std::cout << std::sqrt(error) << std::endl; + std::stringstream ss; + ss << "diffusion_hho_test_" << degree << ".silo"; + + disk::silo_database silo; + silo.create( ss.str() ); + silo.add_mesh( msh, "mesh" ); + silo.add_variable( "mesh", "u", u, disk::zonal_variable_t ); - ofs.close(); - return std::sqrt(error); + std::cout << "L2 error: " << std::sqrt( errorL2 ) << ", A error: " << std::sqrt( errorEnergy ) + << std::endl; + + return std::sqrt( errorL2 ); } @@ -229,14 +232,6 @@ verify_convergence(const std::vector& paths, { typedef typename MeshType::coordinate_type scalar_type; - auto f = [](const point& p) -> auto { - return 2.0 * M_PI * M_PI * sin(p.x() * M_PI) * sin(p.y() * M_PI); - }; - - auto sf = [](const point& p) -> auto { - return sin(p.x() * M_PI) * sin(p.y() * M_PI); - }; - bool success = true; for (size_t i = mindeg; i <= maxdeg; i++) @@ -245,7 +240,7 @@ verify_convergence(const std::vector& paths, std::vector> errdiams; - std::cout << "Convergence rates for k = " << i << ": " << std::flush; + std::cout << "Convergence rates for k = " << i << ": " << std::endl; for (auto& tsp : paths) { @@ -270,8 +265,8 @@ verify_convergence(const std::vector& paths, bool high, low, ok; for (size_t i = 1; i < errdiams.size(); i++) { - auto d = log2(errdiams[i-1].first/errdiams[i].first); - auto e = log2(errdiams[i-1].second/errdiams[i].second); + auto d = std::log( errdiams[i - 1].first / errdiams[i].first ); + auto e = std::log( errdiams[i - 1].second / errdiams[i].second ); auto rate = e/d; ok = (std::abs(expected_rate - rate) < 0.4); /* Test passed */ @@ -280,7 +275,9 @@ verify_convergence(const std::vector& paths, if (low) std::cout << magenta; if (high) std::cout << cyan; + std::ios_base::fmtflags f( std::cout.flags() ); std::cout << std::fixed << std::setprecision(3) << rate << " "; + std::cout.flags( f ); if (low or high) { std::cout << reset; @@ -311,11 +308,16 @@ void test_triangles_specialized(test_type tt) { size_t runs = 2; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri01.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri02.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri03.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri04.mesh2d"); + char *env_mesh_base = getenv( "DISKPP_MESH_PATH" ); + std::string mesh_base = "../../../diskpp/meshes/"; + if ( env_mesh_base ) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_triangles/netgen/tri01.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri02.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri03.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri04.mesh2d" ); typedef disk::simplicial_mesh MT; typedef disk::netgen_mesh_loader LT; @@ -340,11 +342,16 @@ void test_triangles_generic(test_type tt) { size_t runs = 2; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_4.typ1"); + char *env_mesh_base = getenv( "DISKPP_MESH_PATH" ); + std::string mesh_base = "../../../diskpp/meshes/"; + if ( env_mesh_base ) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_1.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_2.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_3.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_4.typ1" ); typedef disk::generic_mesh MT; typedef disk::fvca5_mesh_loader LT; @@ -369,42 +376,17 @@ void test_hexagons_generic(test_type tt) { size_t runs = 2; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_5.typ1"); - - typedef disk::generic_mesh MT; - typedef disk::fvca5_mesh_loader LT; - - switch(tt) - { - case TEST_MEASURE_TIMES: - test_mesh_format(paths, runs, 0, 3, "hexagons_gen"); - break; - - case TEST_VERIFY_CONVERGENCE: - verify_convergence(paths, 0, 3); - break; - - default: - std::cout << "[ Unavailable Test ]" << std::endl; - return; - } -} - -void test_hextri_generic(test_type tt) -{ - size_t runs = 2; - - std::vector paths; - //paths.push_back("../hexagon_splitter/hextri1.typ1"); - paths.push_back("../hexagon_splitter/hextri2.typ1"); - paths.push_back("../hexagon_splitter/hextri3.typ1"); - paths.push_back("../hexagon_splitter/hextri4.typ1"); - paths.push_back("../hexagon_splitter/hextri5.typ1"); + char *env_mesh_base = getenv( "DISKPP_MESH_PATH" ); + std::string mesh_base = "../../../diskpp/meshes/"; + if ( env_mesh_base ) + mesh_base = env_mesh_base; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_1.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_2.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_3.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_4.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_5.typ1" ); typedef disk::generic_mesh MT; typedef disk::fvca5_mesh_loader LT; @@ -412,7 +394,7 @@ void test_hextri_generic(test_type tt) switch(tt) { case TEST_MEASURE_TIMES: - test_mesh_format(paths, runs, 0, 3, "hextri_gen"); + test_mesh_format(paths, runs, 0, 3, "hexagons_gen"); break; case TEST_VERIFY_CONVERGENCE: @@ -429,12 +411,16 @@ void test_kershaw_2d(test_type tt) { size_t runs = 2; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_5.typ1"); + char *env_mesh_base = getenv( "DISKPP_MESH_PATH" ); + std::string mesh_base = "../../../diskpp/meshes/"; + if ( env_mesh_base ) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_1.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_2.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_3.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_4.typ1" ); typedef disk::generic_mesh MT; typedef disk::fvca5_mesh_loader LT; @@ -460,12 +446,16 @@ void test_hexahedra_specialized(test_type tt) { size_t runs = 2; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-2-2-2.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-4-4-4.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-8-8-8.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-16-16-16.hex"); - //paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-32-32-32.hex"); + char *env_mesh_base = getenv( "DISKPP_MESH_PATH" ); + std::string mesh_base = "../../../diskpp/meshes/"; + if ( env_mesh_base ) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-2-2-2.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-4-4-4.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-8-8-8.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-16-16-16.hex" ); typedef disk::cartesian_mesh MT; typedef disk::cartesian_mesh_loader LT; @@ -490,12 +480,16 @@ void test_hexahedra_generic(test_type tt) { size_t runs = 2; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_2x2x2.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_4x4x4.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_8x8x8.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_16x16x16.msh"); - //paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_32x32x32.hex"); + char *env_mesh_base = getenv( "DISKPP_MESH_PATH" ); + std::string mesh_base = "../../../diskpp/meshes/"; + if ( env_mesh_base ) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_2x2x2.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_4x4x4.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_8x8x8.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_16x16x16.msh" ); typedef disk::generic_mesh MT; typedef disk::fvca6_mesh_loader LT; @@ -520,11 +514,17 @@ void test_tetrahedra_specialized(test_type tt) { size_t runs = 2; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet1.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet2.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet3.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet4.mesh"); + char *env_mesh_base = getenv( "DISKPP_MESH_PATH" ); + std::string mesh_base = "../../../diskpp/meshes/"; + if ( env_mesh_base ) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet0.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet1.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet2.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet3.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet4.mesh" ); typedef disk::simplicial_mesh MT; typedef disk::netgen_mesh_loader LT; @@ -549,11 +549,17 @@ void test_tetrahedra_generic(test_type tt) { size_t runs = 2; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.1.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.2.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.3.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.4.msh"); + char *env_mesh_base = getenv( "DISKPP_MESH_PATH" ); + std::string mesh_base = "../../../diskpp/meshes/"; + if ( env_mesh_base ) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet0.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet1.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet2.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet3.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet4.mesh" ); typedef disk::generic_mesh MT; typedef disk::fvca6_mesh_loader LT; @@ -578,11 +584,15 @@ void test_polyhedra_generic(test_type tt) { size_t runs = 2; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_10.msh"); - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_20.msh"); - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_30.msh"); - //paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_40.msh"); + char *env_mesh_base = getenv( "DISKPP_MESH_PATH" ); + std::string mesh_base = "../../../diskpp/meshes/"; + if ( env_mesh_base ) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_10.msh" ); + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_20.msh" ); + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_30.msh" ); typedef disk::generic_mesh MT; typedef disk::fvca6_mesh_loader LT; @@ -660,7 +670,5 @@ int main(int argc, char **argv) std::cout << bold << underline << "Polyhedra" << reset << std::endl; test_polyhedra_generic(tt); - std::cout << bold << underline << "Hextri generic" << reset << std::endl; - test_hextri_generic(tt); - + return 0; } diff --git a/apps/diffusion/src/stabfree_explorer.hpp b/apps/diffusion/src/stabfree_explorer.hpp index 5452e01e..3291fb5a 100644 --- a/apps/diffusion/src/stabfree_explorer.hpp +++ b/apps/diffusion/src/stabfree_explorer.hpp @@ -1,3 +1,5 @@ +#include + #include "diskpp/loaders/loader.hpp" #include "diskpp/loaders/loader_utils.hpp" #include "diskpp/mesh/meshgen.hpp" @@ -143,8 +145,8 @@ operator<<(std::ostream& os, const config& cfg) if (cfg.variant > 0) os << "variant: mixed-order high" << std::endl; - os << "multi_thread: " << std::boolalpha << cfg.multi_thread << std::endl; - + os << "multi_thread: " << std::boolalpha << cfg.multi_thread << std::endl; + return os; } @@ -164,7 +166,7 @@ adjust_stabfree_recdeg(const Mesh& msh, const typename Mesh::cell_type& cl, size_t cd = hdi.cell_degree(); size_t fd = hdi.face_degree(); bool is_mixed_high = (hdi.cell_degree() > hdi.face_degree()); - size_t n = faces(msh, cl).size(); + size_t n = faces(msh, cl).size(); size_t rpd = cd+2; /* HHO space dofs */ @@ -202,7 +204,7 @@ auto test(const Mesh& msh, const config& cfg) Eigen::Matrix Id = Eigen::Matrix::Identity(); - + auto cl = msh[0]; disk::hho_degree_info hdi(cfg.degree); @@ -329,7 +331,7 @@ minimize_step(Mesh& msh) double mym = test(msh); // Restore mpts[i] = orig; - + double dx = 0.5*(mxp - mxm)/eps; double dy = 0.5*(myp - mym)/eps; @@ -338,7 +340,7 @@ minimize_step(Mesh& msh) mpts[i] = newp; double eig = test(msh); mpts[i] = orig; - + std::cout << i << ": " << dx << " " << dy << ", eig: " << eig << ", orig eig: " << origeig << std::endl; candidates[i].value = eig; @@ -505,7 +507,7 @@ void explore(Mesh& msh, const config& cfg) using point_type = typename Mesh::point_type; auto storage = msh.backend_storage(); auto& mpts = storage->points; - + is_self_intersecting(mpts); for(size_t i = 0; i < mpts.size(); i++) { @@ -566,7 +568,7 @@ void explore(Mesh& msh, const config& cfg) std::cout << "\rVertex " << i << ": " << j+1 << "/" << N << std::flush; for (size_t k = 0; k < N; k++) { point_type ofs(eps*j, eps*k); - + mpts[i] = base+ofs; if ( is_self_intersecting(mpts) ) continue; diff --git a/apps/linear_elasticity/src/linear_elasticity_solver.hpp b/apps/linear_elasticity/src/linear_elasticity_solver.hpp index f464c192..0497c836 100644 --- a/apps/linear_elasticity/src/linear_elasticity_solver.hpp +++ b/apps/linear_elasticity/src/linear_elasticity_solver.hpp @@ -79,7 +79,7 @@ class linear_elasticity_solver typedef disk::dynamic_matrix matrix_dynamic; typedef disk::dynamic_vector vector_dynamic; - typedef disk::assembler_mechanics assembler_type; + typedef disk::vector_mechanics_hho_assembler assembler_type; size_t m_cell_degree, m_face_degree; @@ -128,7 +128,7 @@ class linear_elasticity_solver m_elas_parameters.lambda = data.lambda; m_hdi = disk::hho_degree_info(m_cell_degree, m_face_degree); - m_assembler = disk::make_mechanics_assembler(m_msh, m_hdi, m_bnd); + m_assembler = disk::vector_mechanics_hho_assembler(m_msh, m_hdi, m_bnd); m_AL.clear(); m_AL.reserve(m_msh.cells_size()); @@ -210,7 +210,8 @@ class linear_elasticity_solver tc.toc(); ai.time_statcond += tc.elapsed(); - m_assembler.assemble(m_msh, cl, m_bnd, std::get<0>(scnp), 2); + m_assembler.assemble(m_msh, cl, m_bnd, std::get<0>(scnp).first, + std::get<0>(scnp).second); } m_assembler.impose_neumann_boundary_conditions(m_msh, m_bnd); @@ -304,9 +305,7 @@ class linear_elasticity_solver { scalar_type err_dof = 0; - const size_t cbs = disk::vector_basis_size(m_hdi.cell_degree(), dimension, dimension); - const int diff_deg = m_hdi.face_degree() - m_hdi.cell_degree(); - const int di = std::max(diff_deg, 1); + const size_t cbs = disk::vector_basis_size(m_hdi.cell_degree(), dimension, dimension); size_t cell_i = 0; @@ -314,7 +313,7 @@ class linear_elasticity_solver { const auto x = m_solution_data.at(cell_i++); - const vector_dynamic true_dof = disk::project_function(m_msh, cl, m_hdi.cell_degree(), as, di); + const vector_dynamic true_dof = disk::project_function(m_msh, cl, m_hdi.cell_degree(), as, 2); auto cb = disk::make_vector_monomial_basis(m_msh, cl, m_hdi.cell_degree()); const matrix_dynamic mass = disk::make_mass_matrix(m_msh, cl, cb); @@ -341,7 +340,7 @@ class linear_elasticity_solver for (auto& cl : m_msh) { - const auto x = m_solution_data.at(cell_i++); + const auto x = m_solution_data.at(cell_i++); const auto sgr = make_vector_hho_symmetric_laplacian(m_msh, cl, m_hdi); const vector_dynamic GTu = sgr.first * x; diff --git a/apps/nitsche/src/bridge.cpp b/apps/nitsche/src/bridge.cpp index c0ac83cf..f323e687 100644 --- a/apps/nitsche/src/bridge.cpp +++ b/apps/nitsche/src/bridge.cpp @@ -8,22 +8,23 @@ * Dipartimento di Matematica */ - #include - #include - - #include "diskpp/mesh/mesh.hpp" - #include "diskpp/mesh/meshgen.hpp" - #include "diskpp/loaders/loader.hpp" - #include "diskpp/bases/bases.hpp" - #include "diskpp/methods/hho" - #include "diskpp/methods/implementation_hho/curl.hpp" - #include "diskpp/methods/hho_slapl.hpp" - #include "diskpp/methods/hho_assemblers.hpp" - #include "diskpp/solvers/direct_solvers.hpp" - #include "diskpp/common/timecounter.hpp" - #include "diskpp/output/silo.hpp" - #include "operators.hpp" - #include "asm.hpp" +#include +#include +#include + +#include "diskpp/mesh/mesh.hpp" +#include "diskpp/mesh/meshgen.hpp" +#include "diskpp/loaders/loader.hpp" +#include "diskpp/bases/bases.hpp" +#include "diskpp/methods/hho" +#include "diskpp/methods/implementation_hho/curl.hpp" +#include "diskpp/methods/hho_slapl.hpp" +#include "diskpp/methods/hho_assemblers.hpp" +#include "diskpp/solvers/direct_solvers.hpp" +#include "diskpp/common/timecounter.hpp" +#include "diskpp/output/silo.hpp" +#include "operators.hpp" +#include "asm.hpp" template @@ -43,7 +44,7 @@ set_dirichlet(const Mesh& msh, std::vector& bcs, size_t bnd) bcs[fcnum] = true; } fcnum++; - } + } } int main(int argc, char **argv) @@ -96,14 +97,14 @@ int main(int argc, char **argv) return 1; } - std::cout << "mu = " << mu << ", lambda = " << lambda << std::endl; + std::cout << "mu = " << mu << ", lambda = " << lambda << std::endl; using mesh_type = disk::simplicial_mesh; mesh_type msh; - + std::cout << "GMSH: " << std::flush; tc.tic(); - disk::gmsh_geometry_loader< mesh_type > loader; + disk::gmsh_geometry_loader< mesh_type > loader; loader.read_mesh(mesh_filename); loader.populate_mesh(msh); std::cout << tc.toc() << " seconds" << std::endl; @@ -127,7 +128,7 @@ int main(int argc, char **argv) if (mode == hho_mode::standard) { return b == bc::dirichlet; } - + return (b == bc::dirichlet) or (b == bc::neumann); }; @@ -185,7 +186,7 @@ int main(int argc, char **argv) disk::solvers::sparse_lu(assm.LHS, assm.RHS, sol); //Eigen::SparseLU> solver(assm.LHS); //disk::dynamic_vector sol = solver.solve(assm.RHS); - + /* disk::dynamic_vector sol = assm.RHS; disk::solvers::conjugated_gradient_params cgp; @@ -207,7 +208,7 @@ int main(int argc, char **argv) auto locsolF = assm.take_local_solution(msh, cl, sol); disk::dynamic_vector locsol = disk::static_decondensation(lhs, rhs, locsolF); - + u_data(cell_i, 0) = locsol(0); u_data(cell_i, 1) = locsol(1); if constexpr (DIM == 3) { @@ -223,4 +224,4 @@ int main(int argc, char **argv) silo.add_variable("mesh", "u", u_data, disk::zonal_variable_t); return 0; -} \ No newline at end of file +} \ No newline at end of file diff --git a/apps/nitsche/src/linelast.cpp b/apps/nitsche/src/linelast.cpp index 398f59bf..1b331e38 100644 --- a/apps/nitsche/src/linelast.cpp +++ b/apps/nitsche/src/linelast.cpp @@ -8,8 +8,9 @@ * Dipartimento di Matematica */ -#include #include +#include +#include #include "diskpp/mesh/mesh.hpp" #include "diskpp/mesh/meshgen.hpp" @@ -40,7 +41,7 @@ set_dirichlet(const Mesh& msh, std::vector& bcs, size_t bnd) bcs[fcnum] = true; } fcnum++; - } + } } template @@ -121,7 +122,7 @@ int main(int argc, char **argv) { } } - std::cout << "mu = " << mu << ", lambda = " << lambda << std::endl; + std::cout << "mu = " << mu << ", lambda = " << lambda << std::endl; //using mesh_type = disk::simplicial_mesh; //using mesh_type = disk::cartesian_mesh; @@ -140,12 +141,12 @@ int main(int argc, char **argv) { }; msh.transform(tr); } - + const static size_t DIM = mesh_type::dimension; auto fbs = disk::vector_basis_size(degree, DIM-1, DIM); - + std::vector bcs; set_boundary(msh, bcs, bc::neumann, 0); @@ -160,7 +161,7 @@ int main(int argc, char **argv) { if (mode == hho_mode::standard) { return b == bc::dirichlet; } - + return (b == bc::dirichlet) or (b == bc::neumann); }; @@ -243,7 +244,7 @@ int main(int argc, char **argv) { std::cout << "Solver: " << std::flush; disk::dynamic_vector sol; disk::solvers::sparse_lu(assm.LHS, assm.RHS, sol); - + /* Eigen::SparseLU> solver(assm.LHS); disk::dynamic_vector sol = solver.solve(assm.RHS); @@ -270,7 +271,7 @@ int main(int argc, char **argv) { auto locsolF = assm.take_local_solution(msh, cl, sol); disk::dynamic_vector locsol = disk::static_decondensation(lhs, rhs, locsolF); - + u_data(cell_i, 0) = locsol(0); u_data(cell_i, 1) = locsol(1); if constexpr (DIM == 3) { diff --git a/apps/nonlinear_solid_mechanics/CMakeLists.txt b/apps/nonlinear_solid_mechanics/CMakeLists.txt index d600ea18..a92c425a 100755 --- a/apps/nonlinear_solid_mechanics/CMakeLists.txt +++ b/apps/nonlinear_solid_mechanics/CMakeLists.txt @@ -26,4 +26,13 @@ add_executable(hyperelasticity_test src/hyperelasticity_test.cpp) target_link_libraries(hyperelasticity_test diskpp::diskpp) install(TARGETS hyperelasticity_test RUNTIME DESTINATION bin) +option(OPT_NSM_USE_MUMPS "Use MUMPS for nonlinear solid mechanics" OFF) +if (OPT_NSM_USE_MUMPS) + target_compile_definitions(nonlinear_solid_mechanics PUBLIC -DNSM_USE_MUMPS) + target_compile_definitions(contact_test PUBLIC -DNSM_USE_MUMPS) + target_compile_definitions(elasticity_test PUBLIC -DNSM_USE_MUMPS) + target_compile_definitions(elastodynamic_test PUBLIC -DNSM_USE_MUMPS) + target_compile_definitions(hyperelasticity_test PUBLIC -DNSM_USE_MUMPS) +endif() + install(DIRECTORY share/ DESTINATION share) diff --git a/apps/nonlinear_solid_mechanics/share/Elasticity.mfront b/apps/nonlinear_solid_mechanics/share/Elasticity.mfront new file mode 100644 index 00000000..da9f83bd --- /dev/null +++ b/apps/nonlinear_solid_mechanics/share/Elasticity.mfront @@ -0,0 +1,54 @@ +@Behaviour Elasticity; +@Author Helfer Thomas; +@Date 23/11/06; +@Description{ + A very first test + (the most simple one in fact). +} + +@ModellingHypotheses {".+"}; +@ProvidesSymmetricTangentOperator; + +// Material properties +@MaterialProperty stress young; +young.setGlossaryName("YoungModulus"); +@MaterialProperty real nu; +nu.setGlossaryName("PoissonRatio"); + +@ExternalStateVariable stress sigzz; +AxisymmetricalGeneralisedPlaneStress::sigzz.setGlossaryName("AxialStress"); + +// Lame Coefficients +@LocalVariable stress lambda,mu; + +@InitLocalVariables{ + lambda = computeLambda(young,nu); + mu = computeMu(young,nu); +} + +@PredictionOperator{ + static_cast(smt); // remove unused variable warning + computeAlteredElasticStiffness::exe(Dt,lambda,mu); +} + +@Integrator{ + sig = lambda*trace(eto+deto)*StrainStensor::Id()+2*mu*(eto+deto); + if(computeTangentOperator_){ + Dt = lambda*Stensor4::IxI()+2*mu*Stensor4::Id(); + } +} + +@Integrator{ + // here we compute the tangent operator even if we don't need too + static_cast(computeTangentOperator_); + computeAlteredElasticStiffness::exe(Dt,lambda,mu); + sig = Dt*(eto+deto); +} + +@Integrator{ + // here we compute the tangent operator even if we don't need too + static_cast(computeTangentOperator_); + computeAlteredElasticStiffness::exe(Dt,lambda,mu); + sig = Dt*(eto+deto); + sig(2)=this->sigzz+this->dsigzz; +} diff --git a/apps/nonlinear_solid_mechanics/share/IsotropicHardeningVMis.mfront b/apps/nonlinear_solid_mechanics/share/IsotropicHardeningVMis.mfront new file mode 100644 index 00000000..7be5f3d7 --- /dev/null +++ b/apps/nonlinear_solid_mechanics/share/IsotropicHardeningVMis.mfront @@ -0,0 +1,27 @@ +@DSL Implicit; + +@Behaviour IsotropicHardeningVMis; + +@Algorithm NewtonRaphson; +@Epsilon 1.e-14; +@Theta 1; + +@MaterialProperty stress young0; +young0.setGlossaryName("YoungModulus"); +@MaterialProperty real nu0; +nu0.setGlossaryName("PoissonRatio"); +@MaterialProperty stress s0; +s0.setGlossaryName("YieldStrength"); +@MaterialProperty stress H0; +H0.setEntryName("HardeningSlope"); + +@Brick StandardElastoViscoPlasticity{ + stress_potential : "Hooke" { + young_modulus : "young0", + poisson_ratio : "nu0" + }, + inelastic_flow : "Plastic" { + criterion : "Mises", + isotropic_hardening : "Linear" {H : "H0", R0 : "s0"} + } +}; diff --git a/apps/nonlinear_solid_mechanics/share/IsotropicHardeningVMisLogStrain.mfront b/apps/nonlinear_solid_mechanics/share/IsotropicHardeningVMisLogStrain.mfront new file mode 100644 index 00000000..5a5dc930 --- /dev/null +++ b/apps/nonlinear_solid_mechanics/share/IsotropicHardeningVMisLogStrain.mfront @@ -0,0 +1,31 @@ +@DSL Implicit; + +@Behaviour LogarithmicStrainPlasticity; +@Author Thomas Helfer/Jérémy Bleyer; +@Date 07 / 04 / 2020; + +@StrainMeasure Hencky; + +@Algorithm NewtonRaphson; +@Epsilon 1.e-14; +@Theta 1; + +@MaterialProperty stress young0; +young0.setGlossaryName("YoungModulus"); +@MaterialProperty real nu0; +nu0.setGlossaryName("PoissonRatio"); +@MaterialProperty stress s0; +s0.setGlossaryName("YieldStrength"); +@MaterialProperty stress H0; +H0.setEntryName("HardeningSlope"); + +@Brick StandardElastoViscoPlasticity{ + stress_potential : "Hooke" { + young_modulus : "young0", + poisson_ratio : "nu0" + }, + inelastic_flow : "Plastic" { + criterion : "Mises", + isotropic_hardening : "Linear" {H : "H0", R0 : "s0"} + } +}; diff --git a/apps/nonlinear_solid_mechanics/share/tests_data.hpp b/apps/nonlinear_solid_mechanics/share/tests_data.hpp new file mode 100644 index 00000000..76224eb7 --- /dev/null +++ b/apps/nonlinear_solid_mechanics/share/tests_data.hpp @@ -0,0 +1,771 @@ +/* + * /\ Matteo Cicuttin (C) 2016, 2017, 2018 + * /__\ matteo.cicuttin@enpc.fr + * /_\/_\ École Nationale des Ponts et Chaussées - CERMICS + * /\ /\ + * /__\ /__\ DISK++, a template library for DIscontinuous SKeletal + * /_\/_\/_\/_\ methods. + * + * This file is copyright of the following authors: + * Nicolas Pignet (C) 2019, 2024 nicolas.pignet@enpc.fr + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * If you use this code or parts of it for scientific publications, you + * are required to cite it as following: + * + * Hybrid High-Order methods for finite elastoplastic deformations + * within a logarithmic strain framework. + * M. Abbas, A. Ern, N. Pignet. + * International Journal of Numerical Methods in Engineering (2019) + * 120(3), 303-327 + * DOI: 10.1002/nme.6137 + */ + +#include "diskpp/mechanics/NewtonSolver/NonLinearSolver.hpp" + +enum STUDY { + COOK_ELAS, + COOK_HPP, + COOK_LARGE, + COOK_DYNA, + SPHERE_LARGE, + TAYLOR_ROD, + SQUARE_DYNA, + SQUARE_MATER, + WAVE_ELAS, + IMPACT_2D, +}; + +/* Bibliographie */ +/* + * [1] Di Pietro, D. and Ern. A.; A hybrid high-order locking free method for linear elasticity + * on general meshes; Comput. Methods Appl. Mech. Engrg. 203, pp1-21, (2015). + * + * [2] M. Abbas, A. Ern, N. Pignet. Hybrid High-Order methods for finite elastoplastic deformations + * within a logarithmic strain framework; International Journal of Numerical Methods in Engineering + * (2019) 120(3), 303-327. + */ + +/* + * COOK_ELAS: [1] Section 6.3 + * + */ + +template < typename T > +auto getMaterialData( const STUDY &study ) { + disk::mechanics::MaterialData< T > material_data; + + const T GPa = 1e9; + const T MPa = 1e6; + + switch ( study ) { + case STUDY::WAVE_ELAS: { + + const T E = 2.5; + const T nu = 0.25; + + material_data.setMu( E, nu ); + material_data.setLambda( E, nu ); + material_data.setRho( 1.0 ); + + break; + } + case STUDY::COOK_ELAS: { + // Cook Parameters HPP (mm, MPa, kN) + + material_data.setMu( 0.375 ); + material_data.setLambda( 7.5 * 10e6 ); + + break; + } + case STUDY::COOK_HPP: { + // Cook Parameters HPP (mm, GPa, kN) + + const T E = 70; + const T nu = 0.4999; + + material_data.setMu( E, nu ); + material_data.setLambda( E, nu ); + + material_data.setK( 0.0 ); + material_data.setH( 0.135 ); + + material_data.setSigma_y0( 0.243 ); + + material_data.addMfrontParameter( "YoungModulus", material_data.getE() ); + material_data.addMfrontParameter( "PoissonRatio", material_data.getNu() ); + material_data.addMfrontParameter( "HardeningSlope", material_data.getH() ); + material_data.addMfrontParameter( "YieldStrength", material_data.getSigma_y0() ); + break; + } + case STUDY::COOK_LARGE: { + // (mm, GPa, kN) + + const T E = 206.9; + const T nu = 0.29; + + material_data.setMu( E, nu ); + material_data.setLambda( E, nu ); + + material_data.addCurvePoint( 0.0, 0.45 ); + material_data.addCurvePoint( 0.003065, 0.463511 ); + material_data.addCurvePoint( 0.0061270000000000005, 0.476372 ); + material_data.addCurvePoint( 0.009187, 0.488615 ); + material_data.addCurvePoint( 0.012243, 0.500271 ); + material_data.addCurvePoint( 0.015297000000000002, 0.511369 ); + material_data.addCurvePoint( 0.018348, 0.521937 ); + material_data.addCurvePoint( 0.021396000000000002, 0.532001 ); + material_data.addCurvePoint( 0.024443, 0.541585 ); + material_data.addCurvePoint( 0.027487, 0.550714 ); + material_data.addCurvePoint( 0.030528999999999997, 0.55941 ); + material_data.addCurvePoint( 0.033569, 0.567695 ); + material_data.addCurvePoint( 0.036607, 0.575588 ); + material_data.addCurvePoint( 0.039643, 0.58311 ); + material_data.addCurvePoint( 0.042677999999999994, 0.590279 ); + material_data.addCurvePoint( 0.045711, 0.597111 ); + material_data.addCurvePoint( 0.048741999999999994, 0.603625 ); + material_data.addCurvePoint( 0.051772, 0.609835 ); + material_data.addCurvePoint( 0.054801, 0.615757 ); + material_data.addCurvePoint( 0.064887, 0.633592 ); + material_data.addCurvePoint( 0.074961, 0.648851 ); + material_data.addCurvePoint( 0.085024, 0.661934 ); + material_data.addCurvePoint( 0.095079, 0.673181 ); + material_data.addCurvePoint( 0.105126, 0.682878 ); + material_data.addCurvePoint( 0.115166, 0.691265 ); + material_data.addCurvePoint( 0.12520099999999998, 0.698548 ); + material_data.addCurvePoint( 0.135232, 0.704897 ); + material_data.addCurvePoint( 0.145259, 0.710459 ); + material_data.addCurvePoint( 0.155282, 0.715356 ); + material_data.addCurvePoint( 0.16530299999999998, 0.719691 ); + material_data.addCurvePoint( 0.17532199999999998, 0.723553 ); + material_data.addCurvePoint( 0.18533899999999998, 0.727014 ); + material_data.addCurvePoint( 0.195354, 0.730137 ); + material_data.addCurvePoint( 0.205368, 0.732975 ); + material_data.addCurvePoint( 0.21538, 0.735573 ); + material_data.addCurvePoint( 0.22539199999999998, 0.737967 ); + material_data.addCurvePoint( 0.235403, 0.740189 ); + material_data.addCurvePoint( 0.245413, 0.742267 ); + material_data.addCurvePoint( 0.25542200000000004, 0.744222 ); + material_data.addCurvePoint( 0.26543100000000003, 0.746074 ); + material_data.addCurvePoint( 0.27543900000000004, 0.747838 ); + material_data.addCurvePoint( 0.28544800000000004, 0.74953 ); + material_data.addCurvePoint( 0.295456, 0.751158 ); + material_data.addCurvePoint( 0.30546300000000004, 0.752735 ); + material_data.addCurvePoint( 0.401529, 0.766376 ); + material_data.addCurvePoint( 0.501593, 0.779544 ); + material_data.addCurvePoint( 0.6016549999999999, 0.79251 ); + material_data.addCurvePoint( 0.701718, 0.805438 ); + material_data.addCurvePoint( 0.8017799999999999, 0.81836 ); + material_data.addCurvePoint( 0.901843, 0.83128 ); + material_data.addCurvePoint( 1.001905, 0.8442 ); + + material_data.checkRpCurve(); + + break; + } + case STUDY::COOK_DYNA: { + // Cook Parameters (mm, GPa, kN, kg, ms) + // https://www.dynasupport.com/howtos/general/consistent-units + + const T E = 200; + const T nu = 0.3; + + material_data.setMu( E, nu ); + material_data.setLambda( E, nu ); + material_data.setRho( 7.800e-6 ); + + material_data.setK( 0.0 ); + material_data.setH( 0.13 ); + + material_data.setSigma_y0( 0.45 ); + + material_data.addMfrontParameter( "YoungModulus", material_data.getE() ); + material_data.addMfrontParameter( "PoissonRatio", material_data.getNu() ); + material_data.addMfrontParameter( "HardeningSlope", material_data.getH() ); + material_data.addMfrontParameter( "YieldStrength", material_data.getSigma_y0() ); + + break; + } + case STUDY::SQUARE_DYNA: { + // Parameters (m, Pa, N, kg, s) + // https://www.dynasupport.com/howtos/general/consistent-units + + material_data.setMu( 1 ); + material_data.setLambda( 1 ); + material_data.setRho( 1 ); + + material_data.setK( 0.0 ); + material_data.setH( 0.25 ); + + material_data.setSigma_y0( 0.20e9 ); + + material_data.addMfrontParameter( "YoungModulus", material_data.getE() ); + material_data.addMfrontParameter( "PoissonRatio", material_data.getNu() ); + material_data.addMfrontParameter( "HardeningSlope", material_data.getH() ); + material_data.addMfrontParameter( "YieldStrength", material_data.getSigma_y0() ); + + break; + } + case STUDY::SQUARE_MATER: { + // Parameters (m, Pa, N, kg, s) + // https://www.dynasupport.com/howtos/general/consistent-units + + // Steel + // const T E = 200.0e9; + // const T nu = 0.3; + // const T rho = 7800; + // const T H = 0.13e9; + // const T Sy0 = 0.45e9; + + // Gold + const T E = 80.0e9; + const T nu = 0.42; + const T rho = 18900; + const T H = 0.2e9; + const T Sy0 = 0.02e9; + + material_data.setMu( E, nu ); + material_data.setLambda( E, nu ); + material_data.setRho( rho ); + material_data.setK( 0.0 ); + material_data.setH( H ); + material_data.setSigma_y0( Sy0 ); + + material_data.addMfrontParameter( "YoungModulus", material_data.getE() ); + material_data.addMfrontParameter( "PoissonRatio", material_data.getNu() ); + material_data.addMfrontParameter( "HardeningSlope", material_data.getH() ); + material_data.addMfrontParameter( "YieldStrength", material_data.getSigma_y0() ); + + break; + } + case STUDY::SPHERE_LARGE: { + // Sphere Parameters (mm, GPa, kN) + + const T E = 28.95; + const T nu = 0.3; + + material_data.setMu( E, nu ); + material_data.setLambda( E, nu ); + material_data.setK( 0 ); + material_data.setH( 0.0 ); + material_data.setSigma_y0( 6 ); + break; + } + case STUDY::TAYLOR_ROD: { + // (mm, GPa, kN, kg, ms) + // https://www.dynasupport.com/howtos/general/consistent-units + + const T E = 120; + const T nu = 0.35; + + material_data.setMu( E, nu ); + material_data.setLambda( E, nu ); + material_data.setRho( 8.930e-6 ); + + material_data.setK( 0.0 ); + material_data.setH( 0.1 ); + + material_data.setSigma_y0( 0.4 ); + + material_data.addMfrontParameter( "YoungModulus", material_data.getE() ); + material_data.addMfrontParameter( "PoissonRatio", material_data.getNu() ); + material_data.addMfrontParameter( "HardeningSlope", material_data.getH() ); + material_data.addMfrontParameter( "YieldStrength", material_data.getSigma_y0() ); + break; + } + case STUDY::IMPACT_2D: { + // Parameters (m, Pa, N, kg, s) + // https://www.dynasupport.com/howtos/general/consistent-units + + const T E = 1.0; + const T nu = 0.0; + + material_data.setMu( E, nu ); + material_data.setLambda( E, nu ); + material_data.setRho( 1.0 ); + + break; + } + default: { + throw std::invalid_argument( "Unexpected study" ); + break; + } + } + + return material_data; +} + +template < typename T > +void addAdditionalParameters( const STUDY &study, disk::mechanics::NonLinearParameters< T > &rp ) { + + switch ( study ) { + case STUDY::COOK_ELAS: + case STUDY::COOK_HPP: + case STUDY::COOK_LARGE: + case STUDY::SPHERE_LARGE: { + break; + } + case STUDY::COOK_DYNA: + case STUDY::WAVE_ELAS: + case STUDY::SQUARE_DYNA: + case STUDY::SQUARE_MATER: + case STUDY::TAYLOR_ROD: + case STUDY::IMPACT_2D: { + std::map< std::string, T > dyna_para; + dyna_para["beta"] = 0.25; + dyna_para["gamma"] = 0.5; + dyna_para["theta"] = 1.0; + + rp.setUnsteadyParameters( dyna_para ); + rp.setLinearSolver( disk::solvers::direct_solver::pardiso ); + + break; + } + default: { + throw std::invalid_argument( "Unexpected study" ); + break; + } + } +} + +template < template < typename, size_t, typename > class Mesh, typename T, typename Storage > +auto getBoundaryConditions( const Mesh< T, 2, Storage > &msh, + const disk::mechanics::MaterialData< T > &material_data, + const STUDY &study ) { + typedef Mesh< T, 2, Storage > mesh_type; + typedef disk::static_vector< T, 2 > result_type; + + disk::vector_boundary_conditions< mesh_type > bnd( msh ); + + auto zero = [material_data]( const disk::point< T, 2 > &p, const T &time ) -> result_type { + return result_type { 0.0, 0.0 }; + }; + + /* Boundary conditions */ + switch ( study ) { + case STUDY::WAVE_ELAS: { + + auto func_space = [material_data]( const disk::point< T, 2 > &p ) -> result_type { + T ux = -sin( M_PI * p.x() ) * cos( M_PI * p.y() ); + T uy = cos( M_PI * p.x() ) * sin( M_PI * p.y() ); + + return result_type { ux, uy }; + }; + + auto displacement = [material_data, func_space]( const disk::point< T, 2 > &p, + const T &time ) -> result_type { + return time * time * func_space( p ); + }; + + bnd.addDirichletEverywhere( displacement ); + + break; + } + case STUDY::COOK_ELAS: { + auto trac = [material_data]( const disk::point< T, 2 > &p, const T &time ) -> result_type { + T L = 16.; + T F = 1.; + return time * result_type { 0.0, F / L }; + }; + + /* Encast */ + bnd.addDirichletBC( disk::CLAMPED, 1, zero ); + /* Load */ + bnd.addNeumannBC( disk::NEUMANN, 2, trac ); + break; + } + case STUDY::COOK_HPP: { + auto trac = [material_data]( const disk::point< T, 2 > &p, const T &time ) -> result_type { + T L = 16.; + T F = 1.8; + return time * result_type { 0.0, F / L }; + }; + + /* Encast */ + bnd.addDirichletBC( disk::CLAMPED, 1, zero ); + /* Load */ + bnd.addNeumannBC( disk::NEUMANN, 2, trac ); + break; + } + case STUDY::COOK_LARGE: { + auto trac = [material_data]( const disk::point< T, 2 > &p, const T &time ) -> result_type { + T L = 16.; + T F = 5.0; + return time * result_type { 0.0, F / L }; + }; + + /* Encast */ + bnd.addDirichletBC( disk::CLAMPED, 1, zero ); + /* Load */ + bnd.addNeumannBC( disk::NEUMANN, 2, trac ); + break; + } + case STUDY::COOK_DYNA: { + auto trac = [material_data]( const disk::point< T, 2 > &p, const T &time ) -> result_type { + T L = 16.; + T F = 3.6; + T tref = 0.25; + + return std::min( 1.0, time / tref ) * result_type { 0.0, F / L }; + }; + + /* Encast */ + bnd.addDirichletBC( disk::CLAMPED, 1, zero ); + /* Load */ + bnd.addNeumannBC( disk::NEUMANN, 2, trac ); + break; + } + case STUDY::SQUARE_DYNA: { + auto trac = [material_data]( const disk::point< T, 2 > &p, const T &time ) -> result_type { + T L = 1.; + T F = 0.2; + T tref = 1.0; + const auto force = result_type { 0.0, F / L }; + if ( time <= tref ) { + return ( time / tref ) * force; + } + + return force; + }; + + /* BOTTOM */ + bnd.addDirichletBC( disk::CLAMPED, 1, zero ); + /* TOP */ + bnd.addNeumannBC( disk::NEUMANN, 4, trac ); + break; + } + case STUDY::SQUARE_MATER: { + auto trac = [material_data]( const disk::point< T, 2 > &p, const T &time ) -> result_type { + T L = 1.; + T F = 5.15e8; + T tref = 5e-3; + const auto force = result_type { 0.0, F / L }; + if ( time <= tref ) { + return ( time / tref ) * force; + } + + return force; + }; + + /* BOTTOM */ + bnd.addDirichletBC( disk::CLAMPED, 1, zero ); + /* TOP */ + bnd.addNeumannBC( disk::NEUMANN, 4, trac ); + break; + } + case STUDY::IMPACT_2D: { + + auto s = []( const disk::point< T, 2 > &p ) -> T { return 0.0; }; + + /* Encast */ + bnd.addDirichletBC( disk::CLAMPED, 3, zero ); + /* Syme */ + bnd.addDirichletBC( disk::DX, 1, zero ); + /* Contact */ + auto gap = []( const disk::point< T, 2 > &pt, const disk::static_vector< T, 2 > &n ) -> T { + // compute the distance to the plane y = 0 + + if ( std::abs( n( 1 ) ) < T( 1e-12 ) ) + return T( 1e13 ); + const auto dist = std::abs( pt.y() / n( 1 ) ); + return pt.y() < T( 0 ) ? -dist : dist; + }; + + bnd.addContactBC( disk::SIGNORINI_FACE, 0, s, gap ); + break; + } + default: { + throw std::invalid_argument( "Unexpected study" ); + break; + } + } + + return bnd; +} + +template < template < typename, size_t, typename > class Mesh, typename T, typename Storage > +auto getBoundaryConditions( const Mesh< T, 3, Storage > &msh, + const disk::mechanics::MaterialData< T > &material_data, + const STUDY &study ) { + typedef Mesh< T, 3, Storage > mesh_type; + typedef disk::static_vector< T, 3 > result_type; + + disk::vector_boundary_conditions< mesh_type > bnd( msh ); + + auto zero = [material_data]( const disk::point< T, 3 > &p, const T &time ) -> result_type { + return result_type { 0.0, 0., 0. }; + }; + + /* Boundary conditions */ + switch ( study ) { + case STUDY::SPHERE_LARGE: { + + auto deplr = [material_data]( const disk::point< T, 3 > &p, const T &time ) -> result_type { + result_type er = result_type::Zero(); + + er( 0 ) = p.x(); + er( 1 ) = p.y(); + er( 2 ) = p.z(); + + er /= er.norm(); + + return time * 0.157 * er; + }; + + bnd.addDirichletBC( disk::DX, 12, zero ); + bnd.addDirichletBC( disk::DY, 24, zero ); + bnd.addDirichletBC( disk::DZ, 19, zero ); + bnd.addDirichletBC( disk::DIRICHLET, 27, deplr ); + break; + } + case STUDY::TAYLOR_ROD: { + /*RIGHT*/ + bnd.addDirichletBC( disk::DX, 11, zero ); + /*LEFT*/ + bnd.addDirichletBC( disk::DY, 10, zero ); + /*BOTTOM*/ + bnd.addDirichletBC( disk::DZ, 9, zero ); + break; + } + default: { + throw std::invalid_argument( "Unexpected study" ); + break; + } + } + + return bnd; +} + +template < template < typename, size_t, typename > class Mesh, typename T, typename Storage > +void addExternalLoad( const Mesh< T, 2, Storage > &msh, + const disk::mechanics::MaterialData< T > &material_data, const STUDY &study, + disk::mechanics::NonLinearSolver< Mesh< T, 2, Storage > > &nl ) { + typedef Mesh< T, 2, Storage > mesh_type; + typedef disk::static_vector< T, 2 > result_type; + + auto zero = [material_data]( const disk::point< T, 2 > &p, const T &time ) -> result_type { + return result_type { 0.0, 0 }; + }; + + /* External Load */ + switch ( study ) { + case STUDY::COOK_ELAS: + case STUDY::COOK_HPP: + case STUDY::COOK_LARGE: + case STUDY::COOK_DYNA: + case STUDY::SQUARE_DYNA: + case STUDY::SQUARE_MATER: + case STUDY::IMPACT_2D: { + break; + } + case STUDY::WAVE_ELAS: { + + auto func_space = [material_data]( const disk::point< T, 2 > &p ) -> result_type { + T ux = -sin( M_PI * p.x() ) * cos( M_PI * p.y() ); + T uy = cos( M_PI * p.x() ) * sin( M_PI * p.y() ); + + return result_type { ux, uy }; + }; + + auto load = [material_data, func_space]( const disk::point< T, 2 > &p, + const T &time ) -> result_type { + const T mu = material_data.getMu(); + const T rho = material_data.getRho(); + const T pi2t2 = M_PI * M_PI * time * time; + return 2.0 * ( mu * pi2t2 + rho ) * func_space( p ); + }; + + nl.addExternalLoad( load ); + + break; + } + default: { + throw std::invalid_argument( "Unexpected study" ); + break; + } + } +} + +template < template < typename, size_t, typename > class Mesh, typename T, typename Storage > +void addExternalLoad( const Mesh< T, 3, Storage > &msh, + const disk::mechanics::MaterialData< T > &material_data, const STUDY &study, + disk::mechanics::NonLinearSolver< Mesh< T, 3, Storage > > &nl ) { + typedef Mesh< T, 3, Storage > mesh_type; + typedef disk::static_vector< T, 3 > result_type; + + auto zero = [material_data]( const disk::point< T, 3 > &p, const T &time ) -> result_type { + return result_type { 0.0, 0., 0. }; + }; + + /* External Load */ + switch ( study ) { + case STUDY::SPHERE_LARGE: + case STUDY::TAYLOR_ROD: { + break; + } + default: { + throw std::invalid_argument( "Unexpected study" ); + break; + } + } +} + +template < template < typename, size_t, typename > class Mesh, typename T, typename Storage > +void addNonLinearOptions( const Mesh< T, 2, Storage > &msh, + const disk::mechanics::MaterialData< T > &material_data, + const STUDY &study, + disk::mechanics::NonLinearSolver< Mesh< T, 2, Storage > > &nl ) { + typedef Mesh< T, 2, Storage > mesh_type; + typedef disk::static_vector< T, 2 > result_type; + + auto zero = [material_data]( const disk::point< T, 2 > &p ) -> result_type { + return result_type { 0.0, 0. }; + }; + + /* Non-linear parameters */ + switch ( study ) { + case STUDY::COOK_ELAS: { + nl.addBehavior( disk::mechanics::DeformationMeasure::SMALL_DEF, + disk::mechanics::LawType::ELASTIC ); + + nl.addPointPlot( { 47.999, 52 }, "pointA.csv" ); + + break; + } + case STUDY::COOK_HPP: { + nl.addBehavior( disk::mechanics::DeformationMeasure::SMALL_DEF, + disk::mechanics::LawType::LINEAR_HARDENING ); + + nl.addPointPlot( { 47.999, 59.999 }, "pointA.csv" ); + + break; + } + case STUDY::COOK_LARGE: { + nl.addBehavior( disk::mechanics::DeformationMeasure::LOGARITHMIC_DEF, + disk::mechanics::LawType::NONLINEAR_HARDENING ); + + nl.addPointPlot( { 47.999, 59.999 }, "pointA.csv" ); + break; + } + case STUDY::COOK_DYNA: { +#ifdef HAVE_MGIS + /* To compile: mfront --obuild --interface=generic LogarithmicStrainPlasticity.mfront */ + // To use a law developped with Mfront + const auto hypo = mgis::behaviour::Hypothesis::PLANESTRAIN; + const std::string filename = "src/libBehaviour.so"; + nl.addBehavior( filename, "LogarithmicStrainPlasticity", hypo ); +#else + nl.addBehavior( disk::mechanics::DeformationMeasure::LOGARITHMIC_DEF, + disk::mechanics::LawType::LINEAR_HARDENING ); +#endif + + nl.addPointPlot( { 47.999, 59.999 }, "pointA.csv" ); + break; + } + case STUDY::SQUARE_DYNA: + case STUDY::SQUARE_MATER: { +#ifdef HAVE_MGIS + /* To compile: mfront --obuild --interface=generic LogarithmicStrainPlasticity.mfront */ + // To use a law developped with Mfront + const auto hypo = mgis::behaviour::Hypothesis::PLANESTRAIN; + const std::string filename = "src/libBehaviour.so"; + nl.addBehavior( filename, "LogarithmicStrainPlasticity", hypo ); +#else + nl.addBehavior( disk::mechanics::DeformationMeasure::LOGARITHMIC_DEF, + disk::mechanics::LawType::LINEAR_HARDENING ); +#endif + + nl.addPointPlot( { 0.999, 0.999 }, "pointA.csv" ); + break; + } + case STUDY::WAVE_ELAS: { + nl.addBehavior( disk::mechanics::DeformationMeasure::SMALL_DEF, + disk::mechanics::LawType::ELASTIC ); + + break; + } + case STUDY::IMPACT_2D: { + nl.addBehavior( disk::mechanics::DeformationMeasure::SMALL_DEF, + disk::mechanics::LawType::ELASTIC ); + + auto u0 = []( const disk::point< T, 2 > &p ) -> result_type { + T y = p.y(); + T x = p.x(); + + return result_type { 0.0, 0.5 * ( 1. - y ) }; + }; + + nl.initial_guess( u0 ); + nl.addPointPlot( { 0.0025, 0.0 }, "pointA.csv" ); + + break; + } + default: { + throw std::invalid_argument( "Unexpected study" ); + break; + } + } + + // Add after behavior + nl.addMaterialData( material_data ); +} + +template < template < typename, size_t, typename > class Mesh, typename T, typename Storage > +void addNonLinearOptions( const Mesh< T, 3, Storage > &msh, + const disk::mechanics::MaterialData< T > &material_data, + const STUDY &study, + disk::mechanics::NonLinearSolver< Mesh< T, 3, Storage > > &nl ) { + typedef Mesh< T, 3, Storage > mesh_type; + typedef disk::static_vector< T, 3 > result_type; + + auto zero = [material_data]( const disk::point< T, 3 > &p ) -> result_type { + return result_type { 0.0, 0., 0. }; + }; + + /* Non-linear parameters */ + switch ( study ) { + case STUDY::SPHERE_LARGE: { +#ifdef HAVE_MGIS + // To use a law developped with Mfront + const auto hypo = mgis::behaviour::Hypothesis::TRIDIMENSIONAL; + const std::string filename = "src/libBehaviour.so"; + nl.addBehavior( filename, "LogarithmicStrainPlasticity", hypo ); +#else + // To use a native law from DiSk++ + nl.addBehavior( disk::mechanics::DeformationMeasure::LOGARITHMIC_DEF, + disk::mechanics::LawType::LINEAR_HARDENING ); +#endif + break; + } + case STUDY::TAYLOR_ROD: { +#ifdef HAVE_MGIS + /* To compile: mfront --obuild --interface=generic LogarithmicStrainPlasticity.mfront */ + // To use a law developped with Mfront + const auto hypo = mgis::behaviour::Hypothesis::TRIDIMENSIONAL; + const std::string filename = "src/libBehaviour.so"; + nl.addBehavior( filename, "LogarithmicStrainPlasticity", hypo ); +#else + // To use a native law from DiSk++ + nl.addBehavior( disk::mechanics::DeformationMeasure::LOGARITHMIC_DEF, + disk::mechanics::LawType::LINEAR_HARDENING ); +#endif + nl.initial_field( disk::mechanics::FieldName::VITE_CELLS, + []( const disk::point< T, 3 > &p ) -> auto { + return result_type { 0.0, 0.0, -227.0 }; + } ); + nl.addPointPlot( { -0.00001, 3.19999, 0. }, "pointA.csv" ); + + break; + } + default: { + throw std::invalid_argument( "Unexpected study" ); + break; + } + } + + // Add after behavior + nl.addMaterialData( material_data ); +} diff --git a/apps/nonlinear_solid_mechanics/share/PFS.dat b/apps/nonlinear_solid_mechanics/share/userParam.dat similarity index 74% rename from apps/nonlinear_solid_mechanics/share/PFS.dat rename to apps/nonlinear_solid_mechanics/share/userParam.dat index fe879de8..0ce85900 100755 --- a/apps/nonlinear_solid_mechanics/share/PFS.dat +++ b/apps/nonlinear_solid_mechanics/share/userParam.dat @@ -6,28 +6,32 @@ CellDegree GradDegree 1 TimeStep -1 -1.0 1 +2 +0.5 1 +1.0 10 FinalTime 1.0 Sublevel -4 +6 TimeSave -0 -Stabilization -true +2 +0.5 1.0 +NLSolver +NEWTON +LineSearch +SECANT StabType -HH0 +HHO AdaptativeStabilization false Beta -100 +2000 Verbose true Precomputation true IterMax -10 +15 Epsilon 1.0E-6 Theta @@ -39,5 +43,7 @@ NO Threshold 100 Dynamic -False +STATIC +CFL +0.9 EndParameters diff --git a/apps/nonlinear_solid_mechanics/src/contact_test.cpp b/apps/nonlinear_solid_mechanics/src/contact_test.cpp index 88792b2d..03518beb 100644 --- a/apps/nonlinear_solid_mechanics/src/contact_test.cpp +++ b/apps/nonlinear_solid_mechanics/src/contact_test.cpp @@ -24,40 +24,36 @@ * DOI: 10.1002/nme.6137 */ +#include "diskpp/boundary_conditions/boundary_conditions.hpp" +#include "diskpp/common/colormanip.h" +#include "diskpp/common/timecounter.hpp" +#include "diskpp/loaders/loader.hpp" +#include "diskpp/mechanics/NewtonSolver/NonLinearSolver.hpp" +#include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" + #include #include #include #include -#include -#include "diskpp/common/colormanip.h" - -#include "diskpp/boundary_conditions/boundary_conditions.hpp" -#include "diskpp/common/timecounter.hpp" -#include "diskpp/loaders/loader.hpp" -#include "diskpp/mechanics/NewtonSolver/NewtonSolver.hpp" -#include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" +#include -struct error_type -{ - int degree; - int nb_dof; +struct error_type { + int degree; + int nb_dof; double h; double error_L2; double error_H1; }; -struct run_params -{ - int degree; - int l; +struct run_params { + int degree; + int l; bool verbose; bool cell_based; }; -void -usage() -{ +void usage() { std::cout << "Usage: %s " << std::endl; std::cout << " -2: test 2D mesh (default)" << std::endl; std::cout << " -3: test 3D mesh" << std::endl; @@ -69,17 +65,14 @@ usage() std::cout << " -t: test robustness" << std::endl; } -template -void -renumber_boundaries_2d(Mesh& msh) -{ - using T = typename Mesh::coordinate_type; +template < typename Mesh > +void renumber_boundaries_2d( Mesh &msh ) { + using T = typename Mesh::coordinate_type; auto storage = msh.backend_storage(); - auto is_close_to = [](const T val, const T ref) -> bool - { + auto is_close_to = []( const T val, const T ref ) -> bool { T eps = 1E-7; - return std::abs(ref - val) < eps; + return std::abs( ref - val ) < eps; }; /* ----------------- @@ -92,170 +85,149 @@ renumber_boundaries_2d(Mesh& msh) * 1 * */ - for (size_t face_i = 0; face_i < msh.faces_size(); face_i++) - { - auto fc = *std::next(msh.faces_begin(), face_i); - if (storage->boundary_info.at(face_i).is_boundary()) - { - const auto bar = barycenter(msh, fc); - if (is_close_to(bar.y(), T(0))) - { - storage->boundary_info.at(face_i).id(1); - } - else if (is_close_to(bar.x(), T(1))) - { - storage->boundary_info.at(face_i).id(2); - } - else if (is_close_to(bar.y(), T(1))) - { - storage->boundary_info.at(face_i).id(3); - } - else if (is_close_to(bar.x(), T(0))) - { - storage->boundary_info.at(face_i).id(4); - } - else - { - throw std::invalid_argument("dont find the boundaries"); + for ( size_t face_i = 0; face_i < msh.faces_size(); face_i++ ) { + auto fc = *std::next( msh.faces_begin(), face_i ); + if ( storage->boundary_info.at( face_i ).is_boundary() ) { + const auto bar = barycenter( msh, fc ); + if ( is_close_to( bar.y(), T( 0 ) ) ) { + storage->boundary_info.at( face_i ).id( 1 ); + } else if ( is_close_to( bar.x(), T( 1 ) ) ) { + storage->boundary_info.at( face_i ).id( 2 ); + } else if ( is_close_to( bar.y(), T( 1 ) ) ) { + storage->boundary_info.at( face_i ).id( 3 ); + } else if ( is_close_to( bar.x(), T( 0 ) ) ) { + storage->boundary_info.at( face_i ).id( 4 ); + } else { + throw std::invalid_argument( "dont find the boundaries" ); } } } } -template -void -renumber_boundaries_3d(Mesh& msh) -{ - using T = typename Mesh::coordinate_type; +template < typename Mesh > +void renumber_boundaries_3d( Mesh &msh ) { + using T = typename Mesh::coordinate_type; auto storage = msh.backend_storage(); - auto is_close_to = [](const T val, const T ref) -> bool - { + auto is_close_to = []( const T val, const T ref ) -> bool { T eps = 1E-7; - return std::abs(ref - val) < eps; + return std::abs( ref - val ) < eps; }; - for (size_t face_i = 0; face_i < msh.faces_size(); face_i++) - { - auto fc = *std::next(msh.faces_begin(), face_i); - if (storage->boundary_info.at(face_i).is_boundary()) - { - const auto bar = barycenter(msh, fc); - if (is_close_to(bar.z(), T(0))) - { - storage->boundary_info.at(face_i).id(1); - } - else if (is_close_to(bar.z(), T(1))) - { - storage->boundary_info.at(face_i).id(2); - } - else if (is_close_to(bar.x(), T(0))) - { - storage->boundary_info.at(face_i).id(2); - } - else if (is_close_to(bar.x(), T(1))) - { - storage->boundary_info.at(face_i).id(2); - } - else if (is_close_to(bar.y(), T(0))) - { - storage->boundary_info.at(face_i).id(2); - } - else if (is_close_to(bar.y(), T(1))) - { - storage->boundary_info.at(face_i).id(2); - } - else - { - throw std::invalid_argument("dont find the boundaries"); + for ( size_t face_i = 0; face_i < msh.faces_size(); face_i++ ) { + auto fc = *std::next( msh.faces_begin(), face_i ); + if ( storage->boundary_info.at( face_i ).is_boundary() ) { + const auto bar = barycenter( msh, fc ); + if ( is_close_to( bar.z(), T( 0 ) ) ) { + storage->boundary_info.at( face_i ).id( 1 ); + } else if ( is_close_to( bar.z(), T( 1 ) ) ) { + storage->boundary_info.at( face_i ).id( 2 ); + } else if ( is_close_to( bar.x(), T( 0 ) ) ) { + storage->boundary_info.at( face_i ).id( 2 ); + } else if ( is_close_to( bar.x(), T( 1 ) ) ) { + storage->boundary_info.at( face_i ).id( 2 ); + } else if ( is_close_to( bar.y(), T( 0 ) ) ) { + storage->boundary_info.at( face_i ).id( 2 ); + } else if ( is_close_to( bar.y(), T( 1 ) ) ) { + storage->boundary_info.at( face_i ).id( 2 ); + } else { + throw std::invalid_argument( "dont find the boundaries" ); } } } } -template class Mesh, typename T, typename Storage> -error_type -run_tresca_solver(Mesh& msh, - const NewtonSolverParameter& rp, - const disk::MaterialData& material_data) -{ - typedef Mesh mesh_type; - typedef disk::static_vector result_type; - typedef disk::static_matrix grad_type; - typedef disk::vector_boundary_conditions Bnd_type; +template < template < typename, size_t, typename > class Mesh, typename T, typename Storage > +error_type run_tresca_solver( Mesh< T, 2, Storage > &msh, + const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { + typedef Mesh< T, 2, Storage > mesh_type; + typedef disk::static_vector< T, 2 > result_type; + typedef disk::static_matrix< T, 2, 2 > grad_type; + typedef disk::vector_boundary_conditions< mesh_type > Bnd_type; timecounter tc; tc.tic(); - renumber_boundaries_2d(msh); + renumber_boundaries_2d( msh ); - auto load = [material_data](const disk::point& p, const T& time) -> result_type - { - T y = p.y(); - T x = p.x(); - T exy = std::exp(x * y); - T mu = material_data.getMu(); + auto load = [material_data]( const disk::point< T, 2 > &p, const T &time ) -> result_type { + T y = p.y(); + T x = p.x(); + T exy = std::exp( x * y ); + T mu = material_data.getMu(); T lambda = material_data.getLambda(); - T coeff = 0.5 * lambda * y * y - x * x * (0.5 * lambda + 1); + T coeff = 0.5 * lambda * y * y - x * x * ( 0.5 * lambda + 1 ); - T fx = -mu * (lambda * y + x * coeff) + y * (lambda + mu * (lambda + 2)) * (x * y + 2); - T fy = -lambda * x * (mu - 1) * (x * y + 2) + mu * (2 * x * (0.5 * lambda + 1) - y * coeff); + T fx = + -mu * ( lambda * y + x * coeff ) + y * ( lambda + mu * ( lambda + 2 ) ) * ( x * y + 2 ); + T fy = -lambda * x * ( mu - 1 ) * ( x * y + 2 ) + + mu * ( 2 * x * ( 0.5 * lambda + 1 ) - y * coeff ); - return -time * result_type{fx, fy} * exy / (3.0 * (1.0 + material_data.getLambda())); + return -time * result_type { fx, fy } * exy / ( 3.0 * ( 1.0 + material_data.getLambda() ) ); }; - auto solution = [material_data](const disk::point& p) -> result_type - { - T y = p.y(); - T x = p.x(); - T exy = std::exp(x * y); - T coeff = 1.0 / (1.0 + material_data.getLambda()); + auto solution = [material_data]( const disk::point< T, 2 > &p, const T time ) -> result_type { + T y = p.y(); + T x = p.x(); + T exy = std::exp( x * y ); + T coeff = 1.0 / ( 1.0 + material_data.getLambda() ); - return result_type{x * exy * (1.0 + coeff), y * exy * (-1.0 + coeff)} / 6.0; + return time * result_type { x * exy * ( 1.0 + coeff ), y * exy * ( -1.0 + coeff ) } / 6.0; }; - auto s = [rp, material_data](const disk::point& p) -> T - { - T y = p.y(); - T x = p.x(); - T mu = material_data.getMu(); + auto sol = [solution]( const disk::point< T, 2 > &p ) -> auto { return solution( p, 1.0 ); }; + + auto s = [rp, material_data]( const disk::point< T, 2 > &p ) -> T { + T y = p.y(); + T x = p.x(); + T mu = material_data.getMu(); T lambda = material_data.getLambda(); - return mu * x * x * (0.5 * lambda + 1.0) / (3 * lambda + 3.0); + return mu * x * x * ( 0.5 * lambda + 1.0 ) / ( 3 * lambda + 3.0 ); }; - Bnd_type bnd(msh); - bnd.addContactBC(disk::SIGNORINI_FACE, 1, s); - // bnd.addDirichletBC(disk::DIRICHLET, 1, solution); - bnd.addDirichletBC(disk::DIRICHLET, 2, solution); - bnd.addDirichletBC(disk::DIRICHLET, 3, solution); - bnd.addDirichletBC(disk::DIRICHLET, 4, solution); + // compute the distance to the plane y = 0 + auto gap = []( const disk::point< T, 2 > &pt, const disk::static_vector< T, 2 > &n ) -> T { + // compute the distance to the plane y = 0 - disk::mechanics::NewtonSolver nl(msh, bnd, rp); + if ( std::abs( n( 1 ) ) < T( 1e-12 ) ) + return T( 1e13 ); + const auto dist = std::abs( pt.y() / n( 1 ) ); + return pt.y() < T( 0 ) ? -dist : dist; + }; - nl.addBehavior(disk::DeformationMeasure::SMALL_DEF, disk::LawType::ELASTIC); - nl.addMaterialData(material_data); + Bnd_type bnd( msh ); + bnd.addContactBC( disk::SIGNORINI_FACE, 1, s, gap ); + // bnd.addDirichletBC(disk::DIRICHLET, 1, solution); + bnd.addDirichletBC( disk::DIRICHLET, 2, solution ); + bnd.addDirichletBC( disk::DIRICHLET, 3, solution ); + bnd.addDirichletBC( disk::DIRICHLET, 4, solution ); + + disk::mechanics::NonLinearSolver< mesh_type > nl( msh, bnd, rp ); - nl.initial_guess(solution); + nl.addBehavior( disk::mechanics::DeformationMeasure::SMALL_DEF, + disk::mechanics::LawType::ELASTIC ); + nl.addMaterialData( material_data ); + nl.addExternalLoad( load ); + nl.initial_guess( sol ); - if (nl.verbose()) - { + if ( nl.verbose() ) { std::cout << "Solving the problem ..." << '\n'; } - SolverInfo solve_info = nl.compute(load); + disk::mechanics::SolverInfo solve_info = nl.compute(); - if (nl.verbose()) - { + if ( nl.verbose() ) { solve_info.printInfo(); } error_type error; - error.h = average_diameter(msh); - error.degree = rp.m_face_degree; - error.nb_dof = nl.numberOfDofs(); - error.error_L2 = nl.compute_l2_displacement_error(solution); - error.error_H1 = nl.compute_H1_error(solution); + error.h = average_diameter( msh ); + error.degree = rp.m_face_degree; + error.nb_dof = nl.numberOfDofs(); + error.error_L2 = nl.compute_l2_displacement_error( sol ); + error.error_H1 = nl.compute_H1_error( sol ); // nl.compute_stress_GP("stress2D_GP_test.msh"); // nl.compute_continuous_displacement("depl2D_cont_test.msh"); @@ -263,101 +235,122 @@ run_tresca_solver(Mesh& msh, return error; } -template class Mesh, typename T, typename Storage> -error_type -run_tresca_solver(const Mesh& msh, - const NewtonSolverParameter& rp, - const disk::MaterialData& material_data) -{ - typedef Mesh mesh_type; - typedef disk::static_vector result_type; - typedef disk::static_matrix grad_type; - typedef disk::vector_boundary_conditions Bnd_type; +template < template < typename, size_t, typename > class Mesh, typename T, typename Storage > +error_type run_tresca_solver( const Mesh< T, 3, Storage > &msh, + const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { + typedef Mesh< T, 3, Storage > mesh_type; + typedef disk::static_vector< T, 3 > result_type; + typedef disk::static_matrix< T, 3, 3 > grad_type; + typedef disk::vector_boundary_conditions< mesh_type > Bnd_type; timecounter tc; tc.tic(); - renumber_boundaries_3d(msh); + renumber_boundaries_3d( msh ); - auto load = [material_data](const disk::point& p, const T& time) -> result_type - { - T z = p.z(); - T x = p.x(); - T exz = std::exp(x * z); - T mu = material_data.getMu(); + auto load = [material_data]( const disk::point< T, 3 > &p, const T &time ) -> result_type { + T z = p.z(); + T x = p.x(); + T exz = std::exp( x * z ); + T mu = material_data.getMu(); T lambda = material_data.getLambda(); - T coeff = 0.5 * lambda * z * z - x * x * (0.5 * lambda + 1); + T coeff = 0.5 * lambda * z * z - x * x * ( 0.5 * lambda + 1 ); - T fx = -mu * (lambda * z + x * coeff) + z * (lambda + mu * (lambda + 2)) * (x * z + 2); - T fz = -lambda * x * (mu - 1) * (x * z + 2) + mu * (2 * x * (0.5 * lambda + 1) - z * coeff); + T fx = + -mu * ( lambda * z + x * coeff ) + z * ( lambda + mu * ( lambda + 2 ) ) * ( x * z + 2 ); + T fz = -lambda * x * ( mu - 1 ) * ( x * z + 2 ) + + mu * ( 2 * x * ( 0.5 * lambda + 1 ) - z * coeff ); - return -time * result_type{fx, 0.0, fz} * exz / (3.0 * (1.0 + material_data.getLambda())); + return -time * result_type { fx, 0.0, fz } * exz / + ( 3.0 * ( 1.0 + material_data.getLambda() ) ); }; - auto solution = [material_data](const disk::point& p) -> result_type - { - T z = p.z(); - T x = p.x(); - T exz = std::exp(x * z); - T coeff = 1.0 / (1.0 + material_data.getLambda()); + auto solution = [material_data]( const disk::point< T, 3 > &p, const T &time ) -> result_type { + T z = p.z(); + T x = p.x(); + T exz = std::exp( x * z ); + T coeff = 1.0 / ( 1.0 + material_data.getLambda() ); - return result_type{x * exz * (1.0 + coeff), 0.0, z * exz * (-1.0 + coeff)} / 6.0; + return time * result_type { x * exz * ( 1.0 + coeff ), 0.0, z * exz * ( -1.0 + coeff ) } / + 6.0; }; - auto s = [rp, material_data](const disk::point& p) -> T - { - T x = p.x(); - T mu = material_data.getMu(); + auto sol = [solution]( const disk::point< T, 3 > &p ) -> auto { return solution( p, 1.0 ); }; + + auto s = [rp, material_data]( const disk::point< T, 3 > &p ) -> T { + T x = p.x(); + T mu = material_data.getMu(); T lambda = material_data.getLambda(); - return mu * x * x * (0.5 * lambda + 1.0) / (3 * lambda + 3.0); + return mu * x * x * ( 0.5 * lambda + 1.0 ) / ( 3 * lambda + 3.0 ); }; - Bnd_type bnd(msh); - bnd.addContactBC(disk::SIGNORINI_FACE, 1, s); - bnd.addDirichletBC(disk::DIRICHLET, 2, solution); + auto gap = []( const disk::point< T, 3 > &pt, const disk::static_vector< T, 3 > &n ) -> T { + // distance to the plane z = 0 + + // the normal is orthogonal to the plane z = 0 + if ( std::abs( n( 2 ) ) < T( 1E-12 ) ) + return 10E12; - disk::mechanics::NewtonSolver nl(msh, bnd, rp); + const T dist = std::abs( pt.z() / n( 2 ) ); + + if ( pt.z() < T( 0 ) ) + return -dist; + + return dist; + }; - nl.addBehavior(disk::DeformationMeasure::SMALL_DEF, disk::LawType::ELASTIC); - nl.addMaterialData(material_data); + Bnd_type bnd( msh ); + bnd.addContactBC( disk::SIGNORINI_FACE, 1, s, gap ); + bnd.addDirichletBC( disk::DIRICHLET, 2, solution ); - nl.initial_guess(solution); + disk::mechanics::NonLinearSolver< mesh_type > nl( msh, bnd, rp ); - SolverInfo solve_info = nl.compute(load); + nl.addBehavior( disk::mechanics::DeformationMeasure::SMALL_DEF, + disk::mechanics::LawType::ELASTIC ); + nl.addMaterialData( material_data ); + nl.addExternalLoad( load ); + nl.initial_guess( sol ); - if (nl.verbose()) - { + disk::mechanics::SolverInfo solve_info = nl.compute(); + + if ( nl.verbose() ) { solve_info.printInfo(); } error_type error; - error.h = average_diameter(msh); - error.degree = rp.m_face_degree; - error.nb_dof = nl.numberOfDofs(); - error.error_L2 = nl.compute_l2_displacement_error(solution); - error.error_H1 = nl.compute_H1_error(solution); + error.h = average_diameter( msh ); + error.degree = rp.m_face_degree; + error.nb_dof = nl.numberOfDofs(); + error.error_L2 = nl.compute_l2_displacement_error( sol ); + error.error_H1 = nl.compute_H1_error( sol ); return error; } -void -printResults(const std::vector& error) -{ - if (error.size() > 0) - { - std::ios::fmtflags f(std::cout.flags()); - std::cout.precision(4); - std::cout.setf(std::iostream::scientific, std::iostream::floatfield); +void printResults( const std::vector< error_type > &error ) { + if ( error.size() > 0 ) { + std::ios::fmtflags f( std::cout.flags() ); + std::cout.precision( 4 ); + std::cout.setf( std::iostream::scientific, std::iostream::floatfield ); std::cout << "Convergence test for k = " << error[0].degree << std::endl; - std::cout << "-----------------------------------------------------------------------------------" << std::endl; - std::cout << "| Size mesh | Displacement | Convergence | Displacem | Convergence | Total |" << std::endl; - std::cout << "| h | L2 error | rate | H1 error | rate | faces DOF |" << std::endl; - std::cout << "-----------------------------------------------------------------------------------" << std::endl; - - std::string s_dof = " " + std::to_string(error[0].nb_dof) + " "; - s_dof.resize(10); + std::cout + << "-----------------------------------------------------------------------------------" + << std::endl; + std::cout + << "| Size mesh | Displacement | Convergence | Displacem | Convergence | Total |" + << std::endl; + std::cout + << "| h | L2 error | rate | H1 error | rate | faces DOF |" + << std::endl; + std::cout + << "-----------------------------------------------------------------------------------" + << std::endl; + + std::string s_dof = " " + std::to_string( error[0].nb_dof ) + " "; + s_dof.resize( 10 ); std::cout << "| " << error[0].h << " | " << error[0].error_L2 << " | " << " - " @@ -365,45 +358,50 @@ printResults(const std::vector& error) << " - " << " | " << s_dof << " |" << std::endl; - for (int i = 1; i < error.size(); i++) - { - s_dof = " " + std::to_string(error[i].nb_dof) + " "; - s_dof.resize(10); - double rate_depl = - (log10(error[i - 1].error_L2) - log10(error[i].error_L2)) / (log10(error[i - 1].h) - log10(error[i].h)); - double rate_stress = - (log10(error[i - 1].error_H1) - log10(error[i].error_H1)) / (log10(error[i - 1].h) - log10(error[i].h)); - - std::cout << "| " << error[i].h << " | " << error[i].error_L2 << " | " << rate_depl << " | " - << error[i].error_H1 << " | " << rate_stress << " | " << s_dof << " |" << std::endl; + for ( int i = 1; i < error.size(); i++ ) { + s_dof = " " + std::to_string( error[i].nb_dof ) + " "; + s_dof.resize( 10 ); + double rate_depl = ( log10( error[i - 1].error_L2 ) - log10( error[i].error_L2 ) ) / + ( log10( error[i - 1].h ) - log10( error[i].h ) ); + double rate_stress = ( log10( error[i - 1].error_H1 ) - log10( error[i].error_H1 ) ) / + ( log10( error[i - 1].h ) - log10( error[i].h ) ); + + std::cout << "| " << error[i].h << " | " << error[i].error_L2 << " | " << rate_depl + << " | " << error[i].error_H1 << " | " << rate_stress << " | " << s_dof + << " |" << std::endl; } - std::cout << "-----------------------------------------------------------------------------------" << std::endl; + std::cout + << "-----------------------------------------------------------------------------------" + << std::endl; std::cout << " " << std::endl; - std::cout.flags(f); - } - else + std::cout.flags( f ); + } else std::cout << "The file error is empty" << std::endl; } -void -printResults2(const std::vector& error) -{ - if (error.size() > 0) - { - std::ios::fmtflags f(std::cout.flags()); - std::cout.precision(4); - std::cout.setf(std::iostream::scientific, std::iostream::floatfield); +void printResults2( const std::vector< error_type > &error ) { + if ( error.size() > 0 ) { + std::ios::fmtflags f( std::cout.flags() ); + std::cout.precision( 4 ); + std::cout.setf( std::iostream::scientific, std::iostream::floatfield ); std::cout << "Robustesse test for k = " << error[0].degree << std::endl; - std::cout << "-----------------------------------------------------------------------------------" << std::endl; - std::cout << "| Lambda coef| Displacement | Difference | Displacem | Difference | Total |" << std::endl; - std::cout << "| nu | L2 error | | H1 error | | faces DOF |" + std::cout + << "-----------------------------------------------------------------------------------" + << std::endl; + std::cout + << "| Lambda coef| Displacement | Difference | Displacem | Difference | Total |" + << std::endl; + std::cout << "| nu | L2 error | | H1 error | | " + "faces DOF |" << std::endl; - std::cout << "-----------------------------------------------------------------------------------" << std::endl; + std::cout + << "-----------------------------------------------------------------------------------" + << std::endl; - std::string s_dof = " " + std::to_string(error[0].nb_dof) + " "; - s_dof.resize(10); + std::string s_dof = " " + std::to_string( error[0].nb_dof ) + " "; + s_dof.resize( 10 ); std::cout << "| " << error[0].h << " | " << error[0].error_L2 << " | " << " - " @@ -411,492 +409,518 @@ printResults2(const std::vector& error) << " - " << " | " << s_dof << " |" << std::endl; - for (int i = 1; i < error.size(); i++) - { - s_dof = " " + std::to_string(error[i].nb_dof) + " "; - s_dof.resize(10); - double rate_depl = error[i].error_L2 - error[i - 1].error_L2; + for ( int i = 1; i < error.size(); i++ ) { + s_dof = " " + std::to_string( error[i].nb_dof ) + " "; + s_dof.resize( 10 ); + double rate_depl = error[i].error_L2 - error[i - 1].error_L2; double rate_stress = error[i].error_H1 - error[i - 1].error_H1; - std::cout << "| " << error[i].h << " | " << error[i].error_L2 << " | " << rate_depl << " | " - << error[i].error_H1 << " | " << rate_stress << " | " << s_dof << " |" << std::endl; + std::cout << "| " << error[i].h << " | " << error[i].error_L2 << " | " << rate_depl + << " | " << error[i].error_H1 << " | " << rate_stress << " | " << s_dof + << " |" << std::endl; } - std::cout << "-----------------------------------------------------------------------------------" << std::endl; + std::cout + << "-----------------------------------------------------------------------------------" + << std::endl; std::cout << " " << std::endl; - std::cout.flags(f); - } - else + std::cout.flags( f ); + } else std::cout << "The file error is empty" << std::endl; } -template -void -test_triangles_fvca5(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_triangles_fvca5( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_1.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_2.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_3.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_4.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_5.typ1" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_triangles_netgen(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_triangles_netgen( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri01.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri02.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri03.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri04.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri05.mesh2d"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_triangles/netgen/tri01.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri02.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri03.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri04.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri05.mesh2d" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::simplicial_mesh msh; - disk::load_mesh_netgen(paths[i].c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::simplicial_mesh< T, 2 > msh; + disk::load_mesh_netgen( paths[i].c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_hexagons(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_hexagons( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 5; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_1.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_2.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_3.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_4.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_5.typ1" ); - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_kershaws(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_kershaws( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 5; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_1.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_2.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_3.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_4.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_5.typ1" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_quads_fvca5(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_quads_fvca5( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 5; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_1.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_2.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_3.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_4.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_5.typ1" ); - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_quads_diskpp(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_quads_diskpp( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 5; - std::vector paths; + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; // paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-1-1.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-2-2.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-4-4.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-8-8.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-16-16.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-32-32.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-256-256.quad"); - - std::vector error_sumup; - - for (int i = 0; i < runs; i++) - { - disk::cartesian_mesh msh; - disk::load_mesh_diskpp_cartesian(paths[i].c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-2-2.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-4-4.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-8-8.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-16-16.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-32-32.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-256-256.quad" ); + + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::cartesian_mesh< T, 2 > msh; + disk::load_mesh_diskpp_cartesian( paths[i].c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_hexahedra_diskpp(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_hexahedra_diskpp( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-2-2-2.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-4-4-4.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-8-8-8.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-16-16-16.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-32-32-32.hex"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-2-2-2.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-4-4-4.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-8-8-8.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-16-16-16.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-32-32-32.hex" ); - for (int i = 0; i < runs; i++) - { - disk::cartesian_mesh msh; - disk::load_mesh_diskpp_cartesian(paths[i].c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::cartesian_mesh< T, 3 > msh; + disk::load_mesh_diskpp_cartesian( paths[i].c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_hexahedra_fvca6(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_hexahedra_fvca6( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_2x2x2.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_4x4x4.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_8x8x8.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_16x16x16.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_32x32x32.hex"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_2x2x2.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_4x4x4.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_8x8x8.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_16x16x16.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_32x32x32.hex" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca6_3d(paths[i].c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 3 > msh; + disk::load_mesh_fvca6_3d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_tetrahedra_netgen(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_tetrahedra_netgen( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet0.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet1.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet2.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet3.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet4.mesh"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet0.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet1.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet2.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet3.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet4.mesh" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::simplicial_mesh msh; - disk::load_mesh_netgen(paths[i].c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::simplicial_mesh< T, 3 > msh; + disk::load_mesh_netgen( paths[i].c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_polyhedra_fvca6(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_polyhedra_fvca6( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 3; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_10.msh"); - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_20.msh"); - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_30.msh"); - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_40.msh"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_10.msh" ); + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_20.msh" ); + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_30.msh" ); + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_40.msh" ); - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca6_3d(paths[i].c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 3 > msh; + disk::load_mesh_fvca6_3d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_tetrahedra_fvca6(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_tetrahedra_fvca6( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.0.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.1.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.2.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.3.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.4.msh"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.0.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.1.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.2.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.3.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.4.msh" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca6_3d(paths[i].c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 3 > msh; + disk::load_mesh_fvca6_3d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_triangles_fvca5_robust(const NewtonSolverParameter& rp, disk::MaterialData& material_data) -{ +template < typename T > +void test_triangles_fvca5_robust( const disk::mechanics::NonLinearParameters< T > &rp, + disk::mechanics::MaterialData< T > &material_data ) { - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < 5; i++) - { - material_data.setLambda(std::pow(10.0, i)); - std::string path = "../../../diskpp/meshes/2D_triangles/fvca5/mesh1_3.typ1"; - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(path.c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + for ( int i = 0; i < 5; i++ ) { + material_data.setLambda( std::pow( 10.0, i ) ); + std::string path = "../../../diskpp/meshes/2D_triangles/fvca5/mesh1_3.typ1"; + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( path.c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); error_sumup[i].h = material_data.getLambda(); } - printResults2(error_sumup); + printResults2( error_sumup ); } -template -void -test_quads_diskpp_robust(const NewtonSolverParameter& rp, disk::MaterialData& material_data) -{ +template < typename T > +void test_quads_diskpp_robust( const disk::mechanics::NonLinearParameters< T > &rp, + disk::mechanics::MaterialData< T > &material_data ) { - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < 5; i++) - { - material_data.setLambda(std::pow(10.0, i)); - std::string path = "../../../diskpp/meshes/2D_quads/diskpp/testmesh-16-16.quad"; - disk::cartesian_mesh msh; - disk::load_mesh_diskpp_cartesian(path.c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + for ( int i = 0; i < 5; i++ ) { + material_data.setLambda( std::pow( 10.0, i ) ); + std::string path = "../../../diskpp/meshes/2D_quads/diskpp/testmesh-16-16.quad"; + disk::cartesian_mesh< T, 2 > msh; + disk::load_mesh_diskpp_cartesian( path.c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); error_sumup[i].h = material_data.getLambda(); } - printResults2(error_sumup); + printResults2( error_sumup ); } -template -void -test_hexagons_robust(const NewtonSolverParameter& rp, disk::MaterialData& material_data) -{ +template < typename T > +void test_hexagons_robust( const disk::mechanics::NonLinearParameters< T > &rp, + disk::mechanics::MaterialData< T > &material_data ) { - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < 5; i++) - { - material_data.setLambda(std::pow(10.0, i)); - std::string path = "../../../diskpp/meshes/2D_hex/fvca5/hexagonal_4.typ1"; - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(path.c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + for ( int i = 0; i < 5; i++ ) { + material_data.setLambda( std::pow( 10.0, i ) ); + std::string path = "../../../diskpp/meshes/2D_hex/fvca5/hexagonal_4.typ1"; + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( path.c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); error_sumup[i].h = material_data.getLambda(); } - printResults2(error_sumup); + printResults2( error_sumup ); } -template -void -test_kershaws_robust(const NewtonSolverParameter& rp, disk::MaterialData& material_data) -{ +template < typename T > +void test_kershaws_robust( const disk::mechanics::NonLinearParameters< T > &rp, + disk::mechanics::MaterialData< T > &material_data ) { - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < 5; i++) - { - material_data.setLambda(std::pow(10.0, i)); - std::string path = "../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_3.typ1"; - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(path.c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + for ( int i = 0; i < 5; i++ ) { + material_data.setLambda( std::pow( 10.0, i ) ); + std::string path = "../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_3.typ1"; + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( path.c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); error_sumup[i].h = material_data.getLambda(); } - printResults2(error_sumup); + printResults2( error_sumup ); } -template -void -test_tetrahedra_fvca6_robust(const NewtonSolverParameter& rp, disk::MaterialData& material_data) -{ +template < typename T > +void test_tetrahedra_fvca6_robust( const disk::mechanics::NonLinearParameters< T > &rp, + disk::mechanics::MaterialData< T > &material_data ) { - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < 5; i++) - { - material_data.setLambda(std::pow(10.0, i)); - std::string path = "../../../diskpp/meshes/3D_tetras/fvca6/tet.2.msh"; - disk::generic_mesh msh; - disk::load_mesh_fvca6_3d(path.c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + for ( int i = 0; i < 5; i++ ) { + material_data.setLambda( std::pow( 10.0, i ) ); + std::string path = "../../../diskpp/meshes/3D_tetras/fvca6/tet.2.msh"; + disk::generic_mesh< T, 3 > msh; + disk::load_mesh_fvca6_3d< T >( path.c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); error_sumup[i].h = material_data.getLambda(); } - printResults2(error_sumup); + printResults2( error_sumup ); } -template -void -test_hexahedra_fvca6_robust(const NewtonSolverParameter& rp, disk::MaterialData& material_data) -{ +template < typename T > +void test_hexahedra_fvca6_robust( const disk::mechanics::NonLinearParameters< T > &rp, + disk::mechanics::MaterialData< T > &material_data ) { - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < 5; i++) - { - material_data.setLambda(std::pow(10.0, i)); - std::string path = "../../../diskpp/meshes/3D_hexa/fvca6/hexa_8x8x8.msh"; - disk::generic_mesh msh; - disk::load_mesh_fvca6_3d(path.c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + for ( int i = 0; i < 5; i++ ) { + material_data.setLambda( std::pow( 10.0, i ) ); + std::string path = "../../../diskpp/meshes/3D_hexa/fvca6/hexa_8x8x8.msh"; + disk::generic_mesh< T, 3 > msh; + disk::load_mesh_fvca6_3d< T >( path.c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); error_sumup[i].h = material_data.getLambda(); } - printResults2(error_sumup); + printResults2( error_sumup ); } -template -void -test_polyhedra_fvca6_robust(const NewtonSolverParameter& rp, disk::MaterialData& material_data) -{ +template < typename T > +void test_polyhedra_fvca6_robust( const disk::mechanics::NonLinearParameters< T > &rp, + disk::mechanics::MaterialData< T > &material_data ) { - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < 5; i++) - { - material_data.setLambda(std::pow(10.0, i)); - std::string path = "../../../diskpp/meshes/3D_general/fvca6/dbls_20.msh"; - disk::generic_mesh msh; - disk::load_mesh_fvca6_3d(path.c_str(), msh); - error_sumup.push_back(run_tresca_solver(msh, rp, material_data)); + for ( int i = 0; i < 5; i++ ) { + material_data.setLambda( std::pow( 10.0, i ) ); + std::string path = "../../../diskpp/meshes/3D_general/fvca6/dbls_20.msh"; + disk::generic_mesh< T, 3 > msh; + disk::load_mesh_fvca6_3d< T >( path.c_str(), msh ); + error_sumup.push_back( run_tresca_solver( msh, rp, material_data ) ); error_sumup[i].h = material_data.getLambda(); } - printResults2(error_sumup); + printResults2( error_sumup ); } -int -main(int argc, char** argv) -{ +int main( int argc, char **argv ) { using RealType = double; int degree = 1; - int dim = 2; + int dim = 2; // Elasticity Parameters - disk::MaterialData material_data; + disk::mechanics::MaterialData< RealType > material_data; - material_data.setMu(2.0); - material_data.setLambda(2.E4); + material_data.setMu( 2.0 ); + material_data.setLambda( 2.E4 ); - std::cout << "Material coefficients: E = " << material_data.getE() << " , nu = " << material_data.getNu() - << std::endl; + std::cout << "Material coefficients: E = " << material_data.getE() + << " , nu = " << material_data.getNu() << std::endl; // Solver parameters - NewtonSolverParameter rp; - rp.m_precomputation = true; - rp.m_stab_type = HHO; - rp.m_epsilon = 2.0E-6; - rp.m_time_step.front() = std::make_pair(1.0, 1); - rp.m_sublevel = 2; - rp.m_beta = 2 * material_data.getMu(); - rp.m_gamma_0 = 2 * material_data.getMu(); - rp.m_frot_type = TRESCA; - rp.m_threshold = 0; - rp.m_theta = 0; - rp.m_iter_max = 20; - rp.m_sublevel = 0; - - int ch; + disk::mechanics::NonLinearParameters< RealType > rp; + rp.m_precomputation = true; + rp.m_stab_type = disk::mechanics::StabilizationType::HHO; + rp.m_epsilon = 2.0E-6; + rp.m_time_step.front() = std::make_pair( 1.0, 1 ); + rp.m_sublevel = 2; + rp.m_beta = 2 * material_data.getMu(); + rp.m_gamma_0 = 2 * material_data.getMu(); + rp.m_frot_type = disk::mechanics::FrictionType::TRESCA; + rp.m_threshold = 0; + rp.m_theta = 0; + rp.m_iter_max = 20; + rp.m_sublevel = 0; +#ifdef NSM_USE_MUMPS + rp.setLinearSolver( disk::solvers::direct_solver::mumps ); +#endif + + int ch; bool robust = false; - while ((ch = getopt(argc, argv, "23g:k:t:vr")) != -1) - { - switch (ch) - { - case '2': dim = 2; break; - case '3': - dim = 3; - break; - - // case 'g': rp.m_gamma_0 = atof(optarg); break; - - case 'k': - degree = atoi(optarg); - if (degree < 0) - { - std::cout << "Degree must be positive. Falling back to 1." << std::endl; - degree = 1; - } - rp.m_face_degree = degree; - rp.m_cell_degree = degree; - rp.m_grad_degree = degree; - break; - - case 't': rp.m_theta = atof(optarg); break; - - case 'v': rp.m_verbose = true; break; - - case 'r': robust = true; break; - - case '?': - default: - std::cout << "wrong arguments" << std::endl; - usage(); - exit(1); + while ( ( ch = getopt( argc, argv, "23g:k:t:vr" ) ) != -1 ) { + switch ( ch ) { + case '2': + dim = 2; + break; + case '3': + dim = 3; + break; + + // case 'g': rp.m_gamma_0 = atof(optarg); break; + + case 'k': + degree = atoi( optarg ); + if ( degree < 0 ) { + std::cout << "Degree must be positive. Falling back to 1." << std::endl; + degree = 1; + } + rp.m_face_degree = degree; + rp.m_cell_degree = degree + 1; + rp.m_grad_degree = degree; + break; + + case 't': + rp.m_theta = atof( optarg ); + break; + + case 'v': + rp.m_verbose = true; + break; + + case 'r': + robust = true; + break; + + case '?': + default: + std::cout << "wrong arguments" << std::endl; + usage(); + exit( 1 ); } } @@ -905,150 +929,140 @@ main(int argc, char** argv) timecounter tc; - if (rp.m_theta != -1.0) - { - rp.m_gamma_0 *= (rp.m_face_degree + 1.0) * (rp.m_face_degree + dim); + if ( rp.m_theta != -1.0 ) { + rp.m_gamma_0 *= ( rp.m_face_degree + 1.0 ) * ( rp.m_face_degree + dim ); } std::cout << " Test convergence rates for: " << std::endl; std::cout << " ** Face_Degree = " << rp.m_face_degree << std::endl; std::cout << " " << std::endl; - if (dim == 3) - { - if (robust) - { + if ( dim == 3 ) { + if ( robust ) { tc.tic(); std::cout << "-Tetrahedras fvca6:" << std::endl; - test_tetrahedra_fvca6_robust(rp, material_data); + test_tetrahedra_fvca6_robust< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test robustess: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Hexahedras fvca6:" << std::endl; - test_hexahedra_fvca6_robust(rp, material_data); + test_hexahedra_fvca6_robust< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test robustess: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Polyhedra:" << std::endl; - test_polyhedra_fvca6_robust(rp, material_data); + test_polyhedra_fvca6_robust< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test robustess: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; - } - else - { + } else { tc.tic(); std::cout << "-Tetrahedras fvca6:" << std::endl; - test_tetrahedra_fvca6(rp, material_data); + test_tetrahedra_fvca6< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Tetrahedras netgen:" << std::endl; - test_tetrahedra_netgen(rp, material_data); + test_tetrahedra_netgen< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Hexahedras fvca6:" << std::endl; - test_hexahedra_fvca6(rp, material_data); + test_hexahedra_fvca6< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Hexahedras diskpp:" << std::endl; - test_hexahedra_diskpp(rp, material_data); + test_hexahedra_diskpp< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Polyhedra:" << std::endl; - test_polyhedra_fvca6(rp, material_data); + test_polyhedra_fvca6< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; } - } - else if (dim == 2) - { - if (robust) - { + } else if ( dim == 2 ) { + if ( robust ) { tc.tic(); std::cout << "-Triangles fvca5:" << std::endl; - test_triangles_fvca5_robust(rp, material_data); + test_triangles_fvca5_robust< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test robustess: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Quadrangles diskpp:" << std::endl; - test_quads_diskpp_robust(rp, material_data); + test_quads_diskpp_robust< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test robustess: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Hexagons:" << std::endl; - test_hexagons_robust(rp, material_data); + test_hexagons_robust< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test robustess: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Kershaws:" << std::endl; - test_kershaws_robust(rp, material_data); + test_kershaws_robust< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test robustess: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; - } - else - { + } else { tc.tic(); std::cout << "-Triangles fvca5:" << std::endl; - test_triangles_fvca5(rp, material_data); + test_triangles_fvca5< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Triangles netgen:" << std::endl; - test_triangles_netgen(rp, material_data); + test_triangles_netgen< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Quadrangles fvca5:" << std::endl; - test_quads_fvca5(rp, material_data); + test_quads_fvca5< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Quadrangles diskpp:" << std::endl; - test_quads_diskpp(rp, material_data); + test_quads_diskpp< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Hexagons:" << std::endl; - test_hexagons(rp, material_data); + test_hexagons< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Kershaws:" << std::endl; - test_kershaws(rp, material_data); + test_kershaws< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; diff --git a/apps/nonlinear_solid_mechanics/src/elasticity_test.cpp b/apps/nonlinear_solid_mechanics/src/elasticity_test.cpp index 66cf6d6d..c68b813c 100644 --- a/apps/nonlinear_solid_mechanics/src/elasticity_test.cpp +++ b/apps/nonlinear_solid_mechanics/src/elasticity_test.cpp @@ -24,273 +24,269 @@ * DOI: 10.1016/j.cam.2017.09.017 */ +#include "diskpp/boundary_conditions/boundary_conditions.hpp" +#include "diskpp/common/colormanip.h" +#include "diskpp/loaders/loader.hpp" +#include "diskpp/mechanics/NewtonSolver/NonLinearSolver.hpp" +#include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" + #include #include #include #include -#include -#include "diskpp/boundary_conditions/boundary_conditions.hpp" -#include "diskpp/common/colormanip.h" -#include "diskpp/loaders/loader.hpp" -#include "diskpp/mechanics/NewtonSolver/NewtonSolver.hpp" -#include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" +#include -struct error_type -{ - int degree; - int nb_dof; +struct error_type { + int degree; + int nb_dof; double h; double error_L2; double error_H1; }; -void -usage(const char* progname) -{ - printf("Usage: %s \n\n", progname); - printf(" -2: test 2D mesh (default)\n"); - printf(" -3: test 3D mesh\n"); - printf(" -k: face degree (>=0)\n"); - printf(" -l: difference beetween cell and face degree (-1 <= l <= 1) \n"); - printf(" -v: verbose\n"); +void usage( const char *progname ) { + printf( "Usage: %s \n\n", progname ); + printf( " -2: test 2D mesh (default)\n" ); + printf( " -3: test 3D mesh\n" ); + printf( " -k: face degree (>=0)\n" ); + printf( " -l: difference beetween cell and face degree (-1 <= l <= 1) \n" ); + printf( " -v: verbose\n" ); } -template class Mesh, typename T, typename Storage> -error_type -run_linear_elasticity_solver(const Mesh& msh, - const NewtonSolverParameter& rp, - const disk::MaterialData& material_data) -{ - typedef Mesh mesh_type; - typedef disk::static_vector result_type; - typedef disk::static_matrix grad_type; - typedef disk::vector_boundary_conditions Bnd_type; +template < template < typename, size_t, typename > class Mesh, typename T, typename Storage > +error_type run_linear_elasticity_solver( const Mesh< T, 2, Storage > &msh, + const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { + typedef Mesh< T, 2, Storage > mesh_type; + typedef disk::static_vector< T, 2 > result_type; + typedef disk::static_matrix< T, 2, 2 > grad_type; + typedef disk::vector_boundary_conditions< mesh_type > Bnd_type; timecounter tc; tc.tic(); - auto load = [material_data](const disk::point& p, const T& time) -> result_type - { + auto load = [material_data]( const disk::point< T, 2 > &p, const T &time ) -> result_type { const T lambda = material_data.getLambda(); - const T mu = material_data.getMu(); - - T fx = - lambda * cos(M_PI * (p.x() + p.y())) - - 2.0 * mu * - ((4 * lambda + 4) * sin(2 * M_PI * p.y()) * cos(2 * M_PI * p.x()) + sin(M_PI * p.x()) * sin(M_PI * p.y())) + - 2.0 * mu * - (2.0 * lambda * sin(2 * M_PI * p.y()) + 2.0 * sin(2 * M_PI * p.y()) + 0.5 * cos(M_PI * (p.x() + p.y()))); - T fy = - lambda * cos(M_PI * (p.x() + p.y())) + - 2.0 * mu * - ((4 * lambda + 4) * sin(2 * M_PI * p.x()) * cos(2 * M_PI * p.y()) - sin(M_PI * p.x()) * sin(M_PI * p.y())) - - 2.0 * mu * - (2.0 * lambda * sin(2 * M_PI * p.x()) + 2.0 * sin(2 * M_PI * p.x()) - 0.5 * cos(M_PI * (p.x() + p.y()))); - - return -M_PI * M_PI / (lambda + 1) * result_type{fx, fy}; + const T mu = material_data.getMu(); + + T fx = lambda * cos( M_PI * ( p.x() + p.y() ) ) - + 2.0 * mu * + ( ( 4 * lambda + 4 ) * sin( 2 * M_PI * p.y() ) * cos( 2 * M_PI * p.x() ) + + sin( M_PI * p.x() ) * sin( M_PI * p.y() ) ) + + 2.0 * mu * + ( 2.0 * lambda * sin( 2 * M_PI * p.y() ) + 2.0 * sin( 2 * M_PI * p.y() ) + + 0.5 * cos( M_PI * ( p.x() + p.y() ) ) ); + T fy = lambda * cos( M_PI * ( p.x() + p.y() ) ) + + 2.0 * mu * + ( ( 4 * lambda + 4 ) * sin( 2 * M_PI * p.x() ) * cos( 2 * M_PI * p.y() ) - + sin( M_PI * p.x() ) * sin( M_PI * p.y() ) ) - + 2.0 * mu * + ( 2.0 * lambda * sin( 2 * M_PI * p.x() ) + 2.0 * sin( 2 * M_PI * p.x() ) - + 0.5 * cos( M_PI * ( p.x() + p.y() ) ) ); + + return -M_PI * M_PI / ( lambda + 1 ) * result_type { fx, fy }; }; - auto solution = [material_data](const disk::point& p) -> result_type - { - T fx = sin(2 * M_PI * p.y()) * (cos(2 * M_PI * p.x()) - 1) + - 1.0 / (1 + material_data.getLambda()) * sin(M_PI * p.x()) * sin(M_PI * p.y()); - T fy = -sin(2 * M_PI * p.x()) * (cos(2 * M_PI * p.y()) - 1) + - 1.0 / (1 + material_data.getLambda()) * sin(M_PI * p.x()) * sin(M_PI * p.y()); + auto solution = [material_data]( const disk::point< T, 2 > &p ) -> result_type { + T fx = sin( 2 * M_PI * p.y() ) * ( cos( 2 * M_PI * p.x() ) - 1 ) + + 1.0 / ( 1 + material_data.getLambda() ) * sin( M_PI * p.x() ) * sin( M_PI * p.y() ); + T fy = -sin( 2 * M_PI * p.x() ) * ( cos( 2 * M_PI * p.y() ) - 1 ) + + 1.0 / ( 1 + material_data.getLambda() ) * sin( M_PI * p.x() ) * sin( M_PI * p.y() ); - return result_type{fx, fy}; + return result_type { fx, fy }; }; - auto sigma = [material_data](const disk::point& p) -> grad_type - { + auto sigma = [material_data]( const disk::point< T, 2 > &p ) -> grad_type { const T lambda = material_data.getLambda(); - const T mu = material_data.getMu(); + const T mu = material_data.getMu(); - T g11 = - -(2 * (lambda + 1) * sin(2 * M_PI * p.x()) * sin(2 * M_PI * p.y()) - sin(M_PI * p.y()) * cos(M_PI * p.x())); - T g12 = (2 * lambda + 2) * (cos(2 * M_PI * p.x()) - 1) * cos(2 * M_PI * p.y()) + - sin(M_PI * p.x()) * cos(M_PI * p.y()); + T g11 = -( 2 * ( lambda + 1 ) * sin( 2 * M_PI * p.x() ) * sin( 2 * M_PI * p.y() ) - + sin( M_PI * p.y() ) * cos( M_PI * p.x() ) ); + T g12 = ( 2 * lambda + 2 ) * ( cos( 2 * M_PI * p.x() ) - 1 ) * cos( 2 * M_PI * p.y() ) + + sin( M_PI * p.x() ) * cos( M_PI * p.y() ); - T g21 = (-2 * lambda + 2) * (cos(2 * M_PI * p.y()) - 1) * cos(2 * M_PI * p.x()) + - sin(M_PI * p.y()) * cos(M_PI * p.x()); + T g21 = ( -2 * lambda + 2 ) * ( cos( 2 * M_PI * p.y() ) - 1 ) * cos( 2 * M_PI * p.x() ) + + sin( M_PI * p.y() ) * cos( M_PI * p.x() ); - T g22 = - 2 * (lambda + 1) * sin(2 * M_PI * p.x()) * sin(2 * M_PI * p.y()) + sin(M_PI * p.x()) * cos(M_PI * p.y()); + T g22 = 2 * ( lambda + 1 ) * sin( 2 * M_PI * p.x() ) * sin( 2 * M_PI * p.y() ) + + sin( M_PI * p.x() ) * cos( M_PI * p.y() ); grad_type g = grad_type::Zero(); - g(0, 0) = g11; - g(0, 1) = g12; - g(1, 0) = g21; - g(1, 1) = g22; + g( 0, 0 ) = g11; + g( 0, 1 ) = g12; + g( 1, 0 ) = g21; + g( 1, 1 ) = g22; - g *= M_PI / (lambda + 1); + g *= M_PI / ( lambda + 1 ); - const grad_type gs = 0.5 * (g + g.transpose()); + const grad_type gs = 0.5 * ( g + g.transpose() ); const T divu = gs.trace(); - return 2 * mu * gs + lambda * divu * disk::static_matrix::Identity(); + return 2 * mu * gs + lambda * divu * disk::static_matrix< T, 2, 2 >::Identity(); }; - Bnd_type bnd(msh); - bnd.addDirichletEverywhere(solution); + Bnd_type bnd( msh ); + bnd.addDirichletEverywhere( solution ); - disk::mechanics::NewtonSolver nl(msh, bnd, rp); + disk::mechanics::NonLinearSolver< mesh_type > nl( msh, bnd, rp ); - nl.addBehavior(disk::DeformationMeasure::SMALL_DEF, disk::LawType::ELASTIC); - nl.addMaterialData(material_data); + nl.addBehavior( disk::mechanics::DeformationMeasure::SMALL_DEF, + disk::mechanics::LawType::ELASTIC ); + nl.addMaterialData( material_data ); + nl.addExternalLoad( load ); - nl.initial_guess(solution); + nl.initial_guess( solution ); - if (nl.verbose()) - { + if ( nl.verbose() ) { std::cout << "Solving the problem ..." << '\n'; } - SolverInfo solve_info = nl.compute(load); + disk::mechanics::SolverInfo solve_info = nl.compute(); - if (nl.verbose()) - { + if ( nl.verbose() ) { solve_info.printInfo(); } error_type error; - error.h = average_diameter(msh); - error.degree = rp.m_face_degree; - error.nb_dof = nl.numberOfDofs(); - error.error_L2 = nl.compute_l2_displacement_error(solution); - error.error_H1 = nl.compute_H1_error(solution); + error.h = average_diameter( msh ); + error.degree = rp.m_face_degree; + error.nb_dof = nl.numberOfDofs(); + error.error_L2 = nl.compute_l2_displacement_error( solution ); + error.error_H1 = nl.compute_H1_error( solution ); return error; } -template class Mesh, typename T, typename Storage> -error_type -run_linear_elasticity_solver(const Mesh& msh, - const NewtonSolverParameter& rp, - const disk::MaterialData& material_data) -{ - typedef Mesh mesh_type; - typedef disk::static_vector result_type; - typedef disk::static_matrix grad_type; - typedef disk::vector_boundary_conditions Bnd_type; +template < template < typename, size_t, typename > class Mesh, typename T, typename Storage > +error_type run_linear_elasticity_solver( const Mesh< T, 3, Storage > &msh, + const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { + typedef Mesh< T, 3, Storage > mesh_type; + typedef disk::static_vector< T, 3 > result_type; + typedef disk::static_matrix< T, 3, 3 > grad_type; + typedef disk::vector_boundary_conditions< mesh_type > Bnd_type; timecounter tc; tc.tic(); - auto load = [material_data](const disk::point& p, const T& time) -> result_type - { + auto load = [material_data]( const disk::point< T, 3 > &p, const T &time ) -> result_type { const T lambda = material_data.getLambda(); - const T mu = material_data.getMu(); - - T fx = - lambda * cos(M_PI * (p.x() + p.y())) - - 2.0 * mu * - ((4 * lambda + 4) * sin(2 * M_PI * p.y()) * cos(2 * M_PI * p.x()) + sin(M_PI * p.x()) * sin(M_PI * p.y())) + - 2.0 * mu * - (2.0 * lambda * sin(2 * M_PI * p.y()) + 2.0 * sin(2 * M_PI * p.y()) + 0.5 * cos(M_PI * (p.x() + p.y()))); - T fy = - lambda * cos(M_PI * (p.x() + p.y())) + - 2.0 * mu * - ((4 * lambda + 4) * sin(2 * M_PI * p.x()) * cos(2 * M_PI * p.y()) - sin(M_PI * p.x()) * sin(M_PI * p.y())) - - 2.0 * mu * - (2.0 * lambda * sin(2 * M_PI * p.x()) + 2.0 * sin(2 * M_PI * p.x()) - 0.5 * cos(M_PI * (p.x() + p.y()))); - - return -M_PI * M_PI / (lambda + 1) * result_type{fx, fy, 0}; + const T mu = material_data.getMu(); + + T fx = lambda * cos( M_PI * ( p.x() + p.y() ) ) - + 2.0 * mu * + ( ( 4 * lambda + 4 ) * sin( 2 * M_PI * p.y() ) * cos( 2 * M_PI * p.x() ) + + sin( M_PI * p.x() ) * sin( M_PI * p.y() ) ) + + 2.0 * mu * + ( 2.0 * lambda * sin( 2 * M_PI * p.y() ) + 2.0 * sin( 2 * M_PI * p.y() ) + + 0.5 * cos( M_PI * ( p.x() + p.y() ) ) ); + T fy = lambda * cos( M_PI * ( p.x() + p.y() ) ) + + 2.0 * mu * + ( ( 4 * lambda + 4 ) * sin( 2 * M_PI * p.x() ) * cos( 2 * M_PI * p.y() ) - + sin( M_PI * p.x() ) * sin( M_PI * p.y() ) ) - + 2.0 * mu * + ( 2.0 * lambda * sin( 2 * M_PI * p.x() ) + 2.0 * sin( 2 * M_PI * p.x() ) - + 0.5 * cos( M_PI * ( p.x() + p.y() ) ) ); + + return -M_PI * M_PI / ( lambda + 1 ) * result_type { fx, fy, 0 }; }; - auto solution = [material_data](const disk::point& p) -> result_type - { - T fx = sin(2 * M_PI * p.y()) * (cos(2 * M_PI * p.x()) - 1) + - 1.0 / (1 + material_data.getLambda()) * sin(M_PI * p.x()) * sin(M_PI * p.y()); - T fy = -sin(2 * M_PI * p.x()) * (cos(2 * M_PI * p.y()) - 1) + - 1.0 / (1 + material_data.getLambda()) * sin(M_PI * p.x()) * sin(M_PI * p.y()); + auto solution = [material_data]( const disk::point< T, 3 > &p ) -> result_type { + T fx = sin( 2 * M_PI * p.y() ) * ( cos( 2 * M_PI * p.x() ) - 1 ) + + 1.0 / ( 1 + material_data.getLambda() ) * sin( M_PI * p.x() ) * sin( M_PI * p.y() ); + T fy = -sin( 2 * M_PI * p.x() ) * ( cos( 2 * M_PI * p.y() ) - 1 ) + + 1.0 / ( 1 + material_data.getLambda() ) * sin( M_PI * p.x() ) * sin( M_PI * p.y() ); - return result_type{fx, fy, 0}; + return result_type { fx, fy, 0 }; }; - auto sigma = [material_data](const disk::point& p) -> grad_type - { + auto sigma = [material_data]( const disk::point< T, 3 > &p ) -> grad_type { const T lambda = material_data.getLambda(); - const T mu = material_data.getMu(); + const T mu = material_data.getMu(); - T g11 = - -(2 * (lambda + 1) * sin(2 * M_PI * p.x()) * sin(2 * M_PI * p.y()) - sin(M_PI * p.y()) * cos(M_PI * p.x())); - T g12 = (2 * lambda + 2) * (cos(2 * M_PI * p.x()) - 1) * cos(2 * M_PI * p.y()) + - sin(M_PI * p.x()) * cos(M_PI * p.y()); + T g11 = -( 2 * ( lambda + 1 ) * sin( 2 * M_PI * p.x() ) * sin( 2 * M_PI * p.y() ) - + sin( M_PI * p.y() ) * cos( M_PI * p.x() ) ); + T g12 = ( 2 * lambda + 2 ) * ( cos( 2 * M_PI * p.x() ) - 1 ) * cos( 2 * M_PI * p.y() ) + + sin( M_PI * p.x() ) * cos( M_PI * p.y() ); - T g21 = (-2 * lambda + 2) * (cos(2 * M_PI * p.y()) - 1) * cos(2 * M_PI * p.x()) + - sin(M_PI * p.y()) * cos(M_PI * p.x()); + T g21 = ( -2 * lambda + 2 ) * ( cos( 2 * M_PI * p.y() ) - 1 ) * cos( 2 * M_PI * p.x() ) + + sin( M_PI * p.y() ) * cos( M_PI * p.x() ); - T g22 = - 2 * (lambda + 1) * sin(2 * M_PI * p.x()) * sin(2 * M_PI * p.y()) + sin(M_PI * p.x()) * cos(M_PI * p.y()); + T g22 = 2 * ( lambda + 1 ) * sin( 2 * M_PI * p.x() ) * sin( 2 * M_PI * p.y() ) + + sin( M_PI * p.x() ) * cos( M_PI * p.y() ); grad_type g = grad_type::Zero(); - g(0, 0) = g11; - g(0, 1) = g12; - g(1, 0) = g21; - g(1, 1) = g22; + g( 0, 0 ) = g11; + g( 0, 1 ) = g12; + g( 1, 0 ) = g21; + g( 1, 1 ) = g22; - g *= M_PI / (lambda + 1); + g *= M_PI / ( lambda + 1 ); - const grad_type gs = 0.5 * (g + g.transpose()); + const grad_type gs = 0.5 * ( g + g.transpose() ); const T divu = gs.trace(); - return 2 * mu * gs + lambda * divu * disk::static_matrix::Identity(); + return 2 * mu * gs + lambda * divu * disk::static_matrix< T, 3, 3 >::Identity(); }; - Bnd_type bnd(msh); - bnd.addDirichletEverywhere(solution); + Bnd_type bnd( msh ); + bnd.addDirichletEverywhere( solution ); - disk::mechanics::NewtonSolver nl(msh, bnd, rp); + disk::mechanics::NonLinearSolver< mesh_type > nl( msh, bnd, rp ); - nl.addBehavior(disk::DeformationMeasure::SMALL_DEF, disk::LawType::ELASTIC); - nl.addMaterialData(material_data); + nl.addBehavior( disk::mechanics::DeformationMeasure::SMALL_DEF, + disk::mechanics::LawType::ELASTIC ); + nl.addMaterialData( material_data ); + nl.addExternalLoad( load ); + nl.initial_guess( solution ); - nl.initial_guess(solution); - - if (nl.verbose()) - { + if ( nl.verbose() ) { std::cout << "Solving the problem ..." << '\n'; } - SolverInfo solve_info = nl.compute(load); + disk::mechanics::SolverInfo solve_info = nl.compute(); - if (nl.verbose()) - { + if ( nl.verbose() ) { solve_info.printInfo(); } error_type error; - error.h = average_diameter(msh); - error.degree = rp.m_face_degree; - error.nb_dof = nl.numberOfDofs(); - error.error_L2 = nl.compute_l2_displacement_error(solution); - error.error_H1 = nl.compute_H1_error(solution); + error.h = average_diameter( msh ); + error.degree = rp.m_face_degree; + error.nb_dof = nl.numberOfDofs(); + error.error_L2 = nl.compute_l2_displacement_error( solution ); + error.error_H1 = nl.compute_H1_error( solution ); return error; } -void -printResults(const std::vector& error) -{ - if (error.size() > 0) - { - std::ios::fmtflags f(std::cout.flags()); - std::cout.precision(4); - std::cout.setf(std::iostream::scientific, std::iostream::floatfield); +void printResults( const std::vector< error_type > &error ) { + if ( error.size() > 0 ) { + std::ios::fmtflags f( std::cout.flags() ); + std::cout.precision( 4 ); + std::cout.setf( std::iostream::scientific, std::iostream::floatfield ); std::cout << "Convergence test for k = " << error[0].degree << std::endl; - std::cout << "-----------------------------------------------------------------------------------" << std::endl; - std::cout << "| Size mesh | L2 error | Convergence | H1 error | Convergence | Total |" << std::endl; - std::cout << "| h | | rate | | rate | faces DOF |" << std::endl; - std::cout << "-----------------------------------------------------------------------------------" << std::endl; - - std::string s_dof = " " + std::to_string(error[0].nb_dof) + " "; - s_dof.resize(10); + std::cout + << "-----------------------------------------------------------------------------------" + << std::endl; + std::cout + << "| Size mesh | L2 error | Convergence | H1 error | Convergence | Total |" + << std::endl; + std::cout + << "| h | | rate | | rate | faces DOF |" + << std::endl; + std::cout + << "-----------------------------------------------------------------------------------" + << std::endl; + + std::string s_dof = " " + std::to_string( error[0].nb_dof ) + " "; + s_dof.resize( 10 ); std::cout << "| " << error[0].h << " | " << error[0].error_L2 << " | " << " - " @@ -298,349 +294,386 @@ printResults(const std::vector& error) << " - " << " | " << s_dof << " |" << std::endl; - for (int i = 1; i < error.size(); i++) - { - s_dof = " " + std::to_string(error[i].nb_dof) + " "; - s_dof.resize(10); - double rate_depl = - (log10(error[i - 1].error_L2) - log10(error[i].error_L2)) / (log10(error[i - 1].h) - log10(error[i].h)); - double rate_stress = - (log10(error[i - 1].error_H1) - log10(error[i].error_H1)) / (log10(error[i - 1].h) - log10(error[i].h)); - - std::cout << "| " << error[i].h << " | " << error[i].error_L2 << " | " << rate_depl << " | " - << error[i].error_H1 << " | " << rate_stress << " | " << s_dof << " |" << std::endl; + for ( int i = 1; i < error.size(); i++ ) { + s_dof = " " + std::to_string( error[i].nb_dof ) + " "; + s_dof.resize( 10 ); + double rate_depl = ( log10( error[i - 1].error_L2 ) - log10( error[i].error_L2 ) ) / + ( log10( error[i - 1].h ) - log10( error[i].h ) ); + double rate_stress = ( log10( error[i - 1].error_H1 ) - log10( error[i].error_H1 ) ) / + ( log10( error[i - 1].h ) - log10( error[i].h ) ); + + std::cout << "| " << error[i].h << " | " << error[i].error_L2 << " | " << rate_depl + << " | " << error[i].error_H1 << " | " << rate_stress << " | " << s_dof + << " |" << std::endl; } - std::cout << "-----------------------------------------------------------------------------------" << std::endl; + std::cout + << "-----------------------------------------------------------------------------------" + << std::endl; std::cout << " " << std::endl; - std::cout.flags(f); - } - else + std::cout.flags( f ); + } else std::cout << "The file error is empty" << std::endl; } -template -void -test_triangles_fvca5(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_triangles_fvca5( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_1.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_2.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_3.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_4.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_5.typ1" ); - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_triangles_netgen(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_triangles_netgen( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri01.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri02.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri03.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri04.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri05.mesh2d"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_triangles/netgen/tri01.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri02.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri03.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri04.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri05.mesh2d" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::simplicial_mesh msh; - disk::load_mesh_netgen(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::simplicial_mesh< T, 2 > msh; + disk::load_mesh_netgen( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_hexagons(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_hexagons( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 5; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_1.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_2.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_3.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_4.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_5.typ1" ); - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_kershaws(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_kershaws( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 5; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_1.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_2.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_3.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_4.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_5.typ1" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_quads_fvca5(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_quads_fvca5( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 5; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_1.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_2.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_3.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_4.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_5.typ1" ); - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_quads_diskpp(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_quads_diskpp( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-4-4.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-8-8.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-16-16.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-32-32.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-256-256.quad"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-4-4.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-8-8.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-16-16.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-32-32.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-256-256.quad" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::cartesian_mesh msh; - disk::load_mesh_diskpp_cartesian(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::cartesian_mesh< T, 2 > msh; + disk::load_mesh_diskpp_cartesian( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_hexahedra_diskpp(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_hexahedra_diskpp( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-2-2-2.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-4-4-4.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-8-8-8.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-16-16-16.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-32-32-32.hex"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-2-2-2.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-4-4-4.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-8-8-8.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-16-16-16.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-32-32-32.hex" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::cartesian_mesh msh; - disk::load_mesh_diskpp_cartesian(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::cartesian_mesh< T, 3 > msh; + disk::load_mesh_diskpp_cartesian( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_hexahedra_fvca6(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_hexahedra_fvca6( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_2x2x2.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_4x4x4.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_8x8x8.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_16x16x16.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_32x32x32.hex"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_2x2x2.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_4x4x4.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_8x8x8.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_16x16x16.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_32x32x32.hex" ); - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca6_3d(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 3 > msh; + disk::load_mesh_fvca6_3d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_tetrahedra_netgen(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_tetrahedra_netgen( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet0.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet1.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet2.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet3.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet4.mesh"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet0.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet1.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet2.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet3.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet4.mesh" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::simplicial_mesh msh; - disk::load_mesh_netgen(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::simplicial_mesh< T, 3 > msh; + disk::load_mesh_netgen( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_polyhedra_fvca6(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_polyhedra_fvca6( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 3; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_10.msh"); - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_20.msh"); - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_30.msh"); - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_40.msh"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_10.msh" ); + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_20.msh" ); + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_30.msh" ); + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_40.msh" );; - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca6_3d(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 3 > msh; + disk::load_mesh_fvca6_3d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_tetrahedra_fvca6(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_tetrahedra_fvca6( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.0.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.1.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.2.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.3.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.4.msh"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.0.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.1.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.2.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.3.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.4.msh" ); - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca6_3d(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 3 > msh; + disk::load_mesh_fvca6_3d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -int -main(int argc, char** argv) -{ +int main( int argc, char **argv ) { using RealType = double; - int degree = 1; - int l = 0; - int dim = 2; + int degree = 1; + int l = 0; + int dim = 2; bool verbose = false; int ch; - while ((ch = getopt(argc, argv, "23k:l:v")) != -1) - { - switch (ch) - { - case '2': dim = 2; break; - case '3': dim = 3; break; - - case 'k': - degree = atoi(optarg); - if (degree < 0) - { - std::cout << "Degree must be positive. Falling back to 1." << std::endl; - degree = 1; - } - break; - - case 'l': - l = atoi(optarg); - if (l < -1 or l > 1) - { - std::cout << "l can be -1, 0 or 1. Falling back to 0." << std::endl; - l = 0; - } - break; - - case 'v': verbose = true; break; - - case '?': - default: - std::cout << "wrong arguments" << std::endl; - usage(argv[0]); - exit(1); + while ( ( ch = getopt( argc, argv, "23k:l:v" ) ) != -1 ) { + switch ( ch ) { + case '2': + dim = 2; + break; + case '3': + dim = 3; + break; + + case 'k': + degree = atoi( optarg ); + if ( degree < 0 ) { + std::cout << "Degree must be positive. Falling back to 1." << std::endl; + degree = 1; + } + break; + + case 'l': + l = atoi( optarg ); + if ( l < -1 or l > 1 ) { + std::cout << "l can be -1, 0 or 1. Falling back to 0." << std::endl; + l = 0; + } + break; + + case 'v': + verbose = true; + break; + + case '?': + default: + std::cout << "wrong arguments" << std::endl; + usage( argv[0] ); + exit( 1 ); } } // Elasticity Parameters - disk::MaterialData material_data; - material_data.setMu(1.0); - material_data.setLambda(10E5); - - NewtonSolverParameter rp; - rp.setFaceDegree(degree); - rp.setGradDegree(degree); - rp.setCellDegree(degree + l); - rp.setStabilizationParameter(2.0 * material_data.getMu()); - rp.setVerbose(verbose); - rp.setPrecomputation(true); + disk::mechanics::MaterialData< RealType > material_data; + material_data.setMu( 1.0 ); + material_data.setLambda( 10E5 ); + + disk::mechanics::NonLinearParameters< RealType > rp; + rp.setFaceDegree( degree ); + rp.setGradDegree( degree ); + rp.setCellDegree( degree + l ); + rp.setStabilizationParameter( 2.0 * material_data.getMu() ); + rp.setVerbose( verbose ); + rp.setPrecomputation( true ); +#ifdef NSM_USE_MUMPS + rp.setLinearSolver( disk::solvers::direct_solver::mumps ); +#endif argc -= optind; argv += optind; @@ -652,86 +685,83 @@ main(int argc, char** argv) std::cout << " ** Cell_Degree = " << rp.getCellDegree() << std::endl; std::cout << " " << std::endl; - if (dim == 3) - { + if ( dim == 3 ) { tc.tic(); std::cout << "-Tetrahedras fvca6:" << std::endl; - test_tetrahedra_fvca6(rp, material_data); + test_tetrahedra_fvca6< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Tetrahedras netgen:" << std::endl; - test_tetrahedra_netgen(rp, material_data); + test_tetrahedra_netgen< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Hexahedras fvca6:" << std::endl; - test_hexahedra_fvca6(rp, material_data); + test_hexahedra_fvca6< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Hexahedras diskpp:" << std::endl; - test_hexahedra_diskpp(rp, material_data); + test_hexahedra_diskpp< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Polyhedra:" << std::endl; - test_polyhedra_fvca6(rp, material_data); + test_polyhedra_fvca6< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; - } - else if (dim == 2) - { + } else if ( dim == 2 ) { tc.tic(); std::cout << "-Triangles fvca5:" << std::endl; - test_triangles_fvca5(rp, material_data); + test_triangles_fvca5< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Triangles netgen:" << std::endl; - test_triangles_netgen(rp, material_data); + test_triangles_netgen< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Quadrangles fvca5:" << std::endl; - test_quads_fvca5(rp, material_data); + test_quads_fvca5< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Quadrangles diskpp:" << std::endl; - test_quads_diskpp(rp, material_data); + test_quads_diskpp< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Hexagons:" << std::endl; - test_hexagons(rp, material_data); + test_hexagons< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Kershaws:" << std::endl; - test_kershaws(rp, material_data); + test_kershaws< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; } -} \ No newline at end of file +} diff --git a/apps/nonlinear_solid_mechanics/src/elastodynamic_test.cpp b/apps/nonlinear_solid_mechanics/src/elastodynamic_test.cpp index 6ccb0066..8ad9a717 100644 --- a/apps/nonlinear_solid_mechanics/src/elastodynamic_test.cpp +++ b/apps/nonlinear_solid_mechanics/src/elastodynamic_test.cpp @@ -23,286 +23,276 @@ * DOI: 10.1016/j.cam.2017.09.017 */ +#include "diskpp/boundary_conditions/boundary_conditions.hpp" +#include "diskpp/common/colormanip.h" +#include "diskpp/loaders/loader.hpp" +#include "diskpp/mechanics/NewtonSolver/NonLinearSolver.hpp" +#include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" + #include #include #include #include -#include -#include "diskpp/boundary_conditions/boundary_conditions.hpp" -#include "diskpp/common/colormanip.h" -#include "diskpp/loaders/loader.hpp" -#include "diskpp/mechanics/NewtonSolver/NewtonSolver.hpp" -#include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" +#include -struct error_type -{ - int degree; - int nb_dof; +struct error_type { + int degree; + int nb_dof; double h; - double error_L2; - double error_H1; + long double error_L2; + long double error_H1; }; -void -usage(const char* progname) -{ - printf("Usage: %s \n\n", progname); - printf(" -2: test 2D mesh (default)\n"); - printf(" -3: test 3D mesh\n"); - printf(" -k: face degree (>=0)\n"); - printf(" -l: difference beetween cell and face degree (-1 <= l <= 1) \n"); - printf(" -v: verbose\n"); +void usage( const char *progname ) { + printf( "Usage: %s \n\n", progname ); + printf( " -2: test 2D mesh (default)\n" ); + printf( " -3: test 3D mesh\n" ); + printf( " -k: face degree (>=0)\n" ); + printf( " -l: difference beetween cell and face degree (-1 <= l <= 1) \n" ); + printf( " -v: verbose\n" ); } -template class Mesh, typename T, typename Storage> -error_type -run_linear_elasticity_solver(const Mesh& msh, - const NewtonSolverParameter& rp, - const disk::MaterialData& material_data) -{ - typedef Mesh mesh_type; - typedef disk::static_vector result_type; - typedef disk::static_matrix grad_type; - typedef disk::vector_boundary_conditions Bnd_type; +template < template < typename, size_t, typename > class Mesh, typename T, typename Storage > +error_type run_linear_elasticity_solver( const Mesh< T, 2, Storage > &msh, + disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { + typedef Mesh< T, 2, Storage > mesh_type; + typedef disk::static_vector< T, 2 > result_type; + typedef disk::static_matrix< T, 2, 2 > grad_type; + typedef disk::vector_boundary_conditions< mesh_type > Bnd_type; timecounter tc; tc.tic(); - auto load = [material_data](const disk::point& p, const T& time) -> result_type - { - const T lambda = material_data.getLambda(); - const T mu = material_data.getMu(); - - T fx = - lambda * cos(M_PI * (p.x() + p.y())) - - 2.0 * mu * - ((4 * lambda + 4) * sin(2 * M_PI * p.y()) * cos(2 * M_PI * p.x()) + sin(M_PI * p.x()) * sin(M_PI * p.y())) + - 2.0 * mu * - (2.0 * lambda * sin(2 * M_PI * p.y()) + 2.0 * sin(2 * M_PI * p.y()) + 0.5 * cos(M_PI * (p.x() + p.y()))); - T fy = - lambda * cos(M_PI * (p.x() + p.y())) + - 2.0 * mu * - ((4 * lambda + 4) * sin(2 * M_PI * p.x()) * cos(2 * M_PI * p.y()) - sin(M_PI * p.x()) * sin(M_PI * p.y())) - - 2.0 * mu * - (2.0 * lambda * sin(2 * M_PI * p.x()) + 2.0 * sin(2 * M_PI * p.x()) - 0.5 * cos(M_PI * (p.x() + p.y()))); - - return -M_PI * M_PI / (lambda + 1) * result_type{fx, fy}; + // check CFL condition + T h_min = minimum_diameter( msh ); + T vp = std::sqrt( ( material_data.getLambda() + 2.0 * material_data.getMu() ) / + material_data.getRho() ); + const auto dt_crit = h_min / vp; + T CFL = 0.9; + if ( rp.getUnsteadyScheme() == disk::mechanics::DynamicType::LEAP_FROG ) { + CFL /= std::max( 1.0, rp.getStabilizationParameter() ); + } + const T dt = CFL * dt_crit; + std::cout << "dt=" << dt << std::endl; + rp.setTimeStep( 1.0, (int)std::round( 1.0 / dt ) ); + + auto func_space = [material_data]( const disk::point< T, 2 > &p ) -> result_type { + const T coeff = 1.0 / ( 1 + material_data.getLambda() ); + T ux = sin( 2 * M_PI * p.y() ) * ( cos( 2 * M_PI * p.x() ) - 1 ) + + coeff * sin( M_PI * p.x() ) * sin( M_PI * p.y() ); + T uy = -sin( 2 * M_PI * p.x() ) * ( cos( 2 * M_PI * p.y() ) - 1 ) + + coeff * sin( M_PI * p.x() ) * sin( M_PI * p.y() ); + + return result_type { ux, uy }; }; - auto displacement = [material_data](const disk::point& p) -> result_type - { - T time = 1.0; - T fx = sin(2 * M_PI * p.y()) * (cos(2 * M_PI * p.x()) - 1) + - 1.0 / (1 + material_data.getLambda()) * sin(M_PI * p.x()) * sin(M_PI * p.y()); - T fy = -sin(2 * M_PI * p.x()) * (cos(2 * M_PI * p.y()) - 1) + - 1.0 / (1 + material_data.getLambda()) * sin(M_PI * p.x()) * sin(M_PI * p.y()); - - return result_type{fx, fy}; + auto displacement = [material_data, func_space]( const disk::point< T, 2 > &p, + const T &time ) -> result_type { + return time * time * func_space( p ); }; - auto velocity = [material_data](const disk::point& p) -> result_type - { - T fx = sin(2 * M_PI * p.y()) * (cos(2 * M_PI * p.x()) - 1) + - 1.0 / (1 + material_data.getLambda()) * sin(M_PI * p.x()) * sin(M_PI * p.y()); - T fy = -sin(2 * M_PI * p.x()) * (cos(2 * M_PI * p.y()) - 1) + - 1.0 / (1 + material_data.getLambda()) * sin(M_PI * p.x()) * sin(M_PI * p.y()); - - return result_type{fx, fy}; + auto velocity = [material_data, func_space]( const disk::point< T, 2 > &p, + const T &time ) -> result_type { + return 2.0 * time * func_space( p ); }; - auto acceleration = [material_data](const disk::point& p) -> result_type { return result_type{0., 0.}; }; + auto acceleration = [material_data, func_space]( const disk::point< T, 2 > &p, + const T &time ) -> result_type { + return 2.0 * func_space( p ); + }; - auto sigma = [material_data](const disk::point& p) -> grad_type - { + auto load = [material_data, acceleration]( const disk::point< T, 2 > &p, + const T &time ) -> result_type { const T lambda = material_data.getLambda(); - const T mu = material_data.getMu(); - - T g11 = - -(2 * (lambda + 1) * sin(2 * M_PI * p.x()) * sin(2 * M_PI * p.y()) - sin(M_PI * p.y()) * cos(M_PI * p.x())); - T g12 = (2 * lambda + 2) * (cos(2 * M_PI * p.x()) - 1) * cos(2 * M_PI * p.y()) + - sin(M_PI * p.x()) * cos(M_PI * p.y()); - - T g21 = (-2 * lambda + 2) * (cos(2 * M_PI * p.y()) - 1) * cos(2 * M_PI * p.x()) + - sin(M_PI * p.y()) * cos(M_PI * p.x()); - - T g22 = - 2 * (lambda + 1) * sin(2 * M_PI * p.x()) * sin(2 * M_PI * p.y()) + sin(M_PI * p.x()) * cos(M_PI * p.y()); - - grad_type g = grad_type::Zero(); - - g(0, 0) = g11; - g(0, 1) = g12; - g(1, 0) = g21; - g(1, 1) = g22; - - g *= M_PI / (lambda + 1); - - const grad_type gs = 0.5 * (g + g.transpose()); - - const T divu = gs.trace(); - - return 2 * mu * gs + lambda * divu * disk::static_matrix::Identity(); + const T mu = material_data.getMu(); + const T rho = material_data.getRho(); + const T pi2t2 = M_PI * M_PI * time * time; + + T fx = -mu * ( 4 * lambda * sin( 2 * M_PI * p.y() ) + 4 * sin( 2 * M_PI * p.y() ) + + cos( M_PI * ( p.x() + p.y() ) ) ) - + ( 1.0 * lambda * cos( M_PI * ( p.x() + p.y() ) ) - + 2.0 * mu * + ( ( 4 * lambda + 4 ) * sin( 2 * M_PI * p.y() ) * cos( 2 * M_PI * p.x() ) + + sin( M_PI * p.x() ) * sin( M_PI * p.y() ) ) ); + T fy = mu * ( 4 * lambda * sin( 2 * M_PI * p.x() ) + 4 * sin( 2 * M_PI * p.x() ) - + cos( M_PI * ( p.x() + p.y() ) ) ) - + ( 1.0 * lambda * cos( M_PI * ( p.x() + p.y() ) ) + + 2.0 * mu * + ( ( 4 * lambda + 4 ) * sin( 2 * M_PI * p.x() ) * cos( 2 * M_PI * p.y() ) - + sin( M_PI * p.x() ) * sin( M_PI * p.y() ) ) ); + + return ( pi2t2 / ( lambda + 1 ) ) * result_type { fx, fy } + rho * acceleration( p, time ); }; - Bnd_type bnd(msh); - bnd.addDirichletEverywhere(displacement); + Bnd_type bnd( msh ); + bnd.addDirichletEverywhere( displacement ); - disk::mechanics::NewtonSolver nl(msh, bnd, rp); + disk::mechanics::NonLinearSolver< mesh_type > nl( msh, bnd, rp ); - nl.addBehavior(disk::DeformationMeasure::SMALL_DEF, disk::LawType::ELASTIC); - nl.addMaterialData(material_data); + nl.addBehavior( disk::mechanics::DeformationMeasure::SMALL_DEF, + disk::mechanics::LawType::ELASTIC ); + nl.addMaterialData( material_data ); + nl.addExternalLoad( load ); - nl.initial_fields(displacement, velocity, acceleration); + nl.initial_field( + disk::mechanics::FieldName::DEPL, + [displacement]( const disk::point< T, 2 > &p ) { return displacement( p, 0.0 ); } ); + nl.initial_field( disk::mechanics::FieldName::VITE_CELLS, + [velocity]( const disk::point< T, 2 > &p ) { return velocity( p, 0.0 ); } ); + nl.initial_field( + disk::mechanics::FieldName::ACCE_CELLS, + [acceleration]( const disk::point< T, 2 > &p ) { return acceleration( p, 0.0 ); } ); - if (nl.verbose()) - { + nl.addPointPlot( { 0.5, 0.5 }, "pointA.csv" ); + + if ( nl.verbose() ) { std::cout << "Solving the problem ..." << '\n'; } - SolverInfo solve_info = nl.compute(load); + disk::mechanics::SolverInfo solve_info = nl.compute(); - if (nl.verbose()) - { + if ( nl.verbose() ) { solve_info.printInfo(); } - error_type error; - error.h = average_diameter(msh); - error.degree = rp.m_face_degree; - error.nb_dof = nl.numberOfDofs(); - error.error_L2 = nl.compute_l2_displacement_error(displacement); - error.error_H1 = nl.compute_H1_error(displacement); + // nl.output_discontinuous_field( "depl_disc.msh", disk::mechanics::FieldName::DEPL_CELLS ); + error_type error; + error.h = average_diameter( msh ); + error.degree = rp.m_face_degree; + error.nb_dof = nl.numberOfDofs(); + error.error_L2 = nl.compute_l2_error( + disk::mechanics::FieldName::DEPL_CELLS, + [displacement]( const disk::point< T, 2 > &p ) { return displacement( p, 1.0 ); } ); + error.error_H1 = nl.compute_l2_error( + disk::mechanics::FieldName::ACCE_CELLS, + [acceleration]( const disk::point< T, 2 > &p ) { return acceleration( p, 1.0 ); } ); + // error.error_H1 = nl.compute_H1_error([displacement](const disk::point &p) + // { return displacement(p, 1.0); }); + + // std::cout << error.error_L2 << ", " << error.error_H1 << std::endl; + // throw std::runtime_error( "error" ); return error; } -template class Mesh, typename T, typename Storage> -error_type -run_linear_elasticity_solver(const Mesh& msh, - const NewtonSolverParameter& rp, - const disk::MaterialData& material_data) -{ - typedef Mesh mesh_type; - typedef disk::static_vector result_type; - typedef disk::static_matrix grad_type; - typedef disk::vector_boundary_conditions Bnd_type; +template < template < typename, size_t, typename > class Mesh, typename T, typename Storage > +error_type run_linear_elasticity_solver( const Mesh< T, 3, Storage > &msh, + disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { + typedef Mesh< T, 3, Storage > mesh_type; + typedef disk::static_vector< T, 3 > result_type; + typedef disk::static_matrix< T, 3, 3 > grad_type; + typedef disk::vector_boundary_conditions< mesh_type > Bnd_type; timecounter tc; tc.tic(); - auto load = [material_data](const disk::point& p, const T& time) -> result_type - { - const T lambda = material_data.getLambda(); - const T mu = material_data.getMu(); - - T fx = - lambda * cos(M_PI * (p.x() + p.y())) - - 2.0 * mu * - ((4 * lambda + 4) * sin(2 * M_PI * p.y()) * cos(2 * M_PI * p.x()) + sin(M_PI * p.x()) * sin(M_PI * p.y())) + - 2.0 * mu * - (2.0 * lambda * sin(2 * M_PI * p.y()) + 2.0 * sin(2 * M_PI * p.y()) + 0.5 * cos(M_PI * (p.x() + p.y()))); - T fy = - lambda * cos(M_PI * (p.x() + p.y())) + - 2.0 * mu * - ((4 * lambda + 4) * sin(2 * M_PI * p.x()) * cos(2 * M_PI * p.y()) - sin(M_PI * p.x()) * sin(M_PI * p.y())) - - 2.0 * mu * - (2.0 * lambda * sin(2 * M_PI * p.x()) + 2.0 * sin(2 * M_PI * p.x()) - 0.5 * cos(M_PI * (p.x() + p.y()))); - - return -M_PI * M_PI / (lambda + 1) * result_type{fx, fy, 0}; - }; - - auto displacement = [material_data](const disk::point& p) -> result_type - { - T fx = sin(2 * M_PI * p.y()) * (cos(2 * M_PI * p.x()) - 1) + - 1.0 / (1 + material_data.getLambda()) * sin(M_PI * p.x()) * sin(M_PI * p.y()); - T fy = -sin(2 * M_PI * p.x()) * (cos(2 * M_PI * p.y()) - 1) + - 1.0 / (1 + material_data.getLambda()) * sin(M_PI * p.x()) * sin(M_PI * p.y()); - - return result_type{fx, fy, 0}; - }; + // check CFL condition + T h_min = minimum_diameter( msh ); + T vp = std::sqrt( ( material_data.getLambda() + 2.0 * material_data.getMu() ) / + material_data.getRho() ); + const auto dt_crit = h_min / vp; + T CFL = 1.0; + if ( rp.getUnsteadyScheme() == disk::mechanics::DynamicType::LEAP_FROG ) { + CFL /= std::max( 1.0, rp.getStabilizationParameter() ); + } + const T dt = CFL * dt_crit; + std::cout << "dt=" << dt << std::endl; + rp.setTimeStep( 1.0, (int)std::round( 1.0 / dt ) ); - auto sigma = [material_data](const disk::point& p) -> grad_type - { + auto load = [material_data]( const disk::point< T, 3 > &p, const T &time ) -> result_type { const T lambda = material_data.getLambda(); - const T mu = material_data.getMu(); - - T g11 = - -(2 * (lambda + 1) * sin(2 * M_PI * p.x()) * sin(2 * M_PI * p.y()) - sin(M_PI * p.y()) * cos(M_PI * p.x())); - T g12 = (2 * lambda + 2) * (cos(2 * M_PI * p.x()) - 1) * cos(2 * M_PI * p.y()) + - sin(M_PI * p.x()) * cos(M_PI * p.y()); - - T g21 = (-2 * lambda + 2) * (cos(2 * M_PI * p.y()) - 1) * cos(2 * M_PI * p.x()) + - sin(M_PI * p.y()) * cos(M_PI * p.x()); - - T g22 = - 2 * (lambda + 1) * sin(2 * M_PI * p.x()) * sin(2 * M_PI * p.y()) + sin(M_PI * p.x()) * cos(M_PI * p.y()); - - grad_type g = grad_type::Zero(); - - g(0, 0) = g11; - g(0, 1) = g12; - g(1, 0) = g21; - g(1, 1) = g22; - - g *= M_PI / (lambda + 1); - - const grad_type gs = 0.5 * (g + g.transpose()); + const T mu = material_data.getMu(); + + T fx = lambda * cos( M_PI * ( p.x() + p.y() ) ) - + 2.0 * mu * + ( ( 4 * lambda + 4 ) * sin( 2 * M_PI * p.y() ) * cos( 2 * M_PI * p.x() ) + + sin( M_PI * p.x() ) * sin( M_PI * p.y() ) ) + + 2.0 * mu * + ( 2.0 * lambda * sin( 2 * M_PI * p.y() ) + 2.0 * sin( 2 * M_PI * p.y() ) + + 0.5 * cos( M_PI * ( p.x() + p.y() ) ) ); + T fy = lambda * cos( M_PI * ( p.x() + p.y() ) ) + + 2.0 * mu * + ( ( 4 * lambda + 4 ) * sin( 2 * M_PI * p.x() ) * cos( 2 * M_PI * p.y() ) - + sin( M_PI * p.x() ) * sin( M_PI * p.y() ) ) - + 2.0 * mu * + ( 2.0 * lambda * sin( 2 * M_PI * p.x() ) + 2.0 * sin( 2 * M_PI * p.x() ) - + 0.5 * cos( M_PI * ( p.x() + p.y() ) ) ); + + return -M_PI * M_PI / ( lambda + 1 ) * result_type { fx, fy, 0 }; + }; - const T divu = gs.trace(); + auto displacement = [material_data]( const disk::point< T, 3 > &p, + const T &time ) -> result_type { + T fx = sin( 2 * M_PI * p.y() ) * ( cos( 2 * M_PI * p.x() ) - 1 ) + + 1.0 / ( 1 + material_data.getLambda() ) * sin( M_PI * p.x() ) * sin( M_PI * p.y() ); + T fy = -sin( 2 * M_PI * p.x() ) * ( cos( 2 * M_PI * p.y() ) - 1 ) + + 1.0 / ( 1 + material_data.getLambda() ) * sin( M_PI * p.x() ) * sin( M_PI * p.y() ); - return 2 * mu * gs + lambda * divu * disk::static_matrix::Identity(); + return time * result_type { fx, fy, 0 }; }; - Bnd_type bnd(msh); - bnd.addDirichletEverywhere(displacement); + Bnd_type bnd( msh ); + bnd.addDirichletEverywhere( displacement ); - disk::mechanics::NewtonSolver nl(msh, bnd, rp); + disk::mechanics::NonLinearSolver< mesh_type > nl( msh, bnd, rp ); - nl.addBehavior(disk::DeformationMeasure::SMALL_DEF, disk::LawType::ELASTIC); - nl.addMaterialData(material_data); + nl.addBehavior( disk::mechanics::DeformationMeasure::SMALL_DEF, + disk::mechanics::LawType::ELASTIC ); + nl.addMaterialData( material_data ); + nl.addExternalLoad( load ); - nl.initial_guess(displacement); + nl.initial_field( + disk::mechanics::FieldName::DEPL, + [displacement]( const disk::point< T, 3 > &p ) { return displacement( p, 0.0 ); } ); - if (nl.verbose()) - { + if ( nl.verbose() ) { std::cout << "Solving the problem ..." << '\n'; } - SolverInfo solve_info = nl.compute(load); + disk::mechanics::SolverInfo solve_info = nl.compute(); - if (nl.verbose()) - { + if ( nl.verbose() ) { solve_info.printInfo(); } error_type error; - error.h = average_diameter(msh); - error.degree = rp.m_face_degree; - error.nb_dof = nl.numberOfDofs(); - error.error_L2 = nl.compute_l2_displacement_error(displacement); - error.error_H1 = nl.compute_H1_error(displacement); + error.h = average_diameter( msh ); + error.degree = rp.m_face_degree; + error.nb_dof = nl.numberOfDofs(); + error.error_L2 = nl.compute_l2_displacement_error( + [displacement]( const disk::point< T, 3 > &p ) { return displacement( p, 1.0 ); } ); + error.error_H1 = nl.compute_H1_error( + [displacement]( const disk::point< T, 3 > &p ) { return displacement( p, 1.0 ); } ); return error; } -void -printResults(const std::vector& error) -{ - if (error.size() > 0) - { - std::ios::fmtflags f(std::cout.flags()); - std::cout.precision(4); - std::cout.setf(std::iostream::scientific, std::iostream::floatfield); +void printResults( const std::vector< error_type > &error ) { + if ( error.size() > 0 ) { + std::ios::fmtflags f( std::cout.flags() ); + std::cout.precision( 4 ); + std::cout.setf( std::iostream::scientific, std::iostream::floatfield ); std::cout << "Convergence test for k = " << error[0].degree << std::endl; - std::cout << "-----------------------------------------------------------------------------------" << std::endl; - std::cout << "| Size mesh | L2 error | Convergence | H1 error | Convergence | Total |" << std::endl; - std::cout << "| h | | rate | | rate | faces DOF |" << std::endl; - std::cout << "-----------------------------------------------------------------------------------" << std::endl; - - std::string s_dof = " " + std::to_string(error[0].nb_dof) + " "; - s_dof.resize(10); + std::cout + << "-----------------------------------------------------------------------------------" + << std::endl; + std::cout + << "| Size mesh | L2 error | Convergence | H1 error | Convergence | Total |" + << std::endl; + std::cout + << "| h | | rate | | rate | faces DOF |" + << std::endl; + std::cout + << "-----------------------------------------------------------------------------------" + << std::endl; + + std::string s_dof = " " + std::to_string( error[0].nb_dof ) + " "; + s_dof.resize( 10 ); std::cout << "| " << error[0].h << " | " << error[0].error_L2 << " | " << " - " @@ -310,358 +300,403 @@ printResults(const std::vector& error) << " - " << " | " << s_dof << " |" << std::endl; - for (int i = 1; i < error.size(); i++) - { - s_dof = " " + std::to_string(error[i].nb_dof) + " "; - s_dof.resize(10); - double rate_depl = - (log10(error[i - 1].error_L2) - log10(error[i].error_L2)) / (log10(error[i - 1].h) - log10(error[i].h)); - double rate_stress = - (log10(error[i - 1].error_H1) - log10(error[i].error_H1)) / (log10(error[i - 1].h) - log10(error[i].h)); - - std::cout << "| " << error[i].h << " | " << error[i].error_L2 << " | " << rate_depl << " | " - << error[i].error_H1 << " | " << rate_stress << " | " << s_dof << " |" << std::endl; + for ( int i = 1; i < error.size(); i++ ) { + s_dof = " " + std::to_string( error[i].nb_dof ) + " "; + s_dof.resize( 10 ); + double rate_depl = ( log10( error[i - 1].error_L2 ) - log10( error[i].error_L2 ) ) / + ( log10( error[i - 1].h ) - log10( error[i].h ) ); + double rate_stress = ( log10( error[i - 1].error_H1 ) - log10( error[i].error_H1 ) ) / + ( log10( error[i - 1].h ) - log10( error[i].h ) ); + + std::cout << "| " << error[i].h << " | " << error[i].error_L2 << " | " << rate_depl + << " | " << error[i].error_H1 << " | " << rate_stress << " | " << s_dof + << " |" << std::endl; } - std::cout << "-----------------------------------------------------------------------------------" << std::endl; + std::cout + << "-----------------------------------------------------------------------------------" + << std::endl; std::cout << " " << std::endl; - std::cout.flags(f); - } - else + std::cout.flags( f ); + } else std::cout << "The file error is empty" << std::endl; } -template -void -test_triangles_fvca5(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_triangles_fvca5( disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_1.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_2.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_3.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_4.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_5.typ1" ); - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_triangles_netgen(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_triangles_netgen( disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri01.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri02.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri03.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri04.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri05.mesh2d"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_triangles/netgen/tri01.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri02.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri03.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri04.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri05.mesh2d" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::simplicial_mesh msh; - disk::load_mesh_netgen(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::simplicial_mesh< T, 2 > msh; + disk::load_mesh_netgen( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_hexagons(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_hexagons( disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 5; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_1.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_2.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_3.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_4.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_5.typ1" ); - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_kershaws(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_kershaws( disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 5; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_1.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_2.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_3.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_4.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_5.typ1" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_quads_fvca5(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_quads_fvca5( disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 5; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_1.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_2.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_3.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_4.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_5.typ1" ); - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_quads_diskpp(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_quads_diskpp( disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-4-4.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-8-8.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-16-16.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-32-32.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-256-256.quad"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-4-4.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-8-8.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-16-16.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-32-32.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-256-256.quad" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::cartesian_mesh msh; - disk::load_mesh_diskpp_cartesian(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::cartesian_mesh< T, 2 > msh; + disk::load_mesh_diskpp_cartesian( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_hexahedra_diskpp(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_hexahedra_diskpp( disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-2-2-2.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-4-4-4.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-8-8-8.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-16-16-16.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-32-32-32.hex"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-2-2-2.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-4-4-4.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-8-8-8.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-16-16-16.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-32-32-32.hex" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::cartesian_mesh msh; - disk::load_mesh_diskpp_cartesian(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::cartesian_mesh< T, 3 > msh; + disk::load_mesh_diskpp_cartesian( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_hexahedra_fvca6(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_hexahedra_fvca6( disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_2x2x2.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_4x4x4.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_8x8x8.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_16x16x16.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_32x32x32.hex"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_2x2x2.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_4x4x4.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_8x8x8.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_16x16x16.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_32x32x32.hex" ); - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca6_3d(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 3 > msh; + disk::load_mesh_fvca6_3d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_tetrahedra_netgen(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_tetrahedra_netgen( disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet0.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet1.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet2.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet3.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet4.mesh"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet0.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet1.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet2.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet3.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet4.mesh" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::simplicial_mesh msh; - disk::load_mesh_netgen(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::simplicial_mesh< T, 3 > msh; + disk::load_mesh_netgen( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_polyhedra_fvca6(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_polyhedra_fvca6( disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 3; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_10.msh"); - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_20.msh"); - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_30.msh"); - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_40.msh"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_10.msh" ); + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_20.msh" ); + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_30.msh" ); + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_40.msh" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca6_3d(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 3 > msh; + disk::load_mesh_fvca6_3d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_tetrahedra_fvca6(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_tetrahedra_fvca6( disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.0.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.1.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.2.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.3.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.4.msh"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.0.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.1.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.2.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.3.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.4.msh" ); - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca6_3d(paths[i].c_str(), msh); - error_sumup.push_back(run_linear_elasticity_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 3 > msh; + disk::load_mesh_fvca6_3d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_linear_elasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -int -main(int argc, char** argv) -{ +int main( int argc, char **argv ) { using RealType = double; - int degree = 1; - int l = 0; - int dim = 2; + int degree = 1; + int l = 0; + int dim = 2; bool verbose = false; int ch; - while ((ch = getopt(argc, argv, "23k:l:v")) != -1) - { - switch (ch) - { - case '2': dim = 2; break; - case '3': dim = 3; break; - - case 'k': - degree = atoi(optarg); - if (degree < 0) - { - std::cout << "Degree must be positive. Falling back to 1." << std::endl; - degree = 1; - } - break; - - case 'l': - l = atoi(optarg); - if (l < -1 or l > 1) - { - std::cout << "l can be -1, 0 or 1. Falling back to 0." << std::endl; - l = 0; - } - break; - - case 'v': verbose = true; break; - - case '?': - default: - std::cout << "wrong arguments" << std::endl; - usage(argv[0]); - exit(1); + while ( ( ch = getopt( argc, argv, "23k:l:v" ) ) != -1 ) { + switch ( ch ) { + case '2': + dim = 2; + break; + case '3': + dim = 3; + break; + + case 'k': + degree = atoi( optarg ); + if ( degree < 0 ) { + std::cout << "Degree must be positive. Falling back to 1." << std::endl; + degree = 1; + } + break; + + case 'l': + l = atoi( optarg ); + if ( l < -1 or l > 1 ) { + std::cout << "l can be -1, 0 or 1. Falling back to 0." << std::endl; + l = 0; + } + break; + + case 'v': + verbose = true; + break; + + case '?': + default: + std::cout << "wrong arguments" << std::endl; + usage( argv[0] ); + exit( 1 ); } } // Elasticity Parameters - disk::MaterialData material_data; - material_data.setMu(1.0); - material_data.setLambda(1.0); - - NewtonSolverParameter rp; - rp.setFaceDegree(degree); - rp.setGradDegree(degree); - rp.setCellDegree(degree + l); - rp.setStabilizationParameter(2.0 * material_data.getMu()); - rp.setVerbose(verbose); - rp.setPrecomputation(true); - rp.isUnsteady(true); - - std::map dyna_para; - dyna_para["rho"] = 1.0; - dyna_para["beta"] = 0.25; + disk::mechanics::MaterialData< RealType > material_data; + material_data.setMu( 1.0 ); + material_data.setLambda( 1.0 ); + material_data.setRho( 1.0 ); + + disk::mechanics::NonLinearParameters< RealType > rp; + rp.setFaceDegree( degree ); + rp.setGradDegree( degree ); + rp.setCellDegree( degree + l ); + rp.setStabilizationParameter( 10.0 * material_data.getMu() ); + rp.setVerbose( verbose ); + rp.setPrecomputation( true ); + + std::map< std::string, RealType > dyna_para; + dyna_para["beta"] = 1. / 4.; dyna_para["gamma"] = 0.5; - rp.setUnsteadyParameters(dyna_para); - rp.setTimeStep(1.0, 10); + dyna_para["theta"] = 1.0; + + rp.setUnsteadyScheme( disk::mechanics::DynamicType::LEAP_FROG ); + rp.setUnsteadyParameters( dyna_para ); + +#ifdef NSM_USE_MUMPS + rp.setLinearSolver( disk::solvers::direct_solver::mumps ); +#endif + rp.setNonLinearSolver( disk::mechanics::NonLinearSolverType::QNEWTON_BDIAG_STAB ); + rp.setMaximumNumberNLIteration( 1000 ); + + rp.setConvergenceCriteria( 1.e-7 ); + rp.setLineSearch( disk::mechanics::LineSearchType::ANDERSON4 ); argc -= optind; argv += optind; @@ -673,86 +708,83 @@ main(int argc, char** argv) std::cout << " ** Cell_Degree = " << rp.getCellDegree() << std::endl; std::cout << " " << std::endl; - if (dim == 3) - { - tc.tic(); - std::cout << "-Tetrahedras fvca6:" << std::endl; - test_tetrahedra_fvca6(rp, material_data); - tc.toc(); - std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; - std::cout << " " << std::endl; - - tc.tic(); - std::cout << "-Tetrahedras netgen:" << std::endl; - test_tetrahedra_netgen(rp, material_data); - tc.toc(); - std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; - std::cout << " " << std::endl; - - tc.tic(); - std::cout << "-Hexahedras fvca6:" << std::endl; - test_hexahedra_fvca6(rp, material_data); - tc.toc(); - std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; - std::cout << " " << std::endl; - - tc.tic(); - std::cout << "-Hexahedras diskpp:" << std::endl; - test_hexahedra_diskpp(rp, material_data); - tc.toc(); - std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; - std::cout << " " << std::endl; - - tc.tic(); - std::cout << "-Polyhedra:" << std::endl; - test_polyhedra_fvca6(rp, material_data); - tc.toc(); - std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; - std::cout << " " << std::endl; - } - else if (dim == 2) - { + if ( dim == 3 ) { + // tc.tic(); + // std::cout << "-Tetrahedras fvca6:" << std::endl; + // test_tetrahedra_fvca6(rp, material_data); + // tc.toc(); + // std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; + // std::cout << " " << std::endl; + + // tc.tic(); + // std::cout << "-Tetrahedras netgen:" << std::endl; + // test_tetrahedra_netgen(rp, material_data); + // tc.toc(); + // std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; + // std::cout << " " << std::endl; + + // tc.tic(); + // std::cout << "-Hexahedras fvca6:" << std::endl; + // test_hexahedra_fvca6(rp, material_data); + // tc.toc(); + // std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; + // std::cout << " " << std::endl; + + // tc.tic(); + // std::cout << "-Hexahedras diskpp:" << std::endl; + // test_hexahedra_diskpp(rp, material_data); + // tc.toc(); + // std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; + // std::cout << " " << std::endl; + + // tc.tic(); + // std::cout << "-Polyhedra:" << std::endl; + // test_polyhedra_fvca6(rp, material_data); + // tc.toc(); + // std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; + // std::cout << " " << std::endl; + } else if ( dim == 2 ) { tc.tic(); std::cout << "-Triangles fvca5:" << std::endl; - test_triangles_fvca5(rp, material_data); - tc.toc(); - std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; - std::cout << " " << std::endl; - - tc.tic(); - std::cout << "-Triangles netgen:" << std::endl; - test_triangles_netgen(rp, material_data); + test_triangles_fvca5< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; - tc.tic(); - std::cout << "-Quadrangles fvca5:" << std::endl; - test_quads_fvca5(rp, material_data); - tc.toc(); - std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; - std::cout << " " << std::endl; - - tc.tic(); - std::cout << "-Quadrangles diskpp:" << std::endl; - test_quads_diskpp(rp, material_data); - tc.toc(); - std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; - std::cout << " " << std::endl; - - tc.tic(); - std::cout << "-Hexagons:" << std::endl; - test_hexagons(rp, material_data); - tc.toc(); - std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; - std::cout << " " << std::endl; - - tc.tic(); - std::cout << "-Kershaws:" << std::endl; - test_kershaws(rp, material_data); - tc.toc(); - std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; - std::cout << " " << std::endl; + // tc.tic(); + // std::cout << "-Triangles netgen:" << std::endl; + // test_triangles_netgen(rp, material_data); + // tc.toc(); + // std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; + // std::cout << " " << std::endl; + + // tc.tic(); + // std::cout << "-Quadrangles fvca5:" << std::endl; + // test_quads_fvca5(rp, material_data); + // tc.toc(); + // std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; + // std::cout << " " << std::endl; + + // tc.tic(); + // std::cout << "-Quadrangles diskpp:" << std::endl; + // test_quads_diskpp(rp, material_data); + // tc.toc(); + // std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; + // std::cout << " " << std::endl; + + // tc.tic(); + // std::cout << "-Hexagons:" << std::endl; + // test_hexagons(rp, material_data); + // tc.toc(); + // std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; + // std::cout << " " << std::endl; + + // tc.tic(); + // std::cout << "-Kershaws:" << std::endl; + // test_kershaws(rp, material_data); + // tc.toc(); + // std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; + // std::cout << " " << std::endl; } -} \ No newline at end of file +} diff --git a/apps/nonlinear_solid_mechanics/src/hyperelasticity_test.cpp b/apps/nonlinear_solid_mechanics/src/hyperelasticity_test.cpp index 3575351b..140e174b 100644 --- a/apps/nonlinear_solid_mechanics/src/hyperelasticity_test.cpp +++ b/apps/nonlinear_solid_mechanics/src/hyperelasticity_test.cpp @@ -23,116 +23,109 @@ * DOI: 10.1016/j.cam.2017.09.017 */ +#include "diskpp/boundary_conditions/boundary_conditions.hpp" +#include "diskpp/common/colormanip.h" +#include "diskpp/loaders/loader.hpp" +#include "diskpp/mechanics/NewtonSolver/NonLinearSolver.hpp" +#include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" + #include #include #include #include -#include -#include "diskpp/boundary_conditions/boundary_conditions.hpp" -#include "diskpp/common/colormanip.h" -#include "diskpp/loaders/loader.hpp" -#include "diskpp/mechanics/NewtonSolver/NewtonSolver.hpp" -#include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" +#include -struct error_type -{ - int degree; - int nb_dof; +struct error_type { + int degree; + int nb_dof; double h; double error_L2; double error_H1; }; -void -usage(const char* progname) -{ - printf("Usage: %s \n\n", progname); - printf(" -2: test 2D mesh (default)\n"); - printf(" -3: test 3D mesh\n"); - printf(" -k: face degree (>=0)\n"); - printf(" -l: difference beetween cell and face degree (-1 <= l <= 1) \n"); - printf(" -v: verbose\n"); +void usage( const char *progname ) { + printf( "Usage: %s \n\n", progname ); + printf( " -2: test 2D mesh (default)\n" ); + printf( " -3: test 3D mesh\n" ); + printf( " -k: face degree (>=0)\n" ); + printf( " -l: difference beetween cell and face degree (-1 <= l <= 1) \n" ); + printf( " -v: verbose\n" ); } -template class Mesh, typename T, typename Storage> -error_type -run_hyperelasticity_solver(const Mesh& msh, - const NewtonSolverParameter& rp, - const disk::MaterialData& material_data) -{ - typedef Mesh mesh_type; - typedef disk::static_vector result_type; - typedef disk::static_matrix grad_type; - typedef disk::vector_boundary_conditions Bnd_type; +template < template < typename, size_t, typename > class Mesh, typename T, typename Storage > +error_type run_hyperelasticity_solver( const Mesh< T, 2, Storage > &msh, + const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { + typedef Mesh< T, 2, Storage > mesh_type; + typedef disk::static_vector< T, 2 > result_type; + typedef disk::static_matrix< T, 2, 2 > grad_type; + typedef disk::vector_boundary_conditions< mesh_type > Bnd_type; timecounter tc; tc.tic(); const T alpha = 0.1; - auto load = [material_data, alpha](const disk::point& p, const T& time) -> result_type - { + auto load = [material_data, alpha]( const disk::point< T, 2 > &p, + const T &time ) -> result_type { const T lambda = material_data.getLambda(); - const T mu = material_data.getMu(); + const T mu = material_data.getMu(); T fx = 0.0; - T fy = 8 * mu * alpha * M_PI * M_PI * cos(2 * M_PI * p.x()); + T fy = 8 * mu * alpha * M_PI * M_PI * cos( 2 * M_PI * p.x() ); - return result_type{fx, fy}; + return result_type { fx, fy }; }; - auto solution = [material_data, alpha](const disk::point& p) -> result_type - { - T ux = (1.0 / material_data.getLambda() + alpha) * p.x(); - T uy = - (1.0 / material_data.getLambda() - alpha / (1.0 + alpha)) * p.y() + 2 * alpha * (cos(2 * M_PI * p.x()) - 1.0); + auto solution = [material_data, alpha]( const disk::point< T, 2 > &p ) -> result_type { + T ux = ( 1.0 / material_data.getLambda() + alpha ) * p.x(); + T uy = ( 1.0 / material_data.getLambda() - alpha / ( 1.0 + alpha ) ) * p.y() + + 2 * alpha * ( cos( 2 * M_PI * p.x() ) - 1.0 ); - return result_type{ux, uy}; + return result_type { ux, uy }; }; - Bnd_type bnd(msh); - bnd.addDirichletEverywhere(solution); + Bnd_type bnd( msh ); + bnd.addDirichletEverywhere( solution ); - disk::mechanics::NewtonSolver nl(msh, bnd, rp); + disk::mechanics::NonLinearSolver< mesh_type > nl( msh, bnd, rp ); - nl.addBehavior(disk::DeformationMeasure::F_DEF, disk::LawType::NEOHOKEAN); - nl.addMaterialData(material_data); + nl.addBehavior( disk::mechanics::DeformationMeasure::F_DEF, + disk::mechanics::LawType::NEOHOKEAN ); + nl.addMaterialData( material_data ); + nl.addExternalLoad( load ); - nl.initial_guess(solution); + nl.initial_guess( solution ); - if (nl.verbose()) - { + if ( nl.verbose() ) { std::cout << "Solving the problem ..." << '\n'; } - SolverInfo solve_info = nl.compute(load); + disk::mechanics::SolverInfo solve_info = nl.compute(); - if (nl.verbose()) - { + if ( nl.verbose() ) { solve_info.printInfo(); } error_type error; - error.h = average_diameter(msh); - error.degree = rp.m_face_degree; - error.nb_dof = nl.numberOfDofs(); - error.error_L2 = nl.compute_l2_displacement_error(solution); - error.error_H1 = nl.compute_H1_error(solution); + error.h = average_diameter( msh ); + error.degree = rp.m_face_degree; + error.nb_dof = nl.numberOfDofs(); + error.error_L2 = nl.compute_l2_displacement_error( solution ); + error.error_H1 = nl.compute_H1_error( solution ); return error; } -template class Mesh, typename T, typename Storage> -error_type -run_hyperelasticity_solver(const Mesh& msh, - const NewtonSolverParameter& rp, - const disk::MaterialData& material_data) -{ - typedef Mesh mesh_type; - typedef disk::static_vector result_type; - typedef disk::static_matrix grad_type; - typedef disk::vector_boundary_conditions Bnd_type; +template < template < typename, size_t, typename > class Mesh, typename T, typename Storage > +error_type run_hyperelasticity_solver( const Mesh< T, 3, Storage > &msh, + const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { + typedef Mesh< T, 3, Storage > mesh_type; + typedef disk::static_vector< T, 3 > result_type; + typedef disk::static_matrix< T, 3, 3 > grad_type; + typedef disk::vector_boundary_conditions< mesh_type > Bnd_type; timecounter tc; tc.tic(); @@ -140,77 +133,80 @@ run_hyperelasticity_solver(const Mesh& msh, const T alpha = 0.1; const T gamma = 0.1; - auto load = [material_data, alpha, gamma](const disk::point& p, const T& time) -> result_type - { + auto load = [material_data, alpha, gamma]( const disk::point< T, 3 > &p, + const T &time ) -> result_type { const T lambda = material_data.getLambda(); - const T mu = material_data.getMu(); + const T mu = material_data.getMu(); - T fx = alpha * sin(M_PI * p.y()); - T fz = gamma * sin(M_PI * p.x()); + T fx = alpha * sin( M_PI * p.y() ); + T fz = gamma * sin( M_PI * p.x() ); - return mu * M_PI * M_PI * result_type{fx, 0, fz}; + return mu * M_PI * M_PI * result_type { fx, 0, fz }; }; - auto solution = [material_data, alpha, gamma](const disk::point& p) -> result_type - { - T ux = (1.0 / material_data.getLambda() + alpha) * p.x() + alpha * sin(M_PI * p.y()); - T uy = - -(1.0 / material_data.getLambda() + (alpha + gamma + alpha * gamma) / (1.0 + alpha + gamma + alpha * gamma)) * - p.y(); - T uz = (1.0 / material_data.getLambda() + gamma) * p.z() + gamma * sin(M_PI * p.x()); + auto solution = [material_data, alpha, gamma]( const disk::point< T, 3 > &p ) -> result_type { + T ux = ( 1.0 / material_data.getLambda() + alpha ) * p.x() + alpha * sin( M_PI * p.y() ); + T uy = -( 1.0 / material_data.getLambda() + + ( alpha + gamma + alpha * gamma ) / ( 1.0 + alpha + gamma + alpha * gamma ) ) * + p.y(); + T uz = ( 1.0 / material_data.getLambda() + gamma ) * p.z() + gamma * sin( M_PI * p.x() ); - return result_type{ux, uy, uz}; + return result_type { ux, uy, uz }; }; - Bnd_type bnd(msh); - bnd.addDirichletEverywhere(solution); - - disk::mechanics::NewtonSolver nl(msh, bnd, rp); + Bnd_type bnd( msh ); + bnd.addDirichletEverywhere( solution ); - nl.addBehavior(disk::DeformationMeasure::F_DEF, disk::LawType::NEOHOKEAN); - nl.addMaterialData(material_data); + disk::mechanics::NonLinearSolver< mesh_type > nl( msh, bnd, rp ); - nl.initial_guess(solution); + nl.addBehavior( disk::mechanics::DeformationMeasure::F_DEF, + disk::mechanics::LawType::NEOHOKEAN ); + nl.addMaterialData( material_data ); + nl.addExternalLoad( load ); + nl.initial_guess( solution ); - if (nl.verbose()) - { + if ( nl.verbose() ) { std::cout << "Solving the problem ..." << '\n'; } - SolverInfo solve_info = nl.compute(load); + disk::mechanics::SolverInfo solve_info = nl.compute(); - if (nl.verbose()) - { + if ( nl.verbose() ) { solve_info.printInfo(); } error_type error; - error.h = average_diameter(msh); - error.degree = rp.m_face_degree; - error.nb_dof = nl.numberOfDofs(); - error.error_L2 = nl.compute_l2_displacement_error(solution); - error.error_H1 = nl.compute_H1_error(solution); + error.h = average_diameter( msh ); + error.degree = rp.m_face_degree; + error.nb_dof = nl.numberOfDofs(); + error.error_L2 = nl.compute_l2_displacement_error( solution ); + error.error_H1 = nl.compute_H1_error( solution ); return error; } -void -printResults(const std::vector& error) -{ - if (error.size() > 0) - { - std::ios::fmtflags f(std::cout.flags()); - std::cout.precision(4); - std::cout.setf(std::iostream::scientific, std::iostream::floatfield); +void printResults( const std::vector< error_type > &error ) { + if ( error.size() > 0 ) { + std::ios::fmtflags f( std::cout.flags() ); + std::cout.precision( 4 ); + std::cout.setf( std::iostream::scientific, std::iostream::floatfield ); std::cout << "Convergence test for k = " << error[0].degree << std::endl; - std::cout << "-----------------------------------------------------------------------------------" << std::endl; - std::cout << "| Size mesh | L2 error | Convergence | H1 error | Convergence | Total |" << std::endl; - std::cout << "| h | | rate | | rate | faces DOF |" << std::endl; - std::cout << "-----------------------------------------------------------------------------------" << std::endl; - - std::string s_dof = " " + std::to_string(error[0].nb_dof) + " "; - s_dof.resize(10); + std::cout + << "-----------------------------------------------------------------------------------" + << std::endl; + std::cout + << "| Size mesh | L2 error | Convergence | H1 error | Convergence | Total |" + << std::endl; + std::cout + << "| h | | rate | | rate | faces DOF |" + << std::endl; + std::cout + << "-----------------------------------------------------------------------------------" + << std::endl; + + std::string s_dof = " " + std::to_string( error[0].nb_dof ) + " "; + s_dof.resize( 10 ); std::cout << "| " << error[0].h << " | " << error[0].error_L2 << " | " << " - " @@ -218,349 +214,386 @@ printResults(const std::vector& error) << " - " << " | " << s_dof << " |" << std::endl; - for (int i = 1; i < error.size(); i++) - { - s_dof = " " + std::to_string(error[i].nb_dof) + " "; - s_dof.resize(10); - double rate_depl = - (log10(error[i - 1].error_L2) - log10(error[i].error_L2)) / (log10(error[i - 1].h) - log10(error[i].h)); - double rate_stress = - (log10(error[i - 1].error_H1) - log10(error[i].error_H1)) / (log10(error[i - 1].h) - log10(error[i].h)); - - std::cout << "| " << error[i].h << " | " << error[i].error_L2 << " | " << rate_depl << " | " - << error[i].error_H1 << " | " << rate_stress << " | " << s_dof << " |" << std::endl; + for ( int i = 1; i < error.size(); i++ ) { + s_dof = " " + std::to_string( error[i].nb_dof ) + " "; + s_dof.resize( 10 ); + double rate_depl = ( log10( error[i - 1].error_L2 ) - log10( error[i].error_L2 ) ) / + ( log10( error[i - 1].h ) - log10( error[i].h ) ); + double rate_stress = ( log10( error[i - 1].error_H1 ) - log10( error[i].error_H1 ) ) / + ( log10( error[i - 1].h ) - log10( error[i].h ) ); + + std::cout << "| " << error[i].h << " | " << error[i].error_L2 << " | " << rate_depl + << " | " << error[i].error_H1 << " | " << rate_stress << " | " << s_dof + << " |" << std::endl; } - std::cout << "-----------------------------------------------------------------------------------" << std::endl; + std::cout + << "-----------------------------------------------------------------------------------" + << std::endl; std::cout << " " << std::endl; - std::cout.flags(f); - } - else + std::cout.flags( f ); + } else std::cout << "The file error is empty" << std::endl; } -template -void -test_triangles_fvca5(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_triangles_fvca5( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_triangles/fvca5/mesh1_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_1.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_2.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_3.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_4.typ1" ); + paths.push_back( mesh_base + "/2D_triangles/fvca5/mesh1_5.typ1" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_hyperelasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_hyperelasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_triangles_netgen(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_triangles_netgen( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri01.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri02.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri03.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri04.mesh2d"); - paths.push_back("../../../diskpp/meshes/2D_triangles/netgen/tri05.mesh2d"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_triangles/netgen/tri01.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri02.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri03.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri04.mesh2d" ); + paths.push_back( mesh_base + "/2D_triangles/netgen/tri05.mesh2d" ); - for (int i = 0; i < runs; i++) - { - disk::simplicial_mesh msh; - disk::load_mesh_netgen(paths[i].c_str(), msh); - error_sumup.push_back(run_hyperelasticity_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::simplicial_mesh< T, 2 > msh; + disk::load_mesh_netgen( paths[i].c_str(), msh ); + error_sumup.push_back( run_hyperelasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_hexagons(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_hexagons( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 5; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_hex/fvca5/hexagonal_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_1.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_2.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_3.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_4.typ1" ); + paths.push_back( mesh_base + "/2D_hex/fvca5/hexagonal_5.typ1" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_hyperelasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_hyperelasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_kershaws(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_kershaws( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 5; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_kershaw/fvca5/mesh4_1_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_1.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_2.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_3.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_4.typ1" ); + paths.push_back( mesh_base + "/2D_kershaw/fvca5/mesh4_1_5.typ1" ); - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_hyperelasticity_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_hyperelasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_quads_fvca5(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_quads_fvca5( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 5; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_1.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_2.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_3.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_4.typ1"); - paths.push_back("../../../diskpp/meshes/2D_quads/fvca5/mesh2_5.typ1"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_1.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_2.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_3.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_4.typ1" ); + paths.push_back( mesh_base + "/2D_quads/fvca5/mesh2_5.typ1" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca5_2d(paths[i].c_str(), msh); - error_sumup.push_back(run_hyperelasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 2 > msh; + disk::load_mesh_fvca5_2d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_hyperelasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_quads_diskpp(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_quads_diskpp( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-4-4.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-8-8.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-16-16.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-32-32.quad"); - paths.push_back("../../../diskpp/meshes/2D_quads/diskpp/testmesh-256-256.quad"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-4-4.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-8-8.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-16-16.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-32-32.quad" ); + paths.push_back( mesh_base + "/2D_quads/diskpp/testmesh-256-256.quad" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::cartesian_mesh msh; - disk::load_mesh_diskpp_cartesian(paths[i].c_str(), msh); - error_sumup.push_back(run_hyperelasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::cartesian_mesh< T, 2 > msh; + disk::load_mesh_diskpp_cartesian( paths[i].c_str(), msh ); + error_sumup.push_back( run_hyperelasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_hexahedra_diskpp(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_hexahedra_diskpp( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-2-2-2.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-4-4-4.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-8-8-8.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-16-16-16.hex"); - paths.push_back("../../../diskpp/meshes/3D_hexa/diskpp/testmesh-32-32-32.hex"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-2-2-2.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-4-4-4.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-8-8-8.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-16-16-16.hex" ); + paths.push_back( mesh_base + "/3D_hexa/diskpp/testmesh-32-32-32.hex" ); - for (int i = 0; i < runs; i++) - { - disk::cartesian_mesh msh; - disk::load_mesh_diskpp_cartesian(paths[i].c_str(), msh); - error_sumup.push_back(run_hyperelasticity_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::cartesian_mesh< T, 3 > msh; + disk::load_mesh_diskpp_cartesian( paths[i].c_str(), msh ); + error_sumup.push_back( run_hyperelasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_hexahedra_fvca6(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_hexahedra_fvca6( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_2x2x2.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_4x4x4.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_8x8x8.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_16x16x16.msh"); - paths.push_back("../../../diskpp/meshes/3D_hexa/fvca6/hexa_32x32x32.hex"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_2x2x2.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_4x4x4.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_8x8x8.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_16x16x16.msh" ); + paths.push_back( mesh_base + "/3D_hexa/fvca6/hexa_32x32x32.hex" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca6_3d(paths[i].c_str(), msh); - error_sumup.push_back(run_hyperelasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 3 > msh; + disk::load_mesh_fvca6_3d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_hyperelasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_tetrahedra_netgen(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_tetrahedra_netgen( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet0.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet1.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet2.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet3.mesh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/netgen/fvca6_tet4.mesh"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet0.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet1.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet2.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet3.mesh" ); + paths.push_back( mesh_base + "/3D_tetras/netgen/fvca6_tet4.mesh" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::simplicial_mesh msh; - disk::load_mesh_netgen(paths[i].c_str(), msh); - error_sumup.push_back(run_hyperelasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::simplicial_mesh< T, 3 > msh; + disk::load_mesh_netgen( paths[i].c_str(), msh ); + error_sumup.push_back( run_hyperelasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_polyhedra_fvca6(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_polyhedra_fvca6( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 3; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_10.msh"); - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_20.msh"); - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_30.msh"); - paths.push_back("../../../diskpp/meshes/3D_general/fvca6/dbls_40.msh"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; - std::vector error_sumup; + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_10.msh" ); + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_20.msh" ); + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_30.msh" ); + paths.push_back( mesh_base + "/3D_general/fvca6/dbls_40.msh" ); - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca6_3d(paths[i].c_str(), msh); - error_sumup.push_back(run_hyperelasticity_solver(msh, rp, material_data)); + std::vector< error_type > error_sumup; + + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 3 > msh; + disk::load_mesh_fvca6_3d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_hyperelasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -template -void -test_tetrahedra_fvca6(const NewtonSolverParameter& rp, const disk::MaterialData& material_data) -{ +template < typename T > +void test_tetrahedra_fvca6( const disk::mechanics::NonLinearParameters< T > &rp, + const disk::mechanics::MaterialData< T > &material_data ) { int runs = 4; - std::vector paths; - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.0.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.1.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.2.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.3.msh"); - paths.push_back("../../../diskpp/meshes/3D_tetras/fvca6/tet.4.msh"); + char *env_mesh_base = getenv("DISKPP_MESH_PATH"); + std::string mesh_base = "../../../diskpp/meshes/"; + if (env_mesh_base) + mesh_base = env_mesh_base; + + std::vector< std::string > paths; + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.0.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.1.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.2.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.3.msh" ); + paths.push_back( mesh_base + "/3D_tetras/fvca6/tet.4.msh" ); - std::vector error_sumup; + std::vector< error_type > error_sumup; - for (int i = 0; i < runs; i++) - { - disk::generic_mesh msh; - disk::load_mesh_fvca6_3d(paths[i].c_str(), msh); - error_sumup.push_back(run_hyperelasticity_solver(msh, rp, material_data)); + for ( int i = 0; i < runs; i++ ) { + disk::generic_mesh< T, 3 > msh; + disk::load_mesh_fvca6_3d< T >( paths[i].c_str(), msh ); + error_sumup.push_back( run_hyperelasticity_solver( msh, rp, material_data ) ); } - printResults(error_sumup); + printResults( error_sumup ); } -int -main(int argc, char** argv) -{ +int main( int argc, char **argv ) { using RealType = double; - int degree = 1; - int l = 0; - int dim = 2; + int degree = 1; + int l = 0; + int dim = 2; bool verbose = false; int ch; - while ((ch = getopt(argc, argv, "23k:l:v")) != -1) - { - switch (ch) - { - case '2': dim = 2; break; - case '3': dim = 3; break; - - case 'k': - degree = atoi(optarg); - if (degree < 0) - { - std::cout << "Degree must be positive. Falling back to 1." << std::endl; - degree = 1; - } - break; - - case 'l': - l = atoi(optarg); - if (l < -1 or l > 1) - { - std::cout << "l can be -1, 0 or 1. Falling back to 0." << std::endl; - l = 0; - } - break; - - case 'v': verbose = true; break; - - case '?': - default: - std::cout << "wrong arguments" << std::endl; - usage(argv[0]); - exit(1); + while ( ( ch = getopt( argc, argv, "23k:l:v" ) ) != -1 ) { + switch ( ch ) { + case '2': + dim = 2; + break; + case '3': + dim = 3; + break; + + case 'k': + degree = atoi( optarg ); + if ( degree < 0 ) { + std::cout << "Degree must be positive. Falling back to 1." << std::endl; + degree = 1; + } + break; + + case 'l': + l = atoi( optarg ); + if ( l < -1 or l > 1 ) { + std::cout << "l can be -1, 0 or 1. Falling back to 0." << std::endl; + l = 0; + } + break; + + case 'v': + verbose = true; + break; + + case '?': + default: + std::cout << "wrong arguments" << std::endl; + usage( argv[0] ); + exit( 1 ); } } // Elasticity Parameters - disk::MaterialData material_data; - material_data.setMu(1.0); - material_data.setLambda(10); - - NewtonSolverParameter rp; - rp.setFaceDegree(degree); - rp.setGradDegree(degree); - rp.setCellDegree(degree + l); - rp.setStabilizationParameter(2.0 * material_data.getMu()); - rp.setVerbose(verbose); - rp.setPrecomputation(true); + disk::mechanics::MaterialData< RealType > material_data; + material_data.setMu( 1.0 ); + material_data.setLambda( 10 ); + + disk::mechanics::NonLinearParameters< RealType > rp; + rp.setFaceDegree( degree ); + rp.setGradDegree( degree ); + rp.setCellDegree( degree + l ); + rp.setStabilizationParameter( 2.0 * material_data.getMu() ); + rp.setVerbose( verbose ); + rp.setPrecomputation( true ); +#ifdef NSM_USE_MUMPS + rp.setLinearSolver( disk::solvers::direct_solver::mumps ); +#endif argc -= optind; argv += optind; @@ -572,84 +605,81 @@ main(int argc, char** argv) std::cout << " ** Cell_Degree = " << rp.getCellDegree() << std::endl; std::cout << " " << std::endl; - if (dim == 3) - { + if ( dim == 3 ) { tc.tic(); std::cout << "-Tetrahedras fvca6:" << std::endl; - test_tetrahedra_fvca6(rp, material_data); + test_tetrahedra_fvca6< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Tetrahedras netgen:" << std::endl; - test_tetrahedra_netgen(rp, material_data); + test_tetrahedra_netgen< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Hexahedras fvca6:" << std::endl; - test_hexahedra_fvca6(rp, material_data); + test_hexahedra_fvca6< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Hexahedras diskpp:" << std::endl; - test_hexahedra_diskpp(rp, material_data); + test_hexahedra_diskpp< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Polyhedra:" << std::endl; - test_polyhedra_fvca6(rp, material_data); + test_polyhedra_fvca6< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; - } - else if (dim == 2) - { + } else if ( dim == 2 ) { tc.tic(); std::cout << "-Triangles fvca5:" << std::endl; - test_triangles_fvca5(rp, material_data); + test_triangles_fvca5< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Triangles netgen:" << std::endl; - test_triangles_netgen(rp, material_data); + test_triangles_netgen< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Quadrangles fvca5:" << std::endl; - test_quads_fvca5(rp, material_data); + test_quads_fvca5< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Quadrangles diskpp:" << std::endl; - test_quads_diskpp(rp, material_data); + test_quads_diskpp< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Hexagons:" << std::endl; - test_hexagons(rp, material_data); + test_hexagons< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; tc.tic(); std::cout << "-Kershaws:" << std::endl; - test_kershaws(rp, material_data); + test_kershaws< RealType >( rp, material_data ); tc.toc(); std::cout << "Time to test convergence rates: " << tc.elapsed() << std::endl; std::cout << " " << std::endl; diff --git a/apps/nonlinear_solid_mechanics/src/nonlinear_solid_mechanics.cpp b/apps/nonlinear_solid_mechanics/src/nonlinear_solid_mechanics.cpp index ce240262..2bb38356 100644 --- a/apps/nonlinear_solid_mechanics/src/nonlinear_solid_mechanics.cpp +++ b/apps/nonlinear_solid_mechanics/src/nonlinear_solid_mechanics.cpp @@ -24,295 +24,124 @@ * DOI: 10.1002/nme.6137 */ +#include "../share/tests_data.hpp" +#include "diskpp/loaders/loader.hpp" +#include "diskpp/mechanics/NewtonSolver/NonLinearSolver.hpp" + #include #include #include #include #include -#include - -#include "diskpp/boundary_conditions/boundary_conditions.hpp" -#include "diskpp/loaders/loader.hpp" -#include "diskpp/mechanics/NewtonSolver/NewtonSolver.hpp" -#include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" - -#include "diskpp/common/timecounter.hpp" - -template class Mesh, typename T, typename Storage> -void -run_nl_solid_mechanics_solver(const Mesh& msh, - const NewtonSolverParameter& rp, - const disk::MaterialData& material_data) -{ - typedef Mesh mesh_type; - typedef disk::static_vector result_type; - typedef disk::static_matrix result_grad_type; - typedef disk::vector_boundary_conditions Bnd_type; - - auto load = [material_data](const disk::point& p, const T& time) -> result_type { return result_type{0, 0}; }; - - auto solution = [material_data](const disk::point& p) -> result_type { return result_type{0, 0}; }; - - Bnd_type bnd(msh); - - // Cook with quadrilaterals - auto zero = [material_data](const disk::point& p) -> result_type { return result_type{0.0, 0}; }; - - auto trac = [material_data](const disk::point& p) -> result_type { return result_type{0.0, 0.3125}; }; - - bnd.addDirichletBC(disk::CLAMPED, 3, zero); - bnd.addNeumannBC(disk::NEUMANN, 8, trac); - - disk::mechanics::NewtonSolver nl(msh, bnd, rp); - -#ifdef HAVE_MGIS - // To use a law developped with Mfront - const auto hypo = mgis::behaviour::Hypothesis::PLANESTRAIN; - const std::string filename = "src/libBehaviour.dylib"; - // nl.addBehavior(filename, "IsotropicLinearHardeningPlasticity", hypo); - nl.addBehavior(filename, "LogarithmicStrainPlasticity", hypo); -#else - // To use a native law from DiSk++ - nl.addBehavior(disk::DeformationMeasure::LOGARITHMIC_DEF, disk::LawType::LINEAR_HARDENING); -#endif - - nl.addMaterialData(material_data); - - nl.initial_guess(zero); - - if (nl.verbose()) - { - std::cout << "Solving the problem ..." << '\n'; - } - - SolverInfo solve_info = nl.compute(load); - - if (nl.verbose()) - { - solve_info.printInfo(); - } - - if (nl.convergence()) - { - std::cout << "average diameter h: " << average_diameter(msh) << std::endl; - } -} - -template class Mesh, typename T, typename Storage> -void -run_nl_solid_mechanics_solver(const Mesh& msh, - const NewtonSolverParameter& rp, - const disk::MaterialData& material_data) -{ - typedef Mesh mesh_type; - typedef disk::static_vector result_type; - typedef disk::static_matrix result_grad_type; - typedef disk::vector_boundary_conditions Bnd_type; - Bnd_type bnd(msh); - - auto load = [material_data](const disk::point& p, const T& time) -> result_type { - return result_type{0, 0, 0}; - }; - - auto solution = [material_data](const disk::point& p) -> result_type { return result_type{0, 0, 0}; }; - - auto zero = [material_data](const disk::point& p) -> result_type { return result_type{0.0, 0.0, 0.0}; }; - - auto pres = [material_data](const disk::point& p) -> result_type - { - result_type er = result_type::Zero(); - - er(0) = p.x(); - er(1) = p.y(); - er(2) = p.z(); - - er /= er.norm(); - - return 3 * er; - }; - - auto deplr = [material_data](const disk::point& p) -> result_type - { - result_type er = result_type::Zero(); - - er(0) = p.x(); - er(1) = p.y(); - er(2) = p.z(); - - er /= er.norm(); - - return 0.157 * er; - }; +#include - // Sphere Hpp - // bnd.addDirichletBC(disk::DX, 3, zero); - // bnd.addDirichletBC(disk::DY, 13, zero); - // bnd.addDirichletBC(disk::DZ, 24, zero); - // bnd.addNeumannBC(disk::NEUMANN, 27, pres); +template < template < typename, size_t, typename > class Mesh, typename T, size_t N, + typename Storage > +void run_nl_solid_mechanics_solver( const Mesh< T, N, Storage > &msh, + const disk::mechanics::NonLinearParameters< T > &rp, + const STUDY &study ) { + typedef Mesh< T, N, Storage > mesh_type; - // // Sphere GDEF - bnd.addDirichletBC(disk::DX, 12, zero); - bnd.addDirichletBC(disk::DY, 24, zero); - bnd.addDirichletBC(disk::DZ, 19, zero); - bnd.addDirichletBC(disk::DIRICHLET, 27, deplr); + /* Get material parameters */ + const auto material_data = getMaterialData< T >( study ); - disk::mechanics::NewtonSolver nl(msh, bnd, rp); + /* Get boundary conditions */ + const auto bnd = getBoundaryConditions( msh, material_data, study ); -#ifdef HAVE_MGIS - // To use a law developped with Mfront - const auto hypo = mgis::behaviour::Hypothesis::TRIDIMENSIONAL; - const std::string filename = "src/libBehaviour.dylib"; - nl.addBehavior(filename, "LogarithmicStrainPlasticity", hypo); -#else - // To use a native law from DiSk++ - nl.addBehavior(disk::DeformationMeasure::SMALL_DEF, disk::LawType::LINEAR_HARDENING); -#endif + /* Create nonlinear solver */ + disk::mechanics::NonLinearSolver< mesh_type > nl( msh, bnd, rp ); - nl.addMaterialData(material_data); + /* Get external load */ + addExternalLoad( msh, material_data, study, nl ); - nl.initial_guess(zero); + /* Add non linear option */ + addNonLinearOptions( msh, material_data, study, nl ); - if (nl.verbose()) - { + if ( nl.verbose() ) { std::cout << "Solving the problem ..." << '\n'; } - SolverInfo solve_info = nl.compute(load); + disk::mechanics::SolverInfo solve_info = nl.compute(); - if (nl.verbose()) - { + if ( nl.verbose() ) { solve_info.printInfo(); } - if (nl.convergence()) - { - std::cout << "average diameter h: " << average_diameter(msh) << std::endl; + if ( nl.convergence() ) { + std::cout << "average diameter h: " << average_diameter( msh ) << std::endl; } } -int -main(int argc, char** argv) -{ +int main( int argc, char **argv ) { using RealType = double; - char* mesh_filename = nullptr; - - NewtonSolverParameter rp; - - const RealType MPa = 10E6; - const RealType GPa = 10E9; + char *mesh_filename = nullptr; - // Elasticity Parameters - disk::MaterialData material_data; - - // // Cook Parameters HPP (mm, MPa, kN) - RealType E = 70; - RealType nu = 0.4999; - - material_data.setMu(E, nu); - material_data.setLambda(E, nu); - - material_data.setK(0.0); - material_data.setH(0.135); - - material_data.setSigma_y0(0.243); - - material_data.addMfrontParameter("YoungModulus", material_data.getE()); - material_data.addMfrontParameter("PoissonRatio", material_data.getNu()); - material_data.addMfrontParameter("HardeningSlope", material_data.getH()); - material_data.addMfrontParameter("YieldStrength", material_data.getSigma_y0()); - - // readCurve("VEM2_2d.dat", material_data); - - // material_data.setK(0.0); - // material_data.setH(E, 0.13, 0.0); - - // material_data.setSigma_y0(0.450); - - // Old cook - // RealType E = 70; - // RealType nu = 0.4999; - - // material_data.setMu(E, nu); - // material_data.setLambda(E, nu); - // material_data.setK(0.0); - // material_data.setH(0.135); - // material_data.setSigma_y0(0.243); - - // Sphere Parameters (mm, MPa, kN) - // RealType E = 28.95; - // RealType nu = 0.3; - // RealType ET = 0; - - // material_data.setMu(E, nu); - // material_data.setLambda(E, nu); - // material_data.setK(0); - // material_data.setH(0.0); - // material_data.setSigma_y0(6); + disk::mechanics::NonLinearParameters< RealType > rp; int ch; - while ((ch = getopt(argc, argv, "r:")) != -1) - { - switch (ch) - { - case 'r': - if (!rp.readParameters(optarg)) - exit(1); - break; - default: std::cout << "wrong arguments" << std::endl; exit(1); + while ( ( ch = getopt( argc, argv, "r:" ) ) != -1 ) { + switch ( ch ) { + case 'r': + if ( !rp.readParameters( optarg ) ) + exit( 1 ); + break; + default: + std::cout << "wrong arguments" << std::endl; + exit( 1 ); } } argc -= optind; argv += optind; - if (argc == 0) - { + if ( argc == 0 ) { std::cout << "Error" << std::endl; return 0; } mesh_filename = argv[0]; + /* Define study parameters to use */ + const STUDY study = STUDY::IMPACT_2D; + + addAdditionalParameters( study, rp ); + /* Poly 2d*/ - if (std::regex_match(mesh_filename, std::regex(".*\\.poly2d$"))) - { + if ( std::regex_match( mesh_filename, std::regex( ".*\\.poly2d$" ) ) ) { std::cout << "Guessed mesh format: Poly2D format" << std::endl; - disk::generic_mesh msh; - disk::load_mesh_poly(mesh_filename, msh); - run_nl_solid_mechanics_solver(msh, rp, material_data); + disk::generic_mesh< RealType, 2 > msh; + disk::load_mesh_poly< RealType >( mesh_filename, msh, rp.getVerbose() ); + run_nl_solid_mechanics_solver( msh, rp, study ); return 0; } /* Poly 3d*/ - if (std::regex_match(mesh_filename, std::regex(".*\\.poly3d$"))) - { + if ( std::regex_match( mesh_filename, std::regex( ".*\\.poly3d$" ) ) ) { std::cout << "Guessed mesh format: Poly3D format" << std::endl; - disk::generic_mesh msh; - disk::load_mesh_poly(mesh_filename, msh); - run_nl_solid_mechanics_solver(msh, rp, material_data); + disk::generic_mesh< RealType, 3 > msh; + disk::load_mesh_poly< RealType >( mesh_filename, msh, rp.getVerbose() ); + run_nl_solid_mechanics_solver( msh, rp, study ); return 0; } /* Medit 2d*/ - if (std::regex_match(mesh_filename, std::regex(".*\\.medit2d$"))) - { + if ( std::regex_match( mesh_filename, std::regex( ".*\\.medit2d$" ) ) ) { std::cout << "Guessed mesh format: Medit format" << std::endl; - disk::generic_mesh msh; - disk::load_mesh_medit(mesh_filename, msh); - run_nl_solid_mechanics_solver(msh, rp, material_data); + disk::generic_mesh< RealType, 2 > msh; + disk::load_mesh_medit< RealType >( mesh_filename, msh ); + run_nl_solid_mechanics_solver( msh, rp, study ); return 0; } /* Medit 3d*/ - if (std::regex_match(mesh_filename, std::regex(".*\\.medit3d$"))) - { + if ( std::regex_match( mesh_filename, std::regex( ".*\\.medit3d$" ) ) ) { std::cout << "Guessed mesh format: Medit format" << std::endl; - disk::generic_mesh msh; - disk::load_mesh_medit(mesh_filename, msh); - run_nl_solid_mechanics_solver(msh, rp, material_data); + disk::generic_mesh< RealType, 3 > msh; + disk::load_mesh_medit< RealType >( mesh_filename, msh ); + run_nl_solid_mechanics_solver( msh, rp, study ); return 0; } } diff --git a/apps/run_pardiso/src/run_pardiso.cpp b/apps/run_pardiso/src/run_pardiso.cpp index 35a97554..69afba52 100644 --- a/apps/run_pardiso/src/run_pardiso.cpp +++ b/apps/run_pardiso/src/run_pardiso.cpp @@ -4,9 +4,10 @@ int main(void) { +#ifdef HAVE_HDF5 using T = double; disk::sparse_matrix Alhs; - std::cout << "loading matrix\n"; + std::cout << "loading matrix\n"; disk::load_from_hdf5(Alhs, "/home/matteo/tmp/Alhs.h5"); std::cout << "loading vector\n"; @@ -22,6 +23,6 @@ int main(void) disk::dynamic_vector sol = lu.solve(RHS); std::cout << sol << std::endl; - +#endif return 0; } \ No newline at end of file diff --git a/apps/tests/behaviors_test.cpp b/apps/tests/behaviors_test.cpp index 78ef2aeb..2a30b817 100644 --- a/apps/tests/behaviors_test.cpp +++ b/apps/tests/behaviors_test.cpp @@ -37,18 +37,18 @@ main(int argc, char const* argv[]) { using T = double; - disk::Cavitation_qp cav3D; - disk::Cavitation_qp cav2D; - disk::HenckyMises_qp Hen3D; - disk::HenckyMises_qp Hen2D; - disk::IsotropicHardeningVMis_qp isot3D; - disk::IsotropicHardeningVMis_qp isot2D; - disk::LinearIsotropicAndKinematicHardening_qp mix3D; - disk::LinearIsotropicAndKinematicHardening_qp mix2D; - disk::LinearLaw_qp lin3D; - disk::LinearLaw_qp lin2D; - disk::Neohookean_qp neo3D; - disk::Neohookean_qp neo2D; + disk::mechanics::Cavitation_qp< T, 3 > cav3D; + disk::mechanics::Cavitation_qp< T, 2 > cav2D; + disk::mechanics::HenckyMises_qp< T, 3 > Hen3D; + disk::mechanics::HenckyMises_qp< T, 2 > Hen2D; + disk::mechanics::IsotropicHardeningVMis_qp< T, 3 > isot3D; + disk::mechanics::IsotropicHardeningVMis_qp< T, 2 > isot2D; + disk::mechanics::LinearIsotropicAndKinematicHardening_qp< T, 3 > mix3D; + disk::mechanics::LinearIsotropicAndKinematicHardening_qp< T, 2 > mix2D; + disk::mechanics::LinearLaw_qp< T, 3 > lin3D; + disk::mechanics::LinearLaw_qp< T, 2 > lin2D; + disk::mechanics::Neohookean_qp< T, 3 > neo3D; + disk::mechanics::Neohookean_qp< T, 2 > neo2D; return 0; } diff --git a/apps/tests/common.hpp b/apps/tests/common.hpp index bb091b5b..2928440b 100644 --- a/apps/tests/common.hpp +++ b/apps/tests/common.hpp @@ -305,6 +305,45 @@ get_polygonal_generic_meshes(void) return ret; } +template +std::vector< disk::generic_mesh > +get_kershaw_generic_meshes(void) +{ + std::string mesh_path; + + const char *mesh_path_env = getenv(MESH_PATH_ENV_VAR_NAME); + if (mesh_path_env != nullptr) + mesh_path = mesh_path_env; + + std::vector meshfiles; + meshfiles.push_back(mesh_path + "2D_kershaw/fvca5/mesh4_1_1.typ1"); + meshfiles.push_back(mesh_path + "2D_kershaw/fvca5/mesh4_1_2.typ1"); + meshfiles.push_back(mesh_path + "2D_kershaw/fvca5/mesh4_1_3.typ1"); + meshfiles.push_back(mesh_path + "2D_kershaw/fvca5/mesh4_1_4.typ1"); + meshfiles.push_back(mesh_path + "2D_kershaw/fvca5/mesh4_1_5.typ1"); + + typedef disk::generic_mesh mesh_type; + + std::vector< mesh_type > ret; + for (size_t i = 0; i < meshfiles.size(); i++) + { + mesh_type msh; + disk::fvca5_mesh_loader loader; + + if (!loader.read_mesh(meshfiles.at(i))) + { + std::cout << "Problem loading mesh." << std::endl; + ret.clear(); + return ret; + } + loader.populate_mesh(msh); + + ret.push_back(msh); + } + + return ret; +} + template std::vector< disk::simplicial_mesh > get_triangle_netgen_meshes(void) @@ -684,6 +723,19 @@ class tester do_testing(meshes, tf, er, min_degree, max_degree, rate_tolerance); } + void + test_kershaw_generic(size_t min_degree, size_t max_degree, double rate_tolerance) + { + std::cout << yellow << "Mesh under test: kershaw on generic mesh"; + std::cout << nocolor << std::endl; + using T = double; + + auto meshes = get_kershaw_generic_meshes(); + auto tf = get_test_functor(meshes); + auto er = [&](size_t k) { return tf.expected_rate(k); }; + do_testing(meshes, tf, er, min_degree, max_degree, rate_tolerance); + } + void test_triangles_netgen(size_t min_degree, size_t max_degree, double rate_tolerance) { @@ -771,6 +823,7 @@ class tester bool crash_on_nan = false; bool do_triangles_generic = true; bool do_polygonal_generic = true; + bool do_kershaw_generic = true; bool do_triangles_netgen = true; bool do_quads = true; bool do_cartesian_2d_diskpp = true; @@ -785,6 +838,7 @@ class tester crash_on_nan = lua["crash_on_nan"].get_or(false); do_triangles_generic = lua["do_triangles_generic"].get_or(false); do_polygonal_generic = lua["do_polygonal_generic"].get_or(false); + do_kershaw_generic = lua["do_kershaw_generic"].get_or(false); do_triangles_netgen = lua["do_triangles_netgen"].get_or(false); do_quads = lua["do_quads"].get_or(false); do_cartesian_2d_diskpp = lua["do_cartesian_2d_diskpp"].get_or(false); @@ -808,6 +862,9 @@ class tester if (do_polygonal_generic) test_polygonal_generic(min_degree, max_degree, rate_tolerance); + if (do_kershaw_generic) + test_kershaw_generic(min_degree, max_degree, rate_tolerance); + if (do_quads) test_quads(min_degree, max_degree, rate_tolerance); diff --git a/apps/utils/detect_convex_polys.cpp b/apps/utils/detect_convex_polys.cpp new file mode 100644 index 00000000..b4f7c480 --- /dev/null +++ b/apps/utils/detect_convex_polys.cpp @@ -0,0 +1,56 @@ +#include +#include +#include + +#include +#include + +#include + +#include "diskpp/loaders/loader.hpp" +#include "diskpp/output/silo.hpp" + +template +int detect_convex(Mesh& msh, const char *silo_filename) +{ + std::vector cvx; + + for (auto& cl : msh) { + cvx.push_back( double(is_convex(msh, cl)) ); + } + + disk::silo_database silo_db; + silo_db.create(silo_filename); + silo_db.add_mesh(msh, "mesh"); + silo_db.add_variable("mesh", "isconvex", cvx, disk::zonal_variable_t); + silo_db.close(); + + return 0; +} + +int main(int argc, const char *argv[]) +{ + if (argc != 3) + { + std::cout << argv[0] << " " << std::endl; + return 1; + } + + const char *mesh_filename = argv[1]; + const char *silo_filename = argv[2]; + + using T = double; + + /* FVCA5 2D */ + if (std::regex_match(mesh_filename, std::regex(".*\\.typ1$") )) + { + std::cout << "Guessed mesh format: FVCA5 2D" << std::endl; + disk::generic_mesh msh; + disk::load_mesh_fvca5_2d(mesh_filename, msh); + detect_convex(msh, silo_filename); + return 0; + } + + std::cout << "Only FVCA5 file format" << std::endl; + return 1; +} \ No newline at end of file diff --git a/apps/utils/h5io.cpp b/apps/utils/h5io.cpp index 16f866fd..464924a3 100644 --- a/apps/utils/h5io.cpp +++ b/apps/utils/h5io.cpp @@ -4,10 +4,10 @@ int main(void) { +#ifdef HAVE_HDF5 disk::sparse_matrix Ms; Ms.resize(10,10); Ms.setIdentity(); - disk::save_to_hdf5(Ms, "sparse.h5"); disk::sparse_matrix Ns; @@ -22,5 +22,6 @@ int main(void) disk::load_from_hdf5(Nd, "dense.h5"); std::cout << Nd << std::endl; +#endif return 0; } diff --git a/cmake/FindMGIS.cmake b/cmake/FindMGIS.cmake index 3dcc91a4..620f6332 100644 --- a/cmake/FindMGIS.cmake +++ b/cmake/FindMGIS.cmake @@ -35,13 +35,17 @@ find_path(MGIS_INCLUDE_DIRS find_library(MGIS_MFRONT_LIBRARIES NAMES MFrontGenericInterface HINTS ENV MGIS_ROOT ${MGIS_ROOT} - PATH_SUFFIXES lib + PATH_SUFFIXES lib lib64 ) find_package_handle_standard_args(MGIS DEFAULT_MSG MGIS_MFRONT_LIBRARIES MGIS_INCLUDE_DIRS) -if (MGIS_FOUND) - add_library(MGIS INTERFACE) - target_link_libraries(MGIS INTERFACE "${MGIS_MFRONT_LIBRARIES}") - target_include_directories(MGIS INTERFACE "${MGIS_INCLUDE_DIRS}") +if (MGIS_FOUND AND NOT TARGET MGIS::MGIS) + add_library(MGIS::MGIS INTERFACE IMPORTED) + set_target_properties(MGIS::MGIS PROPERTIES + IMPORTED_LOCATION "${MGIS_MFRONT_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${MGIS_INCLUDE_DIRS}" + ) + #target_link_libraries(MGIS::MGIS INTERFACE "${MGIS_MFRONT_LIBRARIES}") + #target_include_directories(MGIS::MGIS INTERFACE "${MGIS_INCLUDE_DIRS}") endif() diff --git a/libdiskpp/CMakeLists.txt b/libdiskpp/CMakeLists.txt index cc10fab2..8c2f764a 100644 --- a/libdiskpp/CMakeLists.txt +++ b/libdiskpp/CMakeLists.txt @@ -38,7 +38,7 @@ add_library(diskpp SHARED ${LIBDISKPP_SOURCES}) ###################################################################### ## Find Eigen 3 -find_package(Eigen3 REQUIRED) +find_package(Eigen3 3.4 REQUIRED) target_link_libraries(diskpp INTERFACE Eigen3::Eigen) ###################################################################### @@ -83,9 +83,7 @@ target_include_directories(diskpp PUBLIC ${LUA_INCLUDE_DIR}) find_package(GMSH) if (GMSH_FOUND) target_link_libraries(diskpp PUBLIC GMSH::GMSH) - target_compile_definitions(diskpp PUBLIC - HAVE_GMSH - ) + target_compile_definitions(diskpp PUBLIC HAVE_GMSH) endif() ###################################################################### @@ -99,18 +97,30 @@ target_link_libraries(diskpp PUBLIC sol2::sol2) ## HDF5 Support find_package(HDF5) if (HDF5_FOUND) - #add_subdirectory(contrib/highfive) - #target_link_libraries(diskpp PUBLIC HighFive::HighFive) add_library(diskpp_highfive INTERFACE) target_include_directories(diskpp_highfive INTERFACE $ $ ) add_library(HighFive::HighFive ALIAS diskpp_highfive) - target_link_libraries(diskpp PUBLIC HighFive::HighFive HDF5::HDF5) - target_compile_definitions(diskpp PUBLIC - HAVE_HDF5 + target_link_libraries(diskpp_highfive INTERFACE HDF5::HDF5) + target_link_libraries(diskpp PUBLIC HighFive::HighFive) + target_compile_definitions(diskpp PUBLIC HAVE_HDF5) + # HighFive is header-only, include have to be installed. + install( + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/contrib/highfive/include/" + DESTINATION include ) +else() + message(STATUS "HDF5 not found: HDF5/HighFive support disabled") +endif() + +###################################################################### +## MGIS Support +find_package(MGIS) +if (MGIS_FOUND) + target_link_libraries(diskpp INTERFACE MGIS::MGIS) + target_compile_definitions(diskpp PUBLIC HAVE_MGIS) endif() ###################################################################### @@ -143,8 +153,21 @@ target_include_directories(diskpp PUBLIC add_library(diskpp::diskpp ALIAS diskpp) +set(DISKPP_INSTALL_TARGETS + diskpp + triangle + jburkardt + gmshtools + sgr + sol2 +) + +if (TARGET diskpp_highfive) + list(APPEND DISKPP_INSTALL_TARGETS diskpp_highfive) +endif() -install(TARGETS diskpp triangle jburkardt gmshtools sgr sol2 diskpp_highfive +install( + TARGETS ${DISKPP_INSTALL_TARGETS} EXPORT DiskppTargets ARCHIVE DESTINATION lib LIBRARY DESTINATION lib @@ -165,9 +188,12 @@ install(EXPORT DiskppTargets DESTINATION lib/cmake/diskpp ) -export(TARGETS diskpp triangle jburkardt gmshtools sgr sol2 diskpp_highfive Spectra - NAMESPACE diskpp:: - FILE "${CMAKE_CURRENT_BINARY_DIR}/DiskppTargets.cmake") +set(DISKPP_EXPORT_TARGETS ${DISKPP_INSTALL_TARGETS} Spectra) + +export( TARGETS ${DISKPP_EXPORT_TARGETS} + NAMESPACE diskpp:: + FILE "${CMAKE_CURRENT_BINARY_DIR}/DiskppTargets.cmake" + ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/DiskppConfig.cmake" diff --git a/libdiskpp/cmake/FindMGIS.cmake b/libdiskpp/cmake/FindMGIS.cmake index 3dcc91a4..620f6332 100644 --- a/libdiskpp/cmake/FindMGIS.cmake +++ b/libdiskpp/cmake/FindMGIS.cmake @@ -35,13 +35,17 @@ find_path(MGIS_INCLUDE_DIRS find_library(MGIS_MFRONT_LIBRARIES NAMES MFrontGenericInterface HINTS ENV MGIS_ROOT ${MGIS_ROOT} - PATH_SUFFIXES lib + PATH_SUFFIXES lib lib64 ) find_package_handle_standard_args(MGIS DEFAULT_MSG MGIS_MFRONT_LIBRARIES MGIS_INCLUDE_DIRS) -if (MGIS_FOUND) - add_library(MGIS INTERFACE) - target_link_libraries(MGIS INTERFACE "${MGIS_MFRONT_LIBRARIES}") - target_include_directories(MGIS INTERFACE "${MGIS_INCLUDE_DIRS}") +if (MGIS_FOUND AND NOT TARGET MGIS::MGIS) + add_library(MGIS::MGIS INTERFACE IMPORTED) + set_target_properties(MGIS::MGIS PROPERTIES + IMPORTED_LOCATION "${MGIS_MFRONT_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${MGIS_INCLUDE_DIRS}" + ) + #target_link_libraries(MGIS::MGIS INTERFACE "${MGIS_MFRONT_LIBRARIES}") + #target_include_directories(MGIS::MGIS INTERFACE "${MGIS_INCLUDE_DIRS}") endif() diff --git a/libdiskpp/include/diskpp/adaptivity/adaptivity.hpp b/libdiskpp/include/diskpp/adaptivity/adaptivity.hpp index 61d3fb11..e0a67dd1 100644 --- a/libdiskpp/include/diskpp/adaptivity/adaptivity.hpp +++ b/libdiskpp/include/diskpp/adaptivity/adaptivity.hpp @@ -25,6 +25,9 @@ #pragma once +#include +#include + namespace disk { diff --git a/libdiskpp/include/diskpp/bases/bases.hpp b/libdiskpp/include/diskpp/bases/bases.hpp index a3960ce7..e83e46f5 100644 --- a/libdiskpp/include/diskpp/bases/bases.hpp +++ b/libdiskpp/include/diskpp/bases/bases.hpp @@ -30,7 +30,7 @@ // #define USE_LEGENDRE // Use or not inertia axes for the local axis (it improves conditioning but it not completely tested) // #define USE_INERTIA_AXES true -#define USE_INERTIA_AXES false +#define USE_INERTIA_AXES true #include "bases_scalar.hpp" #include "bases_matrix.hpp" diff --git a/libdiskpp/include/diskpp/bases/bases_operations.hpp b/libdiskpp/include/diskpp/bases/bases_operations.hpp index 6032b7fa..c382b0d9 100644 --- a/libdiskpp/include/diskpp/bases/bases_operations.hpp +++ b/libdiskpp/include/diskpp/bases/bases_operations.hpp @@ -50,7 +50,7 @@ struct dot_evaluator static_assert(Basis::tensor_order > 0); static const size_t tensor_order = Basis::tensor_order-1; using value_type = typename tensor::value_type; - using normal_type = normal_t::type; + using normal_type = typename normal_t::type; normal_type n; dot_evaluator() = delete; @@ -110,7 +110,7 @@ struct grad_evaluator static const size_t basis_dimension = Basis::basis_dimension; static const size_t tensor_order = Basis::tensor_order+1; using value_type = typename tensor::value_type; - using normal_type = normal_t::type; + using normal_type = typename normal_t::type; normal_type n; grad_evaluator() = delete; diff --git a/libdiskpp/include/diskpp/bases/bases_utils.hpp b/libdiskpp/include/diskpp/bases/bases_utils.hpp index c10dc17a..80ac14ff 100644 --- a/libdiskpp/include/diskpp/bases/bases_utils.hpp +++ b/libdiskpp/include/diskpp/bases/bases_utils.hpp @@ -207,7 +207,7 @@ outer_product(const eigen_compatible_stdvector>& a, const Matrix template Matrix -make_mass_matrix(const Mesh& msh, const Element& elem, const Basis& basis, size_t di = 0) +make_mass_matrix(const Mesh& msh, const Element& elem, const Basis& basis) { const auto degree = basis.degree(); const auto basis_size = basis.size(); @@ -216,7 +216,7 @@ make_mass_matrix(const Mesh& msh, const Element& elem, const Basis& basis, size_ Matrix ret = Matrix::Zero(basis_size, basis_size); - const auto qps = integrate(msh, elem, 2 * (degree+di)); + const auto qps = integrate(msh, elem, 2 * degree); for (auto& qp : qps) { @@ -228,11 +228,7 @@ make_mass_matrix(const Mesh& msh, const Element& elem, const Basis& basis, size_ return ret; } -/* We have a problem here: this definition could be ambiguous with the previous - * one. */ -//#if 0 template -[[deprecated("DiSk++ issue: this declaration is ambiguous, fix is needed")]] Matrix make_mass_matrix(const Mesh& msh, const Element& elem, const Basis& basis, const MaterialField& material_tensor, size_t di = 0) { @@ -255,7 +251,6 @@ make_mass_matrix(const Mesh& msh, const Element& elem, const Basis& basis, const return ret; } -//#endif template Matrix diff --git a/libdiskpp/include/diskpp/boundary_conditions/boundary_conditions.hpp b/libdiskpp/include/diskpp/boundary_conditions/boundary_conditions.hpp index c2fc2ffd..e52a8492 100644 --- a/libdiskpp/include/diskpp/boundary_conditions/boundary_conditions.hpp +++ b/libdiskpp/include/diskpp/boundary_conditions/boundary_conditions.hpp @@ -25,13 +25,20 @@ #pragma once -#include -#include - #include "diskpp/bases/bases.hpp" #include "diskpp/common/eigen.hpp" #include "diskpp/mesh/point.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include + namespace disk { @@ -69,26 +76,6 @@ enum ContactType : size_t namespace priv { -template -T -bnd_product(const T& fact, const T& func) -{ - return fact * func; -} - -template -Matrix -bnd_product(const T& fact, const Matrix& func) -{ - return fact * func; -} - -template -Matrix -bnd_product(const T& fact, const Matrix& func) -{ - return fact * func; -} template struct FunctionType @@ -177,54 +164,77 @@ struct imposed_dofs // ScalarBoundary = true for scalar problem like diffusion // ScalarBoundary = false for vectorial problem like linear_elasticity -template -class BoundaryConditions -{ +template < typename MeshType, bool ScalarBoundary > +class BoundaryConditions { public: - typedef MeshType mesh_type; - typedef typename mesh_type::cell_type cell_type; - typedef typename mesh_type::face_type face_type; - typedef typename mesh_type::coordinate_type scalar_type; - typedef point point_type; - typedef typename priv::FunctionType::function_type function_type; + typedef MeshType mesh_type; + typedef typename mesh_type::cell_type cell_type; + typedef typename mesh_type::face_type face_type; + typedef typename mesh_type::coordinate_type scalar_type; + typedef point< scalar_type, mesh_type::dimension > point_type; + typedef typename priv::FunctionType< scalar_type, mesh_type::dimension, + ScalarBoundary >::function_type fct_result_type; - private: - const mesh_type& m_msh; + using function_type = std::function< fct_result_type( const point_type &, scalar_type ) >; - std::vector> m_dirichlet_func; - std::vector> m_neumann_func; - std::vector> m_robin_func; - std::vector> m_contact_func; + private: + const mesh_type &m_msh; + + std::vector< function_type > m_dirichlet_func; + std::vector< function_type > m_neumann_func; + std::vector< function_type > m_robin_func; + std::vector< std::function< scalar_type( point_type ) > > m_contact_func; + std::vector< std::function< scalar_type( + point_type, static_vector< scalar_type, mesh_type::dimension > ) > > + m_contact_gap; + + template < typename > + inline static constexpr bool always_false_v = false; + + template < typename Function > + static function_type _conv_fct( Function &&fct ) { + using function_t = std::decay_t< Function >; + if constexpr ( std::is_invocable_r_v< fct_result_type, function_t &, const point_type &, + scalar_type > ) { + return function_type( std::forward< Function >( fct ) ); + } else if constexpr ( std::is_invocable_r_v< fct_result_type, function_t &, + const point_type & > ) { + return [fct = std::forward< Function >( fct )]( + const point_type &p, scalar_type ) mutable -> fct_result_type { + return std::invoke( fct, p ); + }; + } else { + static_assert( always_false_v< function_t >, "Boundary function must be callable as " + "f(point) or f(point, time)" ); + } + } // 1) bool to know if a boundary condition is associated to the face // 2) type of boundary conditions // 3) boundary id of the face // 4) boundary function id of the face - typedef std::vector> bnd_storage_type; - bnd_storage_type m_faces_is_dirichlet; - bnd_storage_type m_faces_is_neumann; - bnd_storage_type m_faces_is_robin; - std::vector> m_faces_is_contact; + typedef std::vector< std::tuple< bool, size_t, size_t, size_t > > bnd_storage_type; + bnd_storage_type m_faces_is_dirichlet; + bnd_storage_type m_faces_is_neumann; + bnd_storage_type m_faces_is_robin; + std::vector< std::tuple< bool, size_t, size_t, int > > m_faces_is_contact; size_t m_dirichlet_faces, m_neumann_faces, m_robin_faces, m_contact_faces; - scalar_type m_factor; + scalar_type m_time; // search faces that have the boundary id "b_id" - std::vector - search_faces(const size_t b_id) const - { - std::vector list_faces; + std::vector< size_t > search_faces( const size_t b_id ) const { + std::vector< size_t > list_faces; - for (auto itor = m_msh.boundary_faces_begin(); itor != m_msh.boundary_faces_end(); itor++) - { + for ( auto itor = m_msh.boundary_faces_begin(); itor != m_msh.boundary_faces_end(); + itor++ ) { const auto bfc = *itor; - const auto face_id = m_msh.lookup(bfc); + const auto face_id = m_msh.lookup( bfc ); - if (m_msh.boundary_id(face_id) == b_id) - { - list_faces.push_back(face_id); + if ( m_msh.boundary_id( face_id ) == b_id ) { + list_faces.push_back( face_id ); } } @@ -236,8 +246,8 @@ class BoundaryConditions public: BoundaryConditions() = delete; - BoundaryConditions(const mesh_type& msh) : - m_msh(msh), m_dirichlet_faces(0), m_neumann_faces(0), m_robin_faces(0), m_contact_faces(0), m_factor(1) + BoundaryConditions(const mesh_type &msh) : m_msh(msh), m_dirichlet_faces(0), m_neumann_faces(0), m_robin_faces(0), m_contact_faces(0), + m_time(1.) { m_faces_is_dirichlet.assign(m_msh.faces_size(), std::make_tuple(false, NOTHING, 0, 0)); m_faces_is_neumann.assign(m_msh.faces_size(), std::make_tuple(false, FREE, 0, 0)); @@ -245,6 +255,9 @@ class BoundaryConditions m_faces_is_contact.assign(m_msh.faces_size(), std::make_tuple(false, NO_CONTACT, 0, -1)); } + inline static constexpr scalar_type default_time_marker = + static_cast< scalar_type >( -123456789 ); + void addContactBC(const size_t& btype, const size_t& b_id) { @@ -257,13 +270,12 @@ class BoundaryConditions } } - template - void - addContactBC(const size_t& btype, const size_t& b_id, const Function& bcf) - { + template < typename Function, typename FunctionGap > + void addContactBC( size_t btype, size_t b_id, const Function &bcf, const FunctionGap &gap ) { const size_t bcf_id = m_contact_func.size(); m_contact_func.push_back(bcf); + m_contact_gap.push_back( gap ); const auto list_faces = search_faces(b_id); @@ -274,77 +286,67 @@ class BoundaryConditions } } - template - void - addDirichletEverywhere(const Function& bcf) - { + template < typename Function > + void addDirichletEverywhere( Function &&bcf ) { const size_t bcf_id = m_dirichlet_func.size(); - m_dirichlet_func.push_back(bcf); - for (auto itor = m_msh.boundary_faces_begin(); itor != m_msh.boundary_faces_end(); itor++) - { + m_dirichlet_func.emplace_back( _conv_fct( std::forward< Function >( bcf ) ) ); + + for ( auto itor = m_msh.boundary_faces_begin(); itor != m_msh.boundary_faces_end(); + ++itor ) { const auto bfc = *itor; + const size_t face_id = m_msh.lookup( bfc ); - const auto face_id = m_msh.lookup(bfc); + m_faces_is_dirichlet.at( face_id ) = + std::make_tuple( true, DIRICHLET, size_t { 0 }, bcf_id ); - m_faces_is_dirichlet.at(face_id) = std::make_tuple(true, DIRICHLET, 0, bcf_id); - m_dirichlet_faces++; + ++m_dirichlet_faces; } } - template - void - addRobinBC(const size_t& btype, const size_t& b_id, const Function& bcf) - { - + template < typename Function > + void addRobinBC( size_t btype, size_t b_id, Function &&bcf ) { const size_t bcf_id = m_robin_func.size(); - m_robin_func.push_back(bcf); - const auto list_faces = search_faces(b_id); + m_robin_func.emplace_back( _conv_fct( std::forward< Function >( bcf ) ) ); - for (size_t face_id : list_faces) - { - m_faces_is_robin.at(face_id) = std::make_tuple(true, btype, b_id, bcf_id); - m_robin_faces++; + const auto list_faces = search_faces( b_id ); + + for ( const size_t face_id : list_faces ) { + m_faces_is_robin.at( face_id ) = std::make_tuple( true, btype, b_id, bcf_id ); + + ++m_robin_faces; } } - template - void - addDirichletBC(const size_t& btype, const size_t& b_id, const Function& bcf) - { + template < typename Function > + void addDirichletBC( size_t btype, size_t b_id, Function &&bcf ) { const size_t bcf_id = m_dirichlet_func.size(); - m_dirichlet_func.push_back(bcf); - const auto list_faces = search_faces(b_id); + m_dirichlet_func.emplace_back( _conv_fct( std::forward< Function >( bcf ) ) ); - for (size_t face_id : list_faces) - { - m_faces_is_dirichlet.at(face_id) = std::make_tuple(true, btype, b_id, bcf_id); - m_dirichlet_faces++; + const auto list_faces = search_faces( b_id ); + + for ( const size_t face_id : list_faces ) { + m_faces_is_dirichlet.at( face_id ) = std::make_tuple( true, btype, b_id, bcf_id ); + + ++m_dirichlet_faces; } } - template - void - addNeumannBC(const size_t& btype, const size_t& b_id, const Function& bcf) - { + template < typename Function > + void addNeumannBC( size_t btype, size_t b_id, Function &&bcf ) { const size_t bcf_id = m_neumann_func.size(); - m_neumann_func.push_back(bcf); - const auto list_faces = search_faces(b_id); + m_neumann_func.emplace_back( _conv_fct( std::forward< Function >( bcf ) ) ); - for (size_t face_id : list_faces) - { - m_faces_is_neumann.at(face_id) = std::make_tuple(true, btype, b_id, bcf_id); - m_neumann_faces++; - } - } + const auto list_faces = search_faces( b_id ); - void - multiplyAllFunctionsByAFactor(const scalar_type& factor) - { - m_factor = factor; + for ( const size_t face_id : list_faces ) { + m_faces_is_neumann.at( face_id ) = std::make_tuple( true, btype, b_id, bcf_id ); + + ++m_neumann_faces; + } } size_t @@ -517,7 +519,7 @@ class BoundaryConditions size_t contact_boundary_id(const face_type& fc) const { - return robin_boundary_id(m_msh.lookup(fc)); + return contact_boundary_id( m_msh.lookup( fc ) ); } bool @@ -663,43 +665,71 @@ class BoundaryConditions auto dirichlet_boundary_func(const size_t face_i) const { + return dirichlet_boundary_func(face_i, m_time); + } + + auto + dirichlet_boundary_func(const face_type &fc) const + { + return dirichlet_boundary_func(m_msh.lookup(fc)); + } + + auto dirichlet_boundary_func( const size_t face_i, scalar_type time ) const { if (!is_dirichlet_face(face_i)) { throw std::logic_error("You want the Dirichlet function of face which is not a Dirichlet face"); } - const auto func = m_dirichlet_func.at(std::get<3>(m_faces_is_dirichlet.at(face_i))); - const scalar_type factor = m_factor; + const auto func = m_dirichlet_func.at(std::get<3>(m_faces_is_dirichlet.at(face_i))); - auto rfunc = [ func, factor ](const point_type& p) -> auto { return priv::bnd_product(factor, func(p)); }; + auto rfunc = [func, time]( const point_type &p, + scalar_type t = -default_time_marker ) -> auto { + if ( std::abs( t + default_time_marker ) > 1e-6 ) { + return func(p, t); + } + + return func(p, time); + }; return rfunc; } - auto - dirichlet_boundary_func(const face_type& fc) const - { - return dirichlet_boundary_func(m_msh.lookup(fc)); + auto dirichlet_boundary_func( const face_type &fc, scalar_type time ) const { + return dirichlet_boundary_func(m_msh.lookup(fc), time); } - auto - neumann_boundary_func(const size_t face_i) const - { + auto neumann_boundary_func( const size_t face_i, scalar_type time ) const { if (!is_neumann_face(face_i)) { throw std::logic_error("You want the Neumann function of face which is not a Neumann face"); } - const auto func = m_neumann_func.at(std::get<3>(m_faces_is_neumann.at(face_i))); - const scalar_type factor = m_factor; + const auto func = m_neumann_func.at(std::get<3>(m_faces_is_neumann.at(face_i))); - auto rfunc = [ func, factor ](const point_type& p) -> auto { return priv::bnd_product(factor, func(p)); }; + auto rfunc = [func, time]( const point_type &p, + scalar_type t = -default_time_marker ) -> auto { + if ( std::abs( t + default_time_marker ) > 1e-6 ) { + return func(p, t); + } + + return func(p, time); + }; return rfunc; } auto - neumann_boundary_func(const face_type& fc) const + neumann_boundary_func(const size_t face_i) const + { + return neumann_boundary_func(face_i, m_time); + } + + auto neumann_boundary_func( const face_type &fc, scalar_type time ) const { + return neumann_boundary_func(m_msh.lookup(fc), time); + } + + auto + neumann_boundary_func(const face_type &fc) const { return neumann_boundary_func(m_msh.lookup(fc)); } @@ -713,12 +743,17 @@ class BoundaryConditions } const auto func = m_robin_func.at(std::get<3>(m_faces_is_robin.at(face_i))); - const scalar_type factor = m_factor; + const scalar_type time = m_time; - auto rfunc = [ func, factor ](const point_type& p) -> auto - { - return disk::priv::inner_product(factor, func(p)); + auto rfunc = [func, time]( const point_type &p, + scalar_type t = -default_time_marker ) -> auto { + if ( std::abs( t + default_time_marker ) > 1e-6 ) { + return func(p, t); + } + + return func(p, time); }; + return rfunc; } @@ -752,6 +787,25 @@ class BoundaryConditions return contact_boundary_func(m_msh.lookup(fc)); } + auto contact_boundary_gap( const size_t face_i ) const { + if ( !is_contact_face( face_i ) ) { + throw std::logic_error( + "You want the gap function of a face which is not a conatact face" ); + } + + const auto fid = std::get< 3 >( m_faces_is_contact.at( face_i ) ); + + if ( fid < 0 ) { + throw std::logic_error( "You want the gap function of a face which has not function" ); + } + + return m_contact_gap.at( fid ); + } + + auto contact_boundary_gap( const face_type &fc ) const { + return contact_boundary_gap( m_msh.lookup( fc ) ); + } + void boundary_info() const { @@ -778,6 +832,16 @@ class BoundaryConditions return 0; } + + void setTime( scalar_type time ) { m_time = time; } + + void setTimeAsConst( scalar_type time ) const { + const_cast *>(this)->m_time = time; + } + + scalar_type getTime(void) const { + return m_time; + } }; template diff --git a/libdiskpp/include/diskpp/common/eigen.hpp b/libdiskpp/include/diskpp/common/eigen.hpp index e41ed3dd..370dcdf4 100644 --- a/libdiskpp/include/diskpp/common/eigen.hpp +++ b/libdiskpp/include/diskpp/common/eigen.hpp @@ -30,10 +30,6 @@ #ifdef HAVE_INTEL_MKL /* Don't use MKL! It makes everything slower! */ //#define EIGEN_USE_MKL_ALL -// Fix for eigen version > 3.3.7 -#if !defined(EIGEN_USING_STD) -#define EIGEN_USING_STD(X) using std::X -#endif #include #endif @@ -45,6 +41,11 @@ #include +// Fix for eigen version < 3.3.7 +#ifndef EIGEN_USING_STD +#define EIGEN_USING_STD(X) using std::X +#endif + #include #pragma clang diagnostic pop diff --git a/libdiskpp/include/diskpp/common/simplicial_formula.hpp b/libdiskpp/include/diskpp/common/simplicial_formula.hpp index c46a19ac..93a0eed0 100644 --- a/libdiskpp/include/diskpp/common/simplicial_formula.hpp +++ b/libdiskpp/include/diskpp/common/simplicial_formula.hpp @@ -34,33 +34,39 @@ namespace disk { -/** - * @brief Compute the area of a triangle by using the Kahan formula, - * which minimize the round-off error - * - * @param p0 first point of the triangle - * @param p1 second point of the triangle - * @param p2 third point of the triangle - * @return T area - */ -template -T -area_triangle_kahan(const point& p0, const point& p1, const point& p2) -{ - const T l10 = (p1 - p0).to_vector().norm(); - const T l20 = (p2 - p0).to_vector().norm(); - const T l21 = (p2 - p1).to_vector().norm(); + /** + * @brief Compute the area of a triangle by using the Kahan formula, + * which minimize the round-off error + *https://inria.hal.science/hal-00790071/document + * + * @param p0 first point of the triangle + * @param p1 second point of the triangle + * @param p2 third point of the triangle + * @return T area + */ + template + T area_triangle_kahan(const point &p0, const point &p1, const point &p2) + { + const T l10 = (p1 - p0).to_vector().norm(); + const T l20 = (p2 - p0).to_vector().norm(); + const T l21 = (p2 - p1).to_vector().norm(); - std::array length = {l10, l20, l21}; + std::array length = {l10, l20, l21}; - std::sort(length.begin(), length.end()); + std::sort(length.begin(), length.end()); - const T a = length[2]; - const T b = length[1]; - const T c = length[0]; + const T a = length[2]; + const T b = length[1]; + const T c = length[0]; - return T(0.25) * std::sqrt((a + (b + c)) * (c - (a - b)) * (c + (a - b)) * (a + (b - c))); -} + // Minimal assumption on geometry + if (a > (b + c)) + { + throw std::runtime_error("Area is negative"); + } + + return T(0.25) * std::sqrt((((a + (b + c)) * (a + (b - c))) * (c + (a - b))) * (c - (a - b))); + } /** * @brief Compute the integration basis in order to map a point from the reference to physcal frame (for a triangle) @@ -107,11 +113,11 @@ integration_basis(const point& p0, const point& p1, const point T volume_tetrahedron_kahan(const point& p0, const point& p1, const point& p2, const point& p3) { - const auto v0 = (p1 - p0).to_vector(); - const auto v1 = (p2 - p0).to_vector(); - const auto v2 = (p3 - p0).to_vector(); - - return std::abs(v0.dot(v1.cross(v2))) / T(6); + // facial difference = (u-v+w) + auto fd = [](const T &u, const T &v, const T &w) + { return (std::max(u, w) - v) + std::min(u, w); }; + + // lengths of the edges + const auto l10 = (p1 - p0).to_vector().norm(); + const auto l20 = (p2 - p0).to_vector().norm(); + const auto l30 = (p3 - p0).to_vector().norm(); + + const auto l32 = (p3 - p2).to_vector().norm(); + const auto l31 = (p3 - p1).to_vector().norm(); + const auto l21 = (p2 - p1).to_vector().norm(); + + // sort edges + std::array, 3> length = { + std::make_pair(l10, l32), + std::make_pair(l20, l31), + std::make_pair(l30, l21)}; + + std::sort(length.begin(), length.end(), [&](const std::pair &va, const std::pair &vb) + { return (va.first + va.second < vb.first + vb.second); }); + + const auto [u, U] = length[2]; + const auto [v, V] = length[1]; + const auto [w, W] = length[0]; + + // Accurate products + const auto X = fd(w, U, v) * (U + v + w); + const auto Y = fd(u, V, w) * (V + w + u); + const auto Z = fd(v, W, u) * (W + u + v); + + const auto x = fd(U, v, w) * fd(v, w, U); + const auto y = fd(V, w, u) * fd(w, u, V); + const auto z = fd(W, u, v) * fd(u, v, W); + + // elementary factors + const auto xi = std::sqrt(x * Y * Z); + const auto eta = std::sqrt(y * Z * X); + const auto zeta = std::sqrt(z * X * Y); + const auto lambda = std::sqrt(x * y * z); + + const auto det = T(192.) * u * v * w; + + return std::sqrt((xi + eta + zeta - lambda) * (lambda + xi + eta - zeta) * (eta + zeta + lambda - xi) * (zeta + lambda + xi - eta)) / det; } /** diff --git a/libdiskpp/include/diskpp/geometry/geometry_all.hpp b/libdiskpp/include/diskpp/geometry/geometry_all.hpp index d1830eeb..18dd9fe1 100644 --- a/libdiskpp/include/diskpp/geometry/geometry_all.hpp +++ b/libdiskpp/include/diskpp/geometry/geometry_all.hpp @@ -80,6 +80,23 @@ average_diameter(const Mesh& msh) return h/msh.cells_size(); } +template +auto +minimum_diameter(const Mesh& msh) +{ + typename Mesh::coordinate_type h = 0; + + if (msh.cells_size() > 0) { + h = diameter(msh, msh[0]); + } + + for (auto& cl : msh ) { + h = std::min( diameter(msh, cl), h); + } + + return h; +} + /** * \brief return the list of points of an element * diff --git a/libdiskpp/include/diskpp/geometry/geometry_generic.hpp b/libdiskpp/include/diskpp/geometry/geometry_generic.hpp index fac0a1c3..981f0772 100644 --- a/libdiskpp/include/diskpp/geometry/geometry_generic.hpp +++ b/libdiskpp/include/diskpp/geometry/geometry_generic.hpp @@ -363,6 +363,73 @@ diameter(const generic_mesh&, const typename generic_mesh::face&) return 1.; } +/** + * \brief Allows to known if the given point is inside a 2D cell + * + * \param msh a reference to the mesh + * \param cl a 3D cell + * \param pt coordinate of a point + * + */ + +template < typename T > +bool is_inside( const generic_mesh< T, 2 > &msh, const typename generic_mesh< T, 2 >::cell &cl, + const typename generic_mesh< T, 2 >::point_type &pt ) { + auto tris = triangulate_polygon( msh, cl ); + + for ( auto &tri : tris ) { + + if ( is_inside( tri, pt ) ) { + return true; + } + } + + return false; +} + +/** + * \brief Allows to known if the given point is inside a 2D cell + * + * \param msh a reference to the mesh + * \param cl a 3D cell + * \param pt coordinate of a point + * + */ + +template < typename T > +bool is_inside( const generic_mesh< T, 3 > &msh, const typename generic_mesh< T, 3 >::cell &cl, + const typename generic_mesh< T, 3 >::point_type &pt ) { + + // search in bounding box + const auto pts = points( msh, cl ); + + T xmin = std::numeric_limits< T >::max(), ymin = xmin, zmin = xmin; + T xmax = std::numeric_limits< T >::min(), ymax = xmax, zmax = xmax; + + for ( auto &p : pts ) { + xmin = std::min( xmin, p.x() ); + xmax = std::max( xmax, p.x() ); + ymin = std::min( ymin, p.y() ); + ymax = std::max( ymax, p.y() ); + zmin = std::min( zmin, p.z() ); + zmax = std::max( zmax, p.z() ); + } + + if ( xmin <= pt.x() && pt.x() <= xmax ) { + if ( ymin <= pt.y() && pt.y() <= ymax ) { + if ( zmin <= pt.z() && pt.z() <= zmax ) { + auto rss = split_in_raw_tetrahedra( msh, cl ); + for ( auto &rs : rss ) { + if ( is_inside( rs, pt ) ) { + return true; + } + } + } + } + } + + return false; +} } // namespace disk diff --git a/libdiskpp/include/diskpp/geometry/geometry_generic_triangulations.hpp b/libdiskpp/include/diskpp/geometry/geometry_generic_triangulations.hpp index daa88583..3a174d56 100644 --- a/libdiskpp/include/diskpp/geometry/geometry_generic_triangulations.hpp +++ b/libdiskpp/include/diskpp/geometry/geometry_generic_triangulations.hpp @@ -4,6 +4,9 @@ #include "triangle/triangle_mesher.h" +#include "diskpp/common/simplicial_formula.hpp" +#include "diskpp/mesh/mesh.hpp" + namespace disk { template @@ -24,7 +27,29 @@ template auto measure(const triangle& t) { - return area_triangle_kahan(t.p0, t.p1, t.p2); + return area_triangle_kahan( t.p0, t.p1, t.p2 ); +} + +template < typename T, size_t DIM > +bool is_inside( const triangle< T, DIM > &t, const point< T, DIM > &p ) { + const T tole = 1e-12; + const auto area = measure( t ); + const T un_2a = 1.0 / ( 2.0 * area ); + + const T sp = un_2a * ( t.p0.y() * t.p2.x() - t.p0.x() * t.p2.y() + + ( t.p2.y() - t.p0.y() ) * p.x() + ( t.p0.x() - t.p2.x() ) * p.y() ); + + if ( -tole < sp && sp < ( 1.0 + tole ) ) { + const T tp = un_2a * ( t.p0.x() * t.p1.y() - t.p0.y() * t.p1.x() + + ( t.p0.y() - t.p1.y() ) * p.x() + ( t.p1.x() - t.p0.x() ) * p.y() ); + if ( -tole < tp && tp < ( 1.0 + tole ) ) { + if ( ( sp + tp ) < ( 1.0 + tole ) ) { + return true; + } + } + } + + return false; } /* Call J. R. Shewchuk's Triangle to triangulate a mesh element */ @@ -76,7 +101,7 @@ triangulate_nonconvex_polygon(const generic_mesh& msh, t.p0 = point( tio_out.pointlist[2*p0base+0], tio_out.pointlist[2*p0base+1] ); t.p1 = point( tio_out.pointlist[2*p1base+0], tio_out.pointlist[2*p1base+1] ); t.p2 = point( tio_out.pointlist[2*p2base+0], tio_out.pointlist[2*p2base+1] ); - + ret.push_back(t); } @@ -107,6 +132,16 @@ triangulate_convex_polygon(const generic_mesh& msh, auto pts = points(msh, cl); assert(pts.size() > 2); + + if ( pts.size() == 3 ) { + triangle< T, 2 > t; + t.p0 = pts[0]; + t.p1 = pts[1]; + t.p2 = pts[2]; + ret.push_back( t ); + return ret; + } + auto center = std::accumulate(pts.begin(), pts.end(), point(0,0)); center = center/T(pts.size()); diff --git a/libdiskpp/include/diskpp/geometry/geometry_simplicial.hpp b/libdiskpp/include/diskpp/geometry/geometry_simplicial.hpp index d4c2628d..2d9275e1 100644 --- a/libdiskpp/include/diskpp/geometry/geometry_simplicial.hpp +++ b/libdiskpp/include/diskpp/geometry/geometry_simplicial.hpp @@ -407,6 +407,34 @@ measure(const simplicial_mesh& msh, return (pts[1] - pts[0]).to_vector().norm(); } +template < typename T > +bool is_inside( const simplicial_mesh< T, 2 > &msh, + const typename simplicial_mesh< T, 2 >::cell_type &cl, + const typename simplicial_mesh< T, 2 >::point_type &pt ) { + const T tole = 1e-12; + const auto area = measure( msh, cl ); + const T un_2a = 1.0 / ( 2.0 * area ); + + auto pts = points( msh, cl ); + + const T sp = + un_2a * ( pts[0].y() * pts[2].x() - pts[0].x() * pts[2].y() + + ( pts[2].y() - pts[0].y() ) * pt.x() + ( pts[0].x() - pts[2].x() ) * pt.y() ); + + if ( -tole < sp && sp < ( 1.0 + tole ) ) { + const T tp = + un_2a * ( pts[0].x() * pts[1].y() - pts[0].y() * pts[1].x() + + ( pts[0].y() - pts[1].y() ) * pt.x() + ( pts[1].x() - pts[0].x() ) * pt.y() ); + if ( -tole < tp && tp < ( 1.0 + tole ) ) { + if ( ( sp + tp ) < ( 1.0 + tole ) ) { + return true; + } + } + } + + return false; +} + template bool is_inside(const simplicial_mesh& msh, @@ -428,10 +456,10 @@ is_inside(const simplicial_mesh& msh, T t1 = v0.cross(v1).dot( to_vector(pt - pts[0]) ); if (t1 < 0) count--; else count++; - + T t2 = v4.cross(v2).dot( to_vector(pt - pts[1]) ); if (t2 < 0) count--; else count++; - + T t3 = v1.cross(v3).dot( to_vector(pt - pts[0]) ); if (t3 < 0) count--; else count++; diff --git a/libdiskpp/include/diskpp/loaders/loader_gmsh.hpp b/libdiskpp/include/diskpp/loaders/loader_gmsh.hpp index 44d78828..d0f9384d 100644 --- a/libdiskpp/include/diskpp/loaders/loader_gmsh.hpp +++ b/libdiskpp/include/diskpp/loaders/loader_gmsh.hpp @@ -10,7 +10,9 @@ #pragma once +#ifdef HAVE_GMSH #include "gmsh.h" +#endif #include "diskpp/mesh/mesh_storage.hpp" @@ -21,6 +23,7 @@ namespace disk { template class gmsh_geometry_loader; +#ifdef HAVE_GMSH template class gmsh_geometry_loader> : public mesh_loader> { @@ -1144,5 +1147,6 @@ void dump_subdomain_boundaries(const Mesh& msh) } } } +#endif } //namespace disk diff --git a/libdiskpp/include/diskpp/loaders/loader_poly.hpp b/libdiskpp/include/diskpp/loaders/loader_poly.hpp index 7b9878c1..94124fea 100644 --- a/libdiskpp/include/diskpp/loaders/loader_poly.hpp +++ b/libdiskpp/include/diskpp/loaders/loader_poly.hpp @@ -102,12 +102,11 @@ read_grp_line(std::ifstream& ifs) { std::vector elem; std::string name; - size_t cell_id, nb_elem; + size_t grp_id, nb_elem; ifs >> name; - ifs >> cell_id; + ifs >> grp_id; ifs >> nb_elem; - // std::cout << cell_id << ", " << nb_elem << std::endl; elem.reserve(nb_elem); for (size_t j = 0; j < nb_elem; j++) { @@ -116,7 +115,7 @@ read_grp_line(std::ifstream& ifs) elem.push_back(tmp); } - return std::make_pair(cell_id, elem); + return std::make_pair( grp_id, elem ); } bool @@ -625,9 +624,8 @@ class poly_mesh_loader : public mesh_loader> storage->boundary_info.resize(faces.size()); for (auto& [id, faces] : faces_to_grp) { - for (auto& face_id : faces) - { - boundary_descriptor bi(id, true); + for ( auto &face_id : faces ) { + boundary_descriptor bi( id, true ); storage->boundary_info.at(conv_table.at(face_id)) = bi; } } diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/Fields.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/Fields.hpp new file mode 100644 index 00000000..90ea751e --- /dev/null +++ b/libdiskpp/include/diskpp/mechanics/NewtonSolver/Fields.hpp @@ -0,0 +1,327 @@ +/* + * /\ Matteo Cicuttin (C) 2016, 2017, 2018 + * /__\ matteo.cicuttin@enpc.fr + * /_\/_\ École Nationale des Ponts et Chaussées - CERMICS + * /\ /\ + * /__\ /__\ DISK++, a template library for DIscontinuous SKeletal + * /_\/_\/_\/_\ methods. + * + * This file is copyright of the following authors: + * Nicolas Pignet (C) 2024 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * If you use this code or parts of it for scientific publications, you + * are required to cite it as following: + * + * Hybrid High-Order methods for finite elastoplastic deformations + * within a logarithmic strain framework. + * M. Abbas, A. Ern, N. Pignet. + * International Journal of Numerical Methods in Engineering (2019) + * 120(3), 303-327 + * DOI: 10.1002/nme.6137 + */ + +#pragma once + +#include "diskpp/adaptivity/adaptivity.hpp" + +#include + +namespace disk { + +namespace mechanics { + +enum class FieldName { + DEPL, + DEPL_CELLS, + DEPL_FACES, + VITE_CELLS, + ACCE_CELLS, + RESI_CELLS, +}; + +std::string getFieldName( FieldName name ) { + switch ( name ) { + case FieldName::DEPL: + return "DEPL"; + break; + case FieldName::DEPL_CELLS: + return "DEPL_CELLS"; + break; + case FieldName::DEPL_FACES: + return "DEPL_FACES"; + break; + case FieldName::VITE_CELLS: + return "VITE_CELLS"; + break; + case FieldName::ACCE_CELLS: + return "ACCE_CELLS"; + break; + case FieldName::RESI_CELLS: + return "RESI_CELLS"; + break; + default: + break; + } + + return "Unknown type"; +} + +template < typename T > +T norm( const std::vector< dynamic_vector< T > > &field ) { + T nm = 0.0; + + for ( auto &vect : field ) { + nm += vect.squaredNorm(); + } + + return std::sqrt( nm ); +}; + +template < typename T > +dynamic_vector< T > asVector( const std::vector< dynamic_vector< T > > &field ) { + int size = 0; + + for ( auto &vect : field ) { + size += vect.size(); + } + + dynamic_vector< T > ret = dynamic_vector< T >( size ); + + size = 0; + for ( auto &vect : field ) { + ret.segment( size, vect.size() ) = vect; + size += vect.size(); + } + + return ret; +} + +template < typename T > +void fromVector( const dynamic_vector< T > &vfield, std::vector< dynamic_vector< T > > &field ) { + int size = 0; + for ( auto &vect : field ) { + vect = vfield.segment( size, vect.size() ); + size += vect.size(); + } + + assert( size == vfield.size() ); +} + +/** + * @brief Field at one time. + * + * @tparam scalar_type + */ +template < typename scalar_type > +class TimeField { + typedef dynamic_vector< scalar_type > vector_type; + + std::map< FieldName, std::vector< vector_type > > m_fields; + + scalar_type m_time; + + public: + TimeField() : m_time( 0 ) {} + + /** + * @brief Get the current time + * + */ + scalar_type getTime( void ) const { return m_time; } + + /** + * @brief Set the current time + * + */ + void setTime( scalar_type time ) { m_time = time; } + + void setField( FieldName name, const std::vector< vector_type > &field ) { + m_fields[name] = field; + } + + auto getField( FieldName name ) const { + // std::cout << getFieldName(name) << std::endl; + return m_fields.at( name ); + } + + void clearField( FieldName name ) { + if ( auto search = m_fields.find( name ); search != m_fields.end() ) { + m_fields.erase( search ); + } + } + + void getFieldInfo() const { + std::cout << "The TimeField at time=" << m_time << ", constains " << m_fields.size() + << " fields." << std::endl; + for ( auto &[key, val] : m_fields ) { + std::cout << "Field " << getFieldName( key ) << " with norm: " << norm( val ) + << std::endl; + } + } + + template < typename Mesh > + void createZeroField( FieldName name, const Mesh &mesh, + const MeshDegreeInfo< Mesh > °ree_infos ) { + std::vector< vector_type > field; + + if ( name == FieldName::DEPL || name == FieldName::DEPL_CELLS || + name == FieldName::VITE_CELLS || name == FieldName::ACCE_CELLS ) { + field.reserve( mesh.cells_size() ); + + for ( auto &cl : mesh ) { + const auto di = degree_infos.cellDegreeInfo( mesh, cl ); + const auto num_cell_dofs = + vector_basis_size( di.cell_degree(), Mesh::dimension, Mesh::dimension ); + size_t num_faces_dofs = 0; + + if ( name == FieldName::DEPL ) { + const auto fcs = faces( mesh, cl ); + const auto fcs_di = di.facesDegreeInfo(); + + for ( auto &fc_di : fcs_di ) { + if ( fc_di.hasUnknowns() ) { + num_faces_dofs += vector_basis_size( + fc_di.degree(), Mesh::dimension - 1, Mesh::dimension ); + } + } + } + + field.push_back( vector_type::Zero( num_cell_dofs + num_faces_dofs ) ); + } + } else if ( name == FieldName::DEPL_FACES ) { + field.reserve( mesh.faces_size() ); + + for ( auto itor = mesh.faces_begin(); itor != mesh.faces_end(); itor++ ) { + const auto fc = *itor; + const auto di = degree_infos.degreeInfo( mesh, fc ); + + size_t num_face_dofs = 0; + if ( di.hasUnknowns() ) { + num_face_dofs = + vector_basis_size( di.degree(), Mesh::dimension - 1, Mesh::dimension ); + } + + field.push_back( vector_type::Zero( num_face_dofs ) ); + } + } else { + throw std::runtime_error( "Unknown field" ); + } + + this->setField( name, field ); + } + + template < typename Mesh > + void createField( FieldName name, const Mesh &mesh, const MeshDegreeInfo< Mesh > °ree_infos, + const vector_rhs_function< Mesh > func ) { + std::vector< vector_type > field; + + if ( name == FieldName::DEPL || name == FieldName::DEPL_CELLS || + name == FieldName::VITE_CELLS || name == FieldName::ACCE_CELLS ) { + field.reserve( mesh.cells_size() ); + + for ( auto &cl : mesh ) { + if ( name == FieldName::DEPL ) { + field.push_back( project_function( mesh, cl, degree_infos, func, 2 ) ); + } else { + const auto di = degree_infos.cellDegreeInfo( mesh, cl ); + + field.push_back( project_function( mesh, cl, di.cell_degree(), func, 2 ) ); + } + } + } else if ( name == FieldName::DEPL_FACES ) { + field.reserve( mesh.faces_size() ); + + for ( auto itor = mesh.faces_begin(); itor != mesh.faces_end(); itor++ ) { + const auto fc = *itor; + const auto fdi = degree_infos.degreeInfo( mesh, fc ); + + field.push_back( project_function( mesh, fc, fdi.degree(), func, 2 ) ); + } + } else { + throw std::runtime_error( "Unknown field" ); + } + + this->setField( name, field ); + } + + bool empty() const { return m_fields.empty(); } +}; + +template < typename scalar_type > +class MultiTimeField { + private: + typedef dynamic_vector< scalar_type > vector_type; + typedef TimeField< scalar_type > field_type; + + std::vector< field_type > m_fields; + + public: + MultiTimeField() {}; + + MultiTimeField( const int n_fields ) { m_fields.resize( n_fields ); }; + + void setCurrentTime( scalar_type time ) { m_fields.at( 0 ).setTime( time ); } + + field_type getCurrentTimeField() const { return this->getTimeField( 0 ); } + + field_type getPreviousTimeField() const { return this->getTimeField( -1 ); } + + field_type getTimeField( const int &relative_index ) const { + return m_fields.at( -relative_index ); + } + + void setTimeField( const int &relative_index, const field_type &field ) { + m_fields.at( -relative_index ) = field; + } + + void setCurrentTimeField( const field_type &field ) { return this->setTimeField( 0, field ); } + + auto getField( const int &relative_index, FieldName name ) const { + // std::cout << "Get " << getFieldName(name) << " (" << relative_index + // << "): " << norm(m_fields.at(-relative_index).getField(name)) + // << std::endl; + + return m_fields.at( -relative_index ).getField( name ); + } + + auto getCurrentField( FieldName name ) const { return m_fields.at( 0 ).getField( name ); } + + void setField( const int &relative_index, FieldName name, + const std::vector< vector_type > &field ) { + // std::cout << "Set " << getFieldName(name) << " (" << relative_index + // << "): " << norm(field) << std::endl; + + return m_fields.at( -relative_index ).setField( name, field ); + } + + void setCurrentField( FieldName name, const std::vector< vector_type > &field ) { + return this->setField( 0, name, field ); + } + + template < typename Mesh > + void createField( const int &relative_index, FieldName name, const Mesh &mesh, + const MeshDegreeInfo< Mesh > °ree_infos, + const vector_rhs_function< Mesh > func ) { + m_fields.at( -relative_index ).createField( name, mesh, degree_infos, func ); + } + + auto getNumberOfTimeField() const { return m_fields.size(); } + + void update() { + + int n_fields = this->getNumberOfTimeField(); + + for ( int i = n_fields - 1; i > 0; i-- ) { + m_fields.at( i ) = m_fields.at( i - 1 ); + } + } + + void restore() { m_fields.at( 0 ) = m_fields.at( 1 ); } +}; +} // namespace mechanics + +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/GenericIteration.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/GenericIteration.hpp new file mode 100644 index 00000000..107a407f --- /dev/null +++ b/libdiskpp/include/diskpp/mechanics/NewtonSolver/GenericIteration.hpp @@ -0,0 +1,296 @@ +/* + * /\ Matteo Cicuttin (C) 2016, 2017, 2018 + * /__\ matteo.cicuttin@enpc.fr + * /_\/_\ École Nationale des Ponts et Chaussées - CERMICS + * /\ /\ + * /__\ /__\ DISK++, a template library for DIscontinuous SKeletal + * /_\/_\/_\/_\ methods. + * + * This file is copyright of the following authors: + * Nicolas Pignet (C) 2019 nicolas.pignet@enpc.fr + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * If you use this code or parts of it for scientific publications, you + * are required to cite it as following: + * + * Hybrid High-Order methods for finite elastoplastic deformations + * within a logarithmic strain framework. + * M. Abbas, A. Ern, N. Pignet. + * International Journal of Numerical Methods in Engineering (2019) + * 120(3), 303-327 + * DOI: 10.1002/nme.6137 + */ + +// Generic non-linear iteration + +#pragma once + +#include "diskpp/adaptivity/adaptivity.hpp" +#include "diskpp/bases/bases.hpp" +#include "diskpp/boundary_conditions/boundary_conditions.hpp" +#include "diskpp/common/timecounter.hpp" +#include "diskpp/mechanics/NewtonSolver/Fields.hpp" +#include "diskpp/mechanics/NewtonSolver/LineSearch.hpp" +#include "diskpp/mechanics/NewtonSolver/NewtonSolverComput.hpp" +#include "diskpp/mechanics/NewtonSolver/NewtonSolverDynamic.hpp" +#include "diskpp/mechanics/NewtonSolver/NewtonSolverInformations.hpp" +#include "diskpp/mechanics/NewtonSolver/NonLinearData.hpp" +#include "diskpp/mechanics/NewtonSolver/NonLinearParameters.hpp" +#include "diskpp/mechanics/NewtonSolver/StabilizationManager.hpp" +#include "diskpp/mechanics/NewtonSolver/TimeManager.hpp" +#include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" +#include "diskpp/methods/hho" +#include "diskpp/solvers/direct_solvers.hpp" + +#include +#include +#include +#include +#include + +namespace disk { + +namespace mechanics { + +/** + * @brief Generic non-linear iteration for nonlinear solid mechanics + * + * Specialized for HHO methods + * + * Options : - small and finite deformations + * - plasticity, hyperelasticity (various laws) + * + * @tparam MeshType type of the mesh + */ +template < typename MeshType > +class GenericIteration { + protected: + typedef MeshType mesh_type; + typedef typename mesh_type::cell cell_type; + typedef typename mesh_type::coordinate_type scalar_type; + typedef typename mesh_type::point_type point_type; + + typedef dynamic_matrix< scalar_type > matrix_type; + typedef dynamic_vector< scalar_type > vector_type; + + typedef NonLinearParameters< scalar_type > param_type; + typedef vector_boundary_conditions< mesh_type > bnd_type; + typedef Behavior< mesh_type > behavior_type; + + typedef vector_mechanics_hho_assembler< mesh_type > assembler_type; + typedef mechanical_computation< mesh_type > elem_type; + typedef dynamic_computation< mesh_type > dyna_type; + + typedef std::function< static_vector< scalar_type, mesh_type::dimension >( const point_type &, + scalar_type ) > + func_type; + + using load_at_time_type = + std::function< static_vector< scalar_type, mesh_type::dimension >( const point_type & ) >; + + vector_type m_system_displ; + + assembler_type m_assembler; + + std::vector< vector_type > m_bL; + std::vector< matrix_type > m_AL; + + TimeStep< scalar_type > m_time_step; + + std::shared_ptr< solvers::sparse_solver< scalar_type > > m_lin_solv; + + dyna_type m_dyna; + + scalar_type m_F_int, m_resi_init; + + ConvergenceAcceleration< scalar_type > m_accel; + + bool m_verbose; + + std::unique_ptr< load_at_time_type > _getLoad( const std::unique_ptr< func_type > &lf, + scalar_type time ) { + if ( lf ) { + const auto load_function = *lf; + const auto time_eval = time; + return std::make_unique< std::function< + static_vector< scalar_type, mesh_type::dimension >( const point_type & ) > >( + [load_function, time_eval]( const point_type &p ) -> auto { + return load_function( p, time_eval ); + } ); + } + + return nullptr; + } + + public: + GenericIteration() : m_verbose( false ) {}; + + GenericIteration( const mesh_type &msh, const bnd_type &bnd, const param_type &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + const std::shared_ptr< solvers::sparse_solver< scalar_type > > lin_solv, + const TimeStep< scalar_type > ¤t_step ) + : m_verbose( rp.m_verbose ), + m_time_step( current_step ), + m_dyna( rp ), + m_lin_solv( lin_solv ) { + m_AL.clear(); + m_AL.resize( msh.cells_size() ); + + m_bL.clear(); + m_bL.resize( msh.cells_size() ); + + m_assembler = assembler_type( msh, degree_infos, bnd ); + } + + bool verbose( void ) const { return m_verbose; } + + void verbose( bool v ) { m_verbose = v; } + + virtual InitInfo initialize( const mesh_type &msh, const bnd_type &bnd, const param_type &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + NonLinearData< scalar_type > &data, behavior_type &behavior, + const StabCoeffManager< scalar_type > &stab_manager, + MultiTimeField< scalar_type > &fields ) { + timecounter tc; + tc.tic(); + m_dyna.prediction( msh, degree_infos, m_time_step, fields ); + tc.toc(); + + InitInfo ii; + ii.m_time_dyna = tc.elapsed(); + return ii; + } + + virtual AssemblyInfo assemble( const mesh_type &msh, const bnd_type &bnd, const param_type &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + const std::unique_ptr< func_type > &lf, + NonLinearData< scalar_type > &data, behavior_type &behavior, + StabCoeffManager< scalar_type > &stab_manager, + MultiTimeField< scalar_type > &fields ) { + + throw std::runtime_error( "GenericIteration.assemble has to be overloaded." ); + return AssemblyInfo(); + } + + virtual SolveInfo solve() { + timecounter tc; + + // std::cout << "LHS" << m_assembler.LHS << std::endl; + // std::cout << "RHS" << m_assembler.RHS << std::endl; + + tc.tic(); + const auto status = m_lin_solv->solve( m_assembler.LHS, m_assembler.RHS, m_system_displ ); + tc.toc(); + + if ( status != solvers::direct_solver_status::ok ) { + throw std::runtime_error( "Error during linear system resolution" ); + } + + return SolveInfo( m_assembler.LHS.rows(), m_assembler.LHS.nonZeros(), tc.elapsed() ); + } + + virtual scalar_type postprocess( const mesh_type &msh, const bnd_type &bnd, + const param_type &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + const std::unique_ptr< func_type > &lf, + NonLinearData< scalar_type > &data, behavior_type &behavior, + StabCoeffManager< scalar_type > &stab_manager, + MultiTimeField< scalar_type > &fields ) { + throw std::runtime_error( "GenericIteration.postprocess has to be overloaded." ); + return 0.0; + } + + bool convergence( const param_type &rp, const size_t iter, + const MultiTimeField< scalar_type > &fields ) { + // norm of the solution + auto norm_sol = norm( fields.getCurrentField( FieldName::DEPL_FACES ) ); + + // norm of the rhs + const scalar_type residual = m_assembler.RHS.norm(); + scalar_type max_error = 0.0; + for ( size_t i = 0; i < m_assembler.RHS.size(); i++ ) { + max_error = std::max( max_error, std::abs( m_assembler.RHS( i ) ) ); + } + + // norm of the increment + const scalar_type error_incr = m_system_displ.norm(); + scalar_type relative_displ = 1.0, relative_error = 1.0; + + if ( m_F_int > 1e-12 ) { + relative_error = residual / m_F_int; + } + if ( norm_sol > 1e-12 && iter > 0 ) { + relative_displ = error_incr / norm_sol; + } + + if ( m_verbose ) { + std::string s_iter = " " + std::to_string( iter ) + " "; + s_iter.resize( 9 ); + + if ( iter == 0 ) { + std::cout + << "----------------------------------------------------------------------" + "------------------------" + << std::endl; + std::cout << "| Iteration | Norme l2 incr | Relative incr | Residual l2 | " + "Relative error | Maximum error |" + << std::endl; + std::cout + << "----------------------------------------------------------------------" + "------------------------" + << std::endl; + } + std::ios::fmtflags f( std::cout.flags() ); + std::cout.precision( 5 ); + std::cout.setf( std::iostream::scientific, std::iostream::floatfield ); + std::cout << "| " << s_iter << " | " << error_incr << " | " << relative_displ + << " | " << residual << " | " << relative_error << " | " << max_error + << " |" << std::endl; + std::cout << "-------------------------------------------------------------------------" + "---------------------" + << std::endl; + std::cout.flags( f ); + } + + const scalar_type error = std::max( relative_displ, relative_error ); + // const scalar_type error = relative_error; + + if ( !std::isfinite( error ) || std::isnan( error ) || !std::isfinite( max_error ) || + std::isnan( max_error ) || !std::isfinite( residual ) || std::isnan( residual ) || + !std::isfinite( -residual ) || std::isnan( -residual ) || residual > 1e100 ) { + throw std::runtime_error( "Norm of residual is not finite." ); + } + + if ( residual > 1e20 || relative_displ > 1e20 || relative_error > 1e20 ) { + throw std::runtime_error( "Norm of residual is too large." ); + } + + if ( iter == 0 ) { + this->m_resi_init = residual; + } + + if ( residual > 1e10 * this->m_resi_init ) { + throw std::runtime_error( "Norm of residual diverges." ); + } + + if ( error <= rp.getConvergenceCriteria() ) { + return true; + } else { + return false; + } + } + + virtual scalar_type post_convergence( const mesh_type &msh, const bnd_type &bnd, + const param_type &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + const NonLinearData< scalar_type > &data, + const StabCoeffManager< scalar_type > &stab_manager, + MultiTimeField< scalar_type > &fields ) { + return 0.0; + } +}; +} // namespace mechanics +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/LineSearch.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/LineSearch.hpp new file mode 100644 index 00000000..ef98e19a --- /dev/null +++ b/libdiskpp/include/diskpp/mechanics/NewtonSolver/LineSearch.hpp @@ -0,0 +1,365 @@ +/* + * /\ Matteo Cicuttin (C) 2016, 2017, 2018 + * /__\ matteo.cicuttin@enpc.fr + * /_\/_\ École Nationale des Ponts et Chaussées - CERMICS + * /\ /\ + * /__\ /__\ DISK++, a template library for DIscontinuous SKeletal + * /_\/_\/_\/_\ methods. + * + * This file is copyright of the following authors: + * Nicolas Pignet (C) 2019 nicolas.pignet@enpc.fr + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * If you use this code or parts of it for scientific publications, you + * are required to cite it as following: + * + * Hybrid High-Order methods for finite elastoplastic deformations + * within a logarithmic strain framework. + * M. Abbas, A. Ern, N. Pignet. + * International Journal of Numerical Methods in Engineering (2019) + * 120(3), 303-327 + * DOI: 10.1002/nme.6137 + */ + +#pragma once + +#include + +namespace disk { + +namespace mechanics { + +/** + * @brief LineSearch + * + */ + +// Référence of Aitken and Anderson algorithm. +// Isabelle Ramière, Thomas Helfer. Iterative residual-based vector methods to accelerate fixed +// point iterations. +// Computers & Mathematics with Applications, 2015, 70, pp.2210 - 2226. +// 10.1016/j.camwa.2015.08.025. cea-01403292 + +template < typename T > +class ConvergenceAcceleration { + + typedef dynamic_vector< T > vector_type; + typedef dynamic_matrix< T > matrix_type; + + int n_iter; + + enum kiter { + k = 1, + km = 0, + }; + std::vector< vector_type > G, Xa; + + public: + ConvergenceAcceleration() : n_iter( 0 ) { + G.resize( 2 ); + Xa.resize( 2 ); + } + + vector_type aitken( const vector_type &G_k ) { + // Also called crossed secand method - eq 44. + if ( n_iter == 0 ) { + n_iter++; + Xa[km] = G_k; + return G_k; + } else if ( n_iter == 1 ) { + n_iter++; + G[km] = G_k; + Xa[k] = G_k; + return G_k; + } else { + n_iter++; + G[k] = G_k; + const auto dG_k = G[k] - G[km]; + + const auto dX_k = G[k] - Xa[k]; + const auto dX_km = G[km] - Xa[km]; + const auto ddX = dX_k - dX_km; + + // compute acceleration + const T wr = ddX.dot( dG_k ) / ddX.squaredNorm(); + + // compute accelerted solution + const vector_type Xa_kp = G_k - wr * dX_k; + + // update + G[km] = G[k]; + + Xa[km] = Xa[k]; + Xa[k] = Xa_kp; + + return Xa_kp; + } + } + + vector_type relaxation( const vector_type &X_kp, const T omega = 0.5 ) { + if ( n_iter == 0 ) { + n_iter++; + Xa[k] = X_kp; + return X_kp; + } else { + n_iter++; + + // compute accelerted solution + const vector_type Xa_kp = ( 1.0 - omega ) * Xa[k] + omega * X_kp; + + // update + Xa[k] = Xa_kp; + + return Xa_kp; + } + } + + template < typename Func > + void secant( const Func &func, const double ALF = 0.1, const int MAXIT = 10 ) { + + const T TOLX = std::numeric_limits< T >::epsilon(); + T p0, p1, f1, f0, rho_0, rho_1; + T rho, rho_neg, rho_pos, rho_opt, rho_new, rho_cur; + T f, f_opt, f_cur; + bool b_pos; + + // fixed paramters - from code_aster + const T rho_min = 1e-2, rho_max = 10., rho_excl = 0.9e-2; + const T parmul = 3.0; + + // Doc: + // https://codeaster.pages.pleiade.edf.fr/doc/docaster/manuals/man_r/r5/r5.03.01/Recherche_lin_aire.html + // METHODE="SECANT" + + // Compute residual.dot(increment) (and update solution) + // auto _f = [&fvec, &func, &dx, &xold, &n, &x]( const T &rho ) { + // for ( int j = 0; j < n; j++ ) + // G[j] = xold[j] + rho * dG[j]; + // const auto norm = func( x ); + + // T f = 0.0; + // for ( int j = 0; j < n; j++ ) + // f += fvec[j] * dG[j]; + // return f; + // }; + + // project bound on admissible interval + auto _proj = [rho_min, rho_max, rho_excl]( T &rho ) { + const T rho_tmp = rho; + if ( rho_tmp < rho_min ) { + rho = rho_min; + } + if ( rho_tmp > rho_max ) { + rho = rho_max; + } + if ( rho_tmp < 0.0 && rho_tmp >= -rho_excl ) { + rho = -rho_excl; + } + if ( rho_tmp >= 0 && rho_tmp <= rho_excl ) { + rho = rho_excl; + } + }; + + // initial values + const T f_old = func( 0.0 ); + const T f_cvg = ALF * std::abs( f_old ); + const T sens = ( f_old <= 0.0 ) ? 1.0 : -1.0; + + rho_opt = 1.0, rho = sens * 1.0; + rho_neg = 0.0, rho_pos = std::numeric_limits< T >::signaling_NaN(); + f_opt = 10e100; + + rho_0 = 0.0, rho_1 = rho_0; + f0 = sens * f_old, f1 = f0; + + b_pos = false; + + for ( int its = 0; its < MAXIT; its++ ) { + // Compute new residual + try { + f = func( rho ); + } catch ( ... ) { + break; + } + + rho_cur = sens * rho; + f_cur = sens * f; + + // Store value + rho_0 = rho_1, f0 = f1; + rho_1 = rho_cur, f1 = f_cur; + + // Update bounds + if ( f_cur < 0.0 ) { + rho_neg = rho_cur; + } else { + b_pos = true; + rho_pos = rho_cur; + } + + // Optimal solution until now ? + if ( std::abs( f_cur ) < std::abs( f_opt ) ) { + rho_opt = rho_cur; + f_opt = f_cur; + _proj( rho_opt ); + } + + // Search maximal bound + if ( b_pos ) { + if ( std::abs( f1 ) >= std::abs( f0 ) ) { + // f is not decreased - use dichotomie + rho_new = 0.5 * ( rho_neg + rho_pos ); + } else { + // linear interpolation + if ( std::abs( rho_1 - rho_0 ) > TOLX ) { + p1 = ( f1 - f0 ) / ( rho_1 - rho_0 ); + p0 = f0 - p1 * rho_0; + + if ( std::abs( p1 ) <= std::abs( f0 ) / ( rho_pos + rho_0 ) ) { + rho_new = 0.5 * ( rho_neg + rho_pos ); + } else { + rho_new = -p0 / p1; + } + } else { + // failed + break; + } + } + } else { + rho_new = parmul * rho_cur; + } + + // minimal bound + if ( rho_new < rho_neg ) { + if ( b_pos ) { + rho_new = 0.5 * ( rho_neg + rho_pos ); + } else { + // failed + break; + } + } + + // maximal bound + if ( b_pos && rho_new > rho_pos ) { + rho_new = 0.5 * ( rho_neg + rho_pos ); + } + + // project bound + _proj( rho_new ); + + // update + rho = sens * rho_new; + + // Test convergence ? + if ( std::abs( f_opt ) <= f_cvg ) { + break; + } + } + + /* Return optimal value */ + // std::cout << "rho_opt: " << rho_opt << std::endl; + f = func( rho_opt, false ); + } + + vector_type anderson( const vector_type &G_k ) { + // also called alternate secant method - eq.45 + // special version for M = 1 + if ( n_iter == 0 ) { + n_iter++; + Xa[km] = G_k; + return G_k; + } else if ( n_iter == 1 ) { + n_iter++; + G[km] = G_k; + Xa[k] = G_k; + return G_k; + } + n_iter++; + + G[k] = G_k; + + const auto dX_k = G[k] - Xa[k]; + const auto dX_km = G[km] - Xa[km]; + const auto ddX = dX_k - dX_km; + + // compute acceleration + const T wr = ddX.dot( dX_k ) / ddX.squaredNorm(); + + // compute accelerted solution + const vector_type Xa_kp = ( 1.0 - wr ) * G[k] + wr * G[km]; + + // update + G[km] = G[k]; + + Xa[km] = Xa[k]; + Xa[k] = Xa_kp; + + return Xa_kp; + } + + vector_type anderson( const vector_type &G_k, const int M ) { + // anderson method with M values. + if ( M < 1 ) { + return G_k; + } else if ( M == 1 ) { + return anderson( G_k ); + }; + if ( n_iter == 0 ) { + Xa.resize( M + 1 ); + G.resize( M + 1 ); + n_iter++; + Xa[km] = G_k; + return G_k; + } else if ( n_iter == 1 ) { + n_iter++; + G[km] = G_k; + Xa[k] = G_k; + return G_k; + } + + const int n = G_k.size(); + const int m_k = std::min( M, n_iter - 1 ); + + G[m_k] = G_k; + + matrix_type ddX( n, m_k ); + matrix_type dG( n, m_k ); + + for ( int i = 1; i <= m_k; i++ ) { + const auto dX_i = G[i] - Xa[i]; + const auto dX_im = G[i - 1] - Xa[i - 1]; + ddX.col( i - 1 ) = dX_i - dX_im; + dG.col( i - 1 ) = G[i] - G[i - 1]; + } + + const vector_type dX_k = G[m_k] - Xa[m_k]; + + // Solve least-square problem + const FullPivHouseholderQR< matrix_type > qr( ddX ); + const vector_type gamma = qr.solve( dX_k ); + + // std::cout << "gamma: " << gamma.rows() << ", " << gamma.cols() << std::endl; + // std::cout << "dG: " << dG.rows() << ", " << dG.cols() << std::endl; + + const vector_type Xa_kp = G[m_k] - dG * gamma; + + // Update solution + if ( m_k < M ) { + Xa[n_iter] = Xa_kp; + } else { + for ( int i = 0; i < m_k; i++ ) { + G[i] = G[i + 1]; + Xa[i] = Xa[i + 1]; + } + Xa[m_k] = Xa_kp; + } + n_iter++; + + return Xa_kp; + } +}; +} // namespace mechanics +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonIteration.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonIteration.hpp old mode 100755 new mode 100644 index bb4330ac..4d934c7d --- a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonIteration.hpp +++ b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonIteration.hpp @@ -28,29 +28,11 @@ #pragma once -#include -#include -#include -#include - -#include "diskpp/adaptivity/adaptivity.hpp" -#include "diskpp/bases/bases.hpp" -#include "diskpp/boundary_conditions/boundary_conditions.hpp" -#include "diskpp/common/timecounter.hpp" -#include "diskpp/mechanics/NewtonSolver/NewtonSolverComput.hpp" -#include "diskpp/mechanics/NewtonSolver/NewtonSolverInformations.hpp" -#include "diskpp/mechanics/NewtonSolver/NewtonSolverParameters.hpp" -#include "diskpp/mechanics/NewtonSolver/StabilizationManager.hpp" -#include "diskpp/mechanics/NewtonSolver/TimeManager.hpp" -#include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" -#include "diskpp/methods/hho" -#include "diskpp/solvers/direct_solvers.hpp" - -namespace disk -{ - -namespace mechanics -{ +#include "diskpp/mechanics/NewtonSolver/GenericIteration.hpp" + +namespace disk { + +namespace mechanics { /** * @brief Newton-Raphson iteration for nonlinear solid mechanics @@ -62,501 +44,397 @@ namespace mechanics * * @tparam MeshType type of the mesh */ -template -class NewtonIteration -{ - typedef MeshType mesh_type; - typedef typename mesh_type::coordinate_type scalar_type; - - typedef dynamic_matrix matrix_type; - typedef dynamic_vector vector_type; - - typedef NewtonSolverParameter param_type; - typedef vector_boundary_conditions bnd_type; - typedef Behavior behavior_type; - - typedef vector_mechanics_hho_assembler assembler_type; - typedef mechanical_computation elem_type; - - vector_type m_system_displ; +template < typename MeshType > +class NewtonIteration : public GenericIteration< MeshType > { + private: + typedef typename GenericIteration< MeshType >::mesh_type mesh_type; + typedef typename GenericIteration< MeshType >::cell_type cell_type; + typedef typename GenericIteration< MeshType >::scalar_type scalar_type; - assembler_type m_assembler; + typedef typename GenericIteration< MeshType >::matrix_type matrix_type; + typedef typename GenericIteration< MeshType >::vector_type vector_type; - std::vector m_bL; - std::vector m_AL; + typedef typename GenericIteration< MeshType >::param_type param_type; + typedef typename GenericIteration< MeshType >::bnd_type bnd_type; + typedef typename GenericIteration< MeshType >::behavior_type behavior_type; - std::vector m_postprocess_data; - std::vector m_displ, m_displ_faces; - std::vector m_velocity, m_acce; - std::vector m_velocity_p, m_acce_p, m_acce_pred; - - TimeStep m_time_step; - - scalar_type m_F_int; - - bool m_verbose; + typedef typename GenericIteration< MeshType >::elem_type elem_type; + typedef typename GenericIteration< MeshType >::func_type func_type; public: - NewtonIteration(const mesh_type& msh, - const bnd_type& bnd, - const param_type& rp, - const MeshDegreeInfo& degree_infos, - const TimeStep& current_step) : - m_verbose(rp.m_verbose), - m_time_step(current_step) - { - m_AL.clear(); - m_AL.resize(msh.cells_size()); - - m_bL.clear(); - m_bL.resize(msh.cells_size()); - - m_assembler = assembler_type(msh, degree_infos, bnd); - } - - bool - verbose(void) const - { - return m_verbose; - } - - void - verbose(bool v) - { - m_verbose = v; - } - - void - initialize(const mesh_type& msh, - const param_type& rp, - const std::vector& initial_displ, - const std::vector& initial_displ_faces, - const std::vector& initial_velocity, - const std::vector& initial_acce) - { - m_displ_faces.clear(); - m_displ_faces = initial_displ_faces; - - m_displ.clear(); - m_displ = initial_displ; - - m_velocity.clear(); - m_velocity = initial_velocity; - - m_acce.clear(); - m_acce = initial_acce; - - m_velocity_p.clear(); - m_velocity_p = initial_velocity; - - m_acce_p.clear(); - m_acce_p = initial_acce; - - m_acce_pred.clear(); - m_acce_pred.reserve(msh.cells_size()); + NewtonIteration( const mesh_type &msh, const bnd_type &bnd, const param_type &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + const std::shared_ptr< solvers::sparse_solver< scalar_type > > lin_solv, + const TimeStep< scalar_type > ¤t_step ) + : GenericIteration< MeshType >( msh, bnd, rp, degree_infos, lin_solv, current_step ) {} + + AssemblyInfo assemble( const mesh_type &msh, const bnd_type &bnd, const param_type &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + const std::unique_ptr< func_type > &lf, + NonLinearData< scalar_type > &data, behavior_type &behavior, + StabCoeffManager< scalar_type > &stab_manager, + MultiTimeField< scalar_type > &fields ) override { + elem_type elem; + AssemblyInfo ai; - if (rp.isUnsteady()) - { - auto dyna_rp = rp.getUnsteadyParameters(); - auto beta = dyna_rp["beta"]; - scalar_type dt = m_time_step.increment_time(); + // set RHS to zero + this->m_assembler.initialize(); + this->m_F_int = 0.0; - m_acce_pred.clear(); - m_acce_pred.reserve(msh.cells_size()); + const bool small_def = ( behavior.getDeformation() == SMALL_DEF ); + const bool use_tangent_modulus = rp.getNonLinearSolver() == NonLinearSolverType::NEWTON; - for (auto& cl : msh) - { - const auto cl_id = msh.lookup(cl); - const auto num_cell_dofs = m_acce[cl_id].size(); + // Like if it is an implicit scheme + auto current_time = this->m_time_step.end_time(); + auto depl = fields.getCurrentField( FieldName::DEPL ); + auto depl_faces = fields.getCurrentField( FieldName::DEPL_FACES ); - auto uT = m_displ[cl_id].head(num_cell_dofs); - auto acce_pred = -uT / (beta * dt * dt) - m_velocity[cl_id] / (beta * dt) - - dt * dt / 2.0 * (1.0 - 2.0 * beta) * m_acce[cl_id]; + std::vector< vector_type > resi_cells; - m_acce_pred.push_back(acce_pred); - } + std::vector< vector_type > acce_cells; + if ( this->m_dyna.enable() ) { + acce_cells = fields.getCurrentField( FieldName::ACCE_CELLS ); + resi_cells.reserve( msh.cells_size() ); } - else - { - for (auto& cl : msh) - { - m_acce_pred.push_back(vector_type::Zero(1)); - } - } - } - template - AssemblyInfo - assemble(const mesh_type& msh, - const bnd_type& bnd, - const param_type& rp, - const MeshDegreeInfo& degree_infos, - const LoadFunction& lf, - const std::vector& gradient_precomputed, - const std::vector& stab_precomputed, - behavior_type& behavior, - StabCoeffManager& stab_manager) - { - elem_type elem; - AssemblyInfo ai; - - // set RHS to zero - m_assembler.initialize(); - m_F_int = 0.0; - - const bool small_def = (behavior.getDeformation() == SMALL_DEF); + auto rlf = this->_getLoad( lf, current_time ); timecounter tc, ttot; ttot.tic(); - for (auto& cl : msh) - { - const auto cell_i = msh.lookup(cl); - const auto di = degree_infos.cellDegreeInfo(msh, cl); + for ( auto &cl : msh ) { + const auto cell_i = msh.lookup( cl ); + + const auto huT = depl.at( cell_i ); + + const auto cell_infos = degree_infos.cellDegreeInfo( msh, cl ); + const auto num_cell_dofs = vector_cell_dofs( msh, cell_infos ); + + const auto num_tot_dofs = huT.size(); + const auto num_faces_dofs = num_tot_dofs - num_cell_dofs; // Gradient Reconstruction // std::cout << "Grad" << std::endl; - matrix_type GT; tc.tic(); - if (rp.m_precomputation) - { - GT = gradient_precomputed[cell_i]; - } - else - { - if (small_def) - { - const auto gradrec_sym_full = make_matrix_hho_symmetric_gradrec(msh, cl, degree_infos); - GT = gradrec_sym_full.first; - } - else - { - const auto gradrec_full = make_matrix_hho_gradrec(msh, cl, degree_infos); - GT = gradrec_full.first; - } - } + matrix_type GT = + _gradrec( msh, cl, rp, degree_infos, small_def, data.m_gradient_precomputed ); tc.toc(); ai.m_time_gradrec += tc.elapsed(); - // Begin Assembly - // Build rhs and lhs - // Mechanical Computation tc.tic(); // std::cout << "Elem" << std::endl; - elem.compute(msh, - cl, - bnd, - rp, - degree_infos, - lf, - GT, - m_displ.at(cell_i), - m_acce_pred.at(cell_i), - m_time_step, - behavior, - stab_manager, - small_def); + elem.compute( msh, cl, bnd, rp, degree_infos, rlf, GT, huT, this->m_time_step, behavior, + stab_manager, small_def, true, use_tangent_modulus ); matrix_type lhs = elem.K_int; vector_type rhs = elem.RTF; - m_F_int += elem.F_int.squaredNorm(); + + if ( !this->m_dyna.isExplicit() ) { + this->m_F_int += elem.F_int.squaredNorm(); + } else { + this->m_F_int += elem.F_int.tail( num_faces_dofs ).squaredNorm(); + } tc.toc(); ai.m_time_elem += tc.elapsed(); - ai.m_time_law += elem.time_law; // Stabilisation Contribution // std::cout << "Stab" << std::endl; tc.tic(); + if ( rp.m_stab ) { + const auto beta_s = stab_manager.getValue( msh, cl ); - if (rp.m_stab) - { - matrix_type stab; - if (rp.m_precomputation) - { - stab = stab_precomputed.at(cell_i); - } - else - { - switch (rp.m_stab_type) - { - case HHO: - { - // we do not make any difference for the displacement reconstruction - // if (small_def) - // { - // const auto recons = make_vector_hho_symmetric_laplacian(msh, cl, degree_infos); - // stab_HHO = make_vector_hho_stabilization(msh, cl, recons.first, - // degree_infos); - // } - // else - // { - const auto recons_scalar = make_scalar_hho_laplacian(msh, cl, degree_infos); - stab = make_vector_hho_stabilization_optim(msh, cl, recons_scalar.first, degree_infos); - // } - - break; - } - case HDG: - { - stab = make_vector_hdg_stabilization(msh, cl, degree_infos); - break; - } - case DG: - { - stab = make_vector_dg_stabilization(msh, cl, degree_infos); - break; - } - case NO: - { - break; - } - default: throw std::invalid_argument("Unknown stabilization"); - } - } - - assert(elem.K_int.rows() == stab.rows()); - assert(elem.K_int.cols() == stab.cols()); - assert(elem.RTF.rows() == stab.rows()); - assert(elem.RTF.cols() == m_displ.at(cell_i).cols()); + matrix_type stab = + beta_s * _stab( msh, cl, rp, degree_infos, data.m_stab_precomputed ); - const auto beta_s = stab_manager.getValue(msh, cl); // std::cout << beta_s << std::endl; - lhs += beta_s * stab; - rhs -= beta_s * stab * m_displ.at(cell_i); + lhs += stab; + rhs -= stab * huT; } tc.toc(); ai.m_time_stab += tc.elapsed(); + // Dynamic contribution + if ( this->m_dyna.enable() ) { + this->m_dyna.compute( msh, cl, degree_infos, huT, acce_cells.at( cell_i ), + this->m_time_step ); + if ( !this->m_dyna.isExplicit() ) { + lhs.topLeftCorner( num_cell_dofs, num_cell_dofs ) += this->m_dyna.K_iner; + rhs.head( num_cell_dofs ) += this->m_dyna.R_iner; + } + ai.m_time_dyna += this->m_dyna.time_dyna; + } + // std::cout << "R: " << rhs.norm() << std::endl; // std::cout << rhs.transpose() << std::endl; // Static Condensation // std::cout << "StatCond" << std::endl; - tc.tic(); - const auto scnp = make_vector_static_condensation_withMatrix(msh, cl, degree_infos, lhs, rhs, true); - m_AL[cell_i] = std::get<1>(scnp); - m_bL[cell_i] = std::get<2>(scnp); + if ( this->m_dyna.isExplicit() ) { + tc.tic(); - tc.toc(); - ai.m_time_statcond += tc.elapsed(); + const auto num_cell_dofs = acce_cells.at( cell_i ).size(); + const auto num_tot_dofs = lhs.rows(); + const auto num_faces_dofs = num_tot_dofs - num_cell_dofs; + + this->m_AL[cell_i] = matrix_type::Zero( num_cell_dofs, num_faces_dofs ); + this->m_bL[cell_i] = vector_type::Zero( num_cell_dofs ); + + resi_cells.push_back( rhs.head( num_cell_dofs ) ); + + tc.toc(); + ai.m_time_statcond += tc.elapsed(); + + tc.tic(); + this->m_assembler.assemble_nonlinear( + msh, cl, bnd, lhs.bottomRightCorner( num_faces_dofs, num_faces_dofs ), + rhs.tail( num_faces_dofs ), depl_faces ); + tc.toc(); + ai.m_time_assembler += tc.elapsed(); + } else { + tc.tic(); - const auto& lc = std::get<0>(scnp); + const auto scnp = make_vector_static_condensation_withMatrix( msh, cl, degree_infos, + lhs, rhs, true ); - // std::cout << "rhs: " << lc.second.norm() << std::endl; - // std::cout << lc.second.transpose() << std::endl; - // std::cout << "lhs: " << lc.first.norm() << std::endl; + this->m_AL[cell_i] = std::get< 1 >( scnp ); + this->m_bL[cell_i] = std::get< 2 >( scnp ); - // std::cout << "Assemb" << std::endl; - m_assembler.assemble_nonlinear(msh, cl, bnd, lc.first, lc.second, m_displ_faces); + tc.toc(); + ai.m_time_statcond += tc.elapsed(); + + const auto &lc = std::get< 0 >( scnp ); + tc.tic(); + this->m_assembler.assemble_nonlinear( msh, cl, bnd, lc.first, lc.second, + depl_faces ); + tc.toc(); + ai.m_time_assembler += tc.elapsed(); + } } - m_F_int = sqrt(m_F_int); + if ( this->m_dyna.isExplicit() ) { + fields.setCurrentField( FieldName::RESI_CELLS, resi_cells ); + } + + this->m_F_int = sqrt( this->m_F_int ); // std::cout << "F_int: " << m_F_int << std::endl; - m_assembler.impose_neumann_boundary_conditions(msh, bnd); - m_assembler.finalize(); + ai.m_time_law += elem.time_law; + ai.m_time_contact += elem.time_contact; + ai.m_time_load += elem.time_load; + ai.m_time_rigi += elem.time_rigi; + ai.m_time_fint += elem.time_fint; + + tc.tic(); + this->m_assembler.impose_neumann_boundary_conditions( msh, bnd ); + this->m_assembler.finalize(); + tc.toc(); + ai.m_time_assembler += tc.elapsed(); ttot.toc(); - ai.m_time_assembly = ttot.elapsed(); - ai.m_linear_system_size = m_assembler.LHS.rows(); + ai.m_time_assembly = ttot.elapsed(); + ai.m_linear_system_size = this->m_assembler.LHS.rows(); return ai; } - SolveInfo - solve(void) - { - // std::cout << "begin solve" << std::endl; + scalar_type postprocess( const mesh_type &msh, const bnd_type &bnd, const param_type &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + const std::unique_ptr< func_type > &lf, + NonLinearData< scalar_type > &data, behavior_type &behavior, + StabCoeffManager< scalar_type > &stab_manager, + MultiTimeField< scalar_type > &fields ) override { timecounter tc; - tc.tic(); - m_system_displ = vector_type::Zero(m_assembler.LHS.rows()); + auto depl_faces = fields.getCurrentField( FieldName::DEPL_FACES ); + auto depl_cells = fields.getCurrentField( FieldName::DEPL_CELLS ); + auto depl = fields.getCurrentField( FieldName::DEPL ); - disk::solvers::sparse_lu(m_assembler.LHS, m_assembler.RHS, m_system_displ); + const auto [dudT, idx] = this->m_assembler.expand_solution_nonlinear( + msh, bnd, this->m_system_displ, depl_faces ); - tc.toc(); + auto update_depl_faces = [&msh, &fields, °ree_infos, &dudT, &idx, &depl_faces, + this]( const scalar_type rho = 1.0 ) -> auto { + auto depl_faces_new = depl_faces; - // std::cout << "LHS" << m_assembler.LHS << std::endl; - // std::cout << "RHS" << m_assembler.RHS << std::endl; + const vector_type rho_dudT = rho * dudT; - // std::cout << "end solve" << std::endl; + for ( auto itor = msh.faces_begin(); itor != msh.faces_end(); itor++ ) { + const auto fc = *itor; + const size_t face_id = msh.lookup( fc ); - return SolveInfo(m_assembler.LHS.rows(), m_assembler.LHS.nonZeros(), tc.elapsed()); - } + depl_faces_new.at( face_id ) += + rho_dudT.segment( idx( face_id ), idx( face_id + 1 ) - idx( face_id ) ); + } - scalar_type - postprocess(const mesh_type& msh, - const bnd_type& bnd, - const param_type& rp, - const MeshDegreeInfo& degree_infos) - { - // std::cout << "begin post_process" << std::endl; - timecounter tc; - tc.tic(); + fields.setCurrentField( FieldName::DEPL_FACES, depl_faces_new ); - // std::cout << m_system_displ << std::endl; + return rho_dudT; + }; - // Update cell - for (auto& cl : msh) - { - const auto cell_i = msh.lookup(cl); + auto update_depl_cell = [&msh, &fields, °ree_infos, &idx, &depl, &depl_cells, + this]( const vector_type &ddepl_faces ) -> auto { + // Update cell + auto depl_new = depl; + auto depl_cells_new = depl_cells; - const vector_type xdT = - m_assembler.take_local_solution_nonlinear(msh, cl, bnd, m_system_displ, m_displ_faces); + for ( auto &cl : msh ) { + const auto cell_i = msh.lookup( cl ); - vector_type x_cond = xdT; + const auto cell_infos = degree_infos.cellDegreeInfo( msh, cl ); + const auto faces_infos = cell_infos.facesDegreeInfo(); + const auto num_faces_dofs = vector_faces_dofs( msh, faces_infos ); - // static decondensation - const vector_type xT = m_bL[cell_i] - m_AL[cell_i] * x_cond; + vector_type xdT = vector_type( num_faces_dofs ); - assert(m_displ.at(cell_i).size() == xT.size() + xdT.size()); - // Update element U^{i+1} = U^i + delta U^i /// - m_displ.at(cell_i).head(xT.size()) += xT; - m_displ.at(cell_i).segment(xT.size(), xdT.size()) += xdT; + const auto fcs_id = faces_id( msh, cl ); + size_t face_offset = 0; + for ( size_t face_i = 0; face_i < fcs_id.size(); face_i++ ) { + const size_t face_id = fcs_id[face_i]; + const auto n_face_dofs = idx( face_id + 1 ) - idx( face_id ); - if (rp.isUnsteady()) - { - auto dyna_rp = rp.getUnsteadyParameters(); - auto beta = dyna_rp["beta"]; - auto gamma = dyna_rp["gamma"]; - scalar_type dt = m_time_step.increment_time(); + xdT.segment( face_offset, n_face_dofs ) = + ddepl_faces.segment( idx( face_id ), n_face_dofs ); + face_offset += n_face_dofs; + } - m_acce.at(cell_i) = xT / (beta * dt * dt) + m_acce_pred.at(cell_i); - m_velocity.at(cell_i) = - m_velocity_p.at(cell_i) + dt * ((1.0 - gamma) * m_acce.at(cell_i) + gamma * m_acce.at(cell_i)); + // static decondensation + const vector_type xT = this->m_bL[cell_i] - this->m_AL[cell_i] * xdT; + + // Update element U^{i+1} = U^i + delta U^i + depl_new.at( cell_i ).head( xT.size() ) += xT; + depl_new.at( cell_i ).tail( xdT.size() ) += xdT; + depl_cells_new.at( cell_i ) += xT; + + // std::cout << "KT_F " << m_AL[cell_i].norm() << std::endl; + // std::cout << "sol_F" << std::endl; + // std::cout << xdT.transpose() << std::endl; + // std::cout << "ft" << std::endl; + // std::cout << m_bL[cell_i].transpose() << std::endl; + // std::cout << "sol_T" << std::endl; + // std::cout << xT.transpose() << std::endl; + // std::cout << depl.at(cell_i).transpose() << std::endl; + } + fields.setCurrentField( FieldName::DEPL, depl_new ); + fields.setCurrentField( FieldName::DEPL_CELLS, depl_cells_new ); + + this->m_dyna.postprocess( msh, this->m_time_step, fields ); + }; + + if ( rp.getLineSearch() == LineSearchType::NO_LS ) { + const auto ddepl_faces = update_depl_faces( 1.0 ); + update_depl_cell( ddepl_faces ); + } else if ( rp.getLineSearch() == LineSearchType::SECANT ) { + + auto _func = [&msh, &bnd, &rp, °ree_infos, &lf, &data, &behavior, &stab_manager, + &fields, &dudT, &idx, update_depl_faces, update_depl_cell, + this]( scalar_type rho, const bool compute = true ) -> auto { + // Update unknowns + const auto ddepl_faces = update_depl_faces( rho ); + update_depl_cell( ddepl_faces ); + + // compute new residual + if ( compute && std::abs( rho ) > 1e-32 ) + const auto ai = this->assemble( msh, bnd, rp, degree_infos, lf, data, behavior, + stab_manager, fields ); + + // TODO: Check sign + return -dudT.dot( this->m_assembler.RHS ); + }; + + this->m_accel.secant( _func ); + } else { + + const auto ddepl_faces = update_depl_faces( 1.0 ); + update_depl_cell( ddepl_faces ); + + auto depl_cells_up = fields.getCurrentField( FieldName::DEPL_CELLS ); + auto depl_faces_up = fields.getCurrentField( FieldName::DEPL_FACES ); + + const auto uT = asVector( depl_cells_up ); + const auto udT = asVector( depl_faces_up ); + + vector_type u( uT.size() + udT.size() ); + u.head( uT.size() ) = uT; + u.tail( udT.size() ) = udT; + + vector_type u_new; + if ( rp.getLineSearch() == LineSearchType::RELAXATION ) { + u_new = this->m_accel.relaxation( u ); + } else if ( rp.getLineSearch() == LineSearchType::AITKEN ) { + u_new = this->m_accel.aitken( u ); + } else if ( rp.getLineSearch() == LineSearchType::ANDERSON ) { + u_new = this->m_accel.anderson( u ); + } else if ( rp.getLineSearch() == LineSearchType::ANDERSON2 ) { + u_new = this->m_accel.anderson( u, 2 ); + } else if ( rp.getLineSearch() == LineSearchType::ANDERSON3 ) { + u_new = this->m_accel.anderson( u, 3 ); + } else if ( rp.getLineSearch() == LineSearchType::ANDERSON4 ) { + u_new = this->m_accel.anderson( u, 4 ); + } else if ( rp.getLineSearch() == LineSearchType::ANDERSON5 ) { + u_new = this->m_accel.anderson( u, 5 ); + } else if ( rp.getLineSearch() == LineSearchType::ANDERSON10 ) { + u_new = this->m_accel.anderson( u, 10 ); + } else { + throw std::invalid_argument( "LineSearch algorithm not supported." ); } - // std::cout << "KT_F " << m_AL[cell_i].norm() << std::endl; - // std::cout << "sol_F" << std::endl; - // std::cout << xdT.transpose() << std::endl; - // std::cout << "ft" << std::endl; - // std::cout << m_bL[cell_i].transpose() << std::endl; - // std::cout << "sol_T" << std::endl; - // std::cout << xT.transpose() << std::endl; - // std::cout << (m_displ.at(cell_i)).segment(0, xT.size()).transpose() << std::endl; - } + fromVector( vector_type( u_new.head( uT.size() ) ), depl_cells_up ); + fromVector( vector_type( u_new.tail( udT.size() ) ), depl_faces_up ); - // Update unknowns - // Update face Uf^{i+1} = Uf^i + delta Uf^i - size_t face_i = 0; - for (auto itor = msh.faces_begin(); itor != msh.faces_end(); itor++) - { - const auto fc = *itor; - m_displ_faces.at(face_i++) += - m_assembler.take_local_solution_nonlinear(msh, fc, bnd, m_system_displ, m_displ_faces); - } + fields.setCurrentField( FieldName::DEPL_CELLS, depl_cells_up ); + fields.setCurrentField( FieldName::DEPL_FACES, depl_faces_up ); - // std::cout << "end post_process" << std::endl; - tc.toc(); - return tc.elapsed(); - } + // update depl; + auto depl_up = fields.getCurrentField( FieldName::DEPL ); + for ( auto &cl : msh ) { + const auto cell_i = msh.lookup( cl ); - bool - convergence(const param_type& rp, const size_t iter) - { - // norm of the solution - scalar_type error_un = 0; - for (size_t i = 0; i < m_displ_faces.size(); i++) - { - scalar_type norm = m_displ_faces[i].norm(); - error_un += norm * norm; - } + const auto cell_infos = degree_infos.cellDegreeInfo( msh, cl ); + const auto faces_infos = cell_infos.facesDegreeInfo(); + const auto num_faces_dofs = vector_faces_dofs( msh, faces_infos ); - error_un = std::sqrt(error_un); + vector_type xdT = vector_type( num_faces_dofs ); - if (error_un <= scalar_type(10E-15)) - { - error_un = scalar_type(10E16); - } + const auto fcs_id = faces_id( msh, cl ); + size_t face_offset = 0; + for ( size_t face_i = 0; face_i < fcs_id.size(); face_i++ ) { + const size_t face_id = fcs_id[face_i]; + const auto n_face_dofs = idx( face_id + 1 ) - idx( face_id ); - // norm of the rhs - const scalar_type residual = m_assembler.RHS.norm(); - scalar_type max_error = 0.0; - for (size_t i = 0; i < m_assembler.RHS.size(); i++) - max_error = std::max(max_error, std::abs(m_assembler.RHS(i))); - - // norm of the increment - const scalar_type error_incr = m_system_displ.norm(); - scalar_type relative_displ = error_incr / error_un; - scalar_type relative_error = residual / m_F_int; - - if (iter == 0) - { - relative_displ = 1; - relative_error = 1; - } + xdT.segment( face_offset, n_face_dofs ) = depl_faces_up[face_id]; + face_offset += n_face_dofs; + } - if (m_verbose) - { - std::string s_iter = " " + std::to_string(iter) + " "; - s_iter.resize(9); - - if (iter == 0) - { - std::cout << "----------------------------------------------------------------------" - "------------------------" - << std::endl; - std::cout << "| Iteration | Norme l2 incr | Relative incr | Residual l2 | " - "Relative error | Maximum error |" - << std::endl; - std::cout << "----------------------------------------------------------------------" - "------------------------" - << std::endl; + // static decondensation + const vector_type xT = depl_cells_up[cell_i]; + + // Update element U^{i+1} = U^i + delta U^i + depl_up.at( cell_i ).head( xT.size() ) = xT; + depl_up.at( cell_i ).tail( xdT.size() ) = xdT; + + // std::cout << "KT_F " << m_AL[cell_i].norm() << std::endl; + // std::cout << "sol_F" << std::endl; + // std::cout << xdT.transpose() << std::endl; + // std::cout << "ft" << std::endl; + // std::cout << m_bL[cell_i].transpose() << std::endl; + // std::cout << "sol_T" << std::endl; + // std::cout << xT.transpose() << std::endl; + // std::cout << depl.at(cell_i).transpose() << std::endl; } - std::ios::fmtflags f(std::cout.flags()); - std::cout.precision(5); - std::cout.setf(std::iostream::scientific, std::iostream::floatfield); - std::cout << "| " << s_iter << " | " << error_incr << " | " << relative_displ << " | " << residual - << " | " << relative_error << " | " << max_error << " |" << std::endl; - std::cout << "-------------------------------------------------------------------------" - "---------------------" - << std::endl; - std::cout.flags(f); - } - - const scalar_type error = std::max(relative_displ, relative_error); - if (!isfinite(error)) - throw std::runtime_error("Norm of residual is not finite"); - - if (error <= rp.m_epsilon) - { - return true; - } - else - { - return false; + fields.setCurrentField( FieldName::DEPL, depl_up ); + this->m_dyna.postprocess( msh, this->m_time_step, fields ); } - } - void - save_solutions(std::vector& displ, - std::vector& displ_faces, - std::vector& velocity, - std::vector& acce) - { - displ_faces.clear(); - displ_faces = m_displ_faces; - assert(m_displ_faces.size() == displ_faces.size()); - - displ.clear(); - displ = m_displ; - assert(m_displ.size() == displ.size()); - - velocity.clear(); - velocity = m_velocity; - assert(m_velocity.size() == velocity.size()); - - acce.clear(); - acce = m_acce; - assert(m_acce.size() == acce.size()); + tc.toc(); + return tc.elapsed(); } }; -} -} // end diskpp \ No newline at end of file +} // namespace mechanics +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolver.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolver.hpp deleted file mode 100644 index d95e4dd9..00000000 --- a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolver.hpp +++ /dev/null @@ -1,1145 +0,0 @@ -/* - * /\ Matteo Cicuttin (C) 2016, 2017, 2018 - * /__\ matteo.cicuttin@enpc.fr - * /_\/_\ École Nationale des Ponts et Chaussées - CERMICS - * /\ /\ - * /__\ /__\ DISK++, a template library for DIscontinuous SKeletal - * /_\/_\/_\/_\ methods. - * - * This file is copyright of the following authors: - * Nicolas Pignet (C) 2019 nicolas.pignet@enpc.fr - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * If you use this code or parts of it for scientific publications, you - * are required to cite it as following: - * - * Hybrid High-Order methods for finite elastoplastic deformations - * within a logarithmic strain framework. - * M. Abbas, A. Ern, N. Pignet. - * International Journal of Numerical Methods in Engineering (2019) - * 120(3), 303-327 - * DOI: 10.1002/nme.6137 - */ - -// NewtonRaphson_solver - -#pragma once - -#include -#include -#include - -#include "diskpp/mechanics/NewtonSolver/NewtonSolverInformations.hpp" -#include "diskpp/mechanics/NewtonSolver/NewtonSolverParameters.hpp" -#include "diskpp/mechanics/NewtonSolver/NewtonStep.hpp" -#include "diskpp/mechanics/NewtonSolver/StabilizationManager.hpp" -#include "diskpp/mechanics/NewtonSolver/TimeManager.hpp" -#include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" -#include "diskpp/mechanics/behaviors/tensor_conversion.hpp" -#include "diskpp/mechanics/stress_tensors.hpp" - -#include "diskpp/adaptivity/adaptivity.hpp" -#include "diskpp/boundary_conditions/boundary_conditions.hpp" -#include "diskpp/methods/hho" - -#include "diskpp/output/gmshConvertMesh.hpp" -#include "diskpp/output/gmshDisk.hpp" -#include "diskpp/output/postMesh.hpp" - -#ifdef HAVE_MGIS -#include "MGIS/Behaviour/Behaviour.hxx" -#endif - -#include "diskpp/common/timecounter.hpp" - -namespace disk -{ - -namespace mechanics -{ - -/** - * @brief Newton-Raphson solver for nonlinear solid mechanics - * - * Specialized for HHO methods - * - * Options : - small and finite deformations - * - plasticity, hyperelasticity (various laws) - * - * @tparam Mesh type of the mesh - */ -template -class NewtonSolver -{ - typedef Mesh mesh_type; - typedef typename mesh_type::coordinate_type scalar_type; - - typedef dynamic_matrix matrix_type; - typedef dynamic_vector vector_type; - - typedef NewtonSolverParameter param_type; - typedef vector_boundary_conditions bnd_type; - typedef Behavior behavior_type; - - bnd_type m_bnd; - const mesh_type& m_msh; - param_type m_rp; - behavior_type m_behavior; - MeshDegreeInfo m_degree_infos; - StabCoeffManager m_stab_manager; - - std::vector m_displ, m_displ_faces; - std::vector m_velocity, m_acce; - std::vector m_gradient_precomputed, m_stab_precomputed; - - PostMesh m_post_mesh; - - bool m_verbose, m_convergence; - - void - init_degree(const size_t cell_degree, const size_t face_degree, const size_t grad_degree) - { - m_degree_infos = MeshDegreeInfo(m_msh, cell_degree, face_degree, grad_degree); - - if (m_bnd.nb_faces_contact() > 0) - { - for (auto itor = m_msh.boundary_faces_begin(); itor != m_msh.boundary_faces_end(); itor++) - { - const auto bfc = *itor; - const auto face_id = m_msh.lookup(bfc); - - if (m_bnd.is_contact_face(face_id)) - { - switch (m_bnd.contact_boundary_type(face_id)) - { - case SIGNORINI_FACE: - { - m_degree_infos.degree(m_msh, bfc, face_degree + 1); - break; - } - default: - { - throw std::invalid_argument("Invalid contact type"); - } - } - } - } - } - } - - // Initializa data structures - void - init(void) - { - const auto dimension = mesh_type::dimension; - - size_t total_dof = 0; - - m_displ.clear(); - m_displ_faces.clear(); - - m_displ.reserve(m_msh.cells_size()); - m_displ_faces.reserve(m_msh.faces_size()); - - if (m_rp.isUnsteady()) - { - m_velocity.clear(); - m_acce.clear(); - - m_velocity.reserve(m_msh.cells_size()); - m_acce.reserve(m_msh.cells_size()); - } - - for (auto& cl : m_msh) - { - const auto di = m_degree_infos.cellDegreeInfo(m_msh, cl); - const auto num_cell_dofs = vector_basis_size(di.cell_degree(), dimension, dimension); - total_dof += num_cell_dofs; - - const auto fcs = faces(m_msh, cl); - const auto fcs_di = di.facesDegreeInfo(); - - const auto grad_degree = di.grad_degree(); - - size_t num_faces_dofs = 0; - for (auto& fc_di : fcs_di) - { - if (fc_di.hasUnknowns()) - { - num_faces_dofs += vector_basis_size(fc_di.degree(), dimension - 1, dimension); - } - } - - m_displ.push_back(vector_type::Zero(num_cell_dofs + num_faces_dofs)); - - if (m_rp.isUnsteady()) - { - m_velocity.push_back(vector_type::Zero(num_cell_dofs)); - m_acce.push_back(vector_type::Zero(num_cell_dofs)); - } - } - - for (auto itor = m_msh.faces_begin(); itor != m_msh.faces_end(); itor++) - { - const auto fc = *itor; - const auto di = m_degree_infos.degreeInfo(m_msh, fc); - - size_t num_face_dofs = 0; - if (di.hasUnknowns()) - { - num_face_dofs = vector_basis_size(di.degree(), dimension - 1, dimension); - } - total_dof += num_face_dofs; - - m_displ_faces.push_back(vector_type::Zero(num_face_dofs)); - } - - // compute mesh for post-processing - m_post_mesh = PostMesh(m_msh); - - if (m_verbose) - { - std::cout << "** Numbers of cells: " << m_msh.cells_size() << std::endl; - std::cout << "** Numbers of faces: " << m_msh.faces_size() - << " ( boundary faces: " << m_msh.boundary_faces_size() << " )" << std::endl; - std::cout << "** Numbers of dofs: " << std::endl; - std::cout << " ** Before static condensation: " << total_dof << std::endl; - std::cout << " ** After static condensation: " << this->numberOfDofs() << std::endl; - std::cout << " " << std::endl; - } - } - - /** - * @brief Precompute the gradient reconstruction and stabilization operator for HHO methods - * - */ - void - pre_computation(void) - { - m_gradient_precomputed.clear(); - m_gradient_precomputed.reserve(m_msh.cells_size()); - - m_stab_precomputed.clear(); - m_stab_precomputed.reserve(m_msh.cells_size()); - - for (auto& cl : m_msh) - { - // std::cout << m_degree_infos.cellDegreeInfo(m_msh, cl) << std::endl; - /////// Gradient Reconstruction ///////// - if (m_behavior.getDeformation() == SMALL_DEF) - { - const auto sgr = make_matrix_hho_symmetric_gradrec(m_msh, cl, m_degree_infos); - m_gradient_precomputed.push_back(sgr.first); - } - else - { - const auto gr = make_matrix_hho_gradrec(m_msh, cl, m_degree_infos); - m_gradient_precomputed.push_back(gr.first); - } - - if (m_rp.m_stab) - { - switch (m_rp.m_stab_type) - { - case HHO: - { - // we do not make any difference for the displacement reconstruction - // if (m_behavior.getDeformation() == SMALL_DEF) - // { - // const auto recons = make_vector_hho_symmetric_laplacian(m_msh, cl, m_degree_infos); - // m_stab_precomputed.push_back( - // make_vector_hho_stabilization(m_msh, cl, recons.first, m_degree_infos)); - // } - // else - // { - const auto recons_scalar = make_scalar_hho_laplacian(m_msh, cl, m_degree_infos); - m_stab_precomputed.push_back( - make_vector_hho_stabilization_optim(m_msh, cl, recons_scalar.first, m_degree_infos)); - // } - break; - } - case HDG: - { - m_stab_precomputed.push_back(make_vector_hdg_stabilization(m_msh, cl, m_degree_infos)); - break; - } - case DG: - { - m_stab_precomputed.push_back(make_vector_dg_stabilization(m_msh, cl, m_degree_infos)); - break; - } - case NO: - { - break; - } - default: throw std::invalid_argument("Unknown stabilization"); - } - } - } - } - - public: - NewtonSolver(const mesh_type& msh, const bnd_type& bnd, const param_type& rp) : - m_msh(msh), m_verbose(rp.m_verbose), m_convergence(false), m_rp(rp), m_bnd(bnd), m_stab_manager(msh, rp.m_beta) - { - if (m_verbose) - { - std::cout << "------------------------------------------------------------------------" - "----------------------" - << std::endl; - std::cout - << "|********************** Nonlinear Newton's Solver for solid mechanics ***********************|" - << std::endl; - std::cout << "------------------------------------------------------------------------" - "----------------------" - << std::endl; - } - int face_degree = rp.m_face_degree; - if (rp.m_face_degree < 0) - { - std::cout << "'face_degree' should be > 0. Reverting to 1." << std::endl; - face_degree = 1; - } - - m_rp.m_face_degree = face_degree; - - int cell_degree = rp.m_cell_degree; - if ((face_degree - 1 > cell_degree) or (cell_degree > face_degree + 1)) - { - std::cout << "'cell_degree' should be 'face_degree + 1' =>" - << "'cell_degree' => 'face_degree -1'. Reverting to 'face_degree'." << std::endl; - cell_degree = face_degree; - } - - m_rp.m_cell_degree = cell_degree; - - int grad_degree = rp.m_grad_degree; - if (grad_degree < face_degree) - { - std::cout << "'grad_degree' should be >= 'face_degree'. Reverting to 'face_degree'." << std::endl; - grad_degree = face_degree; - } - - if (m_verbose) - { - m_rp.infos(); - } - - // Initialization - if (m_verbose) - std::cout << "Initialization ..." << std::endl; - this->init_degree(cell_degree, face_degree, grad_degree); - this->init(); - } - - /** - * @brief return a boolean to know if the verbosity mode is activated - * - */ - bool - verbose(void) const - { - return m_verbose; - } - - /** - * @brief Set the verbosity mode - * - * @param v boolean to activate or desactivate the verbosity mode - */ - void - verbose(bool v) - { - m_verbose = v; - } - - /** - * @brief Initialize the inital guess with a given function - * - * @param func given function - */ - void - initial_guess(const vector_rhs_function func) - { - size_t cell_i = 0; - - for (auto& cl : m_msh) - { - m_displ.at(cell_i++) = project_function(m_msh, cl, m_degree_infos, func, 2); - } - - for (auto itor = m_msh.faces_begin(); itor != m_msh.faces_end(); itor++) - { - const auto bfc = *itor; - const auto face_id = m_msh.lookup(bfc); - const auto fdi = m_degree_infos.degreeInfo(m_msh, bfc); - - if (m_bnd.contact_boundary_type(face_id) == SIGNORINI_FACE) - { - const auto proj_bcf = project_function(m_msh, bfc, fdi.degree(), func, 2); - assert(m_displ_faces[face_id].size() == proj_bcf.size()); - - m_displ_faces[face_id] = proj_bcf; - } - else if (m_bnd.contact_boundary_type(face_id) == SIGNORINI_CELL) - { - assert(m_displ_faces[face_id].size() == 0); - } - else - { - const auto proj_bcf = project_function(m_msh, bfc, fdi.degree(), func, 2); - assert(m_displ_faces[face_id].size() == proj_bcf.size()); - - m_displ_faces[face_id] = proj_bcf; - } - } - } - - /** - * @brief Initialize displacement and velocity with a given function - * - * @param func given function - */ - void - initial_fields(const vector_rhs_function depl, - const vector_rhs_function velo, - const vector_rhs_function acce) - { - if (m_rp.isUnsteady()) - { - this->initial_guess(depl); - for (auto& cl : m_msh) - { - const auto cell_id = m_msh.lookup(cl); - const auto di = m_degree_infos.cellDegreeInfo(m_msh, cl); - - m_velocity.at(cell_id) = project_function(m_msh, cl, di.cell_degree(), velo, 2); - m_acce.at(cell_id) = project_function(m_msh, cl, di.cell_degree(), acce, 2); - } - } - } - - /** - * @brief Add a behavior for materials - * - * @param deformation Type of deformation - * @param law Type of Law - */ - void - addBehavior(const size_t deformation, const size_t law) - { - if (m_verbose) - { - std::cout << "Add behavior ..." << std::endl; - } - - m_behavior = behavior_type(m_msh, 2 * m_rp.m_grad_degree, deformation, law); - - if (m_verbose) - { - std::cout << "** Deformations: " << m_behavior.getDeformationName() << std::endl; - std::cout << "** Law: " << m_behavior.getLawName() << std::endl; - std::cout << "** Number of integration points: " << m_behavior.numberOfQP() << std::endl; - } - } - -#ifdef HAVE_MGIS - /** - * @brief Add a behavior for materials - * - * @param deformation Type of deformation - * @param law Type of Law - */ - void - addBehavior(const std::string& filename, const std::string& law, const mgis::behaviour::Hypothesis h) - { - if (m_verbose) - { - std::cout << "Add behavior ..." << std::endl; - } - - m_behavior = behavior_type(m_msh, 2 * m_rp.m_grad_degree, filename, law, h); - - if (m_verbose) - { - std::cout << "** Deformations: " << m_behavior.getDeformationName() << std::endl; - std::cout << "** Law: " << m_behavior.getLawName() << std::endl; - std::cout << "** Number of integration points: " << m_behavior.numberOfQP() << std::endl; - } - } -#endif - - /** - * @brief Add a behavior for materials (by copy) - * - * @param behavior Given behavior - */ - void - addBehavior(const behavior_type& behavior) - { - m_behavior = behavior; - if (m_verbose) - { - std::cout << "Add behavior ..." << std::endl; - std::cout << "** Number of integration points: " << m_behavior.numberOfQP() << std::endl; - } - } - - /** - * @brief Add material properties for the behavior - * - * @param material_data material properties - */ - void - addMaterialData(const MaterialData& material_data) - { - m_behavior.addMaterialData(material_data); - - if (m_verbose) - { - std::cout << "Add material ..." << std::endl; - m_behavior.getMaterialData().print(); - } - } - - template - SolverInfo - compute(const LoadFunction& lf) - { - // Precomputation - if (m_rp.m_precomputation) - { - timecounter t1; - t1.tic(); - this->pre_computation(); - t1.toc(); - if (m_verbose) - std::cout << "Precomputation: " << t1.elapsed() << " sec" << std::endl; - } - - SolverInfo si; - timecounter ttot; - ttot.tic(); - - // list of time step - ListOfTimeStep list_time_step; - if (m_rp.m_has_user_end_time) - list_time_step = ListOfTimeStep(m_rp.m_time_step, m_rp.m_user_end_time); - else - list_time_step = ListOfTimeStep(m_rp.m_time_step); - - if (m_verbose) - std::cout << "** Number of time step: " << list_time_step.numberOfTimeStep() << std::endl; - - // time of saving - bool time_saving = false; - if (m_rp.m_n_time_save > 0) - { - time_saving = true; - } - - // Newton step - NewtonStep newton_step(m_rp); - newton_step.initialize(m_displ, m_displ_faces, m_velocity, m_acce); - - // Loop on time step - while (!list_time_step.empty()) - { - const auto current_step = list_time_step.getCurrentTimeStep(); - const auto current_time = current_step.end_time(); - - if (m_verbose) - { - list_time_step.printCurrentTimeStep(); - } - - auto rlf = [&lf, ¤t_time](const point& p) -> auto - { return lf(p, current_time); }; - - m_bnd.multiplyAllFunctionsByAFactor(current_time); - - // Newton correction - NewtonSolverInfo newton_info = newton_step.compute(m_msh, - m_bnd, - m_rp, - m_degree_infos, - rlf, - current_step, - m_gradient_precomputed, - m_stab_precomputed, - m_behavior, - m_stab_manager); - si.updateInfo(newton_info); - - if (m_verbose) - { - newton_info.printInfo(); - } - - // Test convergence - m_convergence = newton_step.convergence(); - - if (!m_convergence) - { - if (current_step.level() + 1 > m_rp.m_sublevel) - { - std::cout << "***********************************************************" << std::endl; - std::cout << "***** PROBLEM OF CONVERGENCE: We stop the calcul here *****" << std::endl; - std::cout << "***********************************************************" << std::endl; - break; - } - else - { - if (m_verbose) - { - std::cout << "***********************************************************" << std::endl; - std::cout << "***** NO CONVERGENCE: We split the time step ******" << std::endl; - std::cout << "***********************************************************" << std::endl; - } - - list_time_step.splitCurrentTimeStep(); - } - } - else - { - list_time_step.removeCurrentTimeStep(); - m_behavior.update(); - m_stab_manager.update(); - - if (time_saving) - { - if (m_rp.m_time_save.front() < current_time + 1E-5) - { - newton_step.save_solutions(m_displ, m_displ_faces, m_velocity, m_acce); - - std::cout << "** Save results" << std::endl; - std::string name = - "result" + std::to_string(mesh_type::dimension) + "D_t" + std::to_string(current_time) + "_"; - - this->output_discontinuous_displacement(name + "depl_disc.msh"); - this->output_continuous_displacement(name + "depl_cont.msh"); - this->output_CauchyStress_GP(name + "CauchyStress_GP.msh"); - this->output_CauchyStress_GP(name + "CauchyStress_GP_def.msh", true); - this->output_discontinuous_deformed(name + "deformed_disc.msh"); - this->output_is_plastic_GP(name + "plastic_GP.msh"); - this->output_stabCoeff(name + "stabCoeff.msh"); - this->output_equivalentPlasticStrain_GP(name + "equivalentPlasticStrain_GP.msh"); - - m_rp.m_time_save.pop_front(); - if (m_rp.m_time_save.empty()) - time_saving = false; - } - } - } - } - - // save solutions - newton_step.save_solutions(m_displ, m_displ_faces, m_velocity, m_acce); - si.m_time_step = list_time_step.numberOfTimeStep(); - - ttot.toc(); - si.m_time_solver = ttot.elapsed(); - - return si; - } - - bool - convergence() const - { - return m_convergence; - } - - size_t - numberOfDofs() - { - const auto dimension = mesh_type::dimension; - size_t num_faces_dofs = 0; - for (auto itor = m_msh.faces_begin(); itor != m_msh.faces_end(); itor++) - { - const auto fc = *itor; - const auto di = m_degree_infos.degreeInfo(m_msh, fc); - - if (di.hasUnknowns()) - { - num_faces_dofs += vector_basis_size(di.degree(), dimension - 1, dimension); - } - } - return num_faces_dofs; - } - - void - printSolutionCell() const - { - size_t cell_i = 0; - std::cout << "Solution at the cells:" << std::endl; - for (auto& cl : m_msh) - { - const auto di = m_degree_infos.degreeInfo(m_msh, cl); - const auto num_cell_dofs = vector_basis_size(di.cell_degree(), mesh_type::dimension, mesh_type::dimension); - std::cout << "cell " << cell_i << ": " << std::endl; - std::cout << m_displ.at(cell_i++).head(num_cell_dofs).transpose() << std::endl; - } - } - - // compute l2 error - template - scalar_type - compute_l2_displacement_error(const AnalyticalSolution& as) - { - scalar_type err_dof = 0; - - size_t cell_i = 0; - - for (auto& cl : m_msh) - { - const auto cdi = m_degree_infos.degreeInfo(m_msh, cl); - const auto num_cell_dofs = vector_basis_size(cdi.degree(), mesh_type::dimension, mesh_type::dimension); - const vector_type comp_dof = m_displ.at(cell_i++).head(num_cell_dofs); - const vector_type true_dof = project_function(m_msh, cl, cdi.degree(), as, 2); - - const auto cb = make_vector_monomial_basis(m_msh, cl, cdi.degree()); - const matrix_type mass = make_mass_matrix(m_msh, cl, cb); - - const vector_type diff_dof = (true_dof - comp_dof); - assert(comp_dof.size() == true_dof.size()); - err_dof += diff_dof.dot(mass * diff_dof); - } - - return sqrt(err_dof); - } - - // compute l2 error - template - scalar_type - compute_H1_error(const AnalyticalSolution& as) - { - scalar_type err_dof = 0; - - size_t cell_i = 0; - - matrix_type grad; - matrix_type stab; - - for (auto& cl : m_msh) - { - // std::cout << m_degree_infos.cellDegreeInfo(m_msh, cl) << std::endl; - /////// Gradient Reconstruction ///////// - if (m_behavior.getDeformation() == SMALL_DEF) - { - grad = make_matrix_hho_symmetric_gradrec(m_msh, cl, m_degree_infos).second; - } - else - { - grad = make_matrix_hho_gradrec(m_msh, cl, m_degree_infos).second; - } - - if (m_rp.m_stab) - { - switch (m_rp.m_stab_type) - { - case HHO: - { - // we do not make any difference for thre displacement reconstruction - // if (m_behavior.getDeformation() == SMALL_DEF) - // { - // const auto recons = make_vector_hho_symmetric_laplacian(m_msh, cl, m_degree_infos); - // stab = make_vector_hho_stabilization(m_msh, cl, recons.first, - // m_degree_infos); - // } - // else - // { - const auto recons_scalar = make_scalar_hho_laplacian(m_msh, cl, m_degree_infos); - stab = make_vector_hho_stabilization_optim(m_msh, cl, recons_scalar.first, m_degree_infos); - // } - break; - } - case HDG: - { - stab = make_vector_hdg_stabilization(m_msh, cl, m_degree_infos); - break; - } - case DG: - { - stab = make_vector_dg_stabilization(m_msh, cl, m_degree_infos); - break; - } - case NO: - { - break; - stab.setZero(); - } - default: throw std::invalid_argument("Unknown stabilization"); - } - } - - const auto Ah = grad + stab; - - const vector_type comp_dof = m_displ.at(cell_i); - const vector_type true_dof = project_function(m_msh, cl, m_degree_infos, as, 2); - - const vector_type diff_dof = (true_dof - comp_dof); - assert(comp_dof.size() == true_dof.size()); - err_dof += diff_dof.dot(Ah * diff_dof); - - cell_i++; - } - - return sqrt(err_dof); - } - - void - output_discontinuous_displacement(const std::string& filename) const - { - gmsh::Gmesh gmsh(mesh_type::dimension); - - std::vector data; // create data (not used) - const std::vector subdata; // create subdata to save soution at gauss point - - int cell_i = 0; - int nb_nodes = 0; - for (auto& cl : m_msh) - { - const auto di = m_degree_infos.cellDegreeInfo(m_msh, cl); - const auto cb = make_vector_monomial_basis(m_msh, cl, di.cell_degree()); - const vector_type x = m_displ.at(cell_i++).head(cb.size()); - auto cell_nodes = points(m_msh, cl); - std::vector new_nodes; - - // loop on the nodes of the cell - for (auto& pt : cell_nodes) - { - nb_nodes++; - - const auto phi = cb.eval_functions(pt); - const auto depl = eval(x, phi); - - const std::vector deplv = convertToVectorGmsh(depl); - const std::array coor = init_coor(pt); - - // Add a node - const gmsh::Node tmp_node(coor, nb_nodes, 0); - new_nodes.push_back(tmp_node); - gmsh.addNode(tmp_node); - - const gmsh::Data datatmp(nb_nodes, deplv); - data.push_back(datatmp); - } - // Add new element - add_element(gmsh, new_nodes); - } - - // Create and init a nodedata view - gmsh::NodeData nodedata(3, 0.0, "depl_node_disc", data, subdata); - - // Save the view - nodedata.saveNodeData(filename, gmsh); - } - - void - output_continuous_displacement(const std::string& filename) const - { - const auto dimension = mesh_type::dimension; - - gmsh::Gmesh gmsh = convertMesh(m_post_mesh); - auto storage = m_post_mesh.mesh().backend_storage(); - - const static_vector vzero = static_vector::Zero(); - - const size_t nb_nodes(gmsh.getNumberofNodes()); - - // first(number of data at this node), second(cumulated value) - std::vector>> value(nb_nodes, std::make_pair(0, vzero)); - - int cell_i = 0; - for (auto& cl : m_msh) - { - const auto di = m_degree_infos.cellDegreeInfo(m_msh, cl); - const auto cb = make_vector_monomial_basis(m_msh, cl, di.cell_degree()); - const vector_type x = m_displ.at(cell_i).head(cb.size()); - auto cell_nodes = m_post_mesh.nodes_cell(cell_i); - - // Loop on the nodes of the cell - for (auto& point_id : cell_nodes) - { - const auto pt = storage->points[point_id]; - - const auto phi = cb.eval_functions(pt); - const auto depl = eval(x, phi); - - // Add displacement at node - value[point_id].first++; - value[point_id].second += depl; - } - cell_i++; - } - - std::vector data; // create data - std::vector subdata; // create subdata - data.reserve(nb_nodes); // data has a size of nb_node - - // Compute the average value and save it - for (int i_node = 0; i_node < value.size(); i_node++) - { - const static_vector depl_avr = value[i_node].second / double(value[i_node].first); - - const gmsh::Data tmp_data(i_node + 1, convertToVectorGmsh(depl_avr)); - data.push_back(tmp_data); - } - - // Create and init a nodedata view - gmsh::NodeData nodedata(3, 0.0, "depl_node_cont", data, subdata); - // Save the view - nodedata.saveNodeData(filename, gmsh); - } - - void - output_CauchyStress_GP(const std::string& filename, bool def = false) const - { - gmsh::Gmesh gmsh = convertMesh(m_post_mesh); - - std::vector data; // create data (not used) - std::vector subdata; // create subdata to save soution at gauss point - size_t nb_nodes(gmsh.getNumberofNodes()); - - int cell_i = 0; - for (auto& cl : m_msh) - { - const auto di = m_degree_infos.cellDegreeInfo(m_msh, cl); - - const auto uTF = m_displ.at(cell_i); - matrix_type gr; - if (m_rp.m_precomputation) - { - gr = m_gradient_precomputed.at(cell_i); - } - else - { - if (m_behavior.getDeformation() == SMALL_DEF) - { - gr = make_matrix_hho_symmetric_gradrec(m_msh, cl, m_degree_infos).first; - } - else - { - gr = make_matrix_hho_gradrec(m_msh, cl, m_degree_infos).first; - } - } - - const vector_type GTuTF = gr * uTF; - - const auto gb = make_matrix_monomial_basis(m_msh, cl, di.grad_degree()); - const auto gbs = make_sym_matrix_monomial_basis(m_msh, cl, di.grad_degree()); - - const auto cb = make_vector_monomial_basis(m_msh, cl, di.cell_degree()); - const vector_type uT = uTF.head(cb.size()); - - // Loop on nodes - const auto nb_qp = m_behavior.numberOfQP(cell_i); - - for (int i_qp = 0; i_qp < nb_qp; i_qp++) - { - const auto qp = m_behavior.quadrature_point(cell_i, i_qp); - std::vector tens; - - if (m_behavior.getDeformation() == SMALL_DEF) - { - auto stress = m_behavior.compute_stress3D(cell_i, i_qp); - tens = convertToVectorGmsh(stress); - } - else - { - const auto gphi = gb.eval_functions(qp.point()); - const auto GT_iqn = eval(GTuTF, gphi); - const auto FT_iqn = convertGtoF(GT_iqn); - const auto FT_iqn_3D = convertMatrix3DwithOne(FT_iqn); - - auto P = m_behavior.compute_stress3D(cell_i, i_qp); - auto stress = convertPK1toCauchy(P, FT_iqn_3D); - tens = convertToVectorGmsh(stress); - } - - std::array coor = init_coor(qp.point()); - - if (def) - { - const auto cphi = cb.eval_functions(qp.point()); - const auto depl = eval(uT, cphi); - - // Compute new coordinates - for (int j = 0; j < mesh_type::dimension; j++) - coor[j] += depl(j); - } - - // Add GP - // Create a node at gauss point - nb_nodes++; - const gmsh::Node new_node(coor, nb_nodes, 0); - const gmsh::SubData sdata(tens, new_node); - subdata.push_back(sdata); // add subdata - } - cell_i++; - } - - // Save - gmsh::NodeData nodedata(9, 0.0, "CauchyStress_GP", data, subdata); // create and init a nodedata view - - nodedata.saveNodeData(filename, gmsh); // save the view - } - - void - output_is_plastic_GP(const std::string& filename) const - { - gmsh::Gmesh gmsh = convertMesh(m_post_mesh); - - std::vector data; // create data (not used) - std::vector subdata; // create subdata to save soution at gauss point - size_t nb_nodes(gmsh.getNumberofNodes()); - - int cell_i = 0; - for (auto& cl : m_msh) - { - // Loop on nodes - const auto nb_qp = m_behavior.numberOfQP(cell_i); - - for (int i_qp = 0; i_qp < nb_qp; i_qp++) - { - const auto qp = m_behavior.quadrature_point(cell_i, i_qp); - - scalar_type p = 0; - if (m_behavior.is_plastic(cell_i, i_qp)) - p = 1; - - const std::vector p_s = convertToVectorGmsh(p); - - // Add GP - // Create a node at gauss point - nb_nodes++; - const gmsh::Node new_node = convertPoint(qp.point(), nb_nodes); - const gmsh::SubData sdata(p_s, new_node); - subdata.push_back(sdata); // add subdata - } - cell_i++; - } - - // Save - gmsh::NodeData nodedata(1, 0.0, "state_GP", data, subdata); // create and init a nodedata view - - nodedata.saveNodeData(filename, gmsh); // save the view - } - - void - output_equivalentPlasticStrain_GP(const std::string& filename) const - { - gmsh::Gmesh gmsh = convertMesh(m_post_mesh); - - std::vector data; // create data (not used) - std::vector subdata; // create subdata to save soution at gauss point - size_t nb_nodes(gmsh.getNumberofNodes()); - - int cell_i = 0; - for (auto& cl : m_msh) - { - // Loop on nodes - const auto nb_qp = m_behavior.numberOfQP(cell_i); - - for (int i_qp = 0; i_qp < nb_qp; i_qp++) - { - const auto qp = m_behavior.quadrature_point(cell_i, i_qp); - - scalar_type p = m_behavior.equivalentPlasticStrain(cell_i, i_qp); - - const std::vector p_s = convertToVectorGmsh(p); - - // Add GP - // Create a node at gauss point - nb_nodes++; - const gmsh::Node new_node = convertPoint(qp.point(), nb_nodes); - const gmsh::SubData sdata(p_s, new_node); - subdata.push_back(sdata); // add subdata - } - cell_i++; - } - - // Save - gmsh::NodeData nodedata(1, 0.0, "equivalentPlasticStrain_GP", data, subdata); // create and init a nodedata view - - nodedata.saveNodeData(filename, gmsh); // save the view - } - - void - output_discontinuous_deformed(const std::string& filename) const - { - gmsh::Gmesh gmsh(mesh_type::dimension); - auto storage = m_msh.backend_storage(); - - int cell_i = 0; - size_t nb_nodes = 0; - for (auto& cl : m_msh) - { - const auto di = m_degree_infos.cellDegreeInfo(m_msh, cl); - - auto cb = make_vector_monomial_basis(m_msh, cl, di.cell_degree()); - const vector_type x = m_displ.at(cell_i++).head(cb.size()); - const auto cell_nodes = points(m_msh, cl); - std::vector new_nodes; - - // Loop on nodes of the cell - for (auto& pt : cell_nodes) - { - nb_nodes++; - - const auto phi = cb.eval_functions(pt); - const auto depl = eval(x, phi); - - std::array coor = init_coor(pt); - // Compute new coordinates - for (int j = 0; j < mesh_type::dimension; j++) - coor[j] += depl(j); - - // Save node - const gmsh::Node tmp_node(coor, nb_nodes, 0); - new_nodes.push_back(tmp_node); - gmsh.addNode(tmp_node); - } - // Add new element - add_element(gmsh, new_nodes); - } - // Save mesh - gmsh.writeGmesh(filename, 2); - } - - void - output_stabCoeff(const std::string& filename) const - { - gmsh::Gmesh gmsh = convertMesh(m_post_mesh); - - std::vector data; // create data (not used) - std::vector subdata; // create subdata to save soution at gauss point - size_t nb_nodes(gmsh.getNumberofNodes()); - - for (auto& cl : m_msh) - { - - std::array coor = init_coor(barycenter(m_msh, cl)); - double beta = m_stab_manager.getValue(m_msh, cl); - std::vector tens(1, beta); - - // Add GP - // Create a node at gauss point - nb_nodes++; - const gmsh::Node new_node(coor, nb_nodes, 0); - const gmsh::SubData sdata(tens, new_node); - subdata.push_back(sdata); // add subdata - } - - // Save - gmsh::NodeData nodedata(1, 0.0, "StabCoeff", data, subdata); // create and init a nodedata view - - nodedata.saveNodeData(filename, gmsh); // save the view - } -}; -} - -} // end disk diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverComput.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverComput.hpp index b1df5a6e..1c3b01e4 100644 --- a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverComput.hpp +++ b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverComput.hpp @@ -26,8 +26,6 @@ #pragma once -#include - #include "diskpp/bases/bases.hpp" #include "diskpp/common/eigen.hpp" #include "diskpp/common/timecounter.hpp" @@ -39,30 +37,95 @@ #include "diskpp/methods/hho" #include "diskpp/quadratures/quadratures.hpp" -namespace disk -{ +#include + +namespace disk { + +namespace mechanics { + +template < typename mesh_type, typename T > +dynamic_matrix< T > _gradrec( const mesh_type &msh, const typename mesh_type::cell &cl, + const NonLinearParameters< T > &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, bool small_def, + const std::vector< dynamic_matrix< T > > &gradient_precomputed ) { + if ( rp.m_precomputation ) { + const auto cell_i = msh.lookup( cl ); + return gradient_precomputed[cell_i]; + } + + if ( small_def ) { + const auto gradrec_sym_full = make_matrix_hho_symmetric_gradrec( msh, cl, degree_infos ); + return gradrec_sym_full.first; + } else { + const auto gradrec_full = make_matrix_hho_gradrec( msh, cl, degree_infos ); + return gradrec_full.first; + } + + return dynamic_matrix< T >(); +} + +template < typename mesh_type, typename T > +dynamic_matrix< T > _stab( const mesh_type &msh, const typename mesh_type::cell &cl, + const NonLinearParameters< T > &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + const std::vector< dynamic_matrix< T > > &stab_precomputed ) { + if ( rp.m_precomputation ) { + const auto cell_i = msh.lookup( cl ); + return stab_precomputed.at( cell_i ); + } else { + switch ( rp.m_stab_type ) { + case StabilizationType::HHO_SYM: { + const auto recons = make_vector_hho_symmetric_laplacian( msh, cl, degree_infos ); + return make_vector_hho_stabilization( msh, cl, recons.first, degree_infos ); + break; + } + case StabilizationType::HHO: { + const auto recons_scalar = make_scalar_hho_laplacian( msh, cl, degree_infos ); + return make_vector_hho_stabilization_optim( msh, cl, recons_scalar.first, + degree_infos ); + break; + } + case StabilizationType::HDG: { + return make_vector_hdg_stabilization( msh, cl, degree_infos ); + break; + } + case StabilizationType::DG: { + return make_vector_dg_stabilization( msh, cl, degree_infos ); + break; + } + case StabilizationType::NO: { + break; + } + default: + throw std::invalid_argument( "Unknown stabilization" ); + } + } -namespace mechanics -{ + return dynamic_matrix< T >(); +} -template -class mechanical_computation -{ - typedef MeshType mesh_type; +template < typename MeshType > +class mechanical_computation { + typedef MeshType mesh_type; typedef typename mesh_type::coordinate_type scalar_type; - typedef typename mesh_type::cell cell_type; + typedef typename mesh_type::cell cell_type; - typedef NewtonSolverParameter param_type; - typedef Behavior behavior_type; - typedef vector_boundary_conditions bnd_type; + typedef NonLinearParameters< scalar_type > param_type; + typedef Behavior< mesh_type > behavior_type; + typedef vector_boundary_conditions< mesh_type > bnd_type; - typedef static_matrix static_matrix_type; - typedef static_tensor static_tensor_type; + typedef static_matrix< scalar_type, mesh_type::dimension, mesh_type::dimension > + static_matrix_type; + typedef static_tensor< scalar_type, mesh_type::dimension > static_tensor_type; const static int dimension = mesh_type::dimension; - typedef dynamic_matrix matrix_type; - typedef dynamic_vector vector_type; + typedef dynamic_matrix< scalar_type > matrix_type; + typedef dynamic_vector< scalar_type > vector_type; + + typedef std::function< static_vector< scalar_type, mesh_type::dimension >( + const point< scalar_type, mesh_type::dimension > & ) > + func_type; bool two_dim; @@ -73,24 +136,21 @@ class mechanical_computation * @param gphi set of basis function for gradient reconstruction * @return eigen_compatible_stdvector A : gphi */ - eigen_compatible_stdvector - compute_A_gphi(const static_tensor_type& A, const eigen_compatible_stdvector& gphi) const - { + eigen_compatible_stdvector< static_matrix_type > + compute_A_gphi( const static_tensor_type &A, + const eigen_compatible_stdvector< static_matrix_type > &gphi ) const { const auto grad_basis_size = gphi.size(); - const auto DIM2 = dimension * dimension; + const auto DIM2 = dimension * dimension; - disk::eigen_compatible_stdvector Aphi; - Aphi.reserve(grad_basis_size); + disk::eigen_compatible_stdvector< static_matrix_type > Aphi; + Aphi.reserve( grad_basis_size ); // poly classique - for (size_t i = 0; i < grad_basis_size; i += DIM2) - { + for ( size_t i = 0; i < grad_basis_size; i += DIM2 ) { size_t row = i; - for (size_t k = 0; k < dimension; k++) - { // depend de l'ordre des bases - for (size_t l = 0; l < dimension; l++) - { // depend de l'ordre des bases - Aphi.push_back(disk::tm_prod(A, gphi[row], l, k)); + for ( size_t k = 0; k < dimension; k++ ) { // depend de l'ordre des bases + for ( size_t l = 0; l < dimension; l++ ) { // depend de l'ordre des bases + Aphi.push_back( disk::tm_prod( A, gphi[row], l, k ) ); row++; } } @@ -109,190 +169,175 @@ class mechanical_computation * @param RkT_iqn Reconstruction operator evaluated at the quadrature point (symmetric gradient) * in small deformation and gradient in finite deformation) * @param small_def small deformation yes or no - * @return std::pair stress tensor and the tangent modulus + * @return std::pair stress tensor and the tangent + * modulus */ - std::pair - compute_behavior(behavior_type& behavior, - const size_t& cell_id, - const size_t& qp_id, - const static_matrix_type& RkT_iqn, - const bool small_def, - const bool use_tangent_modulus) const - { - if (small_def) - { - return behavior.compute_whole(cell_id, qp_id, RkT_iqn, use_tangent_modulus); - } - else - { - const auto FT_iqn = convertGtoF(RkT_iqn); - return behavior.compute_whole(cell_id, qp_id, FT_iqn, use_tangent_modulus); + std::pair< static_matrix_type, static_tensor_type > + _compute_behavior( behavior_type &behavior, size_t cell_id, size_t qp_id, + const static_matrix_type &RkT_iqn, const bool small_def, + const bool use_tangent_modulus, const bool compute_tangent ) const { + if ( compute_tangent ) { + if ( small_def ) { + return behavior.compute_whole( cell_id, qp_id, RkT_iqn, use_tangent_modulus ); + } else { + const auto FT_iqn = convertGtoF( RkT_iqn ); + return behavior.compute_whole( cell_id, qp_id, FT_iqn, use_tangent_modulus ); + } + } else { + if ( small_def ) { + return std::make_pair( behavior.compute_stress( cell_id, qp_id, RkT_iqn ), + static_tensor_type() ); + } else { + const auto FT_iqn = convertGtoF( RkT_iqn ); + return std::make_pair( behavior.compute_stress( cell_id, qp_id, FT_iqn ), + static_tensor_type() ); + } } } - void - compute_rigidity(const static_tensor_type& Cep, - const eigen_compatible_stdvector& gphi, - const bool& small_def, - const scalar_type weight, - const size_t grad_dim_dofs, - const size_t grad_basis_size, - matrix_type& AT) const - { + void _compute_rigidity( const static_tensor_type &Cep, + const eigen_compatible_stdvector< static_matrix_type > &gphi, + bool small_def, const scalar_type weight, const size_t grad_dim_dofs, + const size_t grad_basis_size, matrix_type &AT ) { // std::cout << "module : " << Cep << std::endl; - if (small_def) - { + timecounter tc; + tc.tic(); + + if ( small_def ) { // upper part - for (size_t j = 0; j < grad_basis_size; j++) - { - const static_matrix_type Cgphi_j = weight * tm_prod(Cep, gphi[j]); + for ( size_t j = 0; j < grad_basis_size; j++ ) { + const static_matrix_type Cgphi_j = weight * tm_prod( Cep, gphi[j] ); // std::cout << j << std::endl; // std::cout << gphi[j] << std::endl; // std::cout << Cgphi_j << std::endl; - for (size_t i = 0; i <= j; i += grad_dim_dofs) - { + for ( size_t i = 0; i <= j; i += grad_dim_dofs ) { // compute (Ekt v, C(u) : Ekt du) - if (two_dim) - { - AT(i, j) += Cgphi_j(0, 0) * gphi[i](0, 0); - AT(i + 1, j) += 2 * Cgphi_j(0, 1) * gphi[i + 1](0, 1); - AT(i + 2, j) += Cgphi_j(1, 1) * gphi[i + 2](1, 1); - } - else - { - AT(i, j) += Cgphi_j(0, 0) * gphi[i](0, 0); - AT(i + 1, j) += 2 * Cgphi_j(0, 1) * gphi[i + 1](0, 1); - AT(i + 2, j) += Cgphi_j(1, 1) * gphi[i + 2](1, 1); - AT(i + 3, j) += 2 * Cgphi_j(0, 2) * gphi[i + 3](0, 2); - AT(i + 4, j) += 2 * Cgphi_j(1, 2) * gphi[i + 4](1, 2); - AT(i + 5, j) += Cgphi_j(2, 2) * gphi[i + 5](2, 2); + if ( two_dim ) { + AT( i, j ) += Cgphi_j( 0, 0 ) * gphi[i]( 0, 0 ); + AT( i + 1, j ) += 2 * Cgphi_j( 0, 1 ) * gphi[i + 1]( 0, 1 ); + AT( i + 2, j ) += Cgphi_j( 1, 1 ) * gphi[i + 2]( 1, 1 ); + } else { + AT( i, j ) += Cgphi_j( 0, 0 ) * gphi[i]( 0, 0 ); + AT( i + 1, j ) += 2 * Cgphi_j( 0, 1 ) * gphi[i + 1]( 0, 1 ); + AT( i + 2, j ) += Cgphi_j( 1, 1 ) * gphi[i + 2]( 1, 1 ); + AT( i + 3, j ) += 2 * Cgphi_j( 0, 2 ) * gphi[i + 3]( 0, 2 ); + AT( i + 4, j ) += 2 * Cgphi_j( 1, 2 ) * gphi[i + 4]( 1, 2 ); + AT( i + 5, j ) += Cgphi_j( 2, 2 ) * gphi[i + 5]( 2, 2 ); } // AT(i, j) += disk::mm_prod(gphi[i], Agphi_j); } } - } - else - { + } else { // lower part - const auto qp_A_gphi = compute_A_gphi(weight * Cep, gphi); + const auto qp_A_gphi = compute_A_gphi( weight * Cep, gphi ); - for (size_t j = 0; j < grad_basis_size; j += grad_dim_dofs) - { + for ( size_t j = 0; j < grad_basis_size; j += grad_dim_dofs ) { size_t col = j; - for (size_t k = 0; k < dimension; k++) - { // depend de l'ordre des bases - for (size_t l = 0; l < dimension; l++) - { // depend de l'ordre des bases - for (size_t i = col; i < grad_basis_size; i++) - { - AT(i, col) += qp_A_gphi[i](l, k) * gphi[col](l, k); + for ( size_t k = 0; k < dimension; k++ ) { // depend de l'ordre des bases + for ( size_t l = 0; l < dimension; l++ ) { // depend de l'ordre des bases + for ( size_t i = col; i < grad_basis_size; i++ ) { + AT( i, col ) += qp_A_gphi[i]( l, k ) * gphi[col]( l, k ); } col++; } } } } + tc.toc(); + time_rigi += tc.elapsed(); } - void - symmetrized_rigidity_matrix(const size_t grad_basis_size, matrix_type& AT, const bool small_def) const - { - if (small_def) - { + void _symmetrized_rigidity_matrix( const size_t grad_basis_size, matrix_type &AT, + const bool small_def ) { + timecounter tc; + tc.tic(); + + if ( small_def ) { // lower part AT - for (size_t j = 0; j < grad_basis_size; j++) - for (size_t i = j; i < grad_basis_size; i++) - AT(i, j) = AT(j, i); - } - else - { + for ( size_t j = 0; j < grad_basis_size; j++ ) + for ( size_t i = j; i < grad_basis_size; i++ ) + AT( i, j ) = AT( j, i ); + } else { // upper part AT - for (size_t i = 0; i < grad_basis_size; i++) - for (size_t j = i; j < grad_basis_size; j++) - AT(i, j) = AT(j, i); + for ( size_t i = 0; i < grad_basis_size; i++ ) + for ( size_t j = i; j < grad_basis_size; j++ ) + AT( i, j ) = AT( j, i ); } + tc.toc(); + time_rigi += tc.elapsed(); } - template - void - compute_external_forces(const mesh_type& msh, const cell_type& cl, const Function& load, const size_t cell_degree) - { - // compute (f,v)_T - const auto cb = make_vector_monomial_basis(msh, cl, cell_degree); - RTF.head(cb.size()) += make_rhs(msh, cl, cb, load, 1); + void compute_external_forces( const mesh_type &msh, const cell_type &cl, + const std::unique_ptr< func_type > &load, + const size_t cell_degree ) { + timecounter tc; + tc.tic(); + + if ( load ) { + // compute (f,v)_T + + const auto cb = make_vector_monomial_basis( msh, cl, cell_degree ); + RTF.head( cb.size() ) += make_rhs( msh, cl, cb, *load, 1 ); + } + tc.toc(); + time_load += tc.elapsed(); } - void - compute_internal_forces(const static_matrix_type& stress, - const eigen_compatible_stdvector& gphi, - const bool& small_def, - const scalar_type weight, - const size_t grad_dim_dofs, - const size_t grad_basis_size, - vector_type& aT) const - { + void compute_internal_forces( const static_matrix_type &stress, + const eigen_compatible_stdvector< static_matrix_type > &gphi, + bool small_def, const scalar_type weight, + const size_t grad_dim_dofs, const size_t grad_basis_size, + vector_type &aT ) { + timecounter tc; + tc.tic(); + // std::cout << "stress" << std::endl; // std::cout << stress << std::endl; const static_matrix_type stress_qp = weight * stress; - if (small_def) - { + if ( small_def ) { // compute (sigma(u), E^k_T v)_T - for (size_t i = 0; i < grad_basis_size; i += grad_dim_dofs) - { - if (two_dim) - { - aT(i) += stress_qp(0, 0) * gphi[i](0, 0); - aT(i + 1) += 2 * stress_qp(0, 1) * gphi[i + 1](0, 1); - aT(i + 2) += stress_qp(1, 1) * gphi[i + 2](1, 1); - } - else - { - aT(i) += stress_qp(0, 0) * gphi[i](0, 0); - aT(i + 1) += 2 * stress_qp(0, 1) * gphi[i + 1](0, 1); - aT(i + 2) += stress_qp(1, 1) * gphi[i + 2](1, 1); - aT(i + 3) += 2 * stress_qp(0, 2) * gphi[i + 3](0, 2); - aT(i + 4) += 2 * stress_qp(1, 2) * gphi[i + 4](1, 2); - aT(i + 5) += stress_qp(2, 2) * gphi[i + 5](2, 2); + for ( size_t i = 0; i < grad_basis_size; i += grad_dim_dofs ) { + if ( two_dim ) { + aT( i ) += stress_qp( 0, 0 ) * gphi[i]( 0, 0 ); + aT( i + 1 ) += 2 * stress_qp( 0, 1 ) * gphi[i + 1]( 0, 1 ); + aT( i + 2 ) += stress_qp( 1, 1 ) * gphi[i + 2]( 1, 1 ); + } else { + aT( i ) += stress_qp( 0, 0 ) * gphi[i]( 0, 0 ); + aT( i + 1 ) += 2 * stress_qp( 0, 1 ) * gphi[i + 1]( 0, 1 ); + aT( i + 2 ) += stress_qp( 1, 1 ) * gphi[i + 2]( 1, 1 ); + aT( i + 3 ) += 2 * stress_qp( 0, 2 ) * gphi[i + 3]( 0, 2 ); + aT( i + 4 ) += 2 * stress_qp( 1, 2 ) * gphi[i + 4]( 1, 2 ); + aT( i + 5 ) += stress_qp( 2, 2 ) * gphi[i + 5]( 2, 2 ); } } - } - else - { + } else { // compute (PK1(u), G^k_T v)_T - for (size_t i = 0; i < grad_basis_size; i += grad_dim_dofs) - { + for ( size_t i = 0; i < grad_basis_size; i += grad_dim_dofs ) { size_t row = i; - for (size_t k = 0; k < dimension; k++) - { // depend de l'ordre des bases - for (size_t l = 0; l < dimension; l++) - { // depend de l'ordre des bases + for ( size_t k = 0; k < dimension; k++ ) { // depend de l'ordre des bases + for ( size_t l = 0; l < dimension; l++ ) { // depend de l'ordre des bases // compute (PK1(u), G^k_T v)_T - aT(row) += stress_qp(l, k) * gphi[row](l, k); + aT( row ) += stress_qp( l, k ) * gphi[row]( l, k ); row++; } } } } + tc.toc(); + time_fint += tc.elapsed(); } - void - compute_contact_terms(const mesh_type& msh, - const cell_type& cl, - const bnd_type& bnd, - const param_type& rp, - const CellDegreeInfo& cell_infos, - const matrix_type& RkT, - const vector_type& uTF, - const TimeStep& time_step, - behavior_type& behavior) - { - if (bnd.cell_has_contact_faces(cl)) - { - const auto& material_data = behavior.getMaterialData(); - auto cc = contact_contribution(msh, material_data, rp, bnd); - cc.compute(cl, cell_infos, RkT, uTF); + void compute_contact_terms( const mesh_type &msh, const cell_type &cl, const bnd_type &bnd, + const param_type &rp, const CellDegreeInfo< mesh_type > &cell_infos, + const matrix_type &RkT, const vector_type &uTF, + const TimeStep< scalar_type > &time_step, + behavior_type &behavior ) { + if ( bnd.cell_has_contact_faces( cl ) ) { + const auto &material_data = behavior.getMaterialData(); + auto cc = contact_contribution( msh, material_data, rp, bnd ); + cc.compute( cl, cell_infos, RkT, uTF ); time_contact += cc.time_contact; @@ -302,19 +347,14 @@ class mechanical_computation } } - size_t - num_grad_dim_dofs(const bool& small_def) const - { - if (small_def) - { - if (two_dim) + size_t num_grad_dim_dofs( bool small_def ) const { + if ( small_def ) { + if ( two_dim ) return 3; else return 6; - } - else - { - if (two_dim) + } else { + if ( two_dim ) return 4; else return 9; @@ -325,74 +365,57 @@ class mechanical_computation matrix_type K_int; vector_type RTF; vector_type F_int; - double time_law; - double time_contact; - double time_dyna; + double time_law, time_load, time_fint, time_rigi; + double time_contact; - mechanical_computation(void) - { - if (dimension == 2) + mechanical_computation( void ) + : time_law( 0. ), time_load( 0. ), time_contact( 0. ), time_fint( 0. ), time_rigi( 0. ) { + if ( dimension == 2 ) two_dim = true; - else if (dimension == 3) + else if ( dimension == 3 ) two_dim = false; else - assert(false); + assert( false ); } - template - void - compute(const mesh_type& msh, - const cell_type& cl, - const bnd_type& bnd, - const param_type& rp, - const MeshDegreeInfo& degree_infos, - const Function& load, - const matrix_type& RkT, - const vector_type& uTF, - const vector_type& aT_pred, - const TimeStep& time_step, - behavior_type& behavior, - StabCoeffManager& stab_manager, - const bool small_def) - { - time_law = 0.0; - time_contact = 0.0; - time_dyna = 0.0; + void compute( const mesh_type &msh, const cell_type &cl, const bnd_type &bnd, + const param_type &rp, const MeshDegreeInfo< mesh_type > °ree_infos, + const std::unique_ptr< func_type > &load, const matrix_type &RkT, + const vector_type &uTF, const TimeStep< scalar_type > &time_step, + behavior_type &behavior, StabCoeffManager< scalar_type > &stab_manager, + const bool small_def, const bool tangent_matix = true, + const bool use_tangent_modulus = true ) { timecounter tc; - const auto cell_infos = degree_infos.cellDegreeInfo(msh, cl); + const auto cell_infos = degree_infos.cellDegreeInfo( msh, cl ); const auto faces_infos = cell_infos.facesDegreeInfo(); const auto cell_degree = cell_infos.cell_degree(); const auto grad_degree = cell_infos.grad_degree(); - const auto cb = make_vector_monomial_basis(msh, cl, cell_degree); - const auto cell_basis_size = vector_basis_size(cell_degree, dimension, dimension); + const auto cell_basis_size = vector_basis_size( cell_degree, dimension, dimension ); size_t gb_size = 0; - if (small_def) - { - gb_size = sym_matrix_basis_size(grad_degree, dimension, dimension); - } - else - { - gb_size = matrix_basis_size(grad_degree, dimension, dimension); + if ( small_def ) { + gb_size = sym_matrix_basis_size( grad_degree, dimension, dimension ); + } else { + gb_size = matrix_basis_size( grad_degree, dimension, dimension ); } const auto grad_basis_size = gb_size; - const auto num_faces_dofs = vector_faces_dofs(msh, faces_infos); + const auto num_faces_dofs = vector_faces_dofs( msh, faces_infos ); const auto num_total_dofs = cell_basis_size + num_faces_dofs; - const auto grad_dim_dofs = num_grad_dim_dofs(small_def); + const auto grad_dim_dofs = num_grad_dim_dofs( small_def ); - matrix_type AT = matrix_type::Zero(grad_basis_size, grad_basis_size); - vector_type aT = vector_type::Zero(grad_basis_size); + matrix_type AT = matrix_type::Zero( grad_basis_size, grad_basis_size ); + vector_type aT = vector_type::Zero( grad_basis_size ); - RTF = vector_type::Zero(num_total_dofs); - F_int = vector_type::Zero(num_total_dofs); + RTF = vector_type::Zero( num_total_dofs ); + F_int = vector_type::Zero( num_total_dofs ); - assert(RkT.cols() == uTF.rows()); - assert(RkT.rows() == grad_basis_size); + assert( RkT.cols() == uTF.rows() ); + assert( RkT.rows() == grad_basis_size ); // std::cout << "sol" << std::endl; // std::cout << uTF.transpose() << std::endl; @@ -402,36 +425,31 @@ class mechanical_computation // std::cout << "RkT: " << RkT.norm() << std::endl; // std::cout << "RkT_Utf: " << RkT_uTF.transpose() << std::endl; - const auto gb = make_matrix_monomial_basis(msh, cl, grad_degree); - const auto gbs = make_sym_matrix_monomial_basis(msh, cl, grad_degree); + const auto gb = make_matrix_monomial_basis( msh, cl, grad_degree ); + const auto gbs = make_sym_matrix_monomial_basis( msh, cl, grad_degree ); - eigen_compatible_stdvector gphi; + eigen_compatible_stdvector< static_matrix_type > gphi; - const auto cell_id = msh.lookup(cl); - const auto nb_qp = behavior.numberOfQP(cell_id); - const bool use_tangent_modulus = true; + const auto cell_id = msh.lookup( cl ); + const auto nb_qp = behavior.numberOfQP( cell_id ); scalar_type beta_comp = 0.0, total_weight = 0.0; - for (int i_qp = 0; i_qp < nb_qp; i_qp++) - { + for ( int i_qp = 0; i_qp < nb_qp; i_qp++ ) { // Compute gradient basis function - const auto qp = behavior.quadrature_point(cell_id, i_qp); + const auto qp = behavior.quadrature_point( cell_id, i_qp ); // std::cout << "qp: " << qp.point() << std::endl; - if (small_def) - { - gphi = gbs.eval_functions(qp.point()); - } - else - { - gphi = gb.eval_functions(qp.point()); + if ( small_def ) { + gphi = gbs.eval_functions( qp.point() ); + } else { + gphi = gb.eval_functions( qp.point() ); } - assert(gphi.size() == grad_basis_size); + assert( gphi.size() == grad_basis_size ); // Compute local gradient and norm // RkT_iqn = Grad_sym for small def else RkT_iqn = Grad - const auto RkT_iqn = eval(RkT_uTF, gphi); + const auto RkT_iqn = eval( RkT_uTF, gphi ); // std::cout << "RkT_iqn" << std::endl; // std::cout << RkT_iqn << std::endl; @@ -439,48 +457,49 @@ class mechanical_computation // Compute behavior // if small_def stress = Cauchy else stress = PK1 tc.tic(); - const auto [stress, Cep] = - compute_behavior(behavior, cell_id, i_qp, RkT_iqn, small_def, use_tangent_modulus); + const auto [stress, Cep] = _compute_behavior( + behavior, cell_id, i_qp, RkT_iqn, small_def, use_tangent_modulus, tangent_matix ); + tc.toc(); + time_law += tc.elapsed(); // std::cout << "stress: " << stress.norm() << std::endl; // std::cout << stress << std::endl; // std::cout << "Cep: " << Cep.norm() << std::endl; // std::cout << Cep << std::endl; - tc.toc(); - time_law += tc.elapsed(); - // Compute rigidity - this->compute_rigidity(Cep, gphi, small_def, qp.weight(), grad_dim_dofs, grad_basis_size, AT); + if ( tangent_matix ) { + // Compute rigidity + this->_compute_rigidity( Cep, gphi, small_def, qp.weight(), grad_dim_dofs, + grad_basis_size, AT ); + } + // Compute internal force - this->compute_internal_forces(stress, gphi, small_def, qp.weight(), grad_dim_dofs, grad_basis_size, aT); + this->compute_internal_forces( stress, gphi, small_def, qp.weight(), grad_dim_dofs, + grad_basis_size, aT ); // compute new possible value for stabilization - if (rp.m_adapt_stab) - { + if ( rp.m_adapt_stab ) { scalar_type sigma_dev_norm, eps_dev_norm; - if (small_def) - { - sigma_dev_norm = deviator(stress).norm(); - eps_dev_norm = deviator(RkT_iqn).norm(); - } - else - { - const auto F = convertGtoF(RkT_iqn); - const auto EGL = convertFtoGreenLagrange(F); - eps_dev_norm = deviator(EGL).norm(); + if ( small_def ) { + sigma_dev_norm = deviator( stress ).norm(); + eps_dev_norm = deviator( RkT_iqn ).norm(); + } else { + const auto F = convertGtoF( RkT_iqn ); + const auto EGL = convertFtoGreenLagrange( F ); + eps_dev_norm = deviator( EGL ).norm(); - const auto PK2 = convertPK1toPK2(stress, F); - sigma_dev_norm = deviator(PK2).norm(); + const auto PK2 = convertPK1toPK2( stress, F ); + sigma_dev_norm = deviator( PK2 ).norm(); // const auto Cauchy = convertPK1toCauchy(stress, F); // const auto eps = convertGtoLinearizedStrain(RkT_iqn); - // std::cout << sigma_dev_norm / eps_dev_norm << " vs " << deviator(Cauchy).norm() / - // deviator(eps).norm() + // std::cout << sigma_dev_norm / eps_dev_norm << " vs " << + // deviator(Cauchy).norm() / deviator(eps).norm() // << std::endl; } total_weight += qp.weight(); - if (eps_dev_norm < 1E-12) + if ( eps_dev_norm < 1E-12 ) beta_comp += qp.weight() * rp.m_beta; else beta_comp += qp.weight() * sigma_dev_norm / eps_dev_norm; @@ -488,32 +507,42 @@ class mechanical_computation } // save new stabilization coeff beta_s in [beta/1000, 1000*beta] - if (rp.m_adapt_stab) - { + if ( rp.m_adapt_stab ) { beta_comp /= total_weight; - const auto beta_s = std::min(1000. * rp.m_beta, std::max(rp.m_beta / 10000., beta_comp)); + const auto beta_s = + std::min( 1000. * rp.m_beta, std::max( rp.m_beta / 10000., beta_comp ) ); // std::cout << beta_comp << " vs " << beta_s << std::endl; - stab_manager.setValueNext(msh, cl, beta_s); + stab_manager.setValueNext( msh, cl, beta_s ); } // compute external forces - this->compute_external_forces(msh, cl, load, cell_degree); + this->compute_external_forces( msh, cl, load, cell_degree ); // std::cout << "R_ext: " << RTF.norm() << std::endl; // std::cout << RTF.transpose() << std::endl; - // Symmetrize rigidity matrix - this->symmetrized_rigidity_matrix(grad_basis_size, AT, small_def); + if ( tangent_matix ) { - // std::cout << "AT: " << AT.norm() << std::endl; - // std::cout << AT << std::endl; - // std::cout << "aT: " << aT.norm() << std::endl; + // Symmetrize rigidity matrix + this->_symmetrized_rigidity_matrix( grad_basis_size, AT, small_def ); - K_int = RkT.transpose() * AT * RkT; + // std::cout << "AT: " << AT.norm() << std::endl; + // std::cout << AT << std::endl; + // std::cout << "aT: " << aT.norm() << std::endl; + + tc.tic(); + K_int = RkT.transpose() * AT * RkT; + tc.toc(); + time_rigi += tc.elapsed(); + } + tc.tic(); F_int = RkT.transpose() * aT; RTF -= F_int; + tc.toc(); + time_fint += tc.elapsed(); // Compute contact terms - this->compute_contact_terms(msh, cl, bnd, rp, cell_infos, RkT, uTF, time_step, behavior); + + this->compute_contact_terms( msh, cl, bnd, rp, cell_infos, RkT, uTF, time_step, behavior ); // std::cout << "K: " << K_int.norm() << std::endl; // // std::cout << K_int << std::endl; @@ -524,34 +553,129 @@ class mechanical_computation // throw std::runtime_error(""); - assert(K_int.rows() == num_total_dofs); - assert(K_int.cols() == num_total_dofs); - assert(RTF.rows() == num_total_dofs); + assert( K_int.rows() == num_total_dofs ); + assert( K_int.cols() == num_total_dofs ); + assert( RTF.rows() == num_total_dofs ); + } - // Unsteady Computation - tc.tic(); - if (rp.isUnsteady()) - { - auto dt = time_step.increment_time(); - auto dyna_rp = rp.getUnsteadyParameters(); - auto beta = dyna_rp["beta"]; - auto rho = dyna_rp["rho"]; + void compute_rigidity_matrix( const mesh_type &msh, const cell_type &cl, const bnd_type &bnd, + const param_type &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + const matrix_type &RkT, const vector_type &uTF, + const TimeStep< scalar_type > &time_step, behavior_type &behavior, + const bool small_def, bool use_tangente = true ) { + timecounter tc; - const matrix_type mass_mat = rho * make_mass_matrix(msh, cl, cb); + const auto cell_infos = degree_infos.cellDegreeInfo( msh, cl ); + const auto faces_infos = cell_infos.facesDegreeInfo(); - K_int.topLeftCorner(cell_basis_size, cell_basis_size) += mass_mat / (beta * dt * dt); + const auto cell_degree = cell_infos.cell_degree(); + const auto grad_degree = cell_infos.grad_degree(); - auto F_iner = (mass_mat / (beta * dt * dt)) * uTF.head(cell_basis_size); - F_int.head(cell_basis_size) += F_iner; - RTF.head(cell_basis_size) -= F_iner; + const auto cell_basis_size = vector_basis_size( cell_degree, dimension, dimension ); - // std::cout << mass_mat.cols() << ", " << aT_pred.rows() << std::endl; - RTF.head(cell_basis_size) += mass_mat * aT_pred; + size_t gb_size = 0; + if ( small_def ) { + gb_size = sym_matrix_basis_size( grad_degree, dimension, dimension ); + } else { + gb_size = matrix_basis_size( grad_degree, dimension, dimension ); } + + const auto grad_basis_size = gb_size; + + const auto num_faces_dofs = vector_faces_dofs( msh, faces_infos ); + const auto num_total_dofs = cell_basis_size + num_faces_dofs; + const auto grad_dim_dofs = num_grad_dim_dofs( small_def ); + + matrix_type AT = matrix_type::Zero( grad_basis_size, grad_basis_size ); + + RTF = vector_type::Zero( num_total_dofs ); + + assert( RkT.cols() == uTF.rows() ); + assert( RkT.rows() == grad_basis_size ); + + // std::cout << "sol" << std::endl; + // std::cout << uTF.transpose() << std::endl; + + const vector_type RkT_uTF = RkT * uTF; + + // std::cout << "RkT: " << RkT.norm() << std::endl; + // std::cout << "RkT_Utf: " << RkT_uTF.transpose() << std::endl; + + const auto gb = make_matrix_monomial_basis( msh, cl, grad_degree ); + const auto gbs = make_sym_matrix_monomial_basis( msh, cl, grad_degree ); + + eigen_compatible_stdvector< static_matrix_type > gphi; + + const auto cell_id = msh.lookup( cl ); + const auto nb_qp = behavior.numberOfQP( cell_id ); + + scalar_type beta_comp = 0.0, total_weight = 0.0; + for ( int i_qp = 0; i_qp < nb_qp; i_qp++ ) { + // Compute gradient basis function + const auto qp = behavior.quadrature_point( cell_id, i_qp ); + // std::cout << "qp: " << qp.point() << std::endl; + + if ( small_def ) { + gphi = gbs.eval_functions( qp.point() ); + } else { + gphi = gb.eval_functions( qp.point() ); + } + + assert( gphi.size() == grad_basis_size ); + + // Compute local gradient and norm + // RkT_iqn = Grad_sym for small def else RkT_iqn = Grad + const auto RkT_iqn = eval( RkT_uTF, gphi ); + + // std::cout << "RkT_iqn" << std::endl; + // std::cout << RkT_iqn << std::endl; + + // Compute behavior + // if small_def stress = Cauchy else stress = PK1 + tc.tic(); + const auto [stress, Cep] = this->_compute_behavior( behavior, cell_id, i_qp, RkT_iqn, + small_def, use_tangente, true ); + tc.toc(); + time_law += tc.elapsed(); + // std::cout << "stress: " << stress.norm() << std::endl; + // std::cout << stress << std::endl; + // std::cout << "Cep: " << Cep.norm() << std::endl; + // std::cout << Cep << std::endl; + + // Compute rigidity + this->_compute_rigidity( Cep, gphi, small_def, qp.weight(), grad_dim_dofs, + grad_basis_size, AT ); + } + + // Symmetrize rigidity matrix + this->_symmetrized_rigidity_matrix( grad_basis_size, AT, small_def ); + + // std::cout << "AT: " << AT.norm() << std::endl; + // std::cout << AT << std::endl; + // std::cout << "aT: " << aT.norm() << std::endl; + + tc.tic(); + K_int = RkT.transpose() * AT * RkT; tc.toc(); - time_dyna += tc.elapsed(); + time_rigi += tc.elapsed(); + // Compute contact terms + // this->compute_contact_terms( msh, cl, bnd, rp, cell_infos, RkT, uTF, time_step, + // behavior ); + + // std::cout << "K: " << K_int.norm() << std::endl; + // // std::cout << K_int << std::endl; + // std::cout << "F_int: " << F_int.norm() << std::endl; + // std::cout << F_int.transpose() << std::endl; + // std::cout << "RTF: " << RTF.norm() << std::endl; + // std::cout << RTF.transpose() << std::endl; + + // throw std::runtime_error(""); + + assert( K_int.rows() == num_total_dofs ); + assert( K_int.cols() == num_total_dofs ); } }; -} +} // namespace mechanics -} // end namespace diskpp \ No newline at end of file +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverContact.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverContact.hpp index 40856e78..36400bab 100644 --- a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverContact.hpp +++ b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverContact.hpp @@ -25,121 +25,72 @@ #pragma once -#include - #include "diskpp/bases/bases.hpp" #include "diskpp/boundary_conditions/boundary_conditions.hpp" #include "diskpp/common/eigen.hpp" #include "diskpp/common/timecounter.hpp" -#include "diskpp/mechanics/NewtonSolver/NewtonSolverParameters.hpp" +#include "diskpp/mechanics/NewtonSolver/NonLinearParameters.hpp" #include "diskpp/mechanics/behaviors/laws/materialData.hpp" #include "diskpp/mechanics/behaviors/maths_tensor.hpp" #include "diskpp/methods/hho" #include "diskpp/quadratures/quadratures.hpp" -namespace disk -{ - -namespace mechanics -{ - -namespace priv -{ -template -T -compute_g0(const disk::point& pt, const static_vector& n) -{ - // compute the distance to the plane y = 0 - - if (std::abs(n(1)) < T(1E-12)) - return 10E12; - - const T dist = std::abs(pt.y() / n(1)); - - if (pt.y() < T(0)) - return -dist; - - return dist; - - // compute the distance to the plane y = -0.05(x-0.5)^2 - // return pt.y() + 0.05 * (pt.x() - 0.5) * (pt.x() - 0.5); -} - -template -T -compute_g0(const disk::point& pt, const static_vector& n) -{ - // distance to the plane z = 0 - - // the normal is orthogonal to the plane z = 0 - if (std::abs(n(2)) < T(1E-12)) - return 10E12; +#include - const T dist = std::abs(pt.z() / n(2)); +namespace disk { - if (pt.z() < T(0)) - return -dist; +namespace mechanics { - return dist; -} +namespace priv { -template -point -new_pt(const Basis& base, const disk::dynamic_vector& tab_coeff, const point& pt) -{ - const auto beval = base.eval_functions(pt); +template < typename Basis, typename T, size_t DIM > +point< T, DIM > new_pt( const Basis &base, const disk::dynamic_vector< T > &tab_coeff, + const point< T, DIM > &pt ) { + const auto beval = base.eval_functions( pt ); - const auto depl = disk::eval(tab_coeff, beval); + const auto depl = disk::eval( tab_coeff, beval ); return pt + depl; } -template -static_vector -compute_normal(const disk::point& a, const disk::point& b) -{ - const static_vector t1 = (b - a).to_vector(); - static_vector nor; - nor(0) = -t1(1); - nor(1) = t1(0); +template < typename T > +static_vector< T, 2 > compute_normal( const disk::point< T, 2 > &a, const disk::point< T, 2 > &b ) { + const static_vector< T, 2 > t1 = ( b - a ).to_vector(); + static_vector< T, 2 > nor; + nor( 0 ) = -t1( 1 ); + nor( 1 ) = t1( 0 ); return nor / nor.norm(); } -template -static_vector -compute_normal(const disk::point& p1, const disk::point& p2, const disk::point& p3) -{ - static_vector t1 = (p2 - p1).to_vector(); - static_vector t2 = (p3 - p1).to_vector(); +template < typename T > +static_vector< T, 3 > compute_normal( const disk::point< T, 3 > &p1, const disk::point< T, 3 > &p2, + const disk::point< T, 3 > &p3 ) { + static_vector< T, 3 > t1 = ( p2 - p1 ).to_vector(); + static_vector< T, 3 > t2 = ( p3 - p1 ).to_vector(); t1 /= t1.norm(); t2 /= t2.norm(); - static_vector nor = t1.cross(t2); + static_vector< T, 3 > nor = t1.cross( t2 ); return nor / nor.norm(); } -template -T -compute_gap_fb(const Mesh& msh, - const Elem& elem, - const ElemBasis& eb, - const disk::dynamic_vector& tab_coeff, - const disk::point& pt, - const static_vector& n) -{ - const disk::point pt_def = new_pt(eb, tab_coeff, pt); - const auto pts = points(msh, elem); - const static_vector n_ref = compute_normal(pts[0], pts[1]); +template < typename Mesh, typename Elem, typename ElemBasis, typename T, typename FunctionGap > +T compute_gap_fb( const Mesh &msh, const Elem &elem, const ElemBasis &eb, + const disk::dynamic_vector< T > &tab_coeff, const FunctionGap &func_gap, + const disk::point< T, 2 > &pt, const static_vector< T, 2 > &n ) { + const disk::point< T, 2 > pt_def = new_pt( eb, tab_coeff, pt ); + const auto pts = points( msh, elem ); + const static_vector< T, 2 > n_ref = compute_normal( pts[0], pts[1] ); - const disk::point pta_def = new_pt(eb, tab_coeff, pts[0]); - const disk::point ptb_def = new_pt(eb, tab_coeff, pts[1]); + const disk::point< T, 2 > pta_def = new_pt( eb, tab_coeff, pts[0] ); + const disk::point< T, 2 > ptb_def = new_pt( eb, tab_coeff, pts[1] ); - const T sign = std::copysign(T(1), n.dot(n_ref)); + const T sign = std::copysign( T( 1 ), n.dot( n_ref ) ); - const static_vector n_def = sign * compute_normal(pta_def, ptb_def); + const static_vector< T, 2 > n_def = sign * compute_normal( pta_def, ptb_def ); // std::cout << "pt: " << pt << std::endl; // std::cout << "pta: " << pts[0] << std::endl; @@ -152,108 +103,92 @@ compute_gap_fb(const Mesh& msh, // std::cout << "normal ref: " << n_ref.transpose() << std::endl; // std::cout << "normal def: " << n_def.transpose() << std::endl; - return compute_g0(pt_def, n_def); + return func_gap( pt_def, n_def ); } -template -T -compute_gap_fb(const Mesh& msh, - const Elem& elem, - const ElemBasis& eb, - const disk::dynamic_vector& tab_coeff, - const disk::point& pt, - const static_vector& n) -{ - const disk::point pt_def = new_pt(eb, tab_coeff, pt); - const auto pts = points(msh, elem); - const static_vector n_ref = compute_normal(pts[0], pts[1], pts[2]); +template < typename Mesh, typename Elem, typename ElemBasis, typename T, typename FunctionGap > +T compute_gap_fb( const Mesh &msh, const Elem &elem, const ElemBasis &eb, + const disk::dynamic_vector< T > &tab_coeff, const FunctionGap &func_gap, + const disk::point< T, 3 > &pt, const static_vector< T, 3 > &n ) { + const disk::point< T, 3 > pt_def = new_pt( eb, tab_coeff, pt ); + const auto pts = points( msh, elem ); + const static_vector< T, 3 > n_ref = compute_normal( pts[0], pts[1], pts[2] ); - const disk::point pt0_def = new_pt(eb, tab_coeff, pts[0]); - const disk::point pt1_def = new_pt(eb, tab_coeff, pts[1]); - const disk::point pt2_def = new_pt(eb, tab_coeff, pts[2]); + const disk::point< T, 3 > pt0_def = new_pt( eb, tab_coeff, pts[0] ); + const disk::point< T, 3 > pt1_def = new_pt( eb, tab_coeff, pts[1] ); + const disk::point< T, 3 > pt2_def = new_pt( eb, tab_coeff, pts[2] ); - const T sign = std::copysign(T(1), n.dot(n_ref)); + const T sign = std::copysign( T( 1 ), n.dot( n_ref ) ); - const static_vector n_def = sign * compute_normal(pt0_def, pt1_def, pt2_def); + const static_vector< T, 3 > n_def = sign * compute_normal( pt0_def, pt1_def, pt2_def ); - return compute_g0(pt_def, n_def); -} + return func_gap( pt_def, n_def ); } +} // namespace priv -template -class contact_contribution -{ +template < typename MeshType > +class contact_contribution { private: - typedef MeshType mesh_type; - typedef typename mesh_type::coordinate_type scalar_type; - typedef typename mesh_type::cell cell_type; - typedef typename mesh_type::face face_type; - typedef point point_type; - typedef disk::MaterialData material_type; - typedef NewtonSolverParameter param_type; - typedef disk::vector_boundary_conditions bnd_type; + typedef MeshType mesh_type; + typedef typename mesh_type::coordinate_type scalar_type; + typedef typename mesh_type::cell cell_type; + typedef typename mesh_type::face face_type; + typedef point< scalar_type, mesh_type::dimension > point_type; + typedef MaterialData< scalar_type > material_type; + typedef NonLinearParameters< scalar_type > param_type; + typedef vector_boundary_conditions< mesh_type > bnd_type; const static int dimension = mesh_type::dimension; - typedef dynamic_matrix matrix_type; - typedef dynamic_vector vector_type; + typedef dynamic_matrix< scalar_type > matrix_type; + typedef dynamic_vector< scalar_type > vector_type; - typedef static_matrix matrix_static; - typedef static_vector vector_static; + typedef static_matrix< scalar_type, dimension, dimension > matrix_static; + typedef static_vector< scalar_type, dimension > vector_static; - typedef Matrix matrix_d_type; + typedef Matrix< scalar_type, Dynamic, dimension > matrix_d_type; - const mesh_type& m_msh; - const material_type& m_material_data; - const param_type& m_rp; - const bnd_type& m_bnd; + const mesh_type &m_msh; + const material_type &m_material_data; + const param_type &m_rp; + const bnd_type &m_bnd; // contact contrib; - - scalar_type - make_hho_distance(const point_type& pt, const vector_static& n) const - { - return priv::compute_g0(pt, n); - } - // normal part of u : u_n = u.n - template - vector_type - make_hho_u_n(const vector_static& n, const TraceBasis& tb, const point_type& pt) const - { - const auto t_phi = tb.eval_functions(pt); + template < typename TraceBasis > + vector_type make_hho_u_n( const vector_static &n, const TraceBasis &tb, + const point_type &pt ) const { + const auto t_phi = tb.eval_functions( pt ); // std::cout << "t_phi: " << t_phi.transpose() << std::endl; //(phi_T . n) - return disk::priv::inner_product(t_phi, n); + return disk::priv::inner_product( t_phi, n ); } // tangential part of u : u_t = u - u_n*n - template - matrix_d_type - make_hho_u_t(const vector_static& n, const TraceBasis& tb, const point_type& pt) const - { - const auto t_phi = tb.eval_functions(pt); - const auto u_n = make_hho_u_n(n, tb, pt); + template < typename TraceBasis > + matrix_d_type make_hho_u_t( const vector_static &n, const TraceBasis &tb, + const point_type &pt ) const { + const auto t_phi = tb.eval_functions( pt ); + const auto u_n = make_hho_u_n( n, tb, pt ); // phi_T - (phi_T . n)n - return t_phi - disk::priv::inner_product(u_n, n); + return t_phi - disk::priv::inner_product( u_n, n ); } // cauchy traction : sigma_n = sigma * n - template - matrix_d_type - make_hho_sigma_n(const matrix_type& ET, const vector_static& n, const GradBasis& gb, const point_type& pt) const - { - matrix_d_type sigma_n = matrix_d_type::Zero(ET.cols(), dimension); + template < typename GradBasis > + matrix_d_type make_hho_sigma_n( const matrix_type &ET, const vector_static &n, + const GradBasis &gb, const point_type &pt ) const { + matrix_d_type sigma_n = matrix_d_type::Zero( ET.cols(), dimension ); - const auto gphi = gb.eval_functions(pt); - const auto gphi_n = disk::priv::inner_product(gphi, n); + const auto gphi = gb.eval_functions( pt ); + const auto gphi_n = disk::priv::inner_product( gphi, n ); sigma_n = 2.0 * m_material_data.getMu() * ET.transpose() * gphi_n; - const auto gphi_trace_n = disk::priv::inner_product(disk::trace(gphi), n); + const auto gphi_trace_n = disk::priv::inner_product( disk::trace( gphi ), n ); sigma_n += m_material_data.getLambda() * ET.transpose() * gphi_trace_n; @@ -261,100 +196,75 @@ class contact_contribution return sigma_n; } - template - vector_type - make_hho_sigma_nn(const matrix_type& ET, const vector_static& n, const GradBasis& gb, const point_type& pt) const - { - const auto sigma_n = make_hho_sigma_n(ET, n, gb, pt); + template < typename GradBasis > + vector_type make_hho_sigma_nn( const matrix_type &ET, const vector_static &n, + const GradBasis &gb, const point_type &pt ) const { + const auto sigma_n = make_hho_sigma_n( ET, n, gb, pt ); // sigma_n . n - return disk::priv::inner_product(sigma_n, n); + return disk::priv::inner_product( sigma_n, n ); } - vector_type - make_hho_sigma_nn(const matrix_d_type& sigma_n, const vector_static& n) const - { + vector_type make_hho_sigma_nn( const matrix_d_type &sigma_n, const vector_static &n ) const { // sigma_n . n - return disk::priv::inner_product(sigma_n, n); + return disk::priv::inner_product( sigma_n, n ); } - template - matrix_d_type - make_hho_sigma_nt(const matrix_type& ET, const vector_static& n, const GradBasis& gb, const point_type& pt) const - { - const auto sigma_n = make_hho_sigma_n(ET, n, gb, pt); - const auto sigma_nn = make_hho_sigma_nn(sigma_n, n); + template < typename GradBasis > + matrix_d_type make_hho_sigma_nt( const matrix_type &ET, const vector_static &n, + const GradBasis &gb, const point_type &pt ) const { + const auto sigma_n = make_hho_sigma_n( ET, n, gb, pt ); + const auto sigma_nn = make_hho_sigma_nn( sigma_n, n ); // sigma_n - sigma_nn * n - return sigma_n - disk::priv::inner_product(sigma_nn, n); + return sigma_n - disk::priv::inner_product( sigma_nn, n ); } - vector_type - make_hho_phi_n_uT(const vector_type& sigma_nn, - const vector_type& uT_n, - const scalar_type& theta, - const scalar_type& gamma_F) const - { + vector_type make_hho_phi_n_uT( const vector_type &sigma_nn, const vector_type &uT_n, + scalar_type theta, scalar_type gamma_F ) const { vector_type phi_n = theta * sigma_nn; - phi_n.head(uT_n.size()) -= gamma_F * uT_n; + phi_n.head( uT_n.size() ) -= gamma_F * uT_n; // theta * sigma_nn - gamma uT_n return phi_n; } - matrix_d_type - make_hho_phi_t_uT(const matrix_d_type& sigma_nt, - const matrix_d_type& uT_t, - const scalar_type& theta, - const scalar_type& gamma_F) const - { + matrix_d_type make_hho_phi_t_uT( const matrix_d_type &sigma_nt, const matrix_d_type &uT_t, + scalar_type theta, scalar_type gamma_F ) const { matrix_d_type phi_t = theta * sigma_nt; - phi_t.block(0, 0, uT_t.rows(), dimension) -= gamma_F * uT_t; + phi_t.block( 0, 0, uT_t.rows(), dimension ) -= gamma_F * uT_t; // theta * sigma_nt - gamma uT_t return phi_t; } - vector_type - make_hho_phi_n_uF(const vector_type& sigma_nn, - const vector_type& uF_n, - const scalar_type& theta, - const scalar_type& gamma_F, - const size_t& offset) const - { + vector_type make_hho_phi_n_uF( const vector_type &sigma_nn, const vector_type &uF_n, + scalar_type theta, scalar_type gamma_F, size_t offset ) const { vector_type phi_n = theta * sigma_nn; - assert(offset + uF_n.size() <= phi_n.size()); + assert( offset + uF_n.size() <= phi_n.size() ); - phi_n.segment(offset, uF_n.size()) -= gamma_F * uF_n; + phi_n.segment( offset, uF_n.size() ) -= gamma_F * uF_n; // theta * sigma_nn - gamma uF_n return phi_n; } - matrix_d_type - make_hho_phi_t_uF(const matrix_d_type& sigma_nt, - const matrix_d_type& uF_t, - const scalar_type& theta, - const scalar_type& gamma_F, - const size_t& offset) const - { + matrix_d_type make_hho_phi_t_uF( const matrix_d_type &sigma_nt, const matrix_d_type &uF_t, + scalar_type theta, scalar_type gamma_F, size_t offset ) const { matrix_d_type phi_t = theta * sigma_nt; - phi_t.block(offset, 0, uF_t.rows(), dimension) -= gamma_F * uF_t; + phi_t.block( offset, 0, uF_t.rows(), dimension ) -= gamma_F * uF_t; // theta * sigma_nt - gamma uF_t return phi_t; } // projection on the ball of radius alpha centered on 0 - vector_static - make_proj_alpha(const vector_static& x, const scalar_type& alpha) const - { + vector_static make_proj_alpha( const vector_static &x, scalar_type alpha ) const { const scalar_type x_norm = x.norm(); - if (x_norm <= alpha) - { + if ( x_norm <= alpha ) { return x; } @@ -362,41 +272,36 @@ class contact_contribution } // derivative of the projection on the ball of radius alpha centered on 0 - matrix_static - make_d_proj_alpha(const vector_static& x, const scalar_type& alpha) const - { + matrix_static make_d_proj_alpha( const vector_static &x, scalar_type alpha ) const { const scalar_type x_norm = x.norm(); - if (x_norm <= alpha) - { + if ( x_norm <= alpha ) { return matrix_static::Identity(); } - return alpha / x_norm * (matrix_static::Identity() - disk::Kronecker(x, x) / (x_norm * x_norm)); + return alpha / x_norm * + ( matrix_static::Identity() - disk::Kronecker( x, x ) / ( x_norm * x_norm ) ); } // compute theta/gamma *(sigma_n, sigma_n)_Fc - matrix_type - make_hho_nitsche(const cell_type& cl, const matrix_type& ET, const CellDegreeInfo& cell_infos) const - { - const auto gb = make_sym_matrix_monomial_basis(m_msh, cl, cell_infos.grad_degree()); - - matrix_type nitsche = matrix_type::Zero(ET.cols(), ET.cols()); - - const auto fcs = m_bnd.faces_with_contact(cl); - for (auto& fc : fcs) - { - const auto n = normal(m_msh, cl, fc); - const auto qps = integrate(m_msh, fc, 2 * cell_infos.grad_degree() + 2); - const auto hF = diameter(m_msh, fc); + matrix_type make_hho_nitsche( const cell_type &cl, const matrix_type &ET, + const CellDegreeInfo< MeshType > &cell_infos ) const { + const auto gb = make_sym_matrix_monomial_basis( m_msh, cl, cell_infos.grad_degree() ); + + matrix_type nitsche = matrix_type::Zero( ET.cols(), ET.cols() ); + + const auto fcs = m_bnd.faces_with_contact( cl ); + for ( auto &fc : fcs ) { + const auto n = normal( m_msh, cl, fc ); + const auto qps = integrate( m_msh, fc, 2 * cell_infos.grad_degree() + 2 ); + const auto hF = diameter( m_msh, fc ); const auto gamma_F = m_rp.m_gamma_0 / hF; - for (auto& qp : qps) - { - const auto sigma_n = make_hho_sigma_n(ET, n, gb, qp.point()); - const auto qp_sigma_n = disk::priv::inner_product(qp.weight() / gamma_F, sigma_n); + for ( auto &qp : qps ) { + const auto sigma_n = make_hho_sigma_n( ET, n, gb, qp.point() ); + const auto qp_sigma_n = disk::priv::inner_product( qp.weight() / gamma_F, sigma_n ); - nitsche += disk::priv::outer_product(qp_sigma_n, sigma_n); + nitsche += disk::priv::outer_product( qp_sigma_n, sigma_n ); } } @@ -404,78 +309,72 @@ class contact_contribution } // compute (phi_n_theta, H(-phi_n_1(u))*phi_n_1)_FC / gamma - matrix_type - make_hho_heaviside_contact(const cell_type& cl, - const matrix_type& ET, - const vector_type& uTF, - const CellDegreeInfo& cell_infos) const - { - const auto cb = make_vector_monomial_basis(m_msh, cl, cell_infos.cell_degree()); - const auto gb = make_sym_matrix_monomial_basis(m_msh, cl, cell_infos.grad_degree()); + matrix_type make_hho_heaviside_contact( const cell_type &cl, const matrix_type &ET, + const vector_type &uTF, + const CellDegreeInfo< MeshType > &cell_infos ) const { + const auto cb = make_vector_monomial_basis( m_msh, cl, cell_infos.cell_degree() ); + const auto gb = make_sym_matrix_monomial_basis( m_msh, cl, cell_infos.grad_degree() ); - matrix_type lhs = matrix_type::Zero(uTF.size(), uTF.size()); + matrix_type lhs = matrix_type::Zero( uTF.size(), uTF.size() ); - const auto fcs = faces(m_msh, cl); - size_t offset = cb.size(); + const auto fcs = faces( m_msh, cl ); + size_t offset = cb.size(); const auto fcs_di = cell_infos.facesDegreeInfo(); - size_t face_i = 0; + size_t face_i = 0; const vector_type ET_uTF = ET * uTF; - for (auto& fc : fcs) - { - const auto fdi = fcs_di[face_i++]; + for ( auto &fc : fcs ) { + const auto fdi = fcs_di[face_i++]; const auto facedeg = fdi.degree(); - const auto fb = make_vector_monomial_basis(m_msh, fc, facedeg); - const auto fbs = fb.size(); + const auto fb = make_vector_monomial_basis( m_msh, fc, facedeg ); + const auto fbs = fb.size(); - if (m_bnd.is_contact_face(fc)) - { - const auto contact_type = m_bnd.contact_boundary_type(fc); - const auto n = normal(m_msh, cl, fc); - const auto qp_deg = std::max(cell_infos.cell_degree(), cell_infos.grad_degree()); - const auto qps = integrate(m_msh, fc, 2 * qp_deg + 2); - const auto hF = diameter(m_msh, fc); - const auto gamma_F = m_rp.m_gamma_0 / hF; + if ( m_bnd.is_contact_face( fc ) ) { + const auto contact_type = m_bnd.contact_boundary_type( fc ); + const auto n = normal( m_msh, cl, fc ); + const auto qp_deg = std::max( cell_infos.cell_degree(), cell_infos.grad_degree() ); + const auto qps = integrate( m_msh, fc, 2 * qp_deg + 2 ); + const auto hF = diameter( m_msh, fc ); + const auto gamma_F = m_rp.m_gamma_0 / hF; - for (auto& qp : qps) - { - const vector_type sigma_nn = make_hho_sigma_nn(ET, n, gb, qp.point()); + for ( auto &qp : qps ) { + const vector_type sigma_nn = make_hho_sigma_nn( ET, n, gb, qp.point() ); - if (contact_type == disk::SIGNORINI_CELL) - { - const vector_type uT_n = make_hho_u_n(n, cb, qp.point()); + if ( contact_type == disk::SIGNORINI_CELL ) { + const vector_type uT_n = make_hho_u_n( n, cb, qp.point() ); - const scalar_type phi_n_1_u = eval_phi_n_uT(ET_uTF, gb, cb, uTF, n, gamma_F, qp.point()); + const scalar_type phi_n_1_u = + eval_phi_n_uT( fc, ET_uTF, gb, cb, uTF, n, gamma_F, qp.point() ); // Heaviside(-phi_n_1(u)) - if (phi_n_1_u <= scalar_type(0)) - { - const vector_type phi_n_theta = make_hho_phi_n_uT(sigma_nn, uT_n, m_rp.m_theta, gamma_F); - const vector_type phi_n_1 = make_hho_phi_n_uT(sigma_nn, uT_n, scalar_type(1), gamma_F); - const auto qp_phi_n_theta = disk::priv::inner_product(qp.weight() / gamma_F, phi_n_theta); + if ( phi_n_1_u <= scalar_type( 0 ) ) { + const vector_type phi_n_theta = + make_hho_phi_n_uT( sigma_nn, uT_n, m_rp.m_theta, gamma_F ); + const vector_type phi_n_1 = + make_hho_phi_n_uT( sigma_nn, uT_n, scalar_type( 1 ), gamma_F ); + const auto qp_phi_n_theta = + disk::priv::inner_product( qp.weight() / gamma_F, phi_n_theta ); - lhs += disk::priv::outer_product(qp_phi_n_theta, phi_n_1); + lhs += disk::priv::outer_product( qp_phi_n_theta, phi_n_1 ); } - } - else - { - const vector_type uF_n = make_hho_u_n(n, fb, qp.point()); + } else { + const vector_type uF_n = make_hho_u_n( n, fb, qp.point() ); - const scalar_type phi_n_1_u = - eval_phi_n_uF(fc, ET_uTF, gb, fb, uTF, offset, n, gamma_F, qp.point()); + const scalar_type phi_n_1_u = eval_phi_n_uF( + fc, ET_uTF, gb, fb, uTF, offset, n, gamma_F, qp.point() ); // Heaviside(-phi_n_1(u)) - if (phi_n_1_u <= scalar_type(0)) - { + if ( phi_n_1_u <= scalar_type( 0 ) ) { const vector_type phi_n_theta = - make_hho_phi_n_uF(sigma_nn, uF_n, m_rp.m_theta, gamma_F, offset); - const vector_type phi_n_1 = - make_hho_phi_n_uF(sigma_nn, uF_n, scalar_type(1), gamma_F, offset); - const auto qp_phi_n_theta = disk::priv::inner_product(qp.weight() / gamma_F, phi_n_theta); + make_hho_phi_n_uF( sigma_nn, uF_n, m_rp.m_theta, gamma_F, offset ); + const vector_type phi_n_1 = make_hho_phi_n_uF( + sigma_nn, uF_n, scalar_type( 1 ), gamma_F, offset ); + const auto qp_phi_n_theta = + disk::priv::inner_product( qp.weight() / gamma_F, phi_n_theta ); - lhs += disk::priv::outer_product(qp_phi_n_theta, phi_n_1); + lhs += disk::priv::outer_product( qp_phi_n_theta, phi_n_1 ); } } } @@ -487,79 +386,70 @@ class contact_contribution } // compute (phi_n_theta, [phi_n_1(u)]R-)_FC / gamma - vector_type - make_hho_negative_contact(const cell_type& cl, - const matrix_type& ET, - const vector_type& uTF, - const CellDegreeInfo& cell_infos) const - { - const auto cb = make_vector_monomial_basis(m_msh, cl, cell_infos.cell_degree()); - const auto gb = make_sym_matrix_monomial_basis(m_msh, cl, cell_infos.grad_degree()); + vector_type make_hho_negative_contact( const cell_type &cl, const matrix_type &ET, + const vector_type &uTF, + const CellDegreeInfo< MeshType > &cell_infos ) const { + const auto cb = make_vector_monomial_basis( m_msh, cl, cell_infos.cell_degree() ); + const auto gb = make_sym_matrix_monomial_basis( m_msh, cl, cell_infos.grad_degree() ); - vector_type rhs = vector_type::Zero(uTF.size()); + vector_type rhs = vector_type::Zero( uTF.size() ); - const auto fcs = faces(m_msh, cl); - size_t offset = cb.size(); + const auto fcs = faces( m_msh, cl ); + size_t offset = cb.size(); const auto fcs_di = cell_infos.facesDegreeInfo(); - size_t face_i = 0; + size_t face_i = 0; const vector_type ET_uTF = ET * uTF; - for (auto& fc : fcs) - { - const auto fdi = fcs_di[face_i++]; + for ( auto &fc : fcs ) { + const auto fdi = fcs_di[face_i++]; const auto facedeg = fdi.degree(); - const auto fb = make_vector_monomial_basis(m_msh, fc, facedeg); - const auto fbs = fb.size(); + const auto fb = make_vector_monomial_basis( m_msh, fc, facedeg ); + const auto fbs = fb.size(); - if (m_bnd.is_contact_face(fc)) - { - const auto contact_type = m_bnd.contact_boundary_type(fc); - const auto n = normal(m_msh, cl, fc); - const auto qp_deg = std::max(cell_infos.cell_degree(), cell_infos.grad_degree()); - const auto qps = integrate(m_msh, fc, 2 * qp_deg + 2); - const auto hF = diameter(m_msh, fc); - const auto gamma_F = m_rp.m_gamma_0 / hF; + if ( m_bnd.is_contact_face( fc ) ) { + const auto contact_type = m_bnd.contact_boundary_type( fc ); + const auto n = normal( m_msh, cl, fc ); + const auto qp_deg = std::max( cell_infos.cell_degree(), cell_infos.grad_degree() ); + const auto qps = integrate( m_msh, fc, 2 * qp_deg + 2 ); + const auto hF = diameter( m_msh, fc ); + const auto gamma_F = m_rp.m_gamma_0 / hF; - for (auto& qp : qps) - { - const vector_type sigma_nn = make_hho_sigma_nn(ET, n, gb, qp.point()); + for ( auto &qp : qps ) { + const vector_type sigma_nn = make_hho_sigma_nn( ET, n, gb, qp.point() ); - if (contact_type == disk::SIGNORINI_CELL) - { - const vector_type uT_n = make_hho_u_n(n, cb, qp.point()); + if ( contact_type == disk::SIGNORINI_CELL ) { - const scalar_type phi_n_1_u = eval_phi_n_uT(ET_uTF, gb, cb, uTF, n, gamma_F, qp.point()); + const scalar_type phi_n_1_u = + eval_phi_n_uT( fc, ET_uTF, gb, cb, uTF, n, gamma_F, qp.point() ); // [phi_n_1_u]_R- - if (phi_n_1_u <= scalar_type(0)) - { - const vector_type phi_n_theta = make_hho_phi_n_uT(sigma_nn, uT_n, m_rp.m_theta, gamma_F); + if ( phi_n_1_u <= scalar_type( 0 ) ) { + const vector_type uT_n = make_hho_u_n( n, cb, qp.point() ); + const vector_type phi_n_theta = + make_hho_phi_n_uT( sigma_nn, uT_n, m_rp.m_theta, gamma_F ); - rhs += (qp.weight() / gamma_F * phi_n_1_u) * phi_n_theta; + rhs += ( qp.weight() / gamma_F * phi_n_1_u ) * phi_n_theta; } - } - else - { - const scalar_type phi_n_1_u = - eval_phi_n_uF(fc, ET_uTF, gb, fb, uTF, offset, n, gamma_F, qp.point()); + } else { + const scalar_type phi_n_1_u = eval_phi_n_uF( + fc, ET_uTF, gb, fb, uTF, offset, n, gamma_F, qp.point() ); // std::cout << "qp: " << qp.point() << std::endl; // std::cout << "phi_n_1_u: " << phi_n_1_u << std::endl; // [phi_n_1_u]_R- - if (phi_n_1_u <= scalar_type(0)) - { - const vector_type uF_n = make_hho_u_n(n, fb, qp.point()); + if ( phi_n_1_u <= scalar_type( 0 ) ) { + const vector_type uF_n = make_hho_u_n( n, fb, qp.point() ); const vector_type phi_n_theta = - make_hho_phi_n_uF(sigma_nn, uF_n, m_rp.m_theta, gamma_F, offset); + make_hho_phi_n_uF( sigma_nn, uF_n, m_rp.m_theta, gamma_F, offset ); // std::cout << "sigma_nn: " << sigma_nn.transpose() << std::endl; // std::cout << "uF_n: " << uF_n.transpose() << std::endl; // std::cout << "phi_n_theta: " << phi_n_theta.transpose() << std::endl; - rhs += (qp.weight() / gamma_F * phi_n_1_u) * phi_n_theta; + rhs += ( qp.weight() / gamma_F * phi_n_1_u ) * phi_n_theta; } } } @@ -570,78 +460,76 @@ class contact_contribution } // compute (phi_t_theta, [phi_t_1(u)]_(s))_FC / gamma - vector_type - make_hho_threshold_tresca(const cell_type& cl, - const matrix_type& ET, - const vector_type& uTF, - const CellDegreeInfo& cell_infos) const - { - const auto cb = make_vector_monomial_basis(m_msh, cl, cell_infos.cell_degree()); - const auto gb = make_sym_matrix_monomial_basis(m_msh, cl, cell_infos.grad_degree()); + vector_type make_hho_threshold_tresca( const cell_type &cl, const matrix_type &ET, + const vector_type &uTF, + const CellDegreeInfo< MeshType > &cell_infos ) const { + const auto cb = make_vector_monomial_basis( m_msh, cl, cell_infos.cell_degree() ); + const auto gb = make_sym_matrix_monomial_basis( m_msh, cl, cell_infos.grad_degree() ); - vector_type rhs = vector_type::Zero(uTF.size()); + vector_type rhs = vector_type::Zero( uTF.size() ); - const auto fcs = faces(m_msh, cl); - size_t offset = cb.size(); + const auto fcs = faces( m_msh, cl ); + size_t offset = cb.size(); const auto fcs_di = cell_infos.facesDegreeInfo(); - size_t face_i = 0; + size_t face_i = 0; const vector_type ET_uTF = ET * uTF; - for (auto& fc : fcs) - { - const auto fdi = fcs_di[face_i++]; + for ( auto &fc : fcs ) { + const auto fdi = fcs_di[face_i++]; const auto facedeg = fdi.degree(); - const auto fb = make_vector_monomial_basis(m_msh, fc, facedeg); - const auto fbs = fb.size(); + const auto fb = make_vector_monomial_basis( m_msh, fc, facedeg ); + const auto fbs = fb.size(); - if (m_bnd.is_contact_face(fc)) - { - const auto contact_type = m_bnd.contact_boundary_type(fc); - const auto n = normal(m_msh, cl, fc); - const auto qp_deg = std::max(cell_infos.cell_degree(), cell_infos.grad_degree()); - const auto qps = integrate(m_msh, fc, 2 * qp_deg + 2); - const auto hF = diameter(m_msh, fc); - const auto gamma_F = m_rp.m_gamma_0 / hF; + if ( m_bnd.is_contact_face( fc ) ) { + const auto contact_type = m_bnd.contact_boundary_type( fc ); + const auto n = normal( m_msh, cl, fc ); + const auto qp_deg = std::max( cell_infos.cell_degree(), cell_infos.grad_degree() ); + const auto qps = integrate( m_msh, fc, 2 * qp_deg + 2 ); + const auto hF = diameter( m_msh, fc ); + const auto gamma_F = m_rp.m_gamma_0 / hF; - const auto s_func = m_bnd.contact_boundary_func(fc); + const auto s_func = m_bnd.contact_boundary_func( fc ); - for (auto& qp : qps) - { - const auto sigma_nt = make_hho_sigma_nt(ET, n, gb, qp.point()); + for ( auto &qp : qps ) { + const auto sigma_nt = make_hho_sigma_nt( ET, n, gb, qp.point() ); - if (contact_type == disk::SIGNORINI_CELL) - { - const auto uT_t = make_hho_u_t(n, cb, qp.point()); + if ( contact_type == disk::SIGNORINI_CELL ) { + const auto uT_t = make_hho_u_t( n, cb, qp.point() ); - const auto phi_t_theta = make_hho_phi_t_uT(sigma_nt, uT_t, m_rp.m_theta, gamma_F); + const auto phi_t_theta = + make_hho_phi_t_uT( sigma_nt, uT_t, m_rp.m_theta, gamma_F ); - const vector_static phi_t_1_u_proj = - eval_proj_phi_t_uT(ET_uTF, gb, cb, uTF, n, gamma_F, s_func(qp.point()), qp.point()); + const vector_static phi_t_1_u_proj = eval_proj_phi_t_uT( + ET_uTF, gb, cb, uTF, n, gamma_F, s_func( qp.point() ), qp.point() ); - const vector_static qp_phi_t_1_u_pro = qp.weight() * phi_t_1_u_proj / gamma_F; + const vector_static qp_phi_t_1_u_pro = + qp.weight() * phi_t_1_u_proj / gamma_F; - rhs += disk::priv::inner_product(phi_t_theta, qp_phi_t_1_u_pro); - } - else - { - const auto uF_t = make_hho_u_t(n, fb, qp.point()); + rhs += disk::priv::inner_product( phi_t_theta, qp_phi_t_1_u_pro ); + } else { + const auto uF_t = make_hho_u_t( n, fb, qp.point() ); - const auto phi_t_theta = make_hho_phi_t_uF(sigma_nt, uF_t, m_rp.m_theta, gamma_F, offset); + const auto phi_t_theta = + make_hho_phi_t_uF( sigma_nt, uF_t, m_rp.m_theta, gamma_F, offset ); // std::cout << "sigma_nt: " << sigma_nt.transpose() << std::endl; - // std::cout << "uF_t: " << uF_t.transpose() << std::endl; - // std::cout << "phi_t_theta: " << phi_t_theta.transpose() << std::endl; + // std::cout << "uF_t: " << uF_t.transpose() << + // std::endl; std::cout << "phi_t_theta: " << + // phi_t_theta.transpose() << std::endl; - const vector_static phi_t_1_u_proj = eval_proj_tresca_phi_t_uF( - ET_uTF, gb, fb, uTF, offset, n, gamma_F, s_func(qp.point()), qp.point()); + const vector_static phi_t_1_u_proj = + eval_proj_tresca_phi_t_uF( ET_uTF, gb, fb, uTF, offset, n, gamma_F, + s_func( qp.point() ), qp.point() ); - const vector_static qp_phi_t_1_u_pro = qp.weight() * phi_t_1_u_proj / gamma_F; + const vector_static qp_phi_t_1_u_pro = + qp.weight() * phi_t_1_u_proj / gamma_F; - // std::cout << "phi_t_1_u_proj: " << phi_t_1_u_proj.transpose() << std::endl; + // std::cout << "phi_t_1_u_proj: " << phi_t_1_u_proj.transpose() << + // std::endl; - rhs += disk::priv::inner_product(phi_t_theta, qp_phi_t_1_u_pro); + rhs += disk::priv::inner_product( phi_t_theta, qp_phi_t_1_u_pro ); } } } @@ -651,78 +539,81 @@ class contact_contribution } // compute (phi_t_theta, (d_proj_alpha(u)) phi_t_1)_FC / gamma - matrix_type - make_hho_matrix_tresca(const cell_type& cl, - const matrix_type& ET, - const vector_type& uTF, - const CellDegreeInfo& cell_infos) const - { - const auto cb = make_vector_monomial_basis(m_msh, cl, cell_infos.cell_degree()); - const auto gb = make_sym_matrix_monomial_basis(m_msh, cl, cell_infos.grad_degree()); + matrix_type make_hho_matrix_tresca( const cell_type &cl, const matrix_type &ET, + const vector_type &uTF, + const CellDegreeInfo< MeshType > &cell_infos ) const { + const auto cb = make_vector_monomial_basis( m_msh, cl, cell_infos.cell_degree() ); + const auto gb = make_sym_matrix_monomial_basis( m_msh, cl, cell_infos.grad_degree() ); - matrix_type lhs = matrix_type::Zero(uTF.size(), uTF.size()); + matrix_type lhs = matrix_type::Zero( uTF.size(), uTF.size() ); - const auto fcs = faces(m_msh, cl); - size_t offset = cb.size(); + const auto fcs = faces( m_msh, cl ); + size_t offset = cb.size(); const auto fcs_di = cell_infos.facesDegreeInfo(); - size_t face_i = 0; + size_t face_i = 0; const vector_type ET_uTF = ET * uTF; - for (auto& fc : fcs) - { - const auto fdi = fcs_di[face_i++]; + for ( auto &fc : fcs ) { + const auto fdi = fcs_di[face_i++]; const auto facedeg = fdi.degree(); - const auto fb = make_vector_monomial_basis(m_msh, fc, facedeg); - const auto fbs = fb.size(); + const auto fb = make_vector_monomial_basis( m_msh, fc, facedeg ); + const auto fbs = fb.size(); - if (m_bnd.is_contact_face(fc)) - { - const auto contact_type = m_bnd.contact_boundary_type(fc); - const auto n = normal(m_msh, cl, fc); - const auto qp_deg = std::max(cell_infos.cell_degree(), cell_infos.grad_degree()); - const auto qps = integrate(m_msh, fc, 2 * qp_deg + 2); - const auto hF = diameter(m_msh, fc); - const auto gamma_F = m_rp.m_gamma_0 / hF; + if ( m_bnd.is_contact_face( fc ) ) { + const auto contact_type = m_bnd.contact_boundary_type( fc ); + const auto n = normal( m_msh, cl, fc ); + const auto qp_deg = std::max( cell_infos.cell_degree(), cell_infos.grad_degree() ); + const auto qps = integrate( m_msh, fc, 2 * qp_deg + 2 ); + const auto hF = diameter( m_msh, fc ); + const auto gamma_F = m_rp.m_gamma_0 / hF; - const auto s_func = m_bnd.contact_boundary_func(fc); + const auto s_func = m_bnd.contact_boundary_func( fc ); - for (auto& qp : qps) - { - const auto sigma_nt = make_hho_sigma_nt(ET, n, gb, qp.point()); + for ( auto &qp : qps ) { + const auto sigma_nt = make_hho_sigma_nt( ET, n, gb, qp.point() ); - if (contact_type == disk::SIGNORINI_CELL) - { - const auto uT_t = make_hho_u_t(n, cb, qp.point()); + if ( contact_type == disk::SIGNORINI_CELL ) { + const auto uT_t = make_hho_u_t( n, cb, qp.point() ); - const auto phi_t_1 = make_hho_phi_t_uT(sigma_nt, uT_t, scalar_type(1), gamma_F); - const auto phi_t_theta = make_hho_phi_t_uT(sigma_nt, uT_t, m_rp.m_theta, gamma_F); + const auto phi_t_1 = + make_hho_phi_t_uT( sigma_nt, uT_t, scalar_type( 1 ), gamma_F ); + const auto phi_t_theta = + make_hho_phi_t_uT( sigma_nt, uT_t, m_rp.m_theta, gamma_F ); - const auto phi_t_1_u = eval_phi_t_uT(ET_uTF, gb, cb, uTF, n, gamma_F, qp.point()); - const auto d_proj_phi_t_u = make_d_proj_alpha(phi_t_1_u, s_func(qp.point())); + const auto phi_t_1_u = + eval_phi_t_uT( ET_uTF, gb, cb, uTF, n, gamma_F, qp.point() ); + const auto d_proj_phi_t_u = + make_d_proj_alpha( phi_t_1_u, s_func( qp.point() ) ); - const auto d_proj_u_phi_t_1 = disk::priv::inner_product(d_proj_phi_t_u, phi_t_1); + const auto d_proj_u_phi_t_1 = + disk::priv::inner_product( d_proj_phi_t_u, phi_t_1 ); - const auto qp_phi_t_theta = disk::priv::inner_product(qp.weight() / gamma_F, phi_t_theta); + const auto qp_phi_t_theta = + disk::priv::inner_product( qp.weight() / gamma_F, phi_t_theta ); - lhs += disk::priv::outer_product(qp_phi_t_theta, d_proj_u_phi_t_1); - } - else - { - const auto uF_t = make_hho_u_t(n, fb, qp.point()); + lhs += disk::priv::outer_product( qp_phi_t_theta, d_proj_u_phi_t_1 ); + } else { + const auto uF_t = make_hho_u_t( n, fb, qp.point() ); - const auto phi_t_1 = make_hho_phi_t_uF(sigma_nt, uF_t, scalar_type(1), gamma_F, offset); - const auto phi_t_theta = make_hho_phi_t_uF(sigma_nt, uF_t, m_rp.m_theta, gamma_F, offset); + const auto phi_t_1 = + make_hho_phi_t_uF( sigma_nt, uF_t, scalar_type( 1 ), gamma_F, offset ); + const auto phi_t_theta = + make_hho_phi_t_uF( sigma_nt, uF_t, m_rp.m_theta, gamma_F, offset ); - const auto phi_t_1_u = eval_phi_t_uF(ET_uTF, gb, fb, uTF, offset, n, gamma_F, qp.point()); - const auto d_proj_phi_t_u = make_d_proj_alpha(phi_t_1_u, s_func(qp.point())); + const auto phi_t_1_u = + eval_phi_t_uF( ET_uTF, gb, fb, uTF, offset, n, gamma_F, qp.point() ); + const auto d_proj_phi_t_u = + make_d_proj_alpha( phi_t_1_u, s_func( qp.point() ) ); - const auto d_proj_u_phi_t_1 = disk::priv::inner_product(d_proj_phi_t_u, phi_t_1); + const auto d_proj_u_phi_t_1 = + disk::priv::inner_product( d_proj_phi_t_u, phi_t_1 ); - const auto qp_phi_t_theta = disk::priv::inner_product(qp.weight() / gamma_F, phi_t_theta); + const auto qp_phi_t_theta = + disk::priv::inner_product( qp.weight() / gamma_F, phi_t_theta ); - lhs += disk::priv::outer_product(qp_phi_t_theta, d_proj_u_phi_t_1); + lhs += disk::priv::outer_product( qp_phi_t_theta, d_proj_u_phi_t_1 ); } } } @@ -733,63 +624,57 @@ class contact_contribution } // compute (phi_t_theta, [phi_t_1(u)]_(s))_FC / gamma - vector_type - make_hho_threshold_coulomb(const cell_type& cl, - const matrix_type& ET, - const vector_type& uTF, - const CellDegreeInfo& cell_infos) const - { - const auto cb = make_vector_monomial_basis(m_msh, cl, cell_infos.cell_degree()); - const auto gb = make_sym_matrix_monomial_basis(m_msh, cl, cell_infos.grad_degree()); + vector_type make_hho_threshold_coulomb( const cell_type &cl, const matrix_type &ET, + const vector_type &uTF, + const CellDegreeInfo< MeshType > &cell_infos ) const { + const auto cb = make_vector_monomial_basis( m_msh, cl, cell_infos.cell_degree() ); + const auto gb = make_sym_matrix_monomial_basis( m_msh, cl, cell_infos.grad_degree() ); - vector_type rhs = vector_type::Zero(uTF.size()); + vector_type rhs = vector_type::Zero( uTF.size() ); - const auto fcs = faces(m_msh, cl); - size_t offset = cb.size(); + const auto fcs = faces( m_msh, cl ); + size_t offset = cb.size(); const auto fcs_di = cell_infos.facesDegreeInfo(); - size_t face_i = 0; + size_t face_i = 0; const vector_type ET_uTF = ET * uTF; - for (auto& fc : fcs) - { - const auto fdi = fcs_di[face_i++]; + for ( auto &fc : fcs ) { + const auto fdi = fcs_di[face_i++]; const auto facedeg = fdi.degree(); - const auto fb = make_vector_monomial_basis(m_msh, fc, facedeg); - const auto fbs = fb.size(); - - if (m_bnd.is_contact_face(fc)) - { - const auto contact_type = m_bnd.contact_boundary_type(fc); - const auto n = normal(m_msh, cl, fc); - const auto qp_deg = std::max(cell_infos.cell_degree(), cell_infos.grad_degree()); - const auto qps = integrate(m_msh, fc, 2 * qp_deg + 2); - const auto hF = diameter(m_msh, fc); - const auto gamma_F = m_rp.m_gamma_0 / hF; - - const auto s_func = m_bnd.contact_boundary_func(fc); - - for (auto& qp : qps) - { - const auto sigma_nt = make_hho_sigma_nt(ET, n, gb, qp.point()); - - if (contact_type == disk::SIGNORINI_CELL) - { - throw std::runtime_error("Not implemented"); - } - else - { - const auto uF_t = make_hho_u_t(n, fb, qp.point()); + const auto fb = make_vector_monomial_basis( m_msh, fc, facedeg ); + const auto fbs = fb.size(); + + if ( m_bnd.is_contact_face( fc ) ) { + const auto contact_type = m_bnd.contact_boundary_type( fc ); + const auto n = normal( m_msh, cl, fc ); + const auto qp_deg = std::max( cell_infos.cell_degree(), cell_infos.grad_degree() ); + const auto qps = integrate( m_msh, fc, 2 * qp_deg + 2 ); + const auto hF = diameter( m_msh, fc ); + const auto gamma_F = m_rp.m_gamma_0 / hF; + + const auto s_func = m_bnd.contact_boundary_func( fc ); - const auto phi_t_theta = make_hho_phi_t_uF(sigma_nt, uF_t, m_rp.m_theta, gamma_F, offset); + for ( auto &qp : qps ) { + const auto sigma_nt = make_hho_sigma_nt( ET, n, gb, qp.point() ); - const vector_static phi_t_1_u_proj = eval_proj_coulomb_phi_t_uF( - fc, ET_uTF, gb, fb, uTF, offset, n, gamma_F, s_func(qp.point()), qp.point()); + if ( contact_type == disk::SIGNORINI_CELL ) { + throw std::runtime_error( "Not implemented" ); + } else { + const auto uF_t = make_hho_u_t( n, fb, qp.point() ); - const vector_static qp_phi_t_1_u_pro = qp.weight() * phi_t_1_u_proj / gamma_F; + const auto phi_t_theta = + make_hho_phi_t_uF( sigma_nt, uF_t, m_rp.m_theta, gamma_F, offset ); + + const vector_static phi_t_1_u_proj = + eval_proj_coulomb_phi_t_uF( fc, ET_uTF, gb, fb, uTF, offset, n, gamma_F, + s_func( qp.point() ), qp.point() ); - rhs += disk::priv::inner_product(phi_t_theta, qp_phi_t_1_u_pro); + const vector_static qp_phi_t_1_u_pro = + qp.weight() * phi_t_1_u_proj / gamma_F; + + rhs += disk::priv::inner_product( phi_t_theta, qp_phi_t_1_u_pro ); } } } @@ -799,71 +684,67 @@ class contact_contribution } // compute (phi_t_theta, (d_proj_alpha(u)) phi_t_1)_FC / gamma - matrix_type - make_hho_matrix_coulomb(const cell_type& cl, - const matrix_type& ET, - const vector_type& uTF, - const CellDegreeInfo& cell_infos) const - { - const auto cb = make_vector_monomial_basis(m_msh, cl, cell_infos.cell_degree()); - const auto gb = make_sym_matrix_monomial_basis(m_msh, cl, cell_infos.grad_degree()); + matrix_type make_hho_matrix_coulomb( const cell_type &cl, const matrix_type &ET, + const vector_type &uTF, + const CellDegreeInfo< MeshType > &cell_infos ) const { + const auto cb = make_vector_monomial_basis( m_msh, cl, cell_infos.cell_degree() ); + const auto gb = make_sym_matrix_monomial_basis( m_msh, cl, cell_infos.grad_degree() ); - matrix_type lhs = matrix_type::Zero(uTF.size(), uTF.size()); + matrix_type lhs = matrix_type::Zero( uTF.size(), uTF.size() ); - const auto fcs = faces(m_msh, cl); - size_t offset = cb.size(); + const auto fcs = faces( m_msh, cl ); + size_t offset = cb.size(); const auto fcs_di = cell_infos.facesDegreeInfo(); - size_t face_i = 0; + size_t face_i = 0; const vector_type ET_uTF = ET * uTF; - for (auto& fc : fcs) - { - const auto fdi = fcs_di[face_i++]; + for ( auto &fc : fcs ) { + const auto fdi = fcs_di[face_i++]; const auto facedeg = fdi.degree(); - const auto fb = make_vector_monomial_basis(m_msh, fc, facedeg); - const auto fbs = fb.size(); - - if (m_bnd.is_contact_face(fc)) - { - const auto contact_type = m_bnd.contact_boundary_type(fc); - const auto n = normal(m_msh, cl, fc); - const auto qp_deg = std::max(cell_infos.cell_degree(), cell_infos.grad_degree()); - const auto qps = integrate(m_msh, fc, 2 * qp_deg + 2); - const auto hF = diameter(m_msh, fc); - const auto gamma_F = m_rp.m_gamma_0 / hF; - - const auto s_func = m_bnd.contact_boundary_func(fc); - - for (auto& qp : qps) - { - const auto sigma_nt = make_hho_sigma_nt(ET, n, gb, qp.point()); - - if (contact_type == disk::SIGNORINI_CELL) - { - assert(false); - } - else - { - const auto uF_t = make_hho_u_t(n, fb, qp.point()); + const auto fb = make_vector_monomial_basis( m_msh, fc, facedeg ); + const auto fbs = fb.size(); - const auto phi_t_1 = make_hho_phi_t_uF(sigma_nt, uF_t, scalar_type(1), gamma_F, offset); - const auto phi_t_theta = make_hho_phi_t_uF(sigma_nt, uF_t, m_rp.m_theta, gamma_F, offset); + if ( m_bnd.is_contact_face( fc ) ) { + const auto contact_type = m_bnd.contact_boundary_type( fc ); + const auto n = normal( m_msh, cl, fc ); + const auto qp_deg = std::max( cell_infos.cell_degree(), cell_infos.grad_degree() ); + const auto qps = integrate( m_msh, fc, 2 * qp_deg + 2 ); + const auto hF = diameter( m_msh, fc ); + const auto gamma_F = m_rp.m_gamma_0 / hF; - const auto phi_t_1_u = eval_phi_t_uF(ET_uTF, gb, fb, uTF, offset, n, gamma_F, qp.point()); - const scalar_type phi_n_1_u = - eval_phi_n_uF(fc, ET_uTF, gb, fb, uTF, offset, n, gamma_F, qp.point()); + const auto s_func = m_bnd.contact_boundary_func( fc ); + + for ( auto &qp : qps ) { + const auto sigma_nt = make_hho_sigma_nt( ET, n, gb, qp.point() ); - const scalar_type proj_phi_n_1_u = std::min(scalar_type(0), phi_n_1_u); - const scalar_type fric_bound = -s_func(qp.point()) * proj_phi_n_1_u; - const auto d_proj_phi_t_u = make_d_proj_alpha(phi_t_1_u, fric_bound); + if ( contact_type == disk::SIGNORINI_CELL ) { + assert( false ); + } else { + const auto uF_t = make_hho_u_t( n, fb, qp.point() ); - const auto d_proj_u_phi_t_1 = disk::priv::inner_product(d_proj_phi_t_u, phi_t_1); + const auto phi_t_1 = + make_hho_phi_t_uF( sigma_nt, uF_t, scalar_type( 1 ), gamma_F, offset ); + const auto phi_t_theta = + make_hho_phi_t_uF( sigma_nt, uF_t, m_rp.m_theta, gamma_F, offset ); - const auto qp_phi_t_theta = disk::priv::inner_product(qp.weight() / gamma_F, phi_t_theta); + const auto phi_t_1_u = + eval_phi_t_uF( ET_uTF, gb, fb, uTF, offset, n, gamma_F, qp.point() ); + const scalar_type phi_n_1_u = eval_phi_n_uF( + fc, ET_uTF, gb, fb, uTF, offset, n, gamma_F, qp.point() ); - lhs += disk::priv::outer_product(qp_phi_t_theta, d_proj_u_phi_t_1); + const scalar_type proj_phi_n_1_u = std::min( scalar_type( 0 ), phi_n_1_u ); + const scalar_type fric_bound = -s_func( qp.point() ) * proj_phi_n_1_u; + const auto d_proj_phi_t_u = make_d_proj_alpha( phi_t_1_u, fric_bound ); + + const auto d_proj_u_phi_t_1 = + disk::priv::inner_product( d_proj_phi_t_u, phi_t_1 ); + + const auto qp_phi_t_theta = + disk::priv::inner_product( qp.weight() / gamma_F, phi_t_theta ); + + lhs += disk::priv::outer_product( qp_phi_t_theta, d_proj_u_phi_t_1 ); } } } @@ -876,39 +757,29 @@ class contact_contribution public: matrix_type K_cont; vector_type F_cont; - double time_contact; - - contact_contribution(const mesh_type& msh, - const material_type& material_data, - const param_type& rp, - const bnd_type& bnd) : - m_msh(msh), - m_material_data(material_data), m_rp(rp), m_bnd(bnd) - { - } + double time_contact; + + contact_contribution( const mesh_type &msh, const material_type &material_data, + const param_type &rp, const bnd_type &bnd ) + : m_msh( msh ), m_material_data( material_data ), m_rp( rp ), m_bnd( bnd ) {} - void - compute(const cell_type& cl, - const CellDegreeInfo& cell_infos, - const matrix_type& ET, - const vector_type& uTF) - { + void compute( const cell_type &cl, const CellDegreeInfo< mesh_type > &cell_infos, + const matrix_type &ET, const vector_type &uTF ) { timecounter tc; tc.tic(); // contact contribution time_contact = 0.0; - const auto cb = disk::make_vector_monomial_basis(m_msh, cl, cell_infos.cell_degree()); - const auto gb = disk::make_sym_matrix_monomial_basis(m_msh, cl, cell_infos.grad_degree()); + const auto cb = disk::make_vector_monomial_basis( m_msh, cl, cell_infos.cell_degree() ); + const auto gb = disk::make_sym_matrix_monomial_basis( m_msh, cl, cell_infos.grad_degree() ); - F_cont = vector_type::Zero(uTF.size()); - K_cont = matrix_type::Zero(uTF.size(), uTF.size()); + F_cont = vector_type::Zero( uTF.size() ); + K_cont = matrix_type::Zero( uTF.size(), uTF.size() ); // compute theta/gamma *(sigma_n, sigma_n)_Fc - if (m_rp.m_theta != 0.0) - { - const matrix_type K_sig = make_hho_nitsche(cl, ET, cell_infos); + if ( m_rp.m_theta != 0.0 ) { + const matrix_type K_sig = make_hho_nitsche( cl, ET, cell_infos ); K_cont -= K_sig; F_cont -= K_sig * uTF; } @@ -917,44 +788,40 @@ class contact_contribution // std::cout << make_hho_nitsche(cl, ET, cell_infos) << std::endl; // compute (phi_n_theta, H(-phi_n_1(u))*phi_n_1)_FC / gamma - K_cont += make_hho_heaviside_contact(cl, ET, uTF, cell_infos); + K_cont += make_hho_heaviside_contact( cl, ET, uTF, cell_infos ); // std::cout << "Heaviside: " << std::endl; // std::cout << make_hho_heaviside_contact(cl, ET, uTF, cell_infos) << std::endl; // compute (phi_n_theta, [phi_n_1(u)]R-)_FC / gamma - F_cont += make_hho_negative_contact(cl, ET, uTF, cell_infos); + F_cont += make_hho_negative_contact( cl, ET, uTF, cell_infos ); // auto Fc1 = make_hho_negative_contact(cl, ET, uTF, cell_infos); // std::cout << "Negative: " << Fc1.norm() << std::endl; // std::cout << Fc1.transpose() << std::endl; // friction contribution - if (m_rp.m_frot_type != NO_FRICTION) - { - if (m_rp.m_frot_type == TRESCA) - { + if ( m_rp.m_frot_type != NO_FRICTION ) { + if ( m_rp.m_frot_type == TRESCA ) { // compute (phi_t_theta, [phi_t_1(u)]_s)_FC / gamma - F_cont += make_hho_threshold_tresca(cl, ET, uTF, cell_infos); + F_cont += make_hho_threshold_tresca( cl, ET, uTF, cell_infos ); // auto Ff1 = make_hho_threshold_tresca(cl, ET, uTF, cell_infos); // std::cout << "Threshold: " << Ff1.norm() << std::endl; // std::cout << Ff1.transpose() << std::endl // compute (phi_t_theta, (d_proj_alpha(u)) phi_t_1)_FC / gamma - K_cont += make_hho_matrix_tresca(cl, ET, uTF, cell_infos); - } - else if (m_rp.m_frot_type == COULOMB) - { + K_cont += make_hho_matrix_tresca( cl, ET, uTF, cell_infos ); + } else if ( m_rp.m_frot_type == COULOMB ) { // compute (phi_t_theta, [phi_t_1(u)]_s)_FC / gamma - F_cont += make_hho_threshold_coulomb(cl, ET, uTF, cell_infos); + F_cont += make_hho_threshold_coulomb( cl, ET, uTF, cell_infos ); // auto Ff1 = make_hho_threshold_tresca(cl, ET, uTF, cell_infos); // std::cout << "Threshold: " << Ff1.norm() << std::endl; // std::cout << Ff1.transpose() << std::endl // compute (phi_t_theta, (d_proj_alpha(u)) phi_t_1)_FC / gamma - K_cont += make_hho_matrix_coulomb(cl, ET, uTF, cell_infos); + K_cont += make_hho_matrix_coulomb( cl, ET, uTF, cell_infos ); } } @@ -967,238 +834,182 @@ class contact_contribution // std::cout << F_cont.transpose() << std::endl; } - template - scalar_type - eval_uT_n(const CellBasis& cb, const vector_type& uTF, const vector_static& n, const point_type& pt) const - { - const vector_type uT_n = make_hho_u_n(n, cb, pt); + template < typename CellBasis > + scalar_type eval_uT_n( const CellBasis &cb, const vector_type &uTF, const vector_static &n, + const point_type &pt ) const { + const vector_type uT_n = make_hho_u_n( n, cb, pt ); - return uT_n.dot(uTF.head(cb.size())); + return uT_n.dot( uTF.head( cb.size() ) ); } - template - vector_static - eval_uT_t(const CellBasis& cb, const vector_type& uTF, const vector_static& n, const point_type& pt) const - { - const auto uT_t = make_hho_u_t(n, cb, pt); + template < typename CellBasis > + vector_static eval_uT_t( const CellBasis &cb, const vector_type &uTF, const vector_static &n, + const point_type &pt ) const { + const auto uT_t = make_hho_u_t( n, cb, pt ); - return uT_t.transpose() * (uTF.head(cb.size())); + return uT_t.transpose() * ( uTF.head( cb.size() ) ); } - template - scalar_type - eval_uF_n(const FaceBasis& fb, const vector_type& uF, const vector_static& n, const point_type& pt) const - { - const vector_type uF_n = make_hho_u_n(n, fb, pt); - assert(uF_n.size() == uF.size()); - return uF_n.dot(uF); + template < typename FaceBasis > + scalar_type eval_uF_n( const FaceBasis &fb, const vector_type &uF, const vector_static &n, + const point_type &pt ) const { + const vector_type uF_n = make_hho_u_n( n, fb, pt ); + assert( uF_n.size() == uF.size() ); + return uF_n.dot( uF ); } - template - vector_static - eval_uF_t(const FaceBasis& fb, const vector_type& uF, const vector_static& n, const point_type& pt) const - { - const auto uF_t = make_hho_u_t(n, fb, pt); - assert(uF_t.rows() == uF.size()); + template < typename FaceBasis > + vector_static eval_uF_t( const FaceBasis &fb, const vector_type &uF, const vector_static &n, + const point_type &pt ) const { + const auto uF_t = make_hho_u_t( n, fb, pt ); + assert( uF_t.rows() == uF.size() ); return uF_t.transpose() * uF; } - template - scalar_type - eval_stress_nn(const vector_type& ET_uTF, const GradBasis& gb, const vector_static& n, const point_type& pt) const - { - const auto stress = eval_stress(ET_uTF, gb, pt); - return (stress * n).dot(n); + template < typename GradBasis > + scalar_type eval_stress_nn( const vector_type &ET_uTF, const GradBasis &gb, + const vector_static &n, const point_type &pt ) const { + const auto stress = eval_stress( ET_uTF, gb, pt ); + return ( stress * n ).dot( n ); } - template - vector_static - eval_stress_nt(const vector_type& ET_uTF, const GradBasis& gb, const vector_static& n, const point_type& pt) const - { - const matrix_static sig = eval_stress(ET_uTF, gb, pt); - const vector_static s_n = sig * n; - const auto s_nn = s_n.dot(n); + template < typename GradBasis > + vector_static eval_stress_nt( const vector_type &ET_uTF, const GradBasis &gb, + const vector_static &n, const point_type &pt ) const { + const matrix_static sig = eval_stress( ET_uTF, gb, pt ); + const vector_static s_n = sig * n; + const auto s_nn = s_n.dot( n ); return s_n - s_nn * n; } - template - scalar_type - eval_phi_n_uT(const vector_type& ET_uTF, - const GradBasis& gb, - const CellBasis& cb, - const vector_type& uTF, - const vector_static& n, - const scalar_type& gamma_F, - const point_type& pt) const - { - const scalar_type sigma_nn = eval_stress_nn(ET_uTF, gb, n, pt); - const scalar_type uT_n = eval_uT_n(cb, uTF, n, pt); - const scalar_type g0 = make_hho_distance(pt, n); - - return sigma_nn - gamma_F * (uT_n - g0); + template < typename GradBasis, typename CellBasis > + scalar_type eval_phi_n_uT( const face_type &fc, const vector_type &ET_uTF, const GradBasis &gb, + const CellBasis &cb, const vector_type &uTF, const vector_static &n, + scalar_type gamma_F, const point_type &pt ) const { + const scalar_type sigma_nn = eval_stress_nn( ET_uTF, gb, n, pt ); + const scalar_type uT_n = eval_uT_n( cb, uTF, n, pt ); + const vector_type uT = uTF.head( cb.size() ); + + const auto gap_func = m_bnd.contact_boundary_gap( fc ); + const scalar_type gap = priv::compute_gap_fb( m_msh, fc, cb, uT, gap_func, pt, n ); + + return sigma_nn + gamma_F * gap; } - template - scalar_type - eval_proj_phi_n_uT(const vector_type& ET_uTF, - const GradBasis& gb, - const CellBasis& cb, - const vector_type& uTF, - const vector_static& n, - const scalar_type& gamma_F, - const point_type& pt) const - { - const scalar_type phi_n_1_u = eval_phi_n_uT(ET_uTF, gb, cb, uTF, n, gamma_F, pt); - - if (phi_n_1_u <= scalar_type(0)) + template < typename GradBasis, typename CellBasis > + scalar_type eval_proj_phi_n_uT( const face_type &fc, const vector_type &ET_uTF, + const GradBasis &gb, const CellBasis &cb, + const vector_type &uTF, const vector_static &n, + scalar_type gamma_F, const point_type &pt ) const { + const scalar_type phi_n_1_u = eval_phi_n_uT( fc, ET_uTF, gb, cb, uTF, n, gamma_F, pt ); + + if ( phi_n_1_u <= scalar_type( 0 ) ) return phi_n_1_u; - return scalar_type(0); + return scalar_type( 0 ); } - template - vector_static - eval_phi_t_uT(const vector_type& ET_uTF, - const GradBasis& gb, - const CellBasis& cb, - const vector_type& uTF, - const vector_static& n, - const scalar_type& gamma_F, - const point_type& pt) const - { - const auto sigma_nt = eval_stress_nt(ET_uTF, gb, n, pt); - const auto uT_t = eval_uT_t(cb, uTF, n, pt); + template < typename GradBasis, typename CellBasis > + vector_static eval_phi_t_uT( const vector_type &ET_uTF, const GradBasis &gb, + const CellBasis &cb, const vector_type &uTF, + const vector_static &n, scalar_type gamma_F, + const point_type &pt ) const { + const auto sigma_nt = eval_stress_nt( ET_uTF, gb, n, pt ); + const auto uT_t = eval_uT_t( cb, uTF, n, pt ); return sigma_nt - gamma_F * uT_t; } - template - vector_static - eval_proj_phi_t_uT(const vector_type& ET_uTF, - const GradBasis& gb, - const CellBasis& cb, - const vector_type& uTF, - const vector_static& n, - const scalar_type& gamma_F, - const scalar_type& s, - const point_type& pt) const - { - const vector_static phi_t_1_u = eval_phi_t_uT(ET_uTF, gb, cb, uTF, n, gamma_F, pt); - - return make_proj_alpha(phi_t_1_u, s); + template < typename GradBasis, typename CellBasis > + vector_static eval_proj_phi_t_uT( const vector_type &ET_uTF, const GradBasis &gb, + const CellBasis &cb, const vector_type &uTF, + const vector_static &n, scalar_type gamma_F, scalar_type s, + const point_type &pt ) const { + const vector_static phi_t_1_u = eval_phi_t_uT( ET_uTF, gb, cb, uTF, n, gamma_F, pt ); + + return make_proj_alpha( phi_t_1_u, s ); } - template - scalar_type - eval_phi_n_uF(const face_type& fc, - const vector_type& ET_uTF, - const GradBasis& gb, - const FaceBasis& fb, - const vector_type& uTF, - const size_t offset, - const vector_static& n, - const scalar_type& gamma_F, - const point_type& pt) const - { - const vector_type uF = uTF.segment(offset, fb.size()); - const scalar_type sigma_nn = eval_stress_nn(ET_uTF, gb, n, pt); - const scalar_type uF_n = eval_uF_n(fb, uF, n, pt); - const scalar_type g0 = make_hho_distance(pt, n); - const scalar_type gap = priv::compute_gap_fb(m_msh, fc, fb, uF, pt, n); + template < typename GradBasis, typename FaceBasis > + scalar_type eval_phi_n_uF( const face_type &fc, const vector_type &ET_uTF, const GradBasis &gb, + const FaceBasis &fb, const vector_type &uTF, const size_t offset, + const vector_static &n, scalar_type gamma_F, + const point_type &pt ) const { + const vector_type uF = uTF.segment( offset, fb.size() ); + const scalar_type sigma_nn = eval_stress_nn( ET_uTF, gb, n, pt ); + const scalar_type uF_n = eval_uF_n( fb, uF, n, pt ); + const auto gap_func = m_bnd.contact_boundary_gap( fc ); + const scalar_type gap = priv::compute_gap_fb( m_msh, fc, fb, uF, gap_func, pt, n ); // std::cout << gap << std::endl; return sigma_nn + gamma_F * gap; } - template + template < typename GradBasis, typename FaceBasis > scalar_type - eval_proj_phi_n_uF(const face_type& fc, - const vector_type& ET_uTF, - const GradBasis& gb, - const FaceBasis& fb, - const vector_type& uTF, - const size_t offset, - const vector_static& n, - const scalar_type& gamma_F, - const point_type& pt) const - { - const scalar_type phi_n_1_u = eval_phi_n_uF(ET_uTF, gb, fb, uTF, offset, n, gamma_F, pt); - - if (phi_n_1_u <= scalar_type(0)) + eval_proj_phi_n_uF( const face_type &fc, const vector_type &ET_uTF, const GradBasis &gb, + const FaceBasis &fb, const vector_type &uTF, const size_t offset, + const vector_static &n, scalar_type gamma_F, const point_type &pt ) const { + const scalar_type phi_n_1_u = eval_phi_n_uF( ET_uTF, gb, fb, uTF, offset, n, gamma_F, pt ); + + if ( phi_n_1_u <= scalar_type( 0 ) ) return phi_n_1_u; - return scalar_type(0); + return scalar_type( 0 ); } - template - vector_static - eval_phi_t_uF(const vector_type& ET_uTF, - const GradBasis& gb, - const FaceBasis& fb, - const vector_type& uTF, - const size_t& offset, - const vector_static& n, - const scalar_type& gamma_F, - const point_type& pt) const - { - const vector_type uF = uTF.segment(offset, fb.size()); - const auto sigma_nt = eval_stress_nt(ET_uTF, gb, n, pt); - const auto uF_t = eval_uF_t(fb, uF, n, pt); + template < typename GradBasis, typename FaceBasis > + vector_static eval_phi_t_uF( const vector_type &ET_uTF, const GradBasis &gb, + const FaceBasis &fb, const vector_type &uTF, size_t offset, + const vector_static &n, scalar_type gamma_F, + const point_type &pt ) const { + const vector_type uF = uTF.segment( offset, fb.size() ); + const auto sigma_nt = eval_stress_nt( ET_uTF, gb, n, pt ); + const auto uF_t = eval_uF_t( fb, uF, n, pt ); return sigma_nt - gamma_F * uF_t; } - template + template < typename GradBasis, typename FaceBasis > vector_static - eval_proj_tresca_phi_t_uF(const vector_type& ET_uTF, - const GradBasis& gb, - const FaceBasis& fb, - const vector_type& uTF, - const size_t& offset, - const vector_static& n, - const scalar_type& gamma_F, - const scalar_type& s, - const point_type& pt) const - { - const vector_static phi_t_1_u = eval_phi_t_uF(ET_uTF, gb, fb, uTF, offset, n, gamma_F, pt); - - return make_proj_alpha(phi_t_1_u, s); + eval_proj_tresca_phi_t_uF( const vector_type &ET_uTF, const GradBasis &gb, const FaceBasis &fb, + const vector_type &uTF, size_t offset, const vector_static &n, + scalar_type gamma_F, scalar_type s, const point_type &pt ) const { + const vector_static phi_t_1_u = + eval_phi_t_uF( ET_uTF, gb, fb, uTF, offset, n, gamma_F, pt ); + + return make_proj_alpha( phi_t_1_u, s ); } - template - vector_static - eval_proj_coulomb_phi_t_uF(const face_type& fc, - const vector_type& ET_uTF, - const GradBasis& gb, - const FaceBasis& fb, - const vector_type& uTF, - const size_t& offset, - const vector_static& n, - const scalar_type& gamma_F, - const scalar_type& Fc, - const point_type& pt) const - { - const vector_static phi_t_1_u = eval_phi_t_uF(ET_uTF, gb, fb, uTF, offset, n, gamma_F, pt); - const scalar_type phi_n_1_u = eval_phi_n_uF(fc, ET_uTF, gb, fb, uTF, offset, n, gamma_F, pt); - const scalar_type proj_phi_n_1_u = std::min(scalar_type(0), phi_n_1_u); - const scalar_type fric_bound = -Fc * proj_phi_n_1_u; - - return make_proj_alpha(phi_t_1_u, fric_bound); + template < typename GradBasis, typename FaceBasis > + vector_static eval_proj_coulomb_phi_t_uF( const face_type &fc, const vector_type &ET_uTF, + const GradBasis &gb, const FaceBasis &fb, + const vector_type &uTF, size_t offset, + const vector_static &n, scalar_type gamma_F, + scalar_type Fc, const point_type &pt ) const { + const vector_static phi_t_1_u = + eval_phi_t_uF( ET_uTF, gb, fb, uTF, offset, n, gamma_F, pt ); + const scalar_type phi_n_1_u = + eval_phi_n_uF( fc, ET_uTF, gb, fb, uTF, offset, n, gamma_F, pt ); + const scalar_type proj_phi_n_1_u = std::min( scalar_type( 0 ), phi_n_1_u ); + const scalar_type fric_bound = -Fc * proj_phi_n_1_u; + + return make_proj_alpha( phi_t_1_u, fric_bound ); } - template - matrix_static - eval_stress(const vector_type& ET_uTF, const GradBasis& gb, const point_type pt) const - { - const auto gphi = gb.eval_functions(pt); + template < typename GradBasis > + matrix_static eval_stress( const vector_type &ET_uTF, const GradBasis &gb, + const point_type pt ) const { + const auto gphi = gb.eval_functions( pt ); - const matrix_static Eu = disk::eval(ET_uTF, gphi); + const matrix_static Eu = disk::eval( ET_uTF, gphi ); - return 2 * m_material_data.getMu() * Eu + m_material_data.getLambda() * Eu.trace() * matrix_static::Identity(); + return 2 * m_material_data.getMu() * Eu + + m_material_data.getLambda() * Eu.trace() * matrix_static::Identity(); } }; -} // end namespace MK +} // namespace mechanics } // end namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverDynamic.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverDynamic.hpp new file mode 100644 index 00000000..01ec6139 --- /dev/null +++ b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverDynamic.hpp @@ -0,0 +1,415 @@ +/* + * /\ Matteo Cicuttin (C) 2016, 2017 + * /__\ matteo.cicuttin@enpc.fr + * /_\/_\ École Nationale des Ponts et Chaussées - CERMICS + * /\ /\ + * /__\ /__\ DISK++, a template library for DIscontinuous SKeletal + * /_\/_\/_\/_\ methods. + * + * This file is copyright of the following authors: + * Nicolas Pignet (C) 2019, 2025 nicolas.pignet@enpc.fr + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * If you use this code or parts of it for scientific publications, you + * are required to cite it as following: + * + * Hybrid High-Order methods for finite elastoplastic deformations + * within a logarithmic strain framework. + * M. Abbas, A. Ern, N. Pignet. + * International Journal of Numerical Methods in Engineering (2019) + * 120(3), 303-327 + * DOI: 10.1002/nme.6137 + */ + +#pragma once + +#include "diskpp/bases/bases.hpp" +#include "diskpp/common/eigen.hpp" +#include "diskpp/common/timecounter.hpp" +#include "diskpp/mechanics/NewtonSolver/Fields.hpp" +#include "diskpp/mechanics/NewtonSolver/NonLinearParameters.hpp" +#include "diskpp/mechanics/NewtonSolver/TimeManager.hpp" +#include "diskpp/methods/hho" +#include "diskpp/quadratures/quadratures.hpp" + +#include + +namespace disk { + +namespace mechanics { + +template < typename T > +int getNumberOfStepToSave( const NonLinearParameters< T > &rp ) { + if ( rp.isUnsteady() ) { + switch ( rp.getUnsteadyScheme() ) { + case DynamicType::NEWMARK: + case DynamicType::THETA: + case DynamicType::BACKWARD_EULER: + case DynamicType::CRANK_NICOLSON: { + return 2; + break; + } + case DynamicType::LEAP_FROG: { + return 3; + break; + } + default: + throw std::invalid_argument( "Unsupported dynamic scheme" ); + break; + } + } + + return 2; +} + +template < typename T > +void reformulation_dynamic( NonLinearParameters< T > &rp ) { + if ( rp.isUnsteady() ) { + switch ( rp.getUnsteadyScheme() ) { + case DynamicType::BACKWARD_EULER: { + rp.setUnsteadyScheme( DynamicType::THETA ); + std::map< std::string, T > dyna_para; + dyna_para["theta"] = 1.0; + rp.setUnsteadyParameters( dyna_para ); + break; + } + case DynamicType::CRANK_NICOLSON: { + rp.setUnsteadyScheme( DynamicType::THETA ); + std::map< std::string, T > dyna_para; + dyna_para["theta"] = 0.5; + rp.setUnsteadyParameters( dyna_para ); + break; + } + default: + break; + } + } +} + +template < typename MeshType > +class dynamic_computation { + typedef MeshType mesh_type; + typedef typename mesh_type::coordinate_type scalar_type; + typedef typename mesh_type::cell cell_type; + + typedef dynamic_matrix< scalar_type > matrix_type; + typedef dynamic_vector< scalar_type > vector_type; + + std::map< std::string, scalar_type > m_param; + DynamicType m_scheme; + + std::vector< vector_type > m_acce_pred; + + public: + matrix_type K_iner; + vector_type R_iner; + + double time_dyna; + + dynamic_computation() : m_scheme( DynamicType::STATIC ) {} + + dynamic_computation( const NonLinearParameters< scalar_type > &rp ) { + m_param = rp.getUnsteadyParameters(); + m_scheme = rp.getUnsteadyScheme(); + + // for (auto &[key, val] : m_param) { + // std::cout << key << " : " << val << std::endl; + // } + } + + bool enable( void ) const { return m_scheme != DynamicType::STATIC; } + + bool isExplicit() const { return m_scheme == DynamicType::LEAP_FROG; } + + void prediction( const mesh_type &mesh, const MeshDegreeInfo< mesh_type > °ree_infos, + const TimeStep< scalar_type > &time_step, + MultiTimeField< scalar_type > &fields ) { + if ( this->enable() ) { + m_acce_pred.clear(); + m_acce_pred.reserve( mesh.cells_size() ); + + switch ( m_scheme ) { + case DynamicType::NEWMARK: { + std::vector< vector_type > acce; + acce.reserve( mesh.cells_size() ); + + const auto depl_prev = fields.getField( -1, FieldName::DEPL_CELLS ); + const auto velo_prev = fields.getField( -1, FieldName::VITE_CELLS ); + const auto acce_prev = fields.getField( -1, FieldName::ACCE_CELLS ); + + const auto beta = m_param.at( "beta" ); + const scalar_type dt = time_step.increment_time(); + const scalar_type cd = 1.0 / ( beta * dt * dt ); + const scalar_type cv = 1.0 / ( beta * dt ); + const scalar_type ca = ( 1.0 - 2.0 * beta ) / ( 2.0 * beta ); + + for ( auto &cl : mesh ) { + const auto cl_id = mesh.lookup( cl ); + const vector_type acce_curr = cv * velo_prev[cl_id] + ca * acce_prev[cl_id]; + m_acce_pred.push_back( cd * depl_prev[cl_id] + acce_curr ); + acce.push_back( -acce_curr ); + } + + fields.setCurrentField( FieldName::ACCE_CELLS, acce ); + break; + } + case DynamicType::THETA: { + std::vector< vector_type > acce; + acce.reserve( mesh.cells_size() ); + + const auto depl_prev = fields.getField( -1, FieldName::DEPL_CELLS ); + const auto velo_prev = fields.getField( -1, FieldName::VITE_CELLS ); + const auto acce_prev = fields.getField( -1, FieldName::ACCE_CELLS ); + + const scalar_type dt = time_step.increment_time(); + const auto theta = m_param.at( "theta" ); + + const scalar_type cd = 1.0 / ( theta * theta * dt * dt ); + const scalar_type cv = 1.0 / ( theta * theta * dt ); + const scalar_type ca = ( 1.0 - theta ) / theta; + + for ( auto &cl : mesh ) { + const auto cl_id = mesh.lookup( cl ); + const vector_type acce_curr = cv * velo_prev[cl_id] + ca * acce_prev[cl_id]; + m_acce_pred.push_back( cd * depl_prev[cl_id] + acce_curr ); + acce.push_back( -acce_curr ); + } + + fields.setCurrentField( FieldName::ACCE_CELLS, acce ); + break; + } + case DynamicType::LEAP_FROG: { + + std::vector< vector_type > vite, acce, depl; + vite.reserve( mesh.cells_size() ); + acce.reserve( mesh.cells_size() ); + depl.reserve( mesh.cells_size() ); + + const auto tf2 = fields.getTimeField( -2 ); + + const auto depl_prev = fields.getField( -1, FieldName::DEPL_CELLS ); + const auto vite_prev = fields.getField( -1, FieldName::VITE_CELLS ); + + auto depl_curr = fields.getCurrentField( FieldName::DEPL ); + + const scalar_type dt = time_step.increment_time(); + const scalar_type dt2 = dt * dt; + const scalar_type dt2s2 = dt * dt / 2.0; + const scalar_type un_dt = 1.0 / dt; + const scalar_type un_dt2 = 1.0 / ( dt * dt ); + + if ( tf2.empty() ) { + const auto acce_prev = fields.getField( -1, FieldName::ACCE_CELLS ); + + for ( auto &cl : mesh ) { + const auto cl_id = mesh.lookup( cl ); + const auto uT = depl_prev.at( cl_id ) + dt * vite_prev.at( cl_id ) + + dt2s2 * acce_prev.at( cl_id ); + const auto vT = vite_prev.at( cl_id ) + dt * acce_prev.at( cl_id ); + const auto aT = acce_prev.at( cl_id ); + + depl_curr[cl_id].head( uT.size() ) = uT; + + acce.push_back( aT ); + vite.push_back( vT ); + depl.push_back( uT ); + } + } else { + const auto resi_prev = fields.getField( -1, FieldName::RESI_CELLS ); + const auto depl_pprev = tf2.getField( FieldName::DEPL_CELLS ); + + for ( auto &cl : mesh ) { + const auto cl_id = mesh.lookup( cl ); + const matrix_type mm = this->mass_matrix( mesh, cl, degree_infos ); + + const vector_type depl_pred = + 2.0 * depl_prev.at( cl_id ) - depl_pprev.at( cl_id ); + + const vector_type uT = + dt2 * ( mm.ldlt().solve( resi_prev.at( cl_id ) ) ) + depl_pred; + const auto vT = un_dt * ( uT - depl_prev.at( cl_id ) ); + const auto aT = un_dt * ( vT - vite_prev.at( cl_id ) ); + + acce.push_back( aT ); + vite.push_back( vT ); + depl.push_back( uT ); + depl_curr[cl_id].head( uT.size() ) = uT; + } + } + + fields.setCurrentField( FieldName::VITE_CELLS, vite ); + fields.setCurrentField( FieldName::ACCE_CELLS, acce ); + fields.setCurrentField( FieldName::DEPL_CELLS, depl ); + fields.setCurrentField( FieldName::DEPL, depl_curr ); + break; + } + default: { + std::runtime_error( "Scheme not implemented for prediction" ); + break; + } + } + } + } + + scalar_type postprocess( const mesh_type &msh, const TimeStep< scalar_type > &time_step, + MultiTimeField< scalar_type > &fields ) const { + timecounter tc; + tc.tic(); + + if ( this->enable() ) { + switch ( m_scheme ) { + case DynamicType::NEWMARK: { + std::vector< vector_type > vite, acce; + vite.reserve( msh.cells_size() ); + acce.reserve( msh.cells_size() ); + + const auto vite_prev = fields.getField( -1, FieldName::VITE_CELLS ); + const auto acce_prev = fields.getField( -1, FieldName::ACCE_CELLS ); + + const auto depl_cells = fields.getCurrentField( FieldName::DEPL_CELLS ); + + auto beta = m_param.at( "beta" ); + auto gamma = m_param.at( "gamma" ); + scalar_type dt = time_step.increment_time(); + + const scalar_type g0 = ( 1.0 - gamma ) * dt, g1 = gamma * dt; + const scalar_type cd = 1.0 / ( beta * dt * dt ); + + for ( auto &cl : msh ) { + const auto cell_i = msh.lookup( cl ); + + auto aT = cd * depl_cells.at( cell_i ) - m_acce_pred[cell_i]; + auto vT = vite_prev.at( cell_i ) + g0 * acce_prev.at( cell_i ) + g1 * aT; + + vite.push_back( vT ); + acce.push_back( aT ); + } + fields.setCurrentField( FieldName::VITE_CELLS, vite ); + fields.setCurrentField( FieldName::ACCE_CELLS, acce ); + break; + } + case DynamicType::THETA: { + std::vector< vector_type > vite, acce; + vite.reserve( msh.cells_size() ); + acce.reserve( msh.cells_size() ); + + const auto vite_prev = fields.getField( -1, FieldName::VITE_CELLS ); + const auto acce_prev = fields.getField( -1, FieldName::ACCE_CELLS ); + + const auto depl_cells = fields.getCurrentField( FieldName::DEPL_CELLS ); + + scalar_type dt = time_step.increment_time(); + const auto theta = m_param.at( "theta" ); + + const scalar_type cd = 1.0 / ( theta * theta * dt * dt ); + + const scalar_type v0 = ( 1.0 - theta ) * dt; + const scalar_type v1 = theta * dt; + + for ( auto &cl : msh ) { + const auto cell_i = msh.lookup( cl ); + auto aT = cd * depl_cells.at( cell_i ) - m_acce_pred[cell_i]; + auto vT = vite_prev.at( cell_i ) + v0 * acce_prev.at( cell_i ) + v1 * aT; + + vite.push_back( vT ); + acce.push_back( aT ); + } + fields.setCurrentField( FieldName::VITE_CELLS, vite ); + fields.setCurrentField( FieldName::ACCE_CELLS, acce ); + break; + } + case DynamicType::LEAP_FROG: { + break; + } + default: { + std::runtime_error( "Scheme not implemented for post-processing" ); + break; + } + } + } + + tc.toc(); + return tc.elapsed(); + } + + void compute( const mesh_type &msh, const cell_type &cl, + const MeshDegreeInfo< mesh_type > °ree_infos, const vector_type &uTF, + const vector_type &aT, const TimeStep< scalar_type > &time_step ) { + // Unsteady Computation + + time_dyna = 0.0; + timecounter tc; + + tc.tic(); + if ( this->enable() ) { + const auto cell_i = msh.lookup( cl ); + + const auto cell_infos = degree_infos.cellDegreeInfo( msh, cl ); + const auto cell_degree = cell_infos.cell_degree(); + + const auto faces_infos = cell_infos.facesDegreeInfo(); + + const auto num_cell_dofs = + vector_basis_size( cell_degree, mesh_type::dimension, mesh_type::dimension ); + const auto num_faces_dofs = vector_faces_dofs( msh, faces_infos ); + const auto num_total_dofs = num_cell_dofs + num_faces_dofs; + + const vector_type uT = uTF.head( num_cell_dofs ); + + R_iner = vector_type::Zero( num_cell_dofs ); + K_iner = matrix_type::Zero( num_cell_dofs, num_cell_dofs ); + + switch ( m_scheme ) { + case DynamicType::NEWMARK: + case DynamicType::THETA: { + + auto dt = time_step.increment_time(); + scalar_type c0 = 1.0; + if ( m_scheme == DynamicType::NEWMARK ) { + c0 = m_param.at( "beta" ); + } else if ( m_scheme == DynamicType::THETA ) { + const scalar_type theta = m_param.at( "theta" ); + c0 = theta * theta; + } + + const matrix_type mass_mat = this->mass_matrix( msh, cl, degree_infos ); + + const auto coeff = 1.0 / ( c0 * dt * dt ); + + K_iner = coeff * mass_mat; + + R_iner -= mass_mat * aT; + break; + } + case DynamicType::LEAP_FROG: { + break; + } + default: { + std::runtime_error( "Scheme not implemented for inertial forces" ); + break; + } + } + } + tc.toc(); + time_dyna += tc.elapsed(); + } + + matrix_type mass_matrix( const mesh_type &msh, const cell_type &cl, + const MeshDegreeInfo< mesh_type > °ree_infos ) const { + + const auto cell_infos = degree_infos.cellDegreeInfo( msh, cl ); + const auto cell_degree = cell_infos.cell_degree(); + + const auto cb = make_vector_monomial_basis( msh, cl, cell_degree ); + + auto rho = m_param.at( "rho" ); + return rho * make_mass_matrix( msh, cl, cb ); + }; +}; + +} // namespace mechanics + +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverInformations.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverInformations.hpp old mode 100755 new mode 100644 index 5af1a6e4..d53cf47f --- a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverInformations.hpp +++ b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverInformations.hpp @@ -28,23 +28,42 @@ #include -class AssemblyInfo -{ +namespace disk { + +namespace mechanics { + +class InitInfo { + public: + double m_time_rigi, m_time_solve, m_time_dyna; + + InitInfo() : m_time_rigi( 0. ), m_time_solve( 0. ), m_time_dyna( 0. ) {} +}; + +class AssemblyInfo { public: size_t m_linear_system_size; double m_time_assembly; double m_time_gradrec, m_time_statcond, m_time_stab, m_time_postpro; - double m_time_elem, m_time_law, m_time_contact, m_time_dyna; - - AssemblyInfo() : - m_linear_system_size(0), m_time_assembly(0.0), m_time_gradrec(0.0), m_time_statcond(0.0), m_time_stab(0.0), - m_time_elem(0.0), m_time_law(0.0), m_time_contact(0.0), m_time_postpro(0.0), m_time_dyna(0.0) - { - } - - AssemblyInfo& - operator+=(const AssemblyInfo& other) - { + double m_time_elem, m_time_law, m_time_contact, m_time_dyna, m_time_assembler; + double m_time_rigi, m_time_load, m_time_fint; + + AssemblyInfo() + : m_linear_system_size( 0 ), + m_time_assembly( 0.0 ), + m_time_gradrec( 0.0 ), + m_time_statcond( 0.0 ), + m_time_stab( 0.0 ), + m_time_elem( 0.0 ), + m_time_law( 0.0 ), + m_time_contact( 0.0 ), + m_time_postpro( 0.0 ), + m_time_dyna( 0.0 ), + m_time_assembler( 0.0 ), + m_time_rigi( 0. ), + m_time_load( 0. ), + m_time_fint( 0. ) {} + + AssemblyInfo &operator+=( const AssemblyInfo &other ) { m_linear_system_size = other.m_linear_system_size; m_time_assembly += other.m_time_assembly; m_time_gradrec += other.m_time_gradrec; @@ -55,108 +74,158 @@ class AssemblyInfo m_time_contact += other.m_time_contact; m_time_dyna += other.m_time_dyna; m_time_postpro += other.m_time_postpro; + m_time_assembler += other.m_time_assembler; + m_time_rigi += other.m_time_rigi; + m_time_fint += other.m_time_fint; + m_time_load += other.m_time_load; return *this; } }; -class SolveInfo -{ +class SolveInfo { public: size_t m_linear_system_size, m_nonzeros; double m_time_solve; - SolveInfo() : m_linear_system_size(0), m_nonzeros(0), m_time_solve(0.0) {} - SolveInfo(const size_t linear_system_size, const size_t nonzeros, const double time_solve) : - m_linear_system_size(linear_system_size), m_nonzeros(nonzeros), m_time_solve(time_solve) - { - } + SolveInfo() : m_linear_system_size( 0 ), m_nonzeros( 0 ), m_time_solve( 0.0 ) {} + SolveInfo( const size_t linear_system_size, const size_t nonzeros, const double time_solve ) + : m_linear_system_size( linear_system_size ), + m_nonzeros( nonzeros ), + m_time_solve( time_solve ) {} }; -class NewtonSolverInfo -{ +class NewtonSolverInfo { public: AssemblyInfo m_assembly_info; - SolveInfo m_solve_info; - double m_time_newton; - size_t m_iter; + SolveInfo m_solve_info; + double m_time_newton; + size_t m_iter; - NewtonSolverInfo() : m_assembly_info(), m_solve_info(), m_time_newton(0.0), m_iter(0) {} + NewtonSolverInfo() : m_assembly_info(), m_solve_info(), m_time_newton( 0.0 ), m_iter( 0 ) {} - void - updateAssemblyInfo(const AssemblyInfo& assembly_info) - { + void updateAssemblyInfo( const AssemblyInfo &assembly_info ) { m_assembly_info += assembly_info; } - void - updateSolveInfo(const SolveInfo& solve_info) - { + void updateSolveInfo( const SolveInfo &solve_info ) { m_solve_info.m_linear_system_size = solve_info.m_linear_system_size; - m_solve_info.m_nonzeros = solve_info.m_nonzeros; + m_solve_info.m_nonzeros = solve_info.m_nonzeros; m_solve_info.m_time_solve += solve_info.m_time_solve; } - void - printInfo() const - { + void updateInitInfo( const InitInfo &init_info ) { + m_assembly_info.m_time_dyna += init_info.m_time_dyna; + m_assembly_info.m_time_rigi += init_info.m_time_rigi; + m_solve_info.m_time_solve += init_info.m_time_solve; + } + + void printInfo() const { std::cout << "** Time in this step " << m_time_newton << " sec" << std::endl; - std::cout << "**** Assembly time: " << m_assembly_info.m_time_assembly << " sec" << std::endl; - std::cout << "****** Gradient reconstruction: " << m_assembly_info.m_time_gradrec << " sec" << std::endl; + std::cout << "**** Assembly time: " << m_assembly_info.m_time_assembly << " sec" + << std::endl; + std::cout << "****** Gradient reconstruction: " << m_assembly_info.m_time_gradrec << " sec" + << std::endl; std::cout << "****** Stabilisation: " << m_assembly_info.m_time_stab << " sec" << std::endl; - std::cout << "****** Mechanical computation: " << m_assembly_info.m_time_elem << " sec" << std::endl; - std::cout << " *** Behavior computation: " << m_assembly_info.m_time_law << " sec" << std::endl; - std::cout << " *** Contact computation: " << m_assembly_info.m_time_contact << " sec" << std::endl; - std::cout << " *** Dynamic computation: " << m_assembly_info.m_time_dyna << " sec" << std::endl; - std::cout << "****** Static condensation: " << m_assembly_info.m_time_statcond << " sec" << std::endl; - std::cout << "****** Postprocess time: " << m_assembly_info.m_time_postpro << " sec" << std::endl; + std::cout << "****** Mechanical computation: " << m_assembly_info.m_time_elem << " sec" + << std::endl; + std::cout << " *** Behavior computation: " << m_assembly_info.m_time_law << " sec" + << std::endl; + std::cout << " *** Contact computation: " << m_assembly_info.m_time_contact << " sec" + << std::endl; + std::cout << " *** Dynamic computation: " << m_assembly_info.m_time_dyna << " sec" + << std::endl; + std::cout << " *** Rigidity computation: " << m_assembly_info.m_time_rigi << " sec" + << std::endl; + std::cout << " *** Force int computation: " << m_assembly_info.m_time_fint << " sec" + << std::endl; + std::cout << " *** Load computation: " << m_assembly_info.m_time_load << " sec" + << std::endl; + std::cout << "****** Static condensation: " << m_assembly_info.m_time_statcond << " sec" + << std::endl; + std::cout << "****** Postprocess time: " << m_assembly_info.m_time_postpro << " sec" + << std::endl; + std::cout << "****** Assembling time: " << m_assembly_info.m_time_assembler << " sec" + << std::endl; std::cout << "**** Solver time: " << m_solve_info.m_time_solve << " sec" << std::endl; } + + std::map< std::string, double > getValues() const { + std::map< std::string, double > vals; + + vals["nb_iter"] = m_iter; + vals["total_time"] = m_time_newton; + vals["assembly_time"] = m_assembly_info.m_time_assembly; + vals["gradrec_time"] = m_assembly_info.m_time_gradrec; + vals["stab_time"] = m_assembly_info.m_time_stab; + vals["law_time"] = m_assembly_info.m_time_law; + vals["contact_time"] = m_assembly_info.m_time_contact; + vals["dyna_time"] = m_assembly_info.m_time_dyna; + vals["rigi_time"] = m_assembly_info.m_time_rigi; + vals["fint_time"] = m_assembly_info.m_time_fint; + vals["load_time"] = m_assembly_info.m_time_load; + vals["stat_cond"] = m_assembly_info.m_time_statcond; + vals["post_time"] = m_assembly_info.m_time_postpro; + vals["assembler_time"] = m_assembly_info.m_time_assembler; + vals["solver_time"] = m_solve_info.m_time_solve; + + return vals; + } }; -class SolverInfo -{ +class SolverInfo { public: NewtonSolverInfo m_newton_info; - double m_time_solver; - size_t m_iter, m_time_step; + double m_time_solver; + size_t m_iter, m_time_step; - SolverInfo() : m_newton_info(), m_time_solver(0.0), m_iter(0), m_time_step(0) {} + SolverInfo() : m_newton_info(), m_time_solver( 0.0 ), m_iter( 0 ), m_time_step( 0 ) {} - void - updateInfo(const NewtonSolverInfo& newton_solver_info) - { + void updateInfo( const NewtonSolverInfo &newton_solver_info ) { m_iter += newton_solver_info.m_iter; - m_newton_info.updateAssemblyInfo(newton_solver_info.m_assembly_info); - m_newton_info.updateSolveInfo(newton_solver_info.m_solve_info); + m_newton_info.updateAssemblyInfo( newton_solver_info.m_assembly_info ); + m_newton_info.updateSolveInfo( newton_solver_info.m_solve_info ); m_newton_info.m_time_newton += newton_solver_info.m_time_newton; } - void - printInfo() const - { + void printInfo() const { std::cout << " " << std::endl; std::cout << "------------------------------------------------------- " << std::endl; std::cout << "Summaring: " << std::endl; - std::cout << "Total Newton's iterations: " << m_iter << " in " << m_time_step << " load increments" - << std::endl; + std::cout << "Total Newton's iterations: " << m_iter << " in " << m_time_step + << " load increments" << std::endl; std::cout << "Total time to solve the problem: " << m_time_solver << " sec" << std::endl; - std::cout << "**** Assembly time: " << m_newton_info.m_assembly_info.m_time_assembly << " sec" << std::endl; - std::cout << "****** Gradient reconstruction: " << m_newton_info.m_assembly_info.m_time_gradrec << " sec" - << std::endl; - std::cout << "****** Stabilisation: " << m_newton_info.m_assembly_info.m_time_stab << " sec" << std::endl; - std::cout << "****** Elementary computation: " << m_newton_info.m_assembly_info.m_time_elem << " sec" - << std::endl; - std::cout << " *** Behavior computation: " << m_newton_info.m_assembly_info.m_time_law << " sec" + std::cout << "**** Assembly time: " << m_newton_info.m_assembly_info.m_time_assembly + << " sec" << std::endl; + std::cout << "****** Gradient reconstruction: " + << m_newton_info.m_assembly_info.m_time_gradrec << " sec" << std::endl; + std::cout << "****** Stabilisation: " << m_newton_info.m_assembly_info.m_time_stab << " sec" << std::endl; - std::cout << " *** Contact computation: " << m_newton_info.m_assembly_info.m_time_contact << " sec" + std::cout << "****** Elementary computation: " << m_newton_info.m_assembly_info.m_time_elem + << " sec" << std::endl; + std::cout << " *** Behavior computation: " << m_newton_info.m_assembly_info.m_time_law + << " sec" << std::endl; + std::cout << " *** Contact computation: " + << m_newton_info.m_assembly_info.m_time_contact << " sec" << std::endl; + std::cout << " *** Dynamic computation: " << m_newton_info.m_assembly_info.m_time_dyna + << " sec" << std::endl; + std::cout << " *** Rigidity computation: " + << m_newton_info.m_assembly_info.m_time_rigi << " sec" << std::endl; + std::cout << " *** Force int computation: " + << m_newton_info.m_assembly_info.m_time_fint << " sec" << std::endl; + std::cout << " *** Load computation: " << m_newton_info.m_assembly_info.m_time_load + << " sec" << std::endl; + std::cout << "****** Static condensation: " << m_newton_info.m_assembly_info.m_time_statcond + << " sec" << std::endl; + std::cout << "****** Postprocess time: " << m_newton_info.m_assembly_info.m_time_postpro + << " sec" << std::endl; + std::cout << "****** Assembling time: " << m_newton_info.m_assembly_info.m_time_assembler + << " sec" << std::endl; + std::cout << "**** Solver time: " << m_newton_info.m_solve_info.m_time_solve << " sec" << std::endl; - std::cout << " *** Dynamic computation: " << m_newton_info.m_assembly_info.m_time_dyna << " sec" - << std::endl; - std::cout << "****** Static condensation: " << m_newton_info.m_assembly_info.m_time_statcond << " sec" - << std::endl; - std::cout << "**** Postprocess time: " << m_newton_info.m_assembly_info.m_time_postpro << " sec" << std::endl; - std::cout << "**** Solver time: " << m_newton_info.m_solve_info.m_time_solve << " sec" << std::endl; std::cout << "------------------------------------------------------- " << std::endl; std::cout << " " << std::endl; } -}; \ No newline at end of file +}; + +} // namespace mechanics +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverParameters.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverParameters.hpp deleted file mode 100755 index e074c5ac..00000000 --- a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonSolverParameters.hpp +++ /dev/null @@ -1,423 +0,0 @@ -/* - * /\ Matteo Cicuttin (C) 2016, 2017, 2018 - * /__\ matteo.cicuttin@enpc.fr - * /_\/_\ École Nationale des Ponts et Chaussées - CERMICS - * /\ /\ - * /__\ /__\ DISK++, a template library for DIscontinuous SKeletal - * /_\/_\/_\/_\ methods. - * - * This file is copyright of the following authors: - * Nicolas Pignet (C) 2018, 2024 nicolas.pignet@enpc.fr - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * If you use this code or parts of it for scientific publications, you - * are required to cite it as following: - * - * Hybrid High-Order methods for finite elastoplastic deformations - * within a logarithmic strain framework. - * M. Abbas, A. Ern, N. Pignet. - * International Journal of Numerical Methods in Engineering (2019) - * 120(3), 303-327 - * DOI: 10.1002/nme.6137 - */ - -#pragma once - -#include -#include -#include -#include -#include - -enum StabilizationType : int -{ - HDG = 0, - HHO = 1, - NO = 2, - DG = 3 -}; - -enum FrictionType : int -{ - NO_FRICTION = 0, - TRESCA = 1, - COULOMB = 2, -}; - -template -class NewtonSolverParameter -{ - public: - int m_face_degree; // face degree - int m_cell_degree; // cell_degree - int m_grad_degree; // grad degree - - std::vector> m_time_step; // number of time time_step - bool m_has_user_end_time; // final time is given - T m_user_end_time; // final time of the simulation - int m_sublevel; // number of sublevel if there are problems - int m_iter_max; // maximun nexton iteration - T m_epsilon; // stop criteria - - bool m_verbose; // some printing - - bool m_precomputation; // to compute the gradient before (it's memory consuption) - - int m_stab_type; // type of stabilization - T m_beta; // stabilization parameter - bool m_stab; // stabilization yes or no - bool m_adapt_stab; // adaptative stabilization - - bool m_dynamic; // dynamic or static simulation - std::map m_dyna_para; // list of parameters - - int m_n_time_save; // number of saving - std::list m_time_save; // list of time where we save result; - - T m_theta; // theta-parameter for contact - T m_gamma_0; // parameter for Nitsche - T m_threshold; // threshol for Tesca friction - int m_frot_type; // Friction type ? - - NewtonSolverParameter() : - m_face_degree(1), m_cell_degree(1), m_grad_degree(1), m_sublevel(5), m_iter_max(20), m_epsilon(T(1E-6)), - m_verbose(false), m_precomputation(false), m_stab(true), m_beta(1), m_stab_type(HHO), m_n_time_save(0), - m_user_end_time(1.0), m_has_user_end_time(false), m_adapt_stab(false), m_dynamic(false), m_theta(1), m_gamma_0(1), - m_threshold(0), m_frot_type(NO_FRICTION) - { - m_time_step.push_back(std::make_pair(m_user_end_time, 1)); - } - - void - infos() - { - std::cout << "Newton Solver's parameters:" << std::endl; - std::cout << " - Face degree: " << m_face_degree << std::endl; - std::cout << " - Cell degree: " << m_cell_degree << std::endl; - std::cout << " - Grad degree: " << m_grad_degree << std::endl; - std::cout << " - Stabilization ?: " << m_stab << std::endl; - std::cout << " - AdaptativeStabilization ?: " << m_adapt_stab << std::endl; - std::cout << " - Type: " << m_stab_type << std::endl; - std::cout << " - Beta: " << m_beta << std::endl; - std::cout << " - Verbose: " << m_verbose << std::endl; - std::cout << " - Sublevel: " << m_sublevel << std::endl; - std::cout << " - IterMax: " << m_iter_max << std::endl; - std::cout << " - Epsilon: " << m_epsilon << std::endl; - std::cout << " - Precomputation: " << m_precomputation << std::endl; - std::cout << " - Dynamic: " << m_dynamic << std::endl; - std::cout << " - Friction ?: " << m_frot_type << std::endl; - std::cout << " - Threshold: " << m_threshold << std::endl; - std::cout << " - Gamma_0: " << m_gamma_0 << std::endl; - std::cout << " - Theta: " << m_theta << std::endl; - } - - bool - readParameters(const std::string& filename) - { - std::ifstream ifs(filename); - std::string keyword; - int line(0); - - if (!ifs.is_open()) - { - std::cout << "Error opening " << filename << std::endl; - return false; - } - - ifs >> keyword; - line++; - if (keyword != "BeginParameters") - { - std::cout << "Expected keyword \"BeginParameters\" line: " << line << std::endl; - return false; - } - - ifs >> keyword; - line++; - while (keyword != "EndParameters") - { - if (keyword == "FaceDegree") - { - ifs >> m_face_degree; - line++; - } - else if (keyword == "CellDegree") - { - ifs >> m_cell_degree; - line++; - } - else if (keyword == "GradDegree") - { - ifs >> m_grad_degree; - line++; - } - else if (keyword == "Sublevel") - { - ifs >> m_sublevel; - line++; - } - else if (keyword == "TimeStep") - { - int n_time_step(0); - ifs >> n_time_step; - line++; - - m_time_step.clear(); - m_time_step.reserve(n_time_step); - for (int i = 0; i < n_time_step; i++) - { - T time(0.0); - int time_step(0); - ifs >> time >> time_step; - m_time_step.push_back(std::make_pair(time, time_step)); - line++; - } - } - else if (keyword == "FinalTime") - { - ifs >> m_user_end_time; - line++; - - m_has_user_end_time = true; - } - else if (keyword == "TimeSave") - { - ifs >> m_n_time_save; - line++; - - m_time_save.clear(); - for (int i = 0; i < m_n_time_save; i++) - { - T time(0.0); - ifs >> time; - m_time_save.push_back(time); - line++; - } - } - else if (keyword == "Stabilization") - { - std::string logical; - ifs >> logical; - line++; - if (logical == "true" || logical == "True") - m_stab = true; - else - { - m_stab = false; - m_stab_type = NO; - } - } - else if (keyword == "AdaptativeStabilization") - { - std::string logical; - ifs >> logical; - line++; - m_adapt_stab = false; - if (logical == "true" || logical == "True") - m_adapt_stab = true; - } - else if (keyword == "StabType") - { - std::string type; - ifs >> type; - line++; - if (type == "HDG") - m_stab_type = HDG; - else if (type == "HHO") - m_stab_type = HHO; - else if (type == "DG") - m_stab_type = DG; - else if (type == "NO") - m_stab_type = NO; - } - else if (keyword == "Beta") - { - ifs >> m_beta; - line++; - } - else if (keyword == "Verbose") - { - std::string logical; - ifs >> logical; - line++; - if (logical == "true" || logical == "True") - m_verbose = true; - else - m_verbose = false; - } - else if (keyword == "IterMax") - { - ifs >> m_iter_max; - line++; - } - else if (keyword == "Epsilon") - { - ifs >> m_epsilon; - line++; - } - else if (keyword == "Precomputation") - { - std::string logical; - ifs >> logical; - line++; - if (logical == "true" || logical == "True") - m_precomputation = true; - else - m_precomputation = false; - } - else if (keyword == "Theta") - { - ifs >> m_theta; - line++; - } - else if (keyword == "Gamma0") - { - ifs >> m_gamma_0; - line++; - } - else if (keyword == "Friction") - { - std::string type; - ifs >> type; - line++; - if (type == "NO") - m_frot_type = NO_FRICTION; - else if (type == "TRESCA") - m_frot_type = TRESCA; - else if (type == "COULOMB") - m_frot_type = COULOMB; - } - else if (keyword == "Threshold") - { - ifs >> m_threshold; - } - else if (keyword == "Dynamic") - { - std::string logical; - ifs >> logical; - line++; - if (logical == "true" || logical == "True") - m_dynamic = true; - else - m_dynamic = false; - } - else - { - std::cout << "Error parsing Parameters file:" << keyword << " line: " << line << std::endl; - return false; - } - - ifs >> keyword; - line++; - } - - ifs.close(); - return true; - } - - void - setFaceDegree(const int face_degree) - { - m_face_degree = face_degree; - } - - int - getFaceDegree() const - { - return m_face_degree; - } - - void - setCellDegree(const int cell_degree) - { - m_cell_degree = cell_degree; - } - - int - getCellDegree() const - { - return m_cell_degree; - } - - void - setGradDegree(const int grad_degree) - { - m_grad_degree = grad_degree; - } - - int - getGradDegree() const - { - return m_face_degree; - } - - void - setStabilizationParameter(const T stab_para) - { - m_beta = stab_para; - } - - T - getStabilizationParameter() const - { - return m_beta; - } - - void - setVerbose(const bool verbose) - { - m_verbose = verbose; - } - - bool - getVerbose() const - { - return m_verbose; - } - - void - setPrecomputation(const bool precomp) - { - m_precomputation = precomp; - } - - bool - getPrecomputation() const - { - return m_precomputation; - } - - bool - isUnsteady() const - { - return m_dynamic; - } - - void - isUnsteady(const bool dyna) - { - m_dynamic = dyna; - } - - auto - getUnsteadyParameters() const - { - return m_dyna_para; - } - - void - setUnsteadyParameters(const std::map dyna_para) - { - m_dyna_para = dyna_para; - } - - void - setTimeStep(const T end_time, const int n_time_step) - { - m_time_step.clear(); - m_time_step.push_back(std::make_pair(end_time, n_time_step)); - } -}; diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonStep.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonStep.hpp deleted file mode 100755 index 684afb3e..00000000 --- a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NewtonStep.hpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - * /\ Matteo Cicuttin (C) 2016, 2017, 2018 - * /__\ matteo.cicuttin@enpc.fr - * /_\/_\ École Nationale des Ponts et Chaussées - CERMICS - * /\ /\ - * /__\ /__\ DISK++, a template library for DIscontinuous SKeletal - * /_\/_\/_\/_\ methods. - * - * This file is copyright of the following authors: - * Nicolas Pignet (C) 2019 nicolas.pignet@enpc.fr - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * If you use this code or parts of it for scientific publications, you - * are required to cite it as following: - * - * Hybrid High-Order methods for finite elastoplastic deformations - * within a logarithmic strain framework. - * M. Abbas, A. Ern, N. Pignet. - * International Journal of Numerical Methods in Engineering (2019) - * 120(3), 303-327 - * DOI: 10.1002/nme.6137 - */ - -// NewtonRaphson_step - -#pragma once - -#include -#include -#include - -#include "diskpp/adaptivity/adaptivity.hpp" -#include "diskpp/boundary_conditions/boundary_conditions.hpp" -#include "diskpp/common/timecounter.hpp" -#include "diskpp/mechanics/NewtonSolver/NewtonIteration.hpp" -#include "diskpp/mechanics/NewtonSolver/NewtonSolverInformations.hpp" -#include "diskpp/mechanics/NewtonSolver/NewtonSolverParameters.hpp" -#include "diskpp/mechanics/NewtonSolver/TimeManager.hpp" -#include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" -#include "diskpp/methods/hho" - -namespace disk -{ - -namespace mechanics -{ - -/** - * @brief Newton-Raphson step for nonlinear solid mechanics - * - * Specialized for HHO methods - * - * Options : - small and finite deformations - * - plasticity, hyperelasticity (various laws) - * - * @tparam MeshType type of the mesh - */ -template -class NewtonStep -{ - typedef MeshType mesh_type; - typedef typename mesh_type::coordinate_type scalar_type; - - typedef dynamic_matrix matrix_type; - typedef dynamic_vector vector_type; - - typedef NewtonSolverParameter param_type; - typedef vector_boundary_conditions bnd_type; - typedef Behavior behavior_type; - - std::vector m_displ, m_displ_faces; - std::vector m_velocity, m_acce; - - bool m_verbose; - bool m_convergence; - - public: - NewtonStep(const param_type& rp) : m_verbose(rp.m_verbose), m_convergence(false) - { - m_displ.clear(); - m_displ_faces.clear(); - m_velocity.clear(); - m_acce.clear(); - } - - /** - * @brief return a boolean to know if the verbosity mode is activated - * - */ - bool - verbose(void) const - { - return m_verbose; - } - - /** - * @brief Set the verbosity mode - * - * @param v boolean to activate or desactivate the verbosity mode - */ - void - verbose(bool v) - { - m_verbose = v; - } - - /** - * @brief Initialize the initial guess of the Newton's step with a given guess - * - * @param initial_displ solution \f$ u_T, u_{\partial T} \f$ for each cell - * @param initial_displ_faces solution \f$ u_{F} \f$ for each face - */ - - void - initialize(const std::vector& initial_displ, - const std::vector& initial_displ_faces, - const std::vector& initial_velocity, - const std::vector& initial_acce) - { - m_displ_faces.clear(); - m_displ_faces = initial_displ_faces; - - m_displ.clear(); - m_displ = initial_displ; - - m_velocity.clear(); - m_velocity = initial_velocity; - - m_acce.clear(); - m_acce = initial_acce; - } - - /** - * @brief Compute the Newton's step until convergence or stopped criterion - * - * @tparam LoadIncrement Type of the loading function - * @param lf loading function - * @param gradient_precomputed contains the precomputed gradient for HHO methods (can be empty) - * @param stab_precomputed contains the precomputed stabilization operators for HHO methods (can be empty) - * @return NewtonSolverInfo Informations about the Newton's step during the computation - */ - template - NewtonSolverInfo - compute(const mesh_type& msh, - const bnd_type& bnd, - const param_type& rp, - const MeshDegreeInfo& degree_infos, - const LoadIncrement& lf, - const TimeStep& current_step, - const std::vector& gradient_precomputed, - const std::vector& stab_precomputed, - behavior_type& behavior, - StabCoeffManager& stab_manager) - { - NewtonSolverInfo ni; - timecounter tc; - tc.tic(); - - // initialise the NewtonRaphson iteration - NewtonIteration newton_iter(msh, bnd, rp, degree_infos, current_step); - - newton_iter.initialize(msh, rp, m_displ, m_displ_faces, m_velocity, m_acce); - - m_convergence = false; - - for (size_t iter = 0; iter < rp.m_iter_max; iter++) - { - // assemble lhs and rhs - AssemblyInfo assembly_info; - try - { - assembly_info = newton_iter.assemble( - msh, bnd, rp, degree_infos, lf, gradient_precomputed, stab_precomputed, behavior, stab_manager); - } - catch (const std::invalid_argument& ia) - { - std::cerr << "Invalid argument: " << ia.what() << std::endl; - m_convergence = false; - tc.toc(); - ni.m_time_newton = tc.elapsed(); - return ni; - } - - ni.updateAssemblyInfo(assembly_info); - // test convergence - try - { - m_convergence = newton_iter.convergence(rp, iter); - } - catch (const std::runtime_error& ia) - { - std::cerr << "Runtime error: " << ia.what() << std::endl; - m_convergence = false; - tc.toc(); - ni.m_time_newton = tc.elapsed(); - return ni; - } - - if (m_convergence) - { - newton_iter.save_solutions(m_displ, m_displ_faces, m_velocity, m_acce); - tc.toc(); - ni.m_time_newton = tc.elapsed(); - return ni; - } - - // solve the global system - SolveInfo solve_info = newton_iter.solve(); - ni.updateSolveInfo(solve_info); - // update unknowns - ni.m_assembly_info.m_time_postpro += newton_iter.postprocess(msh, bnd, rp, degree_infos); - - ni.m_iter++; - } - - tc.toc(); - ni.m_time_newton = tc.elapsed(); - return ni; - } - - /** - * @brief Test convergence of the Newton's iteration - * - * @return true if the norm of the residual is lower that a given criterion - * @return false else - */ - bool - convergence() const - { - return m_convergence; - } - - /** - * @brief Save solution of the Newton's step - * - */ - void - save_solutions(std::vector& displ, - std::vector& displ_faces, - std::vector& velocity, - std::vector& acce) - { - displ_faces.clear(); - displ_faces = m_displ_faces; - assert(m_displ_faces.size() == displ_faces.size()); - - displ.clear(); - displ = m_displ; - assert(m_displ.size() == displ.size()); - - velocity.clear(); - velocity = m_velocity; - assert(m_velocity.size() == velocity.size()); - - acce.clear(); - acce = m_acce; - assert(m_acce.size() == acce.size()); - } -}; -} - -} // end disk diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NonLinearData.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NonLinearData.hpp new file mode 100644 index 00000000..b988a204 --- /dev/null +++ b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NonLinearData.hpp @@ -0,0 +1,48 @@ +/* + * /\ Matteo Cicuttin (C) 2016, 2017, 2018 + * /__\ matteo.cicuttin@enpc.fr + * /_\/_\ École Nationale des Ponts et Chaussées - CERMICS + * /\ /\ + * /__\ /__\ DISK++, a template library for DIscontinuous SKeletal + * /_\/_\/_\/_\ methods. + * + * This file is copyright of the following authors: + * Nicolas Pignet (C) 2019 nicolas.pignet@enpc.fr + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * If you use this code or parts of it for scientific publications, you + * are required to cite it as following: + * + * Hybrid High-Order methods for finite elastoplastic deformations + * within a logarithmic strain framework. + * M. Abbas, A. Ern, N. Pignet. + * International Journal of Numerical Methods in Engineering (2019) + * 120(3), 303-327 + * DOI: 10.1002/nme.6137 + */ + +#pragma once + +#include "diskpp/common/eigen.hpp" + +#include + +namespace disk { + +namespace mechanics { + +template < typename T > +class NonLinearData { + public: + using matrix_type = dynamic_matrix< T >; + using vector_type = dynamic_vector< T >; + + std::vector< matrix_type > m_gradient_precomputed, m_stab_precomputed; + std::shared_ptr< std::map< int, matrix_type > > m_lhs_loc; +}; + +} // namespace mechanics +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NonLinearParameters.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NonLinearParameters.hpp new file mode 100644 index 00000000..5c9eeebd --- /dev/null +++ b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NonLinearParameters.hpp @@ -0,0 +1,639 @@ +/* + * /\ Matteo Cicuttin (C) 2016, 2017, 2018 + * /__\ matteo.cicuttin@enpc.fr + * /_\/_\ École Nationale des Ponts et Chaussées - CERMICS + * /\ /\ + * /__\ /__\ DISK++, a template library for DIscontinuous SKeletal + * /_\/_\/_\/_\ methods. + * + * This file is copyright of the following authors: + * Nicolas Pignet (C) 2018, 2024 nicolas.pignet@enpc.fr + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * If you use this code or parts of it for scientific publications, you + * are required to cite it as following: + * + * Hybrid High-Order methods for finite elastoplastic deformations + * within a logarithmic strain framework. + * M. Abbas, A. Ern, N. Pignet. + * International Journal of Numerical Methods in Engineering (2019) + * 120(3), 303-327 + * DOI: 10.1002/nme.6137 + */ + +#pragma once + +#include "diskpp/solvers/direct_solvers.hpp" + +#include +#include +#include +#include +#include + +namespace disk { + +namespace mechanics { + +enum StabilizationType : int { HDG = 0, HHO = 1, HHO_SYM = 4, NO = 2, DG = 3 }; + +enum FrictionType : int { + NO_FRICTION = 0, + TRESCA = 1, + COULOMB = 2, +}; + +enum DynamicType : int { + STATIC = 0, + NEWMARK = 1, + BACKWARD_EULER = 2, + THETA = 3, + CRANK_NICOLSON = 4, + LEAP_FROG = 5, +}; + +enum NonLinearSolverType { + NEWTON, + PICARD, + QNEWTON_BDIAG_JACO, + QNEWTON_BDIAG_STAB, + QNEWTON_BDIAG_ELAS, +}; + +enum LineSearchType { + NO_LS, + RELAXATION, + AITKEN, + SECANT, + ANDERSON, + ANDERSON2, + ANDERSON3, + ANDERSON4, + ANDERSON5, + ANDERSON10, +}; + +std::string StabilizationName( const StabilizationType &type ) { + switch ( type ) { + case StabilizationType::HDG: { + return "HDG"; + break; + } + case StabilizationType::HHO: { + return "HHO"; + break; + } + case StabilizationType::HHO_SYM: { + return "HHO_SYM"; + break; + } + case StabilizationType::NO: { + return "NO"; + break; + } + case StabilizationType::DG: { + return "DG"; + break; + } + default: + break; + } + + throw std::invalid_argument( "Case not supported" ); +} + +std::string FrictionName( const FrictionType &type ) { + switch ( type ) { + case FrictionType::NO_FRICTION: { + return "NO_FRICTION"; + break; + } + case FrictionType::TRESCA: { + return "TRESCA"; + break; + } + case FrictionType::COULOMB: { + return "COULOMB"; + break; + } + default: + break; + } + + throw std::invalid_argument( "Case not supported" ); +} + +std::string DynaSchemeName( const DynamicType &type ) { + switch ( type ) { + case DynamicType::STATIC: { + return "STATIC"; + break; + } + case DynamicType::NEWMARK: { + return "NEWMARK"; + break; + } + case DynamicType::BACKWARD_EULER: { + return "BACKWARD_EULER"; + break; + } + case DynamicType::THETA: { + return "THETA"; + break; + } + case DynamicType::CRANK_NICOLSON: { + return "CRANK_NICOLSON"; + break; + } + case DynamicType::LEAP_FROG: { + return "LEAP_FROG"; + break; + } + default: + break; + } + + throw std::invalid_argument( "Case not supported" ); +} + +std::string LinearSolverName( const solvers::direct_solver &type ) { + switch ( type ) { + case solvers::direct_solver::autosel: { + return "AUTO"; + break; + } +#ifdef HAVE_PARDISO + case solvers::direct_solver::pardiso: { + return "PARDISO_LU"; + break; + } +#endif +#ifdef HAVE_MUMPS + case solvers::direct_solver::mumps: { + return "MUMPS_LU"; + break; + } +#endif + case solvers::direct_solver::sparselu: { + return "SPARSE_LU"; + break; + } + default: + break; + } + + throw std::invalid_argument( "Case not supported" ); +} + +std::string NonLinearSolverName( const NonLinearSolverType &type ) { + switch ( type ) { + case NonLinearSolverType::NEWTON: { + return "NEWTON"; + break; + } + case NonLinearSolverType::PICARD: { + return "PICARD"; + break; + } + case NonLinearSolverType::QNEWTON_BDIAG_JACO: { + return "QNEWTON_BDIAG_JACO"; + break; + } + case NonLinearSolverType::QNEWTON_BDIAG_STAB: { + return "QNEWTON_BDIAG_STAB"; + break; + } + case NonLinearSolverType::QNEWTON_BDIAG_ELAS: { + return "QNEWTON_BDIAG_ELAS"; + break; + } + default: + break; + } + + throw std::invalid_argument( "Case not supported" ); +} + +std::string LineSearchName( const LineSearchType &type ) { + switch ( type ) { + case LineSearchType::NO_LS: { + return "NO"; + break; + } + case LineSearchType::RELAXATION: { + return "RELAXATION"; + break; + } + case LineSearchType::AITKEN: { + return "AITKEN"; + break; + } + case LineSearchType::SECANT: { + return "SECANT"; + break; + } + case LineSearchType::ANDERSON: { + return "ANDERSON"; + break; + } + case LineSearchType::ANDERSON2: { + return "ANDERSON2"; + break; + } + case LineSearchType::ANDERSON3: { + return "ANDERSON3"; + break; + } + case LineSearchType::ANDERSON4: { + return "ANDERSON4"; + break; + } + case LineSearchType::ANDERSON5: { + return "ANDERSON5"; + break; + } + case LineSearchType::ANDERSON10: { + return "ANDERSON10"; + break; + } + default: + break; + } + + throw std::invalid_argument( "Case not supported" ); +} + +std::string BoolName( bool value ) { return value ? "TRUE" : "FALSE"; } + +template < typename T > +class NonLinearParameters { + public: + int m_face_degree; // face degree + int m_cell_degree; // cell_degree + int m_grad_degree; // grad degree + + std::vector< std::pair< T, int > > m_time_step; // number of time time_step + bool m_has_user_end_time; // final time is given + T m_user_end_time; // final time of the simulation + int m_sublevel; // number of sublevel if there are problems + int m_iter_max; // maximun nexton iteration + T m_epsilon; // stop criteria + + bool m_verbose; // some printing + + bool m_precomputation; // to compute the gradient before (it's memory consuption) + + StabilizationType m_stab_type; // type of stabilization + T m_beta; // stabilization parameter + bool m_stab; // stabilization yes or no + bool m_adapt_stab; // adaptative stabilization + + DynamicType m_dyna_type; // type of dyna + std::map< std::string, T > m_dyna_para; // list of parameters + T m_cfl_factor; // CFL factor + + int m_n_time_save; // number of saving + std::list< T > m_time_save; // list of time where we save result; + + T m_theta; // theta-parameter for contact + T m_gamma_0; // parameter for Nitsche + T m_threshold; // threshol for Tesca friction + FrictionType m_frot_type; // Friction type ? + + solvers::direct_solver m_lin_solv; // linear solver + NonLinearSolverType m_nlin_solv; // non-linear solver + LineSearchType m_lsearch; // line-search + + NonLinearParameters() + : m_face_degree( 1 ), + m_cell_degree( 1 ), + m_grad_degree( 1 ), + m_sublevel( 5 ), + m_iter_max( 20 ), + m_epsilon( T( 1E-6 ) ), + m_verbose( false ), + m_precomputation( false ), + m_stab( true ), + m_beta( 1 ), + m_stab_type( StabilizationType::HHO ), + m_n_time_save( 0 ), + m_user_end_time( 1.0 ), + m_has_user_end_time( false ), + m_adapt_stab( false ), + m_theta( 1 ), + m_gamma_0( 1 ), + m_threshold( 0 ), + m_frot_type( FrictionType::NO_FRICTION ), + m_dyna_type( DynamicType::STATIC ), + m_lin_solv( solvers::direct_solver::autosel ), + m_nlin_solv( NonLinearSolverType::NEWTON ), + m_lsearch( LineSearchType::NO_LS ), + m_cfl_factor( 0.99 ) { + m_time_step.push_back( std::make_pair( m_user_end_time, 1 ) ); + } + + void + error_keyword(int line, std::string keyword, std::string value) + { + throw std::runtime_error("Error during parsing in line: " + std::to_string(line) + "." + + " Keyword: " + keyword + " has an unexpeced value: " + value); + } + + void infos() { + std::cout << "Nonlinear Solver's parameters:" << std::endl; + std::cout << " - Face degree: " << m_face_degree << std::endl; + std::cout << " - Cell degree: " << m_cell_degree << std::endl; + std::cout << " - Grad degree: " << m_grad_degree << std::endl; + std::cout << " - Stabilization ?: " << BoolName( !( m_stab_type == StabilizationType::NO ) ) + << std::endl; + std::cout << " - AdaptativeStabilization ?: " << BoolName( m_adapt_stab ) << std::endl; + std::cout << " - Type: " << StabilizationName( m_stab_type ) << std::endl; + std::cout << " - Beta: " << m_beta << std::endl; + std::cout << " - Verbose: " << BoolName( m_verbose ) << std::endl; + std::cout << " - Sublevel: " << m_sublevel << std::endl; + std::cout << " - IterMax: " << m_iter_max << std::endl; + std::cout << " - Epsilon: " << m_epsilon << std::endl; + std::cout << " - LinearSolver: " << LinearSolverName( m_lin_solv ) << std::endl; + std::cout << " - NonLinearSolver: " << NonLinearSolverName( m_nlin_solv ) << std::endl; + std::cout << " - LineSearch: " << LineSearchName( m_lsearch ) << std::endl; + std::cout << " - Precomputation: " << BoolName( m_precomputation ) << std::endl; + std::cout << " - Dynamic scheme: " << DynaSchemeName( m_dyna_type ) << std::endl; + std::cout << " - CFL factor: " << m_cfl_factor << std::endl; + std::cout << " - Friction ?: " << FrictionName( m_frot_type ) << std::endl; + std::cout << " - Threshold: " << m_threshold << std::endl; + std::cout << " - Gamma_0: " << m_gamma_0 << std::endl; + std::cout << " - Theta: " << m_theta << std::endl; + } + + bool readParameters( const std::string &filename ) { + std::ifstream ifs( filename ); + std::string keyword; + int line( 0 ); + + if ( !ifs.is_open() ) { + std::cout << "Error opening " << filename << std::endl; + return false; + } + + ifs >> keyword; + line++; + if ( keyword != "BeginParameters" ) { + std::cout << "Expected keyword \"BeginParameters\" line: " << line << std::endl; + return false; + } + + ifs >> keyword; + line++; + while ( keyword != "EndParameters" ) { + // std::cout << "Keyword: " << keyword << std::endl; + if ( keyword == "FaceDegree" ) { + ifs >> m_face_degree; + line++; + } else if ( keyword == "CellDegree" ) { + ifs >> m_cell_degree; + line++; + } else if ( keyword == "GradDegree" ) { + ifs >> m_grad_degree; + line++; + } else if ( keyword == "Sublevel" ) { + ifs >> m_sublevel; + line++; + } else if ( keyword == "TimeStep" ) { + int n_time_step( 0 ); + ifs >> n_time_step; + line++; + + m_time_step.clear(); + m_time_step.reserve( n_time_step ); + for ( int i = 0; i < n_time_step; i++ ) { + T time( 0.0 ); + int time_step( 0 ); + ifs >> time >> time_step; + m_time_step.push_back( std::make_pair( time, time_step ) ); + line++; + } + } else if ( keyword == "FinalTime" ) { + ifs >> m_user_end_time; + line++; + + m_has_user_end_time = true; + } else if ( keyword == "TimeSave" ) { + ifs >> m_n_time_save; + line++; + + m_time_save.clear(); + for ( int i = 0; i < m_n_time_save; i++ ) { + T time( 0.0 ); + ifs >> time; + m_time_save.push_back( time ); + line++; + } + } else if ( keyword == "AdaptativeStabilization" ) { + std::string logical; + ifs >> logical; + line++; + m_adapt_stab = false; + if ( logical == "true" || logical == "True" ) + m_adapt_stab = true; + } else if ( keyword == "StabType" ) { + std::string type; + ifs >> type; + line++; + m_stab = true; + if ( type == "HDG" ) + m_stab_type = StabilizationType::HDG; + else if ( type == "HHO" ) + m_stab_type = StabilizationType::HHO; + else if ( type == "HHO_SYM" ) + m_stab_type = StabilizationType::HHO_SYM; + else if ( type == "DG" ) + m_stab_type = StabilizationType::DG; + else if ( type == "NO" ) { + m_stab = false; + m_stab_type = StabilizationType::NO; + } else + error_keyword(line, keyword, type); + } else if ( keyword == "Beta" ) { + ifs >> m_beta; + line++; + } else if ( keyword == "Verbose" ) { + std::string logical; + ifs >> logical; + line++; + m_verbose = false; + if ( logical == "true" || logical == "True" ) + m_verbose = true; + } else if ( keyword == "IterMax" ) { + ifs >> m_iter_max; + line++; + } else if ( keyword == "Epsilon" ) { + ifs >> m_epsilon; + line++; + } else if ( keyword == "Precomputation" ) { + std::string logical; + ifs >> logical; + line++; + m_precomputation = false; + if ( logical == "true" || logical == "True" ) + m_precomputation = true; + } else if ( keyword == "Theta" ) { + ifs >> m_theta; + line++; + } else if ( keyword == "Gamma0" ) { + ifs >> m_gamma_0; + line++; + } else if ( keyword == "Friction" ) { + std::string type; + ifs >> type; + line++; + if ( type == "NO" ) + m_frot_type = FrictionType::NO_FRICTION; + else if ( type == "TRESCA" ) + m_frot_type = FrictionType::TRESCA; + else if ( type == "COULOMB" ) + m_frot_type = FrictionType::COULOMB; + else + error_keyword(line, keyword, type); + } else if ( keyword == "Threshold" ) { + ifs >> m_threshold; + } else if ( keyword == "Dynamic" ) { + std::string type; + ifs >> type; + line++; + if ( type == "STATIC" || type == "NO" ) + m_dyna_type = DynamicType::STATIC; + else if ( type == "NEWMARK" ) + m_dyna_type = DynamicType::NEWMARK; + else if ( type == "BACKWARD_EULER" ) + m_dyna_type = DynamicType::BACKWARD_EULER; + else if (type == "THETA") + m_dyna_type = DynamicType::THETA; + else if ( type == "CRANK_NICOLSON" ) + m_dyna_type = DynamicType::CRANK_NICOLSON; + else if ( type == "LEAP_FROG" ) + m_dyna_type = DynamicType::LEAP_FROG; + else + error_keyword(line, keyword, type); + } else if ( keyword == "CFL" ) { + ifs >> m_cfl_factor; + line++; + } else if ( keyword == "NLSolver" ) { + std::string type; + ifs >> type; + line++; + if ( type == "NEWTON" ) { + m_nlin_solv = NonLinearSolverType::NEWTON; + } else if ( type == "PICARD" ) { + m_nlin_solv = NonLinearSolverType::PICARD; + } else if ( type == "QNEWTON_BDIAG_JACO" ) { + m_nlin_solv = NonLinearSolverType::QNEWTON_BDIAG_JACO; + } else if ( type == "QNEWTON_BDIAG_STAB" ) { + m_nlin_solv = NonLinearSolverType::QNEWTON_BDIAG_STAB; + } else if ( type == "QNEWTON_BDIAG_ELAS" ) { + m_nlin_solv = NonLinearSolverType::QNEWTON_BDIAG_ELAS; + } else { + error_keyword(line, keyword, type); + } + } else if ( keyword == "LineSearch" ) { + std::string type; + ifs >> type; + line++; + if ( type == "NO" || type == "NO_LS" ) { + m_lsearch = LineSearchType::NO_LS; + } else if ( type == "RELAXATION" ) { + m_lsearch = LineSearchType::RELAXATION; + } else if ( type == "AITKEN" ) { + m_lsearch = LineSearchType::AITKEN; + } else if ( type == "SECANT" ) { + m_lsearch = LineSearchType::SECANT; + } else if ( type == "ANDERSON" ) { + m_lsearch = LineSearchType::ANDERSON; + } else if ( type == "ANDERSON2" ) { + m_lsearch = LineSearchType::ANDERSON2; + } else if ( type == "ANDERSON3" ) { + m_lsearch = LineSearchType::ANDERSON3; + } else if ( type == "ANDERSON4" ) { + m_lsearch = LineSearchType::ANDERSON4; + } else if ( type == "ANDERSON5" ) { + m_lsearch = LineSearchType::ANDERSON5; + } else if ( type == "ANDERSON10" ) { + m_lsearch = LineSearchType::ANDERSON10; + } else { + error_keyword(line, keyword, type); + } + } else { + error_keyword(line, keyword, ""); + } + + ifs >> keyword; + line++; + } + + ifs.close(); + return true; + } + + void setFaceDegree( const int face_degree ) { m_face_degree = face_degree; } + + int getFaceDegree() const { return m_face_degree; } + + void setCellDegree( const int cell_degree ) { m_cell_degree = cell_degree; } + + int getCellDegree() const { return m_cell_degree; } + + void setGradDegree( const int grad_degree ) { m_grad_degree = grad_degree; } + + int getGradDegree() const { return m_face_degree; } + + void setStabilizationParameter( const T stab_para ) { m_beta = stab_para; } + + T getStabilizationParameter() const { return m_beta; } + + void setVerbose( const bool verbose ) { m_verbose = verbose; } + + bool getVerbose() const { return m_verbose; } + + void setPrecomputation( const bool precomp ) { m_precomputation = precomp; } + + bool getPrecomputation() const { return m_precomputation; } + + bool isUnsteady() const { return m_dyna_type != STATIC; } + + DynamicType getUnsteadyScheme() const { return m_dyna_type; } + + void setUnsteadyScheme( const DynamicType &scheme ) { m_dyna_type = scheme; } + + auto getUnsteadyParameters() const { return m_dyna_para; } + + auto getCFLFactor() const { return m_cfl_factor; } + + void setUnsteadyParameters( const std::map< std::string, T > dyna_para ) { + m_dyna_para = dyna_para; + } + + void setTimeStep( const T end_time, const int n_time_step ) { + m_time_step.clear(); + m_time_step.push_back( std::make_pair( end_time, n_time_step ) ); + } + + void setLinearSolver( const solvers::direct_solver &type ) { m_lin_solv = type; } + solvers::direct_solver getLinearSolver() const { return m_lin_solv; } + + void setNonLinearSolver( const NonLinearSolverType &type ) { m_nlin_solv = type; } + NonLinearSolverType getNonLinearSolver() const { return m_nlin_solv; } + + LineSearchType getLineSearch() const { return m_lsearch; } + void setLineSearch( const LineSearchType &type ) { m_lsearch = type; } + + void setMaximumNumberNLIteration( const int &n_iter ) { m_iter_max = n_iter; } + int getMaximumNumberNLIteration() const { return m_iter_max; } + + void setConvergenceCriteria( const T &eps ) { m_epsilon = eps; } + T getConvergenceCriteria() const { return m_epsilon; } +}; + +} // namespace mechanics +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NonLinearSolver.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NonLinearSolver.hpp new file mode 100644 index 00000000..1c39f4e2 --- /dev/null +++ b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NonLinearSolver.hpp @@ -0,0 +1,1163 @@ +/* + * /\ Matteo Cicuttin (C) 2016, 2017, 2018 + * /__\ matteo.cicuttin@enpc.fr + * /_\/_\ École Nationale des Ponts et Chaussées - CERMICS + * /\ /\ + * /__\ /__\ DISK++, a template library for DIscontinuous SKeletal + * /_\/_\/_\/_\ methods. + * + * This file is copyright of the following authors: + * Nicolas Pignet (C) 2019 nicolas.pignet@enpc.fr + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * If you use this code or parts of it for scientific publications, you + * are required to cite it as following: + * + * Hybrid High-Order methods for finite elastoplastic deformations + * within a logarithmic strain framework. + * M. Abbas, A. Ern, N. Pignet. + * International Journal of Numerical Methods in Engineering (2019) + * 120(3), 303-327 + * DOI: 10.1002/nme.6137 + */ + +// NewtonRaphson_solver + +#pragma once + +#include "diskpp/adaptivity/adaptivity.hpp" +#include "diskpp/boundary_conditions/boundary_conditions.hpp" +#include "diskpp/mechanics/NewtonSolver/NewtonSolverInformations.hpp" +#include "diskpp/mechanics/NewtonSolver/NonLinearStep.hpp" +#include "diskpp/mechanics/behaviors/tensor_conversion.hpp" +#include "diskpp/mechanics/stress_tensors.hpp" +#include "diskpp/methods/hho" +#include "diskpp/output/gmshConvertMesh.hpp" +#include "diskpp/output/gmshDisk.hpp" +#include "diskpp/output/plotOverTime.hpp" +#include "diskpp/output/postMesh.hpp" + +#include +#include +#include + +#ifdef HAVE_MGIS +#include "MGIS/Behaviour/Behaviour.hxx" +#endif + +#include "diskpp/common/timecounter.hpp" + +namespace disk { + +namespace mechanics { + +/** + * @brief Newton-Raphson solver for nonlinear solid mechanics + * + * Specialized for HHO methods + * + * Options : - small and finite deformations + * - plasticity, hyperelasticity (various laws) + * + * @tparam Mesh type of the mesh + */ +template < typename Mesh > +class NonLinearSolver { + typedef Mesh mesh_type; + typedef typename mesh_type::coordinate_type scalar_type; + typedef typename mesh_type::point_type point_type; + + typedef dynamic_matrix< scalar_type > matrix_type; + typedef dynamic_vector< scalar_type > vector_type; + + typedef NonLinearParameters< scalar_type > param_type; + typedef vector_boundary_conditions< mesh_type > bnd_type; + typedef Behavior< mesh_type > behavior_type; + typedef PlotPointOverTime< mesh_type > ppt_type; + + typedef std::function< static_vector< scalar_type, mesh_type::dimension >( + const point< scalar_type, mesh_type::dimension > &, scalar_type ) > + func_type; + + bnd_type m_bnd; + const mesh_type &m_msh; + param_type m_rp; + behavior_type m_behavior; + MeshDegreeInfo< mesh_type > m_degree_infos; + StabCoeffManager< scalar_type > m_stab_manager; + PostMesh< mesh_type > m_post_mesh; + MultiTimeField< scalar_type > m_fields; + NonLinearData< scalar_type > m_data; + + std::shared_ptr< solvers::sparse_solver< scalar_type > > m_lin_solv; + + std::vector< ppt_type > m_ppt; + + std::unique_ptr< func_type > m_load; + + bool m_verbose, m_convergence; + + void init_degree( const size_t cell_degree, const size_t face_degree, + const size_t grad_degree ) { + m_degree_infos = + MeshDegreeInfo< mesh_type >( m_msh, cell_degree, face_degree, grad_degree ); + + if ( m_bnd.nb_faces_contact() > 0 ) { + for ( auto itor = m_msh.boundary_faces_begin(); itor != m_msh.boundary_faces_end(); + itor++ ) { + const auto bfc = *itor; + const auto face_id = m_msh.lookup( bfc ); + + if ( m_bnd.contact_boundary_type( face_id ) == SIGNORINI_FACE ) { + m_degree_infos.degree( m_msh, bfc, face_degree + 1 ); + break; + } + } + } + } + + // Initializa data structures + void init( void ) { + TimeField< scalar_type > tf; + tf.createZeroField( FieldName::DEPL, m_msh, m_degree_infos ); + tf.createZeroField( FieldName::DEPL_CELLS, m_msh, m_degree_infos ); + tf.createZeroField( FieldName::DEPL_FACES, m_msh, m_degree_infos ); + if ( m_rp.isUnsteady() ) { + tf.createZeroField( FieldName::VITE_CELLS, m_msh, m_degree_infos ); + tf.createZeroField( FieldName::ACCE_CELLS, m_msh, m_degree_infos ); + } + m_fields.setCurrentTimeField( tf ); + + // compute mesh for post-processing + m_post_mesh = PostMesh< mesh_type >( m_msh ); + + if ( m_verbose ) { + std::cout << "** Numbers of cells: " << m_msh.cells_size() << std::endl; + std::cout << "** Numbers of faces: " << m_msh.faces_size() + << " ( boundary faces: " << m_msh.boundary_faces_size() << " )" << std::endl; + std::cout << "** Numbers of dofs after static condensation: " << this->numberOfDofs() + << std::endl; + std::cout << " " << std::endl; + } + } + + /** + * @brief Precompute the gradient reconstruction and stabilization operator for HHO methods + * + */ + void pre_computation( void ) { + m_data.m_gradient_precomputed.clear(); + m_data.m_gradient_precomputed.reserve( m_msh.cells_size() ); + + m_data.m_stab_precomputed.clear(); + m_data.m_stab_precomputed.reserve( m_msh.cells_size() ); + + for ( auto &cl : m_msh ) { + // std::cout << m_degree_infos.cellDegreeInfo(m_msh, cl) << std::endl; + /////// Gradient Reconstruction ///////// + if ( m_behavior.getDeformation() == SMALL_DEF ) { + const auto sgr = make_matrix_hho_symmetric_gradrec( m_msh, cl, m_degree_infos ); + m_data.m_gradient_precomputed.push_back( sgr.first ); + } else { + const auto gr = make_matrix_hho_gradrec( m_msh, cl, m_degree_infos ); + m_data.m_gradient_precomputed.push_back( gr.first ); + } + + if ( m_rp.m_stab ) { + switch ( m_rp.m_stab_type ) { + case StabilizationType::HHO: { + const auto recons_scalar = + make_scalar_hho_laplacian( m_msh, cl, m_degree_infos ); + m_data.m_stab_precomputed.push_back( make_vector_hho_stabilization_optim( + m_msh, cl, recons_scalar.first, m_degree_infos ) ); + break; + } + case StabilizationType::HHO_SYM: { + const auto recons = + make_vector_hho_symmetric_laplacian( m_msh, cl, m_degree_infos ); + m_data.m_stab_precomputed.push_back( + make_vector_hho_stabilization( m_msh, cl, recons.first, m_degree_infos ) ); + break; + } + case StabilizationType::HDG: { + m_data.m_stab_precomputed.push_back( + make_vector_hdg_stabilization( m_msh, cl, m_degree_infos ) ); + break; + } + case StabilizationType::DG: { + m_data.m_stab_precomputed.push_back( + make_vector_dg_stabilization( m_msh, cl, m_degree_infos ) ); + break; + } + case StabilizationType::NO: { + break; + } + default: + throw std::invalid_argument( "Unknown stabilization" ); + } + } + } + } + + // compute l2 error + auto _eval( FieldName name, const int cell_id, const point_type &pt ) { + const auto field = m_fields.getCurrentField( name ); + + const auto cl = m_msh[cell_id]; + + const auto di = m_degree_infos.cellDegreeInfo( m_msh, cl ); + const auto cb = make_vector_monomial_basis( m_msh, cl, di.cell_degree() ); + const vector_type x = field.at( cell_id ); + + const auto phi = cb.eval_functions( pt ); + + return eval( x, phi ); + } + + public: + NonLinearSolver( const mesh_type &msh, const bnd_type &bnd, const param_type &rp ) + : m_msh( msh ), + m_verbose( rp.m_verbose ), + m_convergence( false ), + m_rp( rp ), + m_bnd( bnd ), + m_stab_manager( msh, rp.m_beta ), + m_fields( getNumberOfStepToSave( rp ) ), + m_load( nullptr ), + m_lin_solv( + std::make_shared< solvers::sparse_solver< scalar_type > >( rp.getLinearSolver() ) ) { + if ( m_verbose ) { + std::cout << "------------------------------------------------------------------------" + "-------------" + << std::endl; + std::cout << "|********************** Nonlinear Solver for solid mechanics " + "***********************|" + << std::endl; + std::cout << "------------------------------------------------------------------------" + "-------------" + << std::endl; + } + int face_degree = rp.m_face_degree; + if ( rp.m_face_degree < 0 ) { + std::cout << "'face_degree' should be > 0. Reverting to 1." << std::endl; + face_degree = 1; + } + + m_rp.m_face_degree = face_degree; + + int cell_degree = rp.m_cell_degree; + if ( ( face_degree - 1 > cell_degree ) or ( cell_degree > face_degree + 1 ) ) { + std::cout << "'cell_degree' should be 'face_degree + 1' =>" + << "'cell_degree' => 'face_degree -1'. Reverting to 'face_degree'." + << std::endl; + cell_degree = face_degree; + } + + m_rp.m_cell_degree = cell_degree; + + int grad_degree = rp.m_grad_degree; + if ( grad_degree < face_degree ) { + std::cout << "'grad_degree' should be >= 'face_degree'. Reverting to 'face_degree'." + << std::endl; + grad_degree = face_degree; + } + + if ( m_verbose ) { + m_rp.infos(); + } + + // Initialization + if ( m_verbose ) { + std::cout << std::endl; + std::cout << "Initialization ..." << std::endl; + } + this->init_degree( cell_degree, face_degree, grad_degree ); + this->init(); + } + + /** + * @brief return a boolean to know if the verbosity mode is activated + * + */ + bool verbose( void ) const { return m_verbose; } + + /** + * @brief Set the verbosity mode + * + * @param v boolean to activate or desactivate the verbosity mode + */ + void verbose( bool v ) { m_verbose = v; } + + /** + * @brief Initialize the inital guess with a given function + * + * @param func given function + */ + void initial_guess( const vector_rhs_function< mesh_type > func ) { + size_t cell_i = 0; + + m_fields.createField( 0, FieldName::DEPL, m_msh, m_degree_infos, func ); + m_fields.createField( 0, FieldName::DEPL_CELLS, m_msh, m_degree_infos, func ); + m_fields.createField( 0, FieldName::DEPL_FACES, m_msh, m_degree_infos, func ); + + /*TODO: look for contact.*/ + } + + /** + * @brief Initialize displacement and velocity with a given function + * + * @param func given function + */ + void initial_field( FieldName name, const vector_rhs_function< mesh_type > func ) { + if ( name == FieldName::DEPL ) { + m_fields.createField( 0, FieldName::DEPL_CELLS, m_msh, m_degree_infos, func ); + m_fields.createField( 0, FieldName::DEPL_FACES, m_msh, m_degree_infos, func ); + } + m_fields.createField( 0, name, m_msh, m_degree_infos, func ); + } + + /** + * @brief Add a behavior for materials + * + * @param deformation Type of deformation + * @param law Type of Law + */ + void addBehavior( const size_t deformation, const size_t law ) { + if ( m_verbose ) { + std::cout << std::endl; + std::cout << "Add behavior ..." << std::endl; + } + + const auto mater = m_behavior.getMaterialData(); + m_behavior = behavior_type( m_msh, 2 * m_rp.m_grad_degree, deformation, law ); + m_behavior.addMaterialData( mater ); + + if ( m_verbose ) { + std::cout << "** Deformations: " << m_behavior.getDeformationName() << std::endl; + std::cout << "** Law: " << m_behavior.getLawName() << std::endl; + std::cout << "** Number of integration points: " << m_behavior.numberOfQP() + << std::endl; + } + } + +#ifdef HAVE_MGIS + /** + * @brief Add a behavior for materials + * + * @param deformation Type of deformation + * @param law Type of Law + */ + void addBehavior( const std::string &filename, const std::string &law, + const mgis::behaviour::Hypothesis h ) { + if ( m_verbose ) { + std::cout << std::endl; + std::cout << "Add behavior ..." << std::endl; + } + + const auto mater = m_behavior.getMaterialData(); + m_behavior = behavior_type( m_msh, 2 * m_rp.m_grad_degree, filename, law, h ); + m_behavior.addMaterialData( mater ); + + if ( m_verbose ) { + std::cout << "** Deformations: " << m_behavior.getDeformationName() << std::endl; + std::cout << "** Law: " << m_behavior.getLawName() << std::endl; + std::cout << "** Number of integration points: " << m_behavior.numberOfQP() + << std::endl; + } + } +#endif + + /** + * @brief Add a behavior for materials (by copy) + * + * @param behavior Given behavior + */ + void addBehavior( const behavior_type &behavior ) { + m_behavior = behavior; + if ( m_verbose ) { + std::cout << std::endl; + std::cout << "Add behavior ..." << std::endl; + std::cout << "** Number of integration points: " << m_behavior.numberOfQP() + << std::endl; + } + } + + /** + * @brief Add material properties for the behavior + * + * @param material_data material properties + */ + void addMaterialData( const MaterialData< scalar_type > &material_data ) { + m_behavior.addMaterialData( material_data ); + + if ( m_verbose ) { + std::cout << "Add material ..." << std::endl; + m_behavior.getMaterialData().print(); + } + } + + void addPointPlot( const point_type &pt, const std::string &filename ) { + auto ppt = ppt_type( m_msh, pt ); + + std::vector< std::string > cmps; + cmps.push_back( "n_iter" ); + cmps.push_back( "x" ); + cmps.push_back( "y" ); + if constexpr ( mesh_type::dimension == 3 ) { + cmps.push_back( "z" ); + } + cmps.push_back( "ux" ); + cmps.push_back( "uy" ); + if constexpr ( mesh_type::dimension == 3 ) { + cmps.push_back( "uz" ); + } + + if ( m_rp.isUnsteady() ) { + cmps.push_back( "vx" ); + cmps.push_back( "vy" ); + if constexpr ( mesh_type::dimension == 3 ) { + cmps.push_back( "vz" ); + } + cmps.push_back( "ax" ); + cmps.push_back( "ay" ); + if constexpr ( mesh_type::dimension == 3 ) { + cmps.push_back( "az" ); + } + } + + // stress tensor + + cmps.push_back( "sxx" ); + cmps.push_back( "syy" ); + cmps.push_back( "szz" ); + cmps.push_back( "sxy" ); + + if constexpr ( mesh_type::dimension == 3 ) { + cmps.push_back( "sxz" ); + cmps.push_back( "syz" ); + } + + ppt.addComponents( cmps ); + ppt.setFilename( filename ); + + m_ppt.push_back( ppt ); + } + + void addExternalLoad( const std::unique_ptr< func_type > &load ) { m_load = load; } + void addExternalLoad( const func_type load ) { m_load = std::make_unique( load ); } + + SolverInfo compute() { + // Precomputation + if ( m_rp.m_precomputation ) { + timecounter t1; + t1.tic(); + this->pre_computation(); + t1.toc(); + if ( m_verbose ) + std::cout << "Precomputation: " << t1.elapsed() << " sec" << std::endl; + } + + if ( m_rp.isUnsteady() ) { + reformulation_dynamic( m_rp ); + m_rp.m_dyna_para["rho"] = m_behavior.getMaterialData().getRho(); + } + + // save first state; + for ( auto &ppt : m_ppt ) { + std::vector< static_vector< scalar_type, mesh_type::dimension > > vals; + auto depl = _eval( FieldName::DEPL_CELLS, ppt.getCellId(), ppt.getPoint() ); + // new coords + static_vector< scalar_type, mesh_type::dimension > px; + for ( int i = 0; i < mesh_type::dimension; i++ ) { + px[i] = ppt.getPoint()[i] + depl[i]; + } + vals.push_back( px ); + vals.push_back( depl ); + + if ( m_rp.isUnsteady() ) { + auto vite = _eval( FieldName::VITE_CELLS, ppt.getCellId(), ppt.getPoint() ); + vals.push_back( vite ); + auto acce = _eval( FieldName::ACCE_CELLS, ppt.getCellId(), ppt.getPoint() ); + vals.push_back( acce ); + } + + // stress tensor + const auto vzero = static_vector< scalar_type, mesh_type::dimension >::Zero(); + vals.push_back( vzero ); + vals.push_back( vzero ); + + ppt.addValues( 0.0, 0, vals ); + } + + SolverInfo si; + ppt_type stat; + stat.setFilename( "statistics.csv" ); + + timecounter ttot; + ttot.tic(); + + // check CFL condition + scalar_type h_min = minimum_diameter( m_msh ); + scalar_type vp = 1.0; + if ( m_rp.isUnsteady() && m_rp.getUnsteadyScheme() == DynamicType::LEAP_FROG ) { + const auto &mater = m_behavior.getMaterialData(); + vp = std::sqrt( ( mater.getLambda() + 2.0 * mater.getMu() ) / mater.getRho() ); + } + + // list of time step + ListOfTimeStep< scalar_type > list_time_step; + if ( m_rp.m_has_user_end_time ) + list_time_step = + ListOfTimeStep< scalar_type >( m_rp.m_time_step, m_rp.m_user_end_time ); + else + list_time_step = ListOfTimeStep< scalar_type >( m_rp.m_time_step ); + + if ( m_verbose ) + std::cout << "** Number of time step: " << list_time_step.numberOfTimeStep() + << std::endl; + + // time of saving + bool time_saving = false; + if ( m_rp.m_n_time_save > 0 ) { + time_saving = true; + } + + NewtonSolverInfo newton_info; + + // update initial state; + m_fields.update(); + + // Loop on time step + while ( !list_time_step.empty() ) { + const auto current_step = list_time_step.getCurrentTimeStep(); + const auto current_time = current_step.end_time(); + m_fields.setCurrentTime( current_time ); + + if ( m_rp.getUnsteadyScheme() == DynamicType::LEAP_FROG ) { + const auto dt_crit = ( h_min / vp ) * m_rp.getCFLFactor(); + if ( current_step.increment_time() > dt_crit ) { + throw std::runtime_error( + "CFL is not respected. dt_crit=" + std::to_string( dt_crit ) + + " vs dt=" + std::to_string( current_step.increment_time() ) ); + } + } + + if ( m_verbose ) { + list_time_step.printCurrentTimeStep(); + } + + m_bnd.setTime( current_time ); + + NonLinearStep< mesh_type > nlStep( m_rp ); + + newton_info = + nlStep.compute( m_msh, m_bnd, m_rp, m_degree_infos, m_lin_solv, m_load, + current_step, m_data, m_behavior, m_stab_manager, m_fields ); + + // Test convergence + m_convergence = nlStep.convergence(); + + // Newton correction + si.updateInfo( newton_info ); + + if ( m_verbose ) { + newton_info.printInfo(); + } + + if ( !m_convergence ) { + if ( current_step.level() + 1 > m_rp.m_sublevel ) { + std::cout << "***********************************************************" + << std::endl; + std::cout << "***** PROBLEM OF CONVERGENCE: We stop the calcul here *****" + << std::endl; + std::cout << "***********************************************************" + << std::endl; + break; + } else { + if ( m_verbose ) { + std::cout << "***********************************************************" + << std::endl; + std::cout << "***** NO CONVERGENCE: We split the time step ******" + << std::endl; + std::cout << "***********************************************************" + << std::endl; + } + + list_time_step.splitCurrentTimeStep(); + m_behavior.restore(); + m_fields.restore(); + } + } else { + list_time_step.removeCurrentTimeStep(); + m_behavior.update(); + m_stab_manager.update(); + m_fields.update(); + + if ( time_saving && ( m_rp.m_time_save.front() < current_time + 1E-5 ) ) { + std::cout << "** Save results" << std::endl; + std::string name = "result" + std::to_string( mesh_type::dimension ) + "D_t" + + std::to_string( current_time ) + "_"; + + this->output_discontinuous_field( name + "depl_disc.msh", + FieldName::DEPL_CELLS ); + this->output_continuous_field( name + "depl_cont.msh", FieldName::DEPL_CELLS ); + this->output_CauchyStress_GP( name + "CauchyStress_GP.msh" ); + this->output_CauchyStress_GP( name + "CauchyStress_GP_def.msh", true ); + this->output_discontinuous_deformed( name + "deformed_disc.msh" ); + this->output_is_plastic_GP( name + "plastic_GP.msh" ); + this->output_stabCoeff( name + "stabCoeff.msh" ); + this->output_equivalentPlasticStrain_GP( name + + "equivalentPlasticStrain_GP.msh" ); + if ( m_rp.isUnsteady() ) { + this->output_discontinuous_field( name + "vite_disc.msh", + FieldName::VITE_CELLS ); + this->output_continuous_field( name + "vite_cont.msh", + FieldName::VITE_CELLS ); + this->output_discontinuous_field( name + "acce_disc.msh", + FieldName::ACCE_CELLS ); + this->output_continuous_field( name + "acce_cont.msh", + FieldName::ACCE_CELLS ); + } + + m_rp.m_time_save.pop_front(); + if ( m_rp.m_time_save.empty() ) + time_saving = false; + } + + // Compute observation + for ( auto &ppt : m_ppt ) { + std::vector< static_vector< scalar_type, mesh_type::dimension > > vals; + auto depl = _eval( FieldName::DEPL_CELLS, ppt.getCellId(), ppt.getPoint() ); + // new coords + static_vector< scalar_type, mesh_type::dimension > px; + for ( int i = 0; i < mesh_type::dimension; i++ ) { + px[i] = ppt.getPoint()[i] + depl[i]; + } + + vals.push_back( px ); + vals.push_back( depl ); + + if ( m_rp.isUnsteady() ) { + auto vite = _eval( FieldName::VITE_CELLS, ppt.getCellId(), ppt.getPoint() ); + vals.push_back( vite ); + auto acce = _eval( FieldName::ACCE_CELLS, ppt.getCellId(), ppt.getPoint() ); + vals.push_back( acce ); + } + + // stress + const auto cl = *std::next( m_msh.cells_begin(), ppt.getCellId() ); + const auto di = m_degree_infos.cellDegreeInfo( m_msh, cl ); + const auto stress = + m_behavior.projectStressOnCell( m_msh, cl, di.grad_degree() ); + + const auto gb = make_matrix_monomial_basis( m_msh, cl, di.grad_degree() ); + const auto gphi = gb.eval_functions( ppt.getPoint() ); + const auto GT_iqn = eval( stress, gphi ); + + static_vector< scalar_type, mesh_type::dimension > sdiag, sshea; + + if constexpr ( mesh_type::dimension == 2 ) { + sdiag( 0 ) = GT_iqn( 0, 0 ); + sdiag( 1 ) = GT_iqn( 1, 1 ); + sshea( 0 ) = 0.0; + sshea( 1 ) = GT_iqn( 0, 1 ); + } else { + sdiag( 0 ) = GT_iqn( 0, 0 ); + sdiag( 1 ) = GT_iqn( 1, 1 ); + sdiag( 2 ) = GT_iqn( 2, 2 ); + sshea( 0 ) = GT_iqn( 0, 1 ); + sshea( 1 ) = GT_iqn( 0, 2 ); + sshea( 2 ) = GT_iqn( 1, 2 ); + } + vals.push_back( sdiag ); + vals.push_back( sshea ); + + ppt.addValues( current_time, newton_info.m_iter, vals ); + } + + // Update stats + stat.addValues( current_time, newton_info.getValues() ); + } + } + + for ( auto &ppt : m_ppt ) { + ppt.write(); + } + stat.write(); + + si.m_time_step = list_time_step.numberOfTimeStep(); + + ttot.toc(); + si.m_time_solver = ttot.elapsed(); + + return si; + } + + bool convergence() const { return m_convergence; } + + size_t numberOfDofs() { + const auto dimension = mesh_type::dimension; + size_t num_faces_dofs = 0; + for ( auto itor = m_msh.faces_begin(); itor != m_msh.faces_end(); itor++ ) { + const auto fc = *itor; + const auto di = m_degree_infos.degreeInfo( m_msh, fc ); + + if ( di.hasUnknowns() ) { + num_faces_dofs += vector_basis_size( di.degree(), dimension - 1, dimension ); + } + } + return num_faces_dofs; + } + + void printSolutionCell() const { + size_t cell_i = 0; + const auto depl_cells = m_fields.getCurrentField( FieldName::DEPL_CELLS ); + + std::cout << "Solution at the cells:" << std::endl; + for ( auto &cl : m_msh ) { + std::cout << "cell " << cell_i << ": " << std::endl; + std::cout << depl_cells.at( cell_i++ ).transpose() << std::endl; + } + } + + // compute l2 error + template < typename AnalyticalSolution > + long double compute_l2_error( FieldName name, const AnalyticalSolution &as ) { + using quad_type = long double; + quad_type err_dof = 0.; + + size_t cell_i = 0; + const auto field = m_fields.getCurrentField( name ); + + for ( auto &cl : m_msh ) { + const auto cdi = m_degree_infos.degreeInfo( m_msh, cl ); + const vector_type comp_dof = field.at( cell_i++ ); + const vector_type true_dof = project_function( m_msh, cl, cdi.degree(), as, 2 ); + + const auto cb = make_vector_monomial_basis( m_msh, cl, cdi.degree() ); + const matrix_type mass = make_mass_matrix( m_msh, cl, cb ); + + const vector_type diff_dof = ( true_dof - comp_dof ); + const vector_type mass_diff = mass * diff_dof; + const auto size = diff_dof.size(); + + for ( int i = 0; i < size; i++ ) { + const quad_type x = static_cast< quad_type >( diff_dof( i ) ); + const quad_type y = static_cast< quad_type >( mass_diff( i ) ); + err_dof = std::fma( x, y, err_dof ); + } + } + + return std::sqrt( err_dof ); + } + + // compute l2 error + template < typename AnalyticalSolution > + scalar_type compute_l2_displacement_error( const AnalyticalSolution &as ) { + return compute_l2_error( FieldName::DEPL_CELLS, as ); + } + + // compute l2 error + template < typename AnalyticalSolution > + long double compute_H1_error( const AnalyticalSolution &as ) { + using quad_type = long double; + quad_type err_dof = 0.; + + const auto depl = m_fields.getCurrentField( FieldName::DEPL ); + + matrix_type grad; + matrix_type stab; + + for ( auto &cl : m_msh ) { + // std::cout << m_degree_infos.cellDegreeInfo(m_msh, cl) << std::endl; + /////// Gradient Reconstruction ///////// + if ( m_behavior.getDeformation() == SMALL_DEF ) { + grad = make_matrix_hho_symmetric_gradrec( m_msh, cl, m_degree_infos ).second; + } else { + grad = make_matrix_hho_gradrec( m_msh, cl, m_degree_infos ).second; + } + + if ( m_rp.m_stab ) { + switch ( m_rp.m_stab_type ) { + case StabilizationType::HHO_SYM: { + const auto recons = + make_vector_hho_symmetric_laplacian( m_msh, cl, m_degree_infos ); + stab = make_vector_hho_stabilization( m_msh, cl, recons.first, m_degree_infos ); + break; + } + case StabilizationType::HHO: { + const auto recons_scalar = + make_scalar_hho_laplacian( m_msh, cl, m_degree_infos ); + stab = make_vector_hho_stabilization_optim( m_msh, cl, recons_scalar.first, + m_degree_infos ); + break; + } + case StabilizationType::HDG: { + stab = make_vector_hdg_stabilization( m_msh, cl, m_degree_infos ); + break; + } + case StabilizationType::DG: { + stab = make_vector_dg_stabilization( m_msh, cl, m_degree_infos ); + break; + } + case StabilizationType::NO: { + break; + stab.setZero(); + } + default: + throw std::invalid_argument( "Unknown stabilization" ); + } + } + + const auto Ah = grad + stab; + + const auto cell_i = m_msh.lookup( cl ); + + const vector_type comp_dof = depl.at( cell_i ); + const vector_type true_dof = project_function( m_msh, cl, m_degree_infos, as, 2 ); + + const vector_type diff_dof = ( true_dof - comp_dof ); + const vector_type Ah_diff_dof = Ah * diff_dof; + + const auto size = diff_dof.size(); + for ( int i = 0; i < size; i++ ) { + const quad_type x = static_cast< quad_type >( diff_dof( i ) ); + const quad_type y = static_cast< quad_type >( Ah_diff_dof( i ) ); + err_dof = std::fma( x, y, err_dof ); + } + } + + return std::sqrt( err_dof ); + } + + void output_discontinuous_field( const std::string &filename, FieldName name ) const { + gmsh::Gmesh gmsh( mesh_type::dimension ); + + std::vector< gmsh::Data > data; // create data (not used) + const std::vector< gmsh::SubData > subdata; // create subdata to save soution at gauss point + + const auto depl_cells = m_fields.getCurrentField( name ); + + int cell_i = 0; + int nb_nodes = 0; + for ( auto &cl : m_msh ) { + const auto di = m_degree_infos.cellDegreeInfo( m_msh, cl ); + const auto cb = make_vector_monomial_basis( m_msh, cl, di.cell_degree() ); + const vector_type x = depl_cells.at( cell_i++ ); + auto cell_nodes = points( m_msh, cl ); + std::vector< gmsh::Node > new_nodes; + + // loop on the nodes of the cell + for ( auto &pt : cell_nodes ) { + nb_nodes++; + + const auto phi = cb.eval_functions( pt ); + const auto depl = eval( x, phi ); + + const std::vector< double > deplv = convertToVectorGmsh( depl ); + const std::array< double, 3 > coor = init_coor( pt ); + + // Add a node + const gmsh::Node tmp_node( coor, nb_nodes, 0 ); + new_nodes.push_back( tmp_node ); + gmsh.addNode( tmp_node ); + + const gmsh::Data datatmp( nb_nodes, deplv ); + data.push_back( datatmp ); + } + // Add new element + add_element( gmsh, new_nodes ); + } + + // Create and init a nodedata view + gmsh::NodeData nodedata( 3, 0.0, "depl_node_disc", data, subdata ); + + // Save the view + nodedata.saveNodeData( filename, gmsh ); + } + + void output_continuous_field( const std::string &filename, FieldName name ) const { + const auto dimension = mesh_type::dimension; + + gmsh::Gmesh gmsh = convertMesh( m_post_mesh ); + auto storage = m_post_mesh.mesh().backend_storage(); + + const static_vector< scalar_type, dimension > vzero = + static_vector< scalar_type, dimension >::Zero(); + + const auto depl_cells = m_fields.getCurrentField( FieldName::DEPL_CELLS ); + const size_t nb_nodes( gmsh.getNumberofNodes() ); + + // first(number of data at this node), second(cumulated value) + std::vector< std::pair< size_t, static_vector< scalar_type, dimension > > > value( + nb_nodes, std::make_pair( 0, vzero ) ); + + int cell_i = 0; + for ( auto &cl : m_msh ) { + const auto di = m_degree_infos.cellDegreeInfo( m_msh, cl ); + const auto cb = make_vector_monomial_basis( m_msh, cl, di.cell_degree() ); + const vector_type x = depl_cells.at( cell_i ); + auto cell_nodes = m_post_mesh.nodes_cell( cell_i ); + + // Loop on the nodes of the cell + for ( auto &point_id : cell_nodes ) { + const auto pt = storage->points[point_id]; + + const auto phi = cb.eval_functions( pt ); + const auto depl = eval( x, phi ); + + // Add displacement at node + value[point_id].first++; + value[point_id].second += depl; + } + cell_i++; + } + + std::vector< gmsh::Data > data; // create data + std::vector< gmsh::SubData > subdata; // create subdata + data.reserve( nb_nodes ); // data has a size of nb_node + + // Compute the average value and save it + for ( int i_node = 0; i_node < value.size(); i_node++ ) { + const static_vector< scalar_type, dimension > depl_avr = + value[i_node].second / double( value[i_node].first ); + + const gmsh::Data tmp_data( i_node + 1, convertToVectorGmsh( depl_avr ) ); + data.push_back( tmp_data ); + } + + // Create and init a nodedata view + gmsh::NodeData nodedata( 3, 0.0, "depl_node_cont", data, subdata ); + // Save the view + nodedata.saveNodeData( filename, gmsh ); + } + + void output_CauchyStress_GP( const std::string &filename, bool def = false ) const { + gmsh::Gmesh gmsh = convertMesh( m_post_mesh ); + + std::vector< gmsh::Data > data; // create data (not used) + std::vector< gmsh::SubData > subdata; // create subdata to save soution at gauss point + size_t nb_nodes( gmsh.getNumberofNodes() ); + + const auto depl = m_fields.getCurrentField( FieldName::DEPL ); + + int cell_i = 0; + for ( auto &cl : m_msh ) { + const auto di = m_degree_infos.cellDegreeInfo( m_msh, cl ); + + const auto uTF = depl.at( cell_i ); + matrix_type gr; + if ( m_rp.m_precomputation ) { + gr = m_data.m_gradient_precomputed.at( cell_i ); + } else { + if ( m_behavior.getDeformation() == SMALL_DEF ) { + gr = make_matrix_hho_symmetric_gradrec( m_msh, cl, m_degree_infos ).first; + } else { + gr = make_matrix_hho_gradrec( m_msh, cl, m_degree_infos ).first; + } + } + + const vector_type GTuTF = gr * uTF; + + const auto gb = make_matrix_monomial_basis( m_msh, cl, di.grad_degree() ); + const auto gbs = make_sym_matrix_monomial_basis( m_msh, cl, di.grad_degree() ); + + const auto cb = make_vector_monomial_basis( m_msh, cl, di.cell_degree() ); + const vector_type uT = uTF.head( cb.size() ); + + // Loop on nodes + const auto nb_qp = m_behavior.numberOfQP( cell_i ); + + for ( int i_qp = 0; i_qp < nb_qp; i_qp++ ) { + const auto qp = m_behavior.quadrature_point( cell_i, i_qp ); + std::vector< double > tens; + + if ( m_behavior.getDeformation() == SMALL_DEF ) { + auto stress = m_behavior.compute_stress3D( cell_i, i_qp ); + tens = convertToVectorGmsh( stress ); + } else { + const auto gphi = gb.eval_functions( qp.point() ); + const auto GT_iqn = eval( GTuTF, gphi ); + const auto FT_iqn = convertGtoF( GT_iqn ); + const auto FT_iqn_3D = convertMatrix3DwithOne( FT_iqn ); + + auto P = m_behavior.compute_stress3D( cell_i, i_qp ); + auto stress = convertPK1toCauchy( P, FT_iqn_3D ); + tens = convertToVectorGmsh( stress ); + } + + std::array< double, 3 > coor = init_coor( qp.point() ); + + if ( def ) { + const auto cphi = cb.eval_functions( qp.point() ); + const auto depl = eval( uT, cphi ); + + // Compute new coordinates + for ( int j = 0; j < mesh_type::dimension; j++ ) + coor[j] += depl( j ); + } + + // Add GP + // Create a node at gauss point + nb_nodes++; + const gmsh::Node new_node( coor, nb_nodes, 0 ); + const gmsh::SubData sdata( tens, new_node ); + subdata.push_back( sdata ); // add subdata + } + cell_i++; + } + + // Save + gmsh::NodeData nodedata( 9, 0.0, "CauchyStress_GP", data, + subdata ); // create and init a nodedata view + + nodedata.saveNodeData( filename, gmsh ); // save the view + } + + void output_is_plastic_GP( const std::string &filename ) const { + gmsh::Gmesh gmsh = convertMesh( m_post_mesh ); + + std::vector< gmsh::Data > data; // create data (not used) + std::vector< gmsh::SubData > subdata; // create subdata to save soution at gauss point + size_t nb_nodes( gmsh.getNumberofNodes() ); + + int cell_i = 0; + for ( auto &cl : m_msh ) { + // Loop on nodes + const auto nb_qp = m_behavior.numberOfQP( cell_i ); + + for ( int i_qp = 0; i_qp < nb_qp; i_qp++ ) { + const auto qp = m_behavior.quadrature_point( cell_i, i_qp ); + + scalar_type p = 0; + if ( m_behavior.is_plastic( cell_i, i_qp ) ) + p = 1; + + const std::vector< double > p_s = convertToVectorGmsh( p ); + + // Add GP + // Create a node at gauss point + nb_nodes++; + const gmsh::Node new_node = convertPoint( qp.point(), nb_nodes ); + const gmsh::SubData sdata( p_s, new_node ); + subdata.push_back( sdata ); // add subdata + } + cell_i++; + } + + // Save + gmsh::NodeData nodedata( 1, 0.0, "state_GP", data, + subdata ); // create and init a nodedata view + + nodedata.saveNodeData( filename, gmsh ); // save the view + } + + void output_equivalentPlasticStrain_GP( const std::string &filename ) const { + gmsh::Gmesh gmsh = convertMesh( m_post_mesh ); + + std::vector< gmsh::Data > data; // create data (not used) + std::vector< gmsh::SubData > subdata; // create subdata to save soution at gauss point + size_t nb_nodes( gmsh.getNumberofNodes() ); + + int cell_i = 0; + for ( auto &cl : m_msh ) { + // Loop on nodes + const auto nb_qp = m_behavior.numberOfQP( cell_i ); + + for ( int i_qp = 0; i_qp < nb_qp; i_qp++ ) { + const auto qp = m_behavior.quadrature_point( cell_i, i_qp ); + + scalar_type p = m_behavior.equivalentPlasticStrain( cell_i, i_qp ); + + const std::vector< double > p_s = convertToVectorGmsh( p ); + + // Add GP + // Create a node at gauss point + nb_nodes++; + const gmsh::Node new_node = convertPoint( qp.point(), nb_nodes ); + const gmsh::SubData sdata( p_s, new_node ); + subdata.push_back( sdata ); // add subdata + } + cell_i++; + } + + // Save + gmsh::NodeData nodedata( 1, 0.0, "equivalentPlasticStrain_GP", data, + subdata ); // create and init a nodedata view + + nodedata.saveNodeData( filename, gmsh ); // save the view + } + + void output_discontinuous_deformed( const std::string &filename ) const { + gmsh::Gmesh gmsh( mesh_type::dimension ); + auto storage = m_msh.backend_storage(); + + const auto depl_cells = m_fields.getCurrentField( FieldName::DEPL_CELLS ); + int cell_i = 0; + size_t nb_nodes = 0; + for ( auto &cl : m_msh ) { + const auto di = m_degree_infos.cellDegreeInfo( m_msh, cl ); + + auto cb = make_vector_monomial_basis( m_msh, cl, di.cell_degree() ); + const vector_type x = depl_cells.at( cell_i++ ); + const auto cell_nodes = points( m_msh, cl ); + std::vector< gmsh::Node > new_nodes; + + // Loop on nodes of the cell + for ( auto &pt : cell_nodes ) { + nb_nodes++; + + const auto phi = cb.eval_functions( pt ); + const auto depl = eval( x, phi ); + + std::array< double, 3 > coor = init_coor( pt ); + // Compute new coordinates + for ( int j = 0; j < mesh_type::dimension; j++ ) + coor[j] += depl( j ); + + // Save node + const gmsh::Node tmp_node( coor, nb_nodes, 0 ); + new_nodes.push_back( tmp_node ); + gmsh.addNode( tmp_node ); + } + // Add new element + add_element( gmsh, new_nodes ); + } + // Save mesh + gmsh.writeGmesh( filename, 2 ); + } + + void output_stabCoeff( const std::string &filename ) const { + gmsh::Gmesh gmsh = convertMesh( m_post_mesh ); + + std::vector< gmsh::Data > data; // create data (not used) + std::vector< gmsh::SubData > subdata; // create subdata to save soution at gauss point + size_t nb_nodes( gmsh.getNumberofNodes() ); + + for ( auto &cl : m_msh ) { + + std::array< double, 3 > coor = init_coor( barycenter( m_msh, cl ) ); + double beta = m_stab_manager.getValue( m_msh, cl ); + std::vector< double > tens( 1, beta ); + + // Add GP + // Create a node at gauss point + nb_nodes++; + const gmsh::Node new_node( coor, nb_nodes, 0 ); + const gmsh::SubData sdata( tens, new_node ); + subdata.push_back( sdata ); // add subdata + } + + // Save + gmsh::NodeData nodedata( 1, 0.0, "StabCoeff", data, + subdata ); // create and init a nodedata view + + nodedata.saveNodeData( filename, gmsh ); // save the view + } +}; +} // namespace mechanics + +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/NonLinearStep.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NonLinearStep.hpp new file mode 100644 index 00000000..20e00346 --- /dev/null +++ b/libdiskpp/include/diskpp/mechanics/NewtonSolver/NonLinearStep.hpp @@ -0,0 +1,202 @@ +/* + * /\ Matteo Cicuttin (C) 2016, 2017, 2018 + * /__\ matteo.cicuttin@enpc.fr + * /_\/_\ École Nationale des Ponts et Chaussées - CERMICS + * /\ /\ + * /__\ /__\ DISK++, a template library for DIscontinuous SKeletal + * /_\/_\/_\/_\ methods. + * + * This file is copyright of the following authors: + * Nicolas Pignet (C) 2019 nicolas.pignet@enpc.fr + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * If you use this code or parts of it for scientific publications, you + * are required to cite it as following: + * + * Hybrid High-Order methods for finite elastoplastic deformations + * within a logarithmic strain framework. + * M. Abbas, A. Ern, N. Pignet. + * International Journal of Numerical Methods in Engineering (2019) + * 120(3), 303-327 + * DOI: 10.1002/nme.6137 + */ + +// NewtonRaphson_step + +#pragma once + +#include "diskpp/adaptivity/adaptivity.hpp" +#include "diskpp/boundary_conditions/boundary_conditions.hpp" +#include "diskpp/common/timecounter.hpp" +#include "diskpp/mechanics/NewtonSolver/NewtonIteration.hpp" +#include "diskpp/mechanics/NewtonSolver/NewtonSolverInformations.hpp" +#include "diskpp/mechanics/NewtonSolver/NonLinearParameters.hpp" +#include "diskpp/mechanics/NewtonSolver/QuasiNewtonIteration.hpp" +#include "diskpp/mechanics/NewtonSolver/TimeManager.hpp" +#include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" +#include "diskpp/methods/hho" +#include "diskpp/solvers/direct_solvers.hpp" + +#include +#include +#include + +namespace disk { + +namespace mechanics { + +/** + * @brief Newton-Raphson step for nonlinear solid mechanics + * + * Specialized for HHO methods + * + * Options : - small and finite deformations + * - plasticity, hyperelasticity (various laws) + * + * @tparam MeshType type of the mesh + */ +template < typename MeshType > +class NonLinearStep { + typedef MeshType mesh_type; + typedef typename mesh_type::coordinate_type scalar_type; + + typedef dynamic_matrix< scalar_type > matrix_type; + typedef dynamic_vector< scalar_type > vector_type; + + typedef NonLinearParameters< scalar_type > param_type; + typedef vector_boundary_conditions< mesh_type > bnd_type; + typedef Behavior< mesh_type > behavior_type; + + typedef std::function< static_vector< scalar_type, mesh_type::dimension >( + const point< scalar_type, mesh_type::dimension > &, scalar_type ) > + func_type; + + bool m_verbose; + bool m_convergence; + + public: + NonLinearStep( const param_type &rp ) : m_verbose( rp.m_verbose ), m_convergence( false ) {} + + /** + * @brief return a boolean to know if the verbosity mode is activated + * + */ + bool verbose( void ) const { return m_verbose; } + + /** + * @brief Set the verbosity mode + * + * @param v boolean to activate or desactivate the verbosity mode + */ + void verbose( bool v ) { m_verbose = v; } + + /** + * @brief Compute the Newton's step until convergence or stopped criterion + * + * @return NewtonSolverInfo Informations about the Newton's step during the computation + */ + NewtonSolverInfo + compute( const mesh_type &msh, const bnd_type &bnd, const param_type &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + const std::shared_ptr< solvers::sparse_solver< scalar_type > > lin_solv, + const std::unique_ptr< func_type > &lf, const TimeStep< scalar_type > ¤t_step, + NonLinearData< scalar_type > &data, behavior_type &behavior, + StabCoeffManager< scalar_type > &stab_manager, + MultiTimeField< scalar_type > &fields ) { + NewtonSolverInfo ni; + timecounter tc; + tc.tic(); + + // initialise the NewtonRaphson iteration + + std::unique_ptr< GenericIteration< mesh_type > > nlIter; + + switch ( rp.getNonLinearSolver() ) { + case NonLinearSolverType::NEWTON: + case NonLinearSolverType::PICARD: { + // Newton step + nlIter = std::make_unique< NewtonIteration< mesh_type > >( msh, bnd, rp, degree_infos, + lin_solv, current_step ); + break; + } + case NonLinearSolverType::QNEWTON_BDIAG_JACO: + case NonLinearSolverType::QNEWTON_BDIAG_ELAS: + case NonLinearSolverType::QNEWTON_BDIAG_STAB: { + nlIter = std::make_unique< QuasiNewtonIteration< mesh_type > >( + msh, bnd, rp, degree_infos, lin_solv, current_step ); + break; + } + default: + throw std::runtime_error( "Unexpected NonLinearSolver." ); + break; + } + + auto iinfo = + nlIter->initialize( msh, bnd, rp, degree_infos, data, behavior, stab_manager, fields ); + ni.updateInitInfo( iinfo ); + + m_convergence = false; + + for ( size_t iter = 0; iter < rp.getMaximumNumberNLIteration(); iter++ ) { + // assemble lhs and rhs + AssemblyInfo assembly_info; + try { + assembly_info = nlIter->assemble( msh, bnd, rp, degree_infos, lf, data, behavior, + stab_manager, fields ); + } catch ( const std::invalid_argument &ia ) { + std::cerr << "Invalid argument: " << ia.what() << std::endl; + m_convergence = false; + tc.toc(); + ni.m_time_newton = tc.elapsed(); + return ni; + } + + ni.updateAssemblyInfo( assembly_info ); + // test convergence + try { + m_convergence = nlIter->convergence( rp, iter, fields ); + } catch ( const std::runtime_error &ia ) { + std::cerr << "Runtime error: " << ia.what() << std::endl; + m_convergence = false; + tc.toc(); + ni.m_time_newton = tc.elapsed(); + return ni; + } + + if ( m_convergence ) { + ni.m_assembly_info.m_time_postpro += nlIter->post_convergence( + msh, bnd, rp, degree_infos, data, stab_manager, fields ); + tc.toc(); + ni.m_time_newton = tc.elapsed(); + return ni; + } + + // solve the global system + SolveInfo solve_info = nlIter->solve(); + ni.updateSolveInfo( solve_info ); + // update unknowns + ni.m_assembly_info.m_time_postpro += nlIter->postprocess( + msh, bnd, rp, degree_infos, lf, data, behavior, stab_manager, fields ); + + ni.m_iter++; + } + + tc.toc(); + ni.m_time_newton = tc.elapsed(); + return ni; + } + + /** + * @brief Test convergence of the Newton's iteration + * + * @return true if the norm of the residual is lower that a given criterion + * @return false else + */ + bool convergence() const { return m_convergence; } +}; +} // namespace mechanics + +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/QuasiNewtonIteration.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/QuasiNewtonIteration.hpp new file mode 100644 index 00000000..4010c092 --- /dev/null +++ b/libdiskpp/include/diskpp/mechanics/NewtonSolver/QuasiNewtonIteration.hpp @@ -0,0 +1,557 @@ +/* + * /\ Matteo Cicuttin (C) 2016, 2017, 2018 + * /__\ matteo.cicuttin@enpc.fr + * /_\/_\ École Nationale des Ponts et Chaussées - CERMICS + * /\ /\ + * /__\ /__\ DISK++, a template library for DIscontinuous SKeletal + * /_\/_\/_\/_\ methods. + * + * This file is copyright of the following authors: + * Nicolas Pignet (C) 2019 nicolas.pignet@enpc.fr + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * If you use this code or parts of it for scientific publications, you + * are required to cite it as following: + * + * Hybrid High-Order methods for finite elastoplastic deformations + * within a logarithmic strain framework. + * M. Abbas, A. Ern, N. Pignet. + * International Journal of Numerical Methods in Engineering (2019) + * 120(3), 303-327 + * DOI: 10.1002/nme.6137 + */ + +// QuasiNewton iteration + +#pragma once + +#include "diskpp/mechanics/NewtonSolver/GenericIteration.hpp" + +namespace disk { + +namespace mechanics { + +/** + * @brief Newton-Raphson iteration for nonlinear solid mechanics + * + * Specialized for HHO methods + * + * Options : - small and finite deformations + * - plasticity, hyperelasticity (various laws) + * + * @tparam MeshType type of the mesh + */ +template < typename MeshType > +class QuasiNewtonIteration : public GenericIteration< MeshType > { + typedef typename GenericIteration< MeshType >::mesh_type mesh_type; + typedef typename GenericIteration< MeshType >::cell_type cell_type; + typedef typename GenericIteration< MeshType >::scalar_type scalar_type; + + typedef typename GenericIteration< MeshType >::matrix_type matrix_type; + typedef typename GenericIteration< MeshType >::vector_type vector_type; + + typedef typename GenericIteration< MeshType >::param_type param_type; + typedef typename GenericIteration< MeshType >::bnd_type bnd_type; + typedef typename GenericIteration< MeshType >::behavior_type behavior_type; + + typedef typename GenericIteration< MeshType >::elem_type elem_type; + typedef typename GenericIteration< MeshType >::assembler_type assembler_type; + typedef typename GenericIteration< MeshType >::func_type func_type; + + matrix_type _mass_term( const mesh_type &msh, const cell_type &cl, + const MeshDegreeInfo< mesh_type > °ree_infos ) const { + + const auto cell_infos = degree_infos.cellDegreeInfo( msh, cl ); + const auto faces_infos = cell_infos.facesDegreeInfo(); + const auto num_faces_dofs = vector_faces_dofs( msh, faces_infos ); + + matrix_type mm = matrix_type::Zero( num_faces_dofs, num_faces_dofs ); + + const auto fcs = faces( msh, cl ); + + auto to_vector = []( const matrix_type &scalar_matrix ) { + const int scal_total_dofs = scalar_matrix.rows(); + const int vect_total_tofs = scal_total_dofs * mesh_type::dimension; + + matrix_type mm = matrix_type::Zero( vect_total_tofs, vect_total_tofs ); + + for ( int i = 0; i < scal_total_dofs; i++ ) { + const auto row = i * mesh_type::dimension; + for ( int j = 0; j < scal_total_dofs; j++ ) { + const auto col = j * mesh_type::dimension; + for ( int k = 0; k < mesh_type::dimension; k++ ) { + mm( row + k, col + k ) = scalar_matrix( i, j ); + } + } + } + + return mm; + }; + + int offset = 0; + for ( size_t i = 0; i < fcs.size(); i++ ) { + const auto fdi = faces_infos[i]; + + if ( fdi.hasUnknowns() ) { + const auto fc = fcs[i]; + const auto facdeg = fdi.degree(); + const auto hF = diameter( msh, fc ); + const auto fb = make_scalar_monomial_basis( msh, fc, facdeg ); + const auto fbs = + vector_basis_size( facdeg, mesh_type::dimension - 1, mesh_type::dimension ); + + const matrix_type mass_F = make_mass_matrix( msh, fc, fb ); + + mm.block( offset, offset, fbs, fbs ) = ( 1.0 / hF ) * to_vector( mass_F ); + + offset += fbs; + } + } + assert( offset == num_faces_dofs ); + + return mm; + } + + public: + QuasiNewtonIteration( const mesh_type &msh, const bnd_type &bnd, const param_type &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + const std::shared_ptr< solvers::sparse_solver< scalar_type > > lin_solv, + const TimeStep< scalar_type > ¤t_step ) + : GenericIteration< MeshType >( msh, bnd, rp, degree_infos, lin_solv, current_step ) { + if ( rp.getUnsteadyScheme() != DynamicType::LEAP_FROG ) { + throw std::invalid_argument( "Sheme not supported by QuasiNewton" ); + } + } + + InitInfo initialize( const mesh_type &msh, const bnd_type &bnd, const param_type &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + NonLinearData< scalar_type > &data, behavior_type &behavior, + const StabCoeffManager< scalar_type > &stab_manager, + MultiTimeField< scalar_type > &fields ) override { + InitInfo ii = GenericIteration< MeshType >::initialize( msh, bnd, rp, degree_infos, data, + behavior, stab_manager, fields ); + + const bool use_tangent = rp.getNonLinearSolver() == NonLinearSolverType::QNEWTON_BDIAG_JACO; + if ( use_tangent ) { + this->m_lin_solv->reset(); + } + + if ( !this->m_lin_solv->is_factorized() ) { + elem_type elem; + vector_mechanics_hho_assembler assembler( msh, degree_infos, bnd ); + + timecounter tc; + tc.tic(); + + const bool mixed_order = rp.m_cell_degree > rp.m_face_degree; + const bool small_def = ( behavior.getDeformation() == SMALL_DEF ); + + data.m_lhs_loc = std::make_shared< std::map< int, matrix_type > >(); + auto depl = fields.getCurrentField( FieldName::DEPL ); + + for ( auto &cl : msh ) { + const auto cell_i = msh.lookup( cl ); + + const auto cell_infos = degree_infos.cellDegreeInfo( msh, cl ); + const auto num_cell_dofs = vector_cell_dofs( msh, cell_infos ); + + const auto faces_infos = cell_infos.facesDegreeInfo(); + const auto num_faces_dofs = vector_faces_dofs( msh, faces_infos ); + + const auto beta_s = stab_manager.getValue( msh, cl ); + + matrix_type lhs; + + switch ( rp.getNonLinearSolver() ) { + case NonLinearSolverType::QNEWTON_BDIAG_JACO: + case NonLinearSolverType::QNEWTON_BDIAG_ELAS: { + const auto huT = depl.at( cell_i ); + + matrix_type GT = _gradrec( msh, cl, rp, degree_infos, small_def, + data.m_gradient_precomputed ); + + elem.compute_rigidity_matrix( msh, cl, bnd, rp, degree_infos, GT, huT, + this->m_time_step, behavior, small_def, + use_tangent ); + + const matrix_type stab = + beta_s * _stab( msh, cl, rp, degree_infos, data.m_stab_precomputed ); + + lhs = matrix_type::Zero( num_faces_dofs, num_faces_dofs ); + + int offset = 0; + const auto fcs = faces( msh, cl ); + for ( size_t i = 0; i < fcs.size(); i++ ) { + const auto fdi = faces_infos[i]; + + if ( fdi.hasUnknowns() ) { + const auto facdeg = fdi.degree(); + const auto fbs = vector_basis_size( facdeg, mesh_type::dimension - 1, + mesh_type::dimension ); + + lhs.block( offset, offset, fbs, fbs ) = elem.K_int.block( + num_cell_dofs + offset, num_cell_dofs + offset, fbs, fbs ); + lhs.block( offset, offset, fbs, fbs ) += stab.block( + num_cell_dofs + offset, num_cell_dofs + offset, fbs, fbs ); + + offset += fbs; + } + } + assert( offset == num_faces_dofs ); + break; + } + case NonLinearSolverType::QNEWTON_BDIAG_STAB: { + if ( mixed_order ) { + matrix_type stab = + beta_s * _stab( msh, cl, rp, degree_infos, data.m_stab_precomputed ); + + lhs = stab.bottomRightCorner( num_faces_dofs, num_faces_dofs ); + } else { + lhs = beta_s * _mass_term( msh, cl, degree_infos ); + } + break; + } + default: { + throw std::invalid_argument( "QuasiNewton option is unknown." ); + break; + } + } + + const vector_type rhs = vector_type::Zero( num_faces_dofs ); + + assembler.assemble( msh, cl, bnd, lhs, rhs ); + + if ( bnd.cell_has_dirichlet_faces( cl ) ) { + ( *data.m_lhs_loc )[cell_i] = lhs; + } + } + tc.toc(); + ii.m_time_rigi += elem.time_rigi; + ii.m_time_dyna += tc.elapsed() - elem.time_rigi; + + assembler.finalize(); + + tc.tic(); + const auto status = this->m_lin_solv->factorize( assembler.LHS ); + tc.toc(); + ii.m_time_solve += tc.elapsed(); + + if ( status != solvers::direct_solver_status::ok ) { + throw std::runtime_error( "Fail to factorize the matrix." ); + } + } + + return ii; + } + + AssemblyInfo assemble( const mesh_type &msh, const bnd_type &bnd, const param_type &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + const std::unique_ptr< func_type > &lf, + NonLinearData< scalar_type > &data, behavior_type &behavior, + StabCoeffManager< scalar_type > &stab_manager, + MultiTimeField< scalar_type > &fields ) override { + elem_type elem; + AssemblyInfo ai; + + // set RHS to zero + this->m_assembler.initialize(); + this->m_F_int = 0.0; + + const bool small_def = ( behavior.getDeformation() == SMALL_DEF ); + + const bool mixed_order = rp.m_cell_degree > rp.m_face_degree; + + // Like if it is an implicit scheme + auto current_time = this->m_time_step.end_time(); + auto depl = fields.getCurrentField( FieldName::DEPL ); + auto depl_faces = fields.getCurrentField( FieldName::DEPL_FACES ); + + const auto lhs_loc = data.m_lhs_loc; + + std::vector< vector_type > resi_cells; + resi_cells.reserve( msh.cells_size() ); + + const auto rlf = this->_getLoad( lf, current_time ); + + timecounter tc, ttot; + + ttot.tic(); + + for ( auto &cl : msh ) { + const auto cell_i = msh.lookup( cl ); + + const auto huT = depl.at( cell_i ); + + const auto cell_infos = degree_infos.cellDegreeInfo( msh, cl ); + const auto num_cell_dofs = vector_cell_dofs( msh, cell_infos ); + + const auto num_tot_dofs = huT.size(); + const auto num_faces_dofs = num_tot_dofs - num_cell_dofs; + + // Gradient Reconstruction + // std::cout << "Grad" << std::endl; + tc.tic(); + matrix_type GT = + _gradrec( msh, cl, rp, degree_infos, small_def, data.m_gradient_precomputed ); + tc.toc(); + ai.m_time_gradrec += tc.elapsed(); + + // Mechanical Computation + + tc.tic(); + // std::cout << "Elem" << std::endl; + elem.compute( msh, cl, bnd, rp, degree_infos, rlf, GT, huT, this->m_time_step, behavior, + stab_manager, small_def, false ); + + vector_type rhs = elem.RTF.tail( num_faces_dofs ); + this->m_F_int += elem.F_int.tail( num_faces_dofs ).squaredNorm(); + + resi_cells.push_back( elem.RTF.head( num_cell_dofs ) ); + + tc.toc(); + ai.m_time_elem += tc.elapsed(); + + tc.tic(); + if ( rp.m_stab ) { + const auto beta_s = stab_manager.getValue( msh, cl ); + + matrix_type stab_F = + beta_s * ( _stab( msh, cl, rp, degree_infos, data.m_stab_precomputed ) + .bottomLeftCorner( num_faces_dofs, num_tot_dofs ) ); + + rhs -= stab_F * huT; + } + tc.toc(); + ai.m_time_stab += tc.elapsed(); + + tc.tic(); + this->m_assembler.assemble_nonlinear_rhs( msh, cl, bnd, ( *lhs_loc )[cell_i], rhs, + depl_faces ); + tc.toc(); + ai.m_time_assembler += tc.elapsed(); + } + fields.setCurrentField( FieldName::RESI_CELLS, resi_cells ); + + this->m_F_int = sqrt( this->m_F_int ); + + ai.m_time_law += elem.time_law; + ai.m_time_contact += elem.time_contact; + ai.m_time_load += elem.time_load; + ai.m_time_rigi += elem.time_rigi; + ai.m_time_fint += elem.time_fint; + + tc.tic(); + this->m_assembler.impose_neumann_boundary_conditions( msh, bnd ); + this->m_assembler.finalize(); + tc.toc(); + ai.m_time_assembler += tc.elapsed(); + + ttot.toc(); + ai.m_time_assembly = ttot.elapsed(); + ai.m_linear_system_size = this->m_assembler.LHS.rows(); + return ai; + } + + SolveInfo solve() override { + timecounter tc; + + // std::cout << "RHS" << this->m_assembler.RHS.transpose() << std::endl; + + tc.tic(); + const auto status = this->m_lin_solv->solve( this->m_assembler.RHS, this->m_system_displ ); + tc.toc(); + + if ( status != solvers::direct_solver_status::ok ) { + throw std::runtime_error( "Error during linear system resolution" ); + } + + // std::cout << "SOL" << this->m_system_displ.transpose() << std::endl; + + return SolveInfo( this->m_assembler.LHS.rows(), this->m_assembler.LHS.nonZeros(), + tc.elapsed() ); + } + + scalar_type postprocess( const mesh_type &msh, const bnd_type &bnd, const param_type &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + const std::unique_ptr< func_type > &lf, + NonLinearData< scalar_type > &data, behavior_type &behavior, + StabCoeffManager< scalar_type > &stab_manager, + MultiTimeField< scalar_type > &fields ) override { + timecounter tc; + tc.tic(); + + auto depl_faces = fields.getCurrentField( FieldName::DEPL_FACES ); + + auto [dudT, idx] = this->m_assembler.expand_solution_nonlinear( + msh, bnd, this->m_system_displ, depl_faces ); + + auto update_depl_cell = [&msh, &fields, °ree_infos, &idx, + this]( const std::vector< vector_type > &depl_faces ) -> auto { + auto depl = fields.getCurrentField( FieldName::DEPL ); + + // Update cell + for ( auto &cl : msh ) { + const auto cell_i = msh.lookup( cl ); + + const auto cell_infos = degree_infos.cellDegreeInfo( msh, cl ); + const auto faces_infos = cell_infos.facesDegreeInfo(); + const auto num_faces_dofs = vector_faces_dofs( msh, faces_infos ); + + vector_type udT = vector_type( num_faces_dofs ); + + const auto fcs_id = faces_id( msh, cl ); + size_t face_offset = 0; + for ( size_t face_i = 0; face_i < fcs_id.size(); face_i++ ) { + const size_t face_id = fcs_id[face_i]; + const auto n_face_dofs = idx( face_id + 1 ) - idx( face_id ); + + udT.segment( face_offset, n_face_dofs ) = depl_faces[face_id]; + face_offset += n_face_dofs; + } + + // Update element U^{i+1} = U^i + delta U^i + depl.at( cell_i ).tail( num_faces_dofs ) = udT; + + // std::cout << "KT_F " << m_AL[cell_i].norm() << std::endl; + // std::cout << "sol_F" << std::endl; + // std::cout << xdT.transpose() << std::endl; + // std::cout << "ft" << std::endl; + // std::cout << m_bL[cell_i].transpose() << std::endl; + // std::cout << "sol_T" << std::endl; + // std::cout << xT.transpose() << std::endl; + // std::cout << depl.at(cell_i).transpose() << std::endl; + } + fields.setCurrentField( FieldName::DEPL, depl ); + + this->m_dyna.postprocess( msh, this->m_time_step, fields ); + }; + + /* TODO: fix acceleration */ + + if ( rp.getLineSearch() == LineSearchType::SECANT ) { + + auto _func = [&msh, &bnd, &rp, °ree_infos, &lf, &data, &behavior, &stab_manager, + &fields, &dudT, &idx, depl_faces, update_depl_cell, + this]( scalar_type rho, const bool compute = true ) -> auto { + // update solution + + // Update unknowns + // Update face Uf^{i+1} = Uf^i + delta Uf^i + + auto depl_faces_new = depl_faces; + + for ( auto itor = msh.faces_begin(); itor != msh.faces_end(); itor++ ) { + const auto fc = *itor; + const size_t face_id = msh.lookup( fc ); + + depl_faces_new.at( face_id ) += + rho * dudT.segment( idx( face_id ), idx( face_id + 1 ) - idx( face_id ) ); + } + + fields.setCurrentField( FieldName::DEPL_FACES, depl_faces_new ); + + update_depl_cell( depl_faces_new ); + + // compute new residual + if ( compute && std::abs( rho ) > 1e-32 ) + const auto ai = this->assemble( msh, bnd, rp, degree_infos, lf, data, behavior, + stab_manager, fields ); + // TODO: Check sign + return dudT.dot( this->m_assembler.RHS ); + }; + + this->m_accel.secant( _func ); + } else { + + for ( auto itor = msh.faces_begin(); itor != msh.faces_end(); itor++ ) { + const auto fc = *itor; + const size_t face_id = msh.lookup( fc ); + + depl_faces.at( face_id ) += + dudT.segment( idx( face_id ), idx( face_id + 1 ) - idx( face_id ) ); + } + + if ( rp.getLineSearch() != LineSearchType::NO_LS ) { + + vector_type udT_new; + if ( rp.getLineSearch() == LineSearchType::RELAXATION ) { + udT_new = this->m_accel.relaxation( asVector( depl_faces ) ); + } else if ( rp.getLineSearch() == LineSearchType::AITKEN ) { + udT_new = this->m_accel.aitken( asVector( depl_faces ) ); + } else if ( rp.getLineSearch() == LineSearchType::ANDERSON ) { + udT_new = this->m_accel.anderson( asVector( depl_faces ) ); + } else if ( rp.getLineSearch() == LineSearchType::ANDERSON2 ) { + udT_new = this->m_accel.anderson( asVector( depl_faces ), 2 ); + } else if ( rp.getLineSearch() == LineSearchType::ANDERSON3 ) { + udT_new = this->m_accel.anderson( asVector( depl_faces ), 3 ); + } else if ( rp.getLineSearch() == LineSearchType::ANDERSON4 ) { + udT_new = this->m_accel.anderson( asVector( depl_faces ), 4 ); + } else if ( rp.getLineSearch() == LineSearchType::ANDERSON5 ) { + udT_new = this->m_accel.anderson( asVector( depl_faces ), 5 ); + } else if ( rp.getLineSearch() == LineSearchType::ANDERSON10 ) { + udT_new = this->m_accel.anderson( asVector( depl_faces ), 10 ); + } else { + throw std::invalid_argument( "LineSearch algorithm not supported." ); + } + + fromVector( udT_new, depl_faces ); + } + + fields.setCurrentField( FieldName::DEPL_FACES, depl_faces ); + + update_depl_cell( depl_faces ); + } + + tc.toc(); + return tc.elapsed(); + } + + scalar_type post_convergence( const mesh_type &msh, const bnd_type &bnd, const param_type &rp, + const MeshDegreeInfo< mesh_type > °ree_infos, + const NonLinearData< scalar_type > &data, + const StabCoeffManager< scalar_type > &stab_manager, + MultiTimeField< scalar_type > &fields ) override { + timecounter tc; + tc.tic(); + + if ( rp.m_stab ) { + const auto depl = fields.getCurrentField( FieldName::DEPL ); + auto resi_cells = fields.getCurrentField( FieldName::RESI_CELLS ); + + // Update cell + + for ( auto &cl : msh ) { + const auto cell_i = msh.lookup( cl ); + + const auto cell_infos = degree_infos.cellDegreeInfo( msh, cl ); + const auto num_cell_dofs = vector_cell_dofs( msh, cell_infos ); + + const auto beta_s = stab_manager.getValue( msh, cl ); + const matrix_type stab = + beta_s * _stab( msh, cl, rp, degree_infos, data.m_stab_precomputed ); + + const auto num_tot_dofs = stab.cols(); + + resi_cells[cell_i] -= + stab.topLeftCorner( num_cell_dofs, num_tot_dofs ) * depl[cell_i]; + } + fields.setCurrentField( FieldName::RESI_CELLS, resi_cells ); + + // std::cout << "DEPL: " << norm( depl ) << std::endl; + // std::cout << "DEPL_CELLS: " << norm( fields.getCurrentField( FieldName::DEPL_CELLS ) + // ) + // << std::endl; + // std::cout << "DEPL_FACES: " << norm( fields.getCurrentField( FieldName::DEPL_FACES ) + // ) + // << std::endl; + // std::cout << "RESI_CELLS: " << norm( resi_cells ) << std::endl; + } + tc.toc(); + return tc.elapsed(); + } +}; +} // namespace mechanics +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/StabilizationManager.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/StabilizationManager.hpp index faa7704b..16a39a56 100644 --- a/libdiskpp/include/diskpp/mechanics/NewtonSolver/StabilizationManager.hpp +++ b/libdiskpp/include/diskpp/mechanics/NewtonSolver/StabilizationManager.hpp @@ -30,49 +30,38 @@ #include #include -namespace disk -{ +namespace disk { -namespace mechanics -{ +namespace mechanics { /** * @brief Represent a time step on the time interval [start_time, end_time] * * @tparam T scalar type */ -template -class StabCoef -{ +template < typename T > +class StabCoef { private: T m_coeff; public: - StabCoef() : m_coeff(T(1)) {} + StabCoef() : m_coeff( T( 1 ) ) {} /** * @brief Construct a new StabCoef object * * @param coeff value of the stabilization coefficient */ - StabCoef(const T coeff) : m_coeff(coeff) {} + StabCoef( const T coeff ) : m_coeff( coeff ) {} /** * @brief Return the value of the stabiliztion coefficient * * @return T value of the stabiliztion coefficient */ - T - getValue(void) const - { - return m_coeff; - } + T getValue( void ) const { return m_coeff; } - void - setValue(const T& value) - { - m_coeff = value; - } + void setValue( const T &value ) { m_coeff = value; } }; /** @@ -80,55 +69,42 @@ class StabCoef * * @tparam T scalar type */ -template -class StabCoeffManager -{ +template < typename T > +class StabCoeffManager { private: - std::vector> m_stab_coeff; - std::vector> m_stab_coeff_new; + std::vector< StabCoef< T > > m_stab_coeff; + std::vector< StabCoef< T > > m_stab_coeff_new; public: - template - StabCoeffManager(const Mesh& mesh, const T value) - { + template < typename Mesh > + StabCoeffManager( const Mesh &mesh, const T value ) { m_stab_coeff.clear(); - m_stab_coeff.reserve(mesh.cells_size()); + m_stab_coeff.reserve( mesh.cells_size() ); m_stab_coeff_new.clear(); - m_stab_coeff_new.reserve(mesh.cells_size()); + m_stab_coeff_new.reserve( mesh.cells_size() ); - for (auto& cl : mesh) - { - m_stab_coeff.push_back(value); - m_stab_coeff_new.push_back(value); + for ( auto &cl : mesh ) { + m_stab_coeff.push_back( value ); + m_stab_coeff_new.push_back( value ); } } - template - T - getValue(const Mesh& mesh, const typename Mesh::cell& cl) const - { - return m_stab_coeff[mesh.lookup(cl)].getValue(); + template < typename Mesh > + T getValue( const Mesh &mesh, const typename Mesh::cell &cl ) const { + return m_stab_coeff[mesh.lookup( cl )].getValue(); } - template - void - setValue(const Mesh& mesh, const typename Mesh::cell& cl, const T& value) - { - m_stab_coeff[mesh.lookup(cl)].setValue(value); + template < typename Mesh > + void setValue( const Mesh &mesh, const typename Mesh::cell &cl, const T &value ) { + m_stab_coeff[mesh.lookup( cl )].setValue( value ); } - template - void - setValueNext(const Mesh& mesh, const typename Mesh::cell& cl, const T& value) - { - m_stab_coeff_new[mesh.lookup(cl)].setValue(value); + template < typename Mesh > + void setValueNext( const Mesh &mesh, const typename Mesh::cell &cl, const T &value ) { + m_stab_coeff_new[mesh.lookup( cl )].setValue( value ); } - void - update() - { - m_stab_coeff = m_stab_coeff_new; - } + void update() { m_stab_coeff = m_stab_coeff_new; } }; -} -} \ No newline at end of file +} // namespace mechanics +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/NewtonSolver/TimeManager.hpp b/libdiskpp/include/diskpp/mechanics/NewtonSolver/TimeManager.hpp index 90c178e9..c71d0e8e 100644 --- a/libdiskpp/include/diskpp/mechanics/NewtonSolver/TimeManager.hpp +++ b/libdiskpp/include/diskpp/mechanics/NewtonSolver/TimeManager.hpp @@ -30,26 +30,23 @@ #include #include -namespace disk -{ +namespace disk { -namespace mechanics -{ +namespace mechanics { /** * @brief Represent a time step on the time interval [start_time, end_time] * * @tparam T scalar type */ -template -class TimeStep -{ +template < typename T > +class TimeStep { private: - T m_start_time, m_end_time; + T m_start_time, m_end_time; size_t m_level; public: - TimeStep() : m_start_time(T(0)), m_end_time(T(0)), m_level(0) {} + TimeStep() : m_start_time( T( 0 ) ), m_end_time( T( 0 ) ), m_level( 0 ) {} /** * @brief Construct a new TimeStep object @@ -58,54 +55,36 @@ class TimeStep * @param end_time end of the time step * @param level level of time refining */ - TimeStep(const T start_time, const T end_time, const size_t level) : - m_start_time(start_time), m_end_time(end_time), m_level(level) - { - } + TimeStep( const T start_time, const T end_time, const size_t level ) + : m_start_time( start_time ), m_end_time( end_time ), m_level( level ) {} /** * @brief Return the start of the time step * * @return T start time */ - T - start_time(void) const - { - return m_start_time; - } + T start_time( void ) const { return m_start_time; } /** * @brief Return the end of the time step * * @return T end time */ - T - end_time(void) const - { - return m_end_time; - } + T end_time( void ) const { return m_end_time; } /** * @brief Return increment the time step * * @return T increment time */ - T - increment_time(void) const - { - return m_end_time - m_start_time; - } + T increment_time( void ) const { return m_end_time - m_start_time; } /** * @brief Return the level of time refining * * @return size_t level */ - size_t - level(void) const - { - return m_level; - } + size_t level( void ) const { return m_level; } }; /** @@ -113,62 +92,55 @@ class TimeStep * * @tparam T scalar type */ -template -class ListOfTimeStep -{ +template < typename T > +class ListOfTimeStep { private: - std::list> list_steps; - size_t n_time_step_comp; - T user_end_time; - - template - void - addTimeStepping(const T end_time, const I n_step, const size_t level) - { - T start_time = T(0); - - if (!list_steps.empty()) - { + std::list< TimeStep< T > > list_steps; + size_t n_time_step_comp; + T user_end_time; + + template < typename I > + void addTimeStepping( const T end_time, const I n_step, const size_t level ) { + T start_time = T( 0 ); + + if ( !list_steps.empty() ) { start_time = list_steps.back().end_time(); } - const T delta_t = (end_time - start_time) / T(n_step); + const T delta_t = ( end_time - start_time ) / T( n_step ); - for (I i = 0; i < n_step; i++) - { - if ((start_time + (i + 1) * delta_t) <= user_end_time) - { - const TimeStep step(start_time + i * delta_t, start_time + (i + 1) * delta_t, level); - list_steps.push_back(step); + for ( I i = 0; i < n_step; i++ ) { + if ( ( start_time + ( i + 1 ) * delta_t ) <= user_end_time ) { + const TimeStep< T > step( start_time + i * delta_t, + start_time + ( i + 1 ) * delta_t, level ); + list_steps.push_back( step ); } } } public: - ListOfTimeStep() : n_time_step_comp(0), user_end_time(0) { list_steps.clear(); } + ListOfTimeStep() : n_time_step_comp( 0 ), user_end_time( 0 ) { list_steps.clear(); } - ListOfTimeStep(const T end_time, const size_t n_step) : n_time_step_comp(0), user_end_time(end_time) - { - this->addTimeStepping(end_time, n_step, 0); + ListOfTimeStep( const T end_time, const size_t n_step ) + : n_time_step_comp( 0 ), user_end_time( end_time ) { + this->addTimeStepping( end_time, n_step, 0 ); } - template - ListOfTimeStep(const std::vector> list_of_time_step) : n_time_step_comp(0) - { + template < typename I > + ListOfTimeStep( const std::vector< std::pair< T, I > > list_of_time_step ) + : n_time_step_comp( 0 ) { user_end_time = list_of_time_step[list_of_time_step.size() - 1].first; - for (auto& [time, n_step] : list_of_time_step) - { - this->addTimeStepping(time, n_step, 0); + for ( auto &[time, n_step] : list_of_time_step ) { + this->addTimeStepping( time, n_step, 0 ); } } - template - ListOfTimeStep(const std::vector> list_of_time_step, const T final_time) : n_time_step_comp(0) - { + template < typename I > + ListOfTimeStep( const std::vector< std::pair< T, I > > list_of_time_step, const T final_time ) + : n_time_step_comp( 0 ) { user_end_time = final_time; - for (auto& [time, n_step] : list_of_time_step) - { - this->addTimeStepping(time, n_step, 0); + for ( auto &[time, n_step] : list_of_time_step ) { + this->addTimeStepping( time, n_step, 0 ); } } @@ -177,117 +149,90 @@ class ListOfTimeStep * * @return true No more time step */ - bool - empty(void) const - { - return list_steps.empty(); - } + bool empty( void ) const { return list_steps.empty(); } /** * @brief Return the number of time step * * @return size_t number of time step */ - size_t - numberOfTimeStep(void) const - { - return list_steps.size() + n_time_step_comp; - } + size_t numberOfTimeStep( void ) const { return list_steps.size() + n_time_step_comp; } /** * @brief Return the number of time step * * @return size_t number of time step */ - size_t - numberOfRemainingTimeStep(void) const - { - return list_steps.size(); - } + size_t numberOfRemainingTimeStep( void ) const { return list_steps.size(); } /** * @brief Return the number of time step already realized * * @return size_t number of time step realisized */ - size_t - numberOfTimeStepRealized(void) const - { - return n_time_step_comp; - } + size_t numberOfTimeStepRealized( void ) const { return n_time_step_comp; } /** * @brief Return the index (n-th)-time step * * @return size_t index of current time step */ - size_t - indexOfCurrentTimeStep(void) const - { - return n_time_step_comp + 1; - } + size_t indexOfCurrentTimeStep( void ) const { return n_time_step_comp + 1; } /** * @brief Get the Current Time Step object * * @return TimeStep Current time step */ - TimeStep - getCurrentTimeStep(void) const - { - return list_steps.front(); - } + TimeStep< T > getCurrentTimeStep( void ) const { return list_steps.front(); } /** * @brief Remove the current time step * */ - void - removeCurrentTimeStep(void) - { + void removeCurrentTimeStep( void ) { list_steps.pop_front(); n_time_step_comp++; } /** - * @brief Split the Current time step in two equal sub-time step. This allows to refine the time step + * @brief Split the Current time step in two equal sub-time step. This allows to refine the time + * step * */ - void - splitCurrentTimeStep(void) - { - const TimeStep CurrentStep = this->getCurrentTimeStep(); + void splitCurrentTimeStep( void ) { + const TimeStep< T > CurrentStep = this->getCurrentTimeStep(); const T start_time = CurrentStep.start_time(); - const T end_time = CurrentStep.end_time(); + const T end_time = CurrentStep.end_time(); - const T new_time = start_time + (end_time - start_time) / T(2); + const T new_time = start_time + ( end_time - start_time ) / T( 2 ); - const TimeStep newStep1(start_time, new_time, CurrentStep.level() + 1); - const TimeStep newStep2(new_time, end_time, CurrentStep.level() + 1); + const TimeStep< T > newStep1( start_time, new_time, CurrentStep.level() + 1 ); + const TimeStep< T > newStep2( new_time, end_time, CurrentStep.level() + 1 ); list_steps.pop_front(); - list_steps.push_front(newStep2); - list_steps.push_front(newStep1); + list_steps.push_front( newStep2 ); + list_steps.push_front( newStep1 ); } /** * @brief Print informations about current time step * */ - void - printCurrentTimeStep(void) const - { - const TimeStep current_step = this->getCurrentTimeStep(); - const T current_time = current_step.end_time(); + void printCurrentTimeStep( void ) const { + const TimeStep< T > current_step = this->getCurrentTimeStep(); + const T current_time = current_step.end_time(); + std::cout << std::endl; std::cout << "------------------------------------------------------------------------" "----------------------" << std::endl; std::cout << "************************ Time : " << current_time - << " sec (step: " << this->indexOfCurrentTimeStep() << "/" << this->numberOfTimeStep() - << ", sublevel: " << current_step.level() << " ) *************************|" << std::endl; + << " sec (step: " << this->indexOfCurrentTimeStep() << "/" + << this->numberOfTimeStep() << ", sublevel: " << current_step.level() + << " ) *************************|" << std::endl; } }; -} -} \ No newline at end of file +} // namespace mechanics +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/Cavitation/Cavitation_qp.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/Cavitation/Cavitation_qp.hpp index 64a72213..b9f200c9 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/Cavitation/Cavitation_qp.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/Cavitation/Cavitation_qp.hpp @@ -37,8 +37,8 @@ #define _USE_MATH_DEFINES #include -namespace disk -{ +namespace disk { +namespace mechanics { // Law for Linear Isotropic and Kinematic Hardening model with von Mises Criteria in small @@ -66,189 +66,204 @@ namespace disk * 6- U(J) = sqrt( ( J^2 -1 - 2 *ln(J)) /2) * */ -template -class Cavitation_qp : public law_qp_bones -{ +template < typename T, int DIM > +class Cavitation_qp : public law_qp_bones< T, DIM > { public: - typedef T scalar_type; - typedef static_matrix static_matrix_type; - typedef static_matrix static_matrix_type3D; - const static size_t dimension = DIM; - typedef MaterialData data_type; + typedef T scalar_type; + typedef static_matrix< scalar_type, DIM, DIM > static_matrix_type; + typedef static_matrix< scalar_type, 3, 3 > static_matrix_type3D; + const static size_t dimension = DIM; + typedef MaterialData< scalar_type > data_type; private: - scalar_type - compute_U(const data_type& data, scalar_type J) const - { - switch (data.getType()) - { - case 1: return log(J); - case 2: return (J - 1.0); - case 3: return log10(J); - case 4: return 1.0 / (1.0 - J); - case 5: return (J * J - 1.0); - case 6: return sqrt((J * J - 1.0 - 2.0 * log(J)) / 2.0); - - default: throw std::invalid_argument("NeoHookeanLaw: m_type have to be <= 6"); + scalar_type compute_U( const data_type &data, scalar_type J ) const { + switch ( data.getType() ) { + case 1: + return log( J ); + case 2: + return ( J - 1.0 ); + case 3: + return log10( J ); + case 4: + return 1.0 / ( 1.0 - J ); + case 5: + return ( J * J - 1.0 ); + case 6: + return sqrt( ( J * J - 1.0 - 2.0 * log( J ) ) / 2.0 ); + + default: + throw std::invalid_argument( "NeoHookeanLaw: m_type have to be <= 6" ); } } - scalar_type - compute_T1(const data_type& data, scalar_type J) const - { - switch (data.getType()) - { - case 1: return log(J); - case 2: return J * (J - 1.0); - case 3: return log(J) / (log(10) * log(10)); - case 4: return (J - 1.0) / (J * J); - case 5: return 2 * J * J * (J * J - 1.0); - case 6: return (J * J - 1.0) / 2.0; - - default: throw std::invalid_argument("NeoHookeanLaw: m_type have to be <= 6"); + scalar_type compute_T1( const data_type &data, scalar_type J ) const { + switch ( data.getType() ) { + case 1: + return log( J ); + case 2: + return J * ( J - 1.0 ); + case 3: + return log( J ) / ( log( 10 ) * log( 10 ) ); + case 4: + return ( J - 1.0 ) / ( J * J ); + case 5: + return 2 * J * J * ( J * J - 1.0 ); + case 6: + return ( J * J - 1.0 ) / 2.0; + + default: + throw std::invalid_argument( "NeoHookeanLaw: m_type have to be <= 6" ); } } - scalar_type - compute_T2(const data_type& data, scalar_type J) const - { - switch (data.getType()) - { - case 1: return 1.0; - case 2: return J * (2.0 * J - 1.0); - case 3: return 1.0 / (log(10) * log(10)); - case 4: return (2.0 - J) / (J * J); - case 5: return J * J * (8.0 * J * J - 4.0); - case 6: return J * J; - - default: throw std::invalid_argument("NeoHookeanLaw: m_type have to be <= 6"); + scalar_type compute_T2( const data_type &data, scalar_type J ) const { + switch ( data.getType() ) { + case 1: + return 1.0; + case 2: + return J * ( 2.0 * J - 1.0 ); + case 3: + return 1.0 / ( log( 10 ) * log( 10 ) ); + case 4: + return ( 2.0 - J ) / ( J * J ); + case 5: + return J * J * ( 8.0 * J * J - 4.0 ); + case 6: + return J * J; + + default: + throw std::invalid_argument( "NeoHookeanLaw: m_type have to be <= 6" ); } } - static_tensor - compute_tangent_moduli_A(const data_type& data) const - { + static_tensor< scalar_type, 3 > compute_tangent_moduli_A( const data_type &data ) const { const scalar_type J = this->m_estrain_curr.determinant(); - if (J <= 0.0) - { - const std::string mess = "J= " + std::to_string(J) + " <= 0"; - throw std::invalid_argument(mess); + if ( J <= 0.0 ) { + const std::string mess = "J= " + std::to_string( J ) + " <= 0"; + throw std::invalid_argument( mess ); } - const static_matrix_type3D invF = this->m_estrain_curr.inverse(); + const static_matrix_type3D invF = this->m_estrain_curr.inverse(); const static_matrix_type3D invFt = invF.transpose(); - const static_matrix_type3D C = mechanics::convertFtoCauchyGreenRight(this->m_estrain_curr); + const static_matrix_type3D C = + mechanics::convertFtoCauchyGreenRight( this->m_estrain_curr ); const scalar_type trace_C = C.trace(); - const scalar_type T1 = compute_T1(data, J); - const scalar_type T2 = compute_T2(data, J); + const scalar_type T1 = compute_T1( data, J ); + const scalar_type T2 = compute_T2( data, J ); - const static_tensor I4 = IdentityTensor4(); - const static_tensor invFt_invF = ProductInf(invFt, invF); - const static_tensor invFt_invFt = Kronecker(invFt, invFt); - const static_tensor F_F = Kronecker(this->m_estrain_curr, this->m_estrain_curr); + const static_tensor< scalar_type, 3 > I4 = IdentityTensor4< scalar_type, 3 >(); + const static_tensor< scalar_type, 3 > invFt_invF = ProductInf( invFt, invF ); + const static_tensor< scalar_type, 3 > invFt_invFt = Kronecker( invFt, invFt ); + const static_tensor< scalar_type, 3 > F_F = + Kronecker( this->m_estrain_curr, this->m_estrain_curr ); - const auto Aiso = data.getMu() * std::pow(3.0, -0.25) * - (std::pow(trace_C, -0.25) * I4 - 0.5 * std::pow(trace_C, -5.0 / 4.0) * F_F); - const auto Avol = data.getLambda() * T2 * invFt_invFt + (data.getMu() - data.getLambda() * T1) * invFt_invF; + const auto Aiso = + data.getMu() * std::pow( 3.0, -0.25 ) * + ( std::pow( trace_C, -0.25 ) * I4 - 0.5 * std::pow( trace_C, -5.0 / 4.0 ) * F_F ); + const auto Avol = data.getLambda() * T2 * invFt_invFt + + ( data.getMu() - data.getLambda() * T1 ) * invFt_invF; return Aiso + Avol; } public: - Cavitation_qp() : law_qp_bones() {} + Cavitation_qp() : law_qp_bones< T, DIM >() {} - Cavitation_qp(const point& point, const scalar_type& weight) : law_qp_bones(point, weight) - { - } + Cavitation_qp( const point< scalar_type, DIM > &point, scalar_type weight ) + : law_qp_bones< T, DIM >( point, weight ) {} - static_matrix_type3D - compute_stress3D(const data_type& data) const - { + static_matrix_type3D compute_stress3D( const data_type &data ) const { const scalar_type J = this->m_estrain_curr.determinant(); - if (J <= 0.0) - { - const std::string mess = "J= " + std::to_string(J) + " <= 0"; - throw std::invalid_argument(mess); + if ( J <= 0.0 ) { + const std::string mess = "J= " + std::to_string( J ) + " <= 0"; + throw std::invalid_argument( mess ); } const static_matrix_type3D invF = this->m_estrain_curr.inverse(); - const scalar_type T1 = compute_T1(data, J); - const static_matrix_type3D C = this->m_estrain_curr.transpose() * this->m_estrain_curr; + const scalar_type T1 = compute_T1( data, J ); + const static_matrix_type3D C = this->m_estrain_curr.transpose() * this->m_estrain_curr; - const auto Piso = data.getMu() * std::pow(3.0 * C.trace(), -1.0 / 4.0) * this->m_estrain_curr; - const auto Pvol = (data.getLambda() * T1 - data.getMu()) * invF.transpose(); + const auto Piso = + data.getMu() * std::pow( 3.0 * C.trace(), -1.0 / 4.0 ) * this->m_estrain_curr; + const auto Pvol = ( data.getLambda() * T1 - data.getMu() ) * invF.transpose(); return Piso + Pvol; } - static_matrix_type - compute_stress(const data_type& data) const - { - return convertMatrix(compute_stress3D(data)); + static_matrix_type compute_stress( const data_type &data ) const { + return convertMatrix< scalar_type, DIM >( compute_stress3D( data ) ); } - static_matrix_type3D - compute_stressPrev3D(const data_type& data) const - { + static_matrix_type3D compute_stressPrev3D( const data_type &data ) const { const scalar_type J = this->m_estrain_prev.determinant(); - if (J <= 0.0) - { - const std::string mess = "J= " + std::to_string(J) + " <= 0"; - throw std::invalid_argument(mess); + if ( J <= 0.0 ) { + const std::string mess = "J= " + std::to_string( J ) + " <= 0"; + throw std::invalid_argument( mess ); } const static_matrix_type3D invF = this->m_estrain_prev.inverse(); - const scalar_type T1 = compute_T1(data, J); - const static_matrix_type3D C = this->m_estrain_prev.transpose() * this->m_estrain_prev; + const scalar_type T1 = compute_T1( data, J ); + const static_matrix_type3D C = this->m_estrain_prev.transpose() * this->m_estrain_prev; - const auto Piso = data.getMu() * std::pow(3.0 * C.trace(), -1.0 / 4.0) * this->m_estrain_prev; - const auto Pvol = (data.getLambda() * T1 - data.getMu()) * invF.transpose(); + const auto Piso = + data.getMu() * std::pow( 3.0 * C.trace(), -1.0 / 4.0 ) * this->m_estrain_prev; + const auto Pvol = ( data.getLambda() * T1 - data.getMu() ) * invF.transpose(); return Piso + Pvol; } - scalar_type - compute_energy(const data_type& data) const - { + scalar_type compute_energy( const data_type &data ) const { const scalar_type J = this->m_estrain_curr.determinant(); - if (J <= 0.0) - { - const std::string mess = "J= " + std::to_string(J) + " <= 0"; - throw std::invalid_argument(mess); + if ( J <= 0.0 ) { + const std::string mess = "J= " + std::to_string( J ) + " <= 0"; + throw std::invalid_argument( mess ); } const static_matrix_type3D C = this->m_estrain_curr.transpose() * this->m_estrain_curr; - const scalar_type Wiso = 2.0 * data.getMu() / std::pow(3.0, 5.0 / 4.0) * std::pow(C.trace(), 3.0 / 4.0); + const scalar_type Wiso = + 2.0 * data.getMu() / std::pow( 3.0, 5.0 / 4.0 ) * std::pow( C.trace(), 3.0 / 4.0 ); const scalar_type Wvol = - data.getLambda() / 2.0 * compute_U(data, J) * compute_U(data, J) - data.getMu() * log(J); + data.getLambda() / 2.0 * compute_U( data, J ) * compute_U( data, J ) - + data.getMu() * log( J ); return Wiso + Wvol; } - std::pair> - compute_whole3D(const static_matrix_type3D& F_curr, const data_type& data, bool tangentmodulus = true) - { + std::pair< static_matrix_type3D, static_tensor< scalar_type, 3 > > + compute_whole3D( const static_matrix_type3D &F_curr, const data_type &data, + bool tangentmodulus = true ) { // is always elastic this->m_estrain_curr = F_curr; - const auto PK1 = this->compute_stress3D(data); - const auto A = this->compute_tangent_moduli_A(data); + const auto PK1 = this->compute_stress3D( data ); + const auto A = this->compute_tangent_moduli_A( data ); + + return std::make_pair( PK1, A ); + } + + std::pair< static_matrix_type, static_tensor< scalar_type, DIM > > + compute_whole( const static_matrix_type &F_curr, const data_type &data, + bool tangentmodulus = true ) { + const static_matrix_type3D F3D = convertMatrix3DwithOne( F_curr ); + const auto behaviors3D = compute_whole3D( F3D, data, tangentmodulus ); + + const static_matrix_type PK1 = convertMatrix< scalar_type, DIM >( behaviors3D.first ); + const static_tensor< scalar_type, DIM > A = + convertTensor< scalar_type, DIM >( behaviors3D.second ); - return std::make_pair(PK1, A); + return std::make_pair( PK1, A ); } - std::pair> - compute_whole(const static_matrix_type& F_curr, const data_type& data, bool tangentmodulus = true) - { - const static_matrix_type3D F3D = convertMatrix3DwithOne(F_curr); - const auto behaviors3D = compute_whole3D(F3D, data, tangentmodulus); + static_matrix_type compute_stress( const static_matrix_type &F_curr, const data_type &data ) { + const static_matrix_type3D F3D = convertMatrix3DwithOne( F_curr ); + const auto behaviors3D = compute_whole3D( F3D, data, false ); - const static_matrix_type PK1 = convertMatrix(behaviors3D.first); - const static_tensor A = convertTensor(behaviors3D.second); + const static_matrix_type PK1 = convertMatrix< scalar_type, DIM >( behaviors3D.first ); - return std::make_pair(PK1, A); + return PK1; } }; -} +} // namespace mechanics +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/HenckyMises/HenckyMises_qp.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/HenckyMises/HenckyMises_qp.hpp index cec8e259..a677cb08 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/HenckyMises/HenckyMises_qp.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/HenckyMises/HenckyMises_qp.hpp @@ -36,101 +36,100 @@ #define _USE_MATH_DEFINES #include -namespace disk -{ - +namespace disk { +namespace mechanics { // Law for Linear Isotropic and Kinematic Hardening model with von Mises Criteria in small // Input : symetric stain tensor(Gs) // dev = normL2(Gs - trace(Gs) / dim * Id) -// Stress : sigma = 2 *\tilde{mu}(dev(Gs)) * Gs + \tilde{lambda}(dev(Gs)) * trace(Gs) * Id +// Stress : sigma = 2 *\tilde{mu}(dev(Gs)) * Gs + \tilde{lambda}(dev(Gs)) * trace(Gs) * +// Id // \tilde{mu}(dev(Gs)) = mu * (1 + (1 + dev(Gs)) ^ {-1 / 2}) // \tilde{lambda}(dev(Gs)) = ((lambda + mu / 2) - mu / 2 * (1 + dev(Gs)) ^ {-1 / 2}) // Tangent Moduli : C = 2 * mu * I4 + lambda * prod_Kronecker(Id, Id) / // it is the elastic moduli -template -class HenckyMises_qp : public law_qp_bones -{ +template < typename T, int DIM > +class HenckyMises_qp : public law_qp_bones< T, DIM > { public: - typedef T scalar_type; - typedef static_matrix static_matrix_type; - typedef static_matrix static_matrix_type3D; - const static size_t dimension = DIM; - typedef MaterialData data_type; + typedef T scalar_type; + typedef static_matrix< scalar_type, DIM, DIM > static_matrix_type; + typedef static_matrix< scalar_type, 3, 3 > static_matrix_type3D; + const static size_t dimension = DIM; + typedef MaterialData< scalar_type > data_type; private: - scalar_type - tildemu(const data_type& data, const scalar_type& normL2dev) const - { - return data.getMu() * (1.0 + 1.0 / std::sqrt(1 + normL2dev * normL2dev)); + scalar_type tildemu( const data_type &data, scalar_type normL2dev ) const { + return data.getMu() * ( 1.0 + 1.0 / std::sqrt( 1 + normL2dev * normL2dev ) ); } - scalar_type - tildelambda(const data_type& data, const scalar_type& normL2dev) const - { - return (data.getLambda() + data.getMu() / 2.0) - data.getMu() / (2.0 * std::sqrt(1.0 + normL2dev * normL2dev)); + scalar_type tildelambda( const data_type &data, scalar_type normL2dev ) const { + return ( data.getLambda() + data.getMu() / 2.0 ) - + data.getMu() / ( 2.0 * std::sqrt( 1.0 + normL2dev * normL2dev ) ); } - scalar_type - derivativetildemu(const data_type& data, const scalar_type& normL2dev) const - { - const auto term3_2 = (1.0 + normL2dev * normL2dev) * std::sqrt(1.0 + normL2dev * normL2dev); + scalar_type derivativetildemu( const data_type &data, scalar_type normL2dev ) const { + const auto term3_2 = + ( 1.0 + normL2dev * normL2dev ) * std::sqrt( 1.0 + normL2dev * normL2dev ); return -data.getMu() * normL2dev / term3_2; } - scalar_type - derivativetildelambda(const data_type& data, const scalar_type& normL2dev) const - { - return derivativetildemu(normL2dev) / scalar_type(2); + scalar_type derivativetildelambda( const data_type &data, scalar_type normL2dev ) const { + return derivativetildemu( normL2dev ) / scalar_type( 2 ); } public: - HenckyMises_qp() : law_qp_bones() {} + HenckyMises_qp() : law_qp_bones< T, DIM >() {} - HenckyMises_qp(const point& point, const scalar_type& weight) : - law_qp_bones(point, weight) - { - } + HenckyMises_qp( const point< scalar_type, DIM > &point, scalar_type weight ) + : law_qp_bones< T, DIM >( point, weight ) {} - static_matrix_type3D - compute_stress3D(const data_type& data) const - { + static_matrix_type3D compute_stress3D( const data_type &data ) const { const static_matrix_type3D Id = static_matrix_type3D::Identity(); const static_matrix_type3D Gs = this->m_estrain_curr; - const scalar_type normFrodev = deviator(Gs).norm(); + const scalar_type normFrodev = deviator( Gs ).norm(); - return tildemu(data, normFrodev) * Gs + tildelambda(data, normFrodev) * Gs.trace() * Id; + return tildemu( data, normFrodev ) * Gs + tildelambda( data, normFrodev ) * Gs.trace() * Id; } - static_matrix_type - compute_stress(const data_type& data) const - { + static_matrix_type compute_stress( const data_type &data ) const { const static_matrix_type Id = static_matrix_type::Identity(); - const static_matrix_type Gs = this->m_estrain_curr.block(0, 0, DIM, DIM); + const static_matrix_type Gs = this->m_estrain_curr.block( 0, 0, DIM, DIM ); - const scalar_type normFrodev = deviator(Gs).norm(); + const scalar_type normFrodev = deviator( Gs ).norm(); - return tildemu(data, normFrodev) * Gs + tildelambda(data, normFrodev) * Gs.trace() * Id; + return tildemu( data, normFrodev ) * Gs + tildelambda( data, normFrodev ) * Gs.trace() * Id; } - std::pair> - compute_whole(const static_matrix_type& strain_curr, const data_type& data, bool tangentmodulus = true) - { - static_tensor Cep = this->elastic_modulus(data); + std::pair< static_matrix_type, static_tensor< scalar_type, DIM > > + compute_whole( const static_matrix_type &strain_curr, const data_type &data, + bool tangentmodulus = true ) { + static_tensor< scalar_type, DIM > Cep = this->elastic_modulus( data ); + + // is always elastic + this->m_estrain_curr = convertMatrix3D( strain_curr ); + + // compute Cauchy stress + const static_matrix_type stress = this->compute_stress( data ); + + return std::make_pair( stress, Cep ); + } + static_matrix_type compute_stress( const static_matrix_type &strain_curr, + const data_type &data ) { // is always elastic - this->m_estrain_curr = convertMatrix3D(strain_curr); + this->m_estrain_curr = convertMatrix3D( strain_curr ); // compute Cauchy stress - const static_matrix_type stress = this->compute_stress(data); + const static_matrix_type stress = this->compute_stress( data ); - return std::make_pair(stress, Cep); + return stress; } }; -} +} // namespace mechanics +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/IsotropicHardeningVMis/IsotropicHardeningVMis_qp.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/IsotropicHardeningVMis/IsotropicHardeningVMis_qp.hpp index b871df6d..e6e9b129 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/IsotropicHardeningVMis/IsotropicHardeningVMis_qp.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/IsotropicHardeningVMis/IsotropicHardeningVMis_qp.hpp @@ -36,250 +36,228 @@ #define _USE_MATH_DEFINES #include -namespace disk -{ - +namespace disk { +namespace mechanics { // Law for Isotropic Hardening model with von Mises Criteria in small deformation // where the curve (p, R(p)) is given point by point // see https://www.code-aster.org/doc/default/en/man_r/r5/r5.03.02.pdf section 3.1.2 -template -class IsotropicHardeningVMis_qp : public law_qp_bones -{ +template < typename T, int DIM > +class IsotropicHardeningVMis_qp : public law_qp_bones< T, DIM > { public: - const static size_t dimension = DIM; - typedef T scalar_type; - typedef static_matrix static_matrix_type; - typedef static_matrix static_matrix_type3D; - typedef MaterialData data_type; + const static size_t dimension = DIM; + typedef T scalar_type; + typedef static_matrix< scalar_type, DIM, DIM > static_matrix_type; + typedef static_matrix< scalar_type, 3, 3 > static_matrix_type3D; + typedef MaterialData< scalar_type > data_type; private: // internal variables at previous step static_matrix_type3D m_pstrain_prev; // plastic strain - scalar_type m_p_prev; // cumulate plastic strain + scalar_type m_p_prev; // cumulate plastic strain // internal variables at current step - static_matrix_type3D m_pstrain_curr; // plastic strain - scalar_type m_p_curr; // cumulate plastic strain - bool m_is_plastic_curr; // the gauss point is plastic ? + static_matrix_type3D m_pstrain_curr; // plastic strain + scalar_type m_p_curr; // cumulate plastic strain + bool m_is_plastic_curr; // the gauss point is plastic ? public: - IsotropicHardeningVMis_qp() : - law_qp_bones(), m_pstrain_prev(static_matrix_type3D::Zero()), m_p_prev(scalar_type(0)), - m_pstrain_curr(static_matrix_type3D::Zero()), m_p_curr(scalar_type(0)), m_is_plastic_curr(false) - { - } - - IsotropicHardeningVMis_qp(const point& point, const scalar_type& weight) : - law_qp_bones(point, weight), m_pstrain_prev(static_matrix_type3D::Zero()), m_p_prev(scalar_type(0)), - m_pstrain_curr(static_matrix_type3D::Zero()), m_p_curr(scalar_type(0)), m_is_plastic_curr(false) - { - } - - bool - is_plastic() const - { - return m_is_plastic_curr; + IsotropicHardeningVMis_qp() + : law_qp_bones< T, DIM >(), + m_pstrain_prev( static_matrix_type3D::Zero() ), + m_p_prev( scalar_type( 0 ) ), + m_pstrain_curr( static_matrix_type3D::Zero() ), + m_p_curr( scalar_type( 0 ) ), + m_is_plastic_curr( false ) {} + + IsotropicHardeningVMis_qp( const point< scalar_type, DIM > &point, scalar_type weight ) + : law_qp_bones< T, DIM >( point, weight ), + m_pstrain_prev( static_matrix_type3D::Zero() ), + m_p_prev( scalar_type( 0 ) ), + m_pstrain_curr( static_matrix_type3D::Zero() ), + m_p_curr( scalar_type( 0 ) ), + m_is_plastic_curr( false ) {} + + bool is_plastic() const { return m_is_plastic_curr; } + + static_matrix_type3D getPlasticStrain() const { return m_pstrain_curr; } + + static_matrix_type getTotalStrain() const { + return convertMatrix< scalar_type, DIM >( this->m_estrain_curr + m_pstrain_curr ); } - static_matrix_type3D - getPlasticStrain() const - { - return m_pstrain_curr; + static_matrix_type getTotalStrainPrev() const { + return convertMatrix< scalar_type, DIM >( this->m_estrain_prev + m_pstrain_prev ); } - static_matrix_type - getTotalStrain() const - { - return convertMatrix(this->m_estrain_curr + m_pstrain_curr); - } - - static_matrix_type - getTotalStrainPrev() const - { - return convertMatrix(this->m_estrain_prev + m_pstrain_prev); - } + scalar_type getEquivalentPlasticStrain() const { return m_p_curr; } - scalar_type - getEquivalentPlasticStrain() const - { - return m_p_curr; + void update() { + law_qp_bones< T, DIM >::update(); + m_pstrain_prev = m_pstrain_curr; + m_p_prev = m_p_curr; } - void - update() - { - law_qp_bones::update(); - m_pstrain_prev = m_pstrain_curr; - m_p_prev = m_p_curr; + void restore() { + law_qp_bones< T, DIM >::restore(); + m_pstrain_curr = m_pstrain_prev; + m_p_curr = m_p_prev; } - static_matrix_type3D - compute_stress3D(const data_type& data) const - { + static_matrix_type3D compute_stress3D( const data_type &data ) const { const static_matrix_type3D Id = static_matrix_type3D::Identity(); - const auto stress = - 2 * data.getMu() * this->m_estrain_curr + data.getLambda() * this->m_estrain_curr.trace() * Id; + const auto stress = 2 * data.getMu() * this->m_estrain_curr + + data.getLambda() * this->m_estrain_curr.trace() * Id; return stress; } - static_matrix_type - compute_stress(const data_type& data) const - { - return convertMatrix(compute_stress3D(data)); + static_matrix_type compute_stress( const data_type &data ) const { + return convertMatrix< scalar_type, DIM >( compute_stress3D( data ) ); } - static_matrix_type3D - compute_stress3DPrev(const data_type& data) const - { + static_matrix_type3D compute_stress3DPrev( const data_type &data ) const { const static_matrix_type3D Id = static_matrix_type3D::Identity(); - const auto stress = - 2 * data.getMu() * this->m_estrain_prev + data.getLambda() * this->m_estrain_prev.trace() * Id; + const auto stress = 2 * data.getMu() * this->m_estrain_prev + + data.getLambda() * this->m_estrain_prev.trace() * Id; return stress; } - static_matrix_type - compute_stressPrev(const data_type& data) const - { + static_matrix_type compute_stressPrev( const data_type &data ) const { const static_matrix_type3D Id = static_matrix_type3D::Identity(); - const auto stress = - 2 * data.getMu() * this->m_estrain_prev + data.getLambda() * this->m_estrain_prev.trace() * Id; + const auto stress = 2 * data.getMu() * this->m_estrain_prev + + data.getLambda() * this->m_estrain_prev.trace() * Id; - return convertMatrix(stress); + return convertMatrix< scalar_type, DIM >( stress ); } - std::pair> - compute_whole3D(const static_matrix_type3D& strain_curr, const data_type& data, bool tangentmodulus = true) - { - static_tensor Cep = this->elastic_modulus3D(data); - const auto RpCurve = data.getRpCurve(); - const auto nb_point = RpCurve.size(); + std::pair< static_matrix_type3D, static_tensor< scalar_type, 3 > > + compute_whole3D( const static_matrix_type3D &strain_curr, const data_type &data, + bool tangentmodulus = true ) { + static_tensor< scalar_type, 3 > Cep = this->elastic_modulus3D( data ); + const auto RpCurve = data.getRpCurve(); + const auto nb_point = RpCurve.size(); - const static_matrix_type3D incr_strain = strain_curr - convertMatrix3D(this->getTotalStrainPrev()); - const static_matrix_type3D estrain_trial = this->m_estrain_prev + incr_strain; // elastic strain trial + const static_matrix_type3D incr_strain = + strain_curr - convertMatrix3D( this->getTotalStrainPrev() ); + const static_matrix_type3D estrain_trial = + this->m_estrain_prev + incr_strain; // elastic strain trial - if (nb_point == 0) - { + if ( nb_point == 0 ) { + throw std::runtime_error( "The traction curved is not defined." ); // We don't have points for the traction curve // we suppose that we are in linear elasticity // elastic evolution m_is_plastic_curr = false; // update this->m_estrain_curr = estrain_trial; - m_pstrain_curr = m_pstrain_prev; - m_p_curr = m_p_prev; - } - else - { + m_pstrain_curr = m_pstrain_prev; + m_p_curr = m_p_prev; + } else { // we search i0 such that p_prev \in [p_i0, p_{i0+1}] size_t i0 = nb_point - 2; - for (size_t i = 0; i < nb_point - 1; i++) - { - if (m_p_prev < RpCurve[i + 1].getP()) - { + for ( size_t i = 0; i < nb_point - 1; i++ ) { + if ( m_p_prev < RpCurve[i + 1].getP() ) { i0 = i; break; } } const scalar_type Rp0 = RpCurve[i0].getRp(); - const scalar_type p0 = RpCurve[i0].getP(); - const scalar_type H0 = (RpCurve[i0 + 1].getRp() - Rp0) / (RpCurve[i0 + 1].getP() - p0); + const scalar_type p0 = RpCurve[i0].getP(); + const scalar_type H0 = + ( RpCurve[i0 + 1].getRp() - Rp0 ) / ( RpCurve[i0 + 1].getP() - p0 ); // prediction - const static_matrix_type3D se = 2 * data.getMu() * deviator(estrain_trial); - const scalar_type se_eq = this->sigmaeq(se); - const scalar_type Phi_trial0 = se_eq - Rp0 - H0 * (m_p_prev - p0); + const static_matrix_type3D se = 2 * data.getMu() * deviator( estrain_trial ); + const scalar_type se_eq = this->sigmaeq( se ); + const scalar_type Phi_trial0 = se_eq - Rp0 - H0 * ( m_p_prev - p0 ); // debug informations // std::cout << "point: " << i0 << " on " << nb_point << std::endl; // std::cout << "Rp0: " << Rp0 << ", p0: " << p0 << ", H0: " << H0 << std::endl; - // std::cout << "se_eq: " << se_eq << ", Rp " << Rp0 + H0 * (m_p_prev - p0) << ", Phi: " << Phi_trial0 << - // std::endl; + // std::cout << "se_eq: " << se_eq << ", Rp " << Rp0 + H0 * (m_p_prev - p0) << ", Phi: " + // << Phi_trial0 << std::endl; - if ((std::abs(se.trace()) / se.norm()) > 1E-8) - { - // std::cout << std::abs(se.trace()) << ", " << se.norm() << ", " << (std::abs(se.trace()) / se.norm()) + if ( ( std::abs( se.trace() ) / se.norm() ) > 1E-8 ) { + // std::cout << std::abs(se.trace()) << ", " << se.norm() << ", " << + // (std::abs(se.trace()) / se.norm()) // << std::endl; - std::string mess = "Se_trace= " + std::to_string(se.trace()) + " <= 0"; - throw std::invalid_argument(mess); + std::string mess = "Se_trace= " + std::to_string( se.trace() ) + " <= 0"; + throw std::invalid_argument( mess ); } // check - if (Phi_trial0 < scalar_type(0)) - { + if ( Phi_trial0 < scalar_type( 0 ) ) { // elastic evolution m_is_plastic_curr = false; - } - else - { + } else { // plastic evolution m_is_plastic_curr = true; } // corection - if (m_is_plastic_curr) - { + if ( m_is_plastic_curr ) { const scalar_type troismu = 3 * data.getMu(); - size_t i1 = nb_point - 2; - for (size_t i = i0 + 1; i < nb_point - 1; i++) - { - const scalar_type eq = RpCurve[i].getRp() - troismu * (m_p_prev - RpCurve[i].getP()) - se_eq; + size_t i1 = nb_point - 2; + for ( size_t i = i0 + 1; i < nb_point - 1; i++ ) { + const scalar_type eq = + RpCurve[i].getRp() - troismu * ( m_p_prev - RpCurve[i].getP() ) - se_eq; - if (eq > scalar_type(0)) - { + if ( eq > scalar_type( 0 ) ) { i1 = i - 1; break; } } const scalar_type Rp1 = RpCurve[i1].getRp(); - const scalar_type p1 = RpCurve[i1].getP(); - const scalar_type H1 = (RpCurve[i1 + 1].getRp() - Rp1) / (RpCurve[i1 + 1].getP() - p1); + const scalar_type p1 = RpCurve[i1].getP(); + const scalar_type H1 = + ( RpCurve[i1 + 1].getRp() - Rp1 ) / ( RpCurve[i1 + 1].getP() - p1 ); - const scalar_type Phi_trial1 = se_eq - Rp1 - H1 * (m_p_prev - p1); + const scalar_type Phi_trial1 = se_eq - Rp1 - H1 * ( m_p_prev - p1 ); - const scalar_type dem = troismu + H1; - const static_matrix_type3D normal = scalar_type(3.) * se / (scalar_type(2.) * se_eq); - const scalar_type delta_p = Phi_trial1 / dem; + const scalar_type dem = troismu + H1; + const static_matrix_type3D normal = + scalar_type( 3. ) * se / ( scalar_type( 2. ) * se_eq ); + const scalar_type delta_p = Phi_trial1 / dem; - // std::cout << "P: " << m_p_prev << ", Rp: " << Rp1 + H1 * (m_p_prev - p1) << ", H: " << H1 + // std::cout << "P: " << m_p_prev << ", Rp: " << Rp1 + H1 * (m_p_prev - p1) << ", H: + // " << H1 // << ", Si: " << se_eq << ", dp: " << delta_p << std::endl; // update - m_p_curr = m_p_prev + delta_p; + m_p_curr = m_p_prev + delta_p; this->m_estrain_curr = estrain_trial - delta_p * normal; - m_pstrain_curr = m_pstrain_prev + delta_p * normal; + m_pstrain_curr = m_pstrain_prev + delta_p * normal; - if (tangentmodulus) - { + if ( tangentmodulus ) { // compute cep coherent - const static_tensor nxn = Kronecker(normal, normal); - const static_tensor Is = IdentitySymTensor4(); - const static_tensor Pdev = Is - IxI() / scalar_type(3); - const scalar_type mu2 = data.getMu() * data.getMu(); - - Cep += 4 * mu2 * (delta_p / se_eq - 1.0 / dem) * nxn - 6.0 * mu2 * delta_p / se_eq * Pdev; + const static_tensor< scalar_type, 3 > nxn = Kronecker( normal, normal ); + const static_tensor< scalar_type, 3 > Is = + IdentitySymTensor4< scalar_type, 3 >(); + const static_tensor< scalar_type, 3 > Pdev = + Is - IxI< scalar_type, 3 >() / scalar_type( 3 ); + const scalar_type mu2 = data.getMu() * data.getMu(); + + Cep += 4 * mu2 * ( delta_p / se_eq - 1.0 / dem ) * nxn - + 6.0 * mu2 * delta_p / se_eq * Pdev; } - } - else - { + } else { // update this->m_estrain_curr = estrain_trial; - m_pstrain_curr = m_pstrain_prev; - m_p_curr = m_p_prev; + m_pstrain_curr = m_pstrain_prev; + m_p_curr = m_p_prev; } } - if (std::abs(m_pstrain_curr.trace()) > 1E-8) - { - const std::string mess = "eps_p= " + std::to_string(m_pstrain_curr.trace()) + " <= 0"; - throw std::invalid_argument(mess); + if ( std::abs( m_pstrain_curr.trace() ) > 1E-8 ) { + const std::string mess = "eps_p= " + std::to_string( m_pstrain_curr.trace() ) + " <= 0"; + throw std::invalid_argument( mess ); } // std::cout << "ep:" << std::endl; @@ -292,21 +270,33 @@ class IsotropicHardeningVMis_qp : public law_qp_bones // std::cout << m_p_curr << std::endl; // compute Cauchy stress - const static_matrix_type3D stress = this->compute_stress3D(data); + const static_matrix_type3D stress = this->compute_stress3D( data ); - return std::make_pair(stress, Cep); + return std::make_pair( stress, Cep ); } - std::pair> - compute_whole(const static_matrix_type& strain_curr, const data_type& data, bool tangentmodulus = true) - { - const static_matrix_type3D strain3D_curr = convertMatrix3D(strain_curr); - const auto behaviors3D = this->compute_whole3D(strain3D_curr, data, tangentmodulus); + std::pair< static_matrix_type, static_tensor< scalar_type, DIM > > + compute_whole( const static_matrix_type &strain_curr, const data_type &data, + bool tangentmodulus = true ) { + const static_matrix_type3D strain3D_curr = convertMatrix3D( strain_curr ); + const auto behaviors3D = this->compute_whole3D( strain3D_curr, data, tangentmodulus ); - const static_matrix_type stress = convertMatrix(behaviors3D.first); - const static_tensor Cep = convertTensor(behaviors3D.second); + const static_matrix_type stress = convertMatrix< scalar_type, DIM >( behaviors3D.first ); + const static_tensor< scalar_type, DIM > Cep = + convertTensor< scalar_type, DIM >( behaviors3D.second ); - return std::make_pair(stress, Cep); + return std::make_pair( stress, Cep ); + } + + static_matrix_type compute_stress( const static_matrix_type &strain_curr, + const data_type &data ) { + const static_matrix_type3D strain3D_curr = convertMatrix3D( strain_curr ); + const auto behaviors3D = this->compute_whole3D( strain3D_curr, data, false ); + + const static_matrix_type stress = convertMatrix< scalar_type, DIM >( behaviors3D.first ); + + return stress; } }; -} +} // namespace mechanics +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/LinearElasticityLaw/LinearElasticityLaw.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/LinearElasticityLaw/LinearElasticityLaw.hpp index 7fb2d93d..beaa358d 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/LinearElasticityLaw/LinearElasticityLaw.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/LinearElasticityLaw/LinearElasticityLaw.hpp @@ -34,89 +34,89 @@ #include "diskpp/mechanics/behaviors/tensor_conversion.hpp" #include "diskpp/mesh/point.hpp" -namespace disk -{ - +namespace disk { +namespace mechanics { // Law for linear elasticity -template -class LinearElasticity_qp : public law_qp_bones -{ +template < typename T, int DIM > +class LinearElasticity_qp : public law_qp_bones< T, DIM > { public: - const static size_t dimension = DIM; - typedef T scalar_type; - typedef static_matrix static_matrix_type; - typedef static_matrix static_matrix_type3D; - typedef MaterialData data_type; + const static size_t dimension = DIM; + typedef T scalar_type; + typedef static_matrix< scalar_type, DIM, DIM > static_matrix_type; + typedef static_matrix< scalar_type, 3, 3 > static_matrix_type3D; + typedef MaterialData< scalar_type > data_type; - LinearElasticity_qp() : law_qp_bones() {} + LinearElasticity_qp() : law_qp_bones< T, DIM >() {} - LinearElasticity_qp(const point& point, const scalar_type& weight) : - law_qp_bones(point, weight) - { - } + LinearElasticity_qp( const point< scalar_type, DIM > &point, scalar_type weight ) + : law_qp_bones< T, DIM >( point, weight ) {} - static_matrix_type3D - compute_stress3D(const data_type& data) const - { + static_matrix_type3D compute_stress3D( const data_type &data ) const { const static_matrix_type3D Id = static_matrix_type3D::Identity(); - const auto stress = - 2 * data.getMu() * this->m_estrain_curr + data.getLambda() * this->m_estrain_curr.trace() * Id; + const auto stress = 2 * data.getMu() * this->m_estrain_curr + + data.getLambda() * this->m_estrain_curr.trace() * Id; return stress; } - static_matrix_type - compute_stress(const data_type& data) const - { - return convertMatrix(compute_stress3D(data)); + static_matrix_type compute_stress( const data_type &data ) const { + return convertMatrix< scalar_type, DIM >( compute_stress3D( data ) ); } - static_matrix_type3D - compute_stress3DPrev(const data_type& data) const - { + static_matrix_type3D compute_stress3DPrev( const data_type &data ) const { const static_matrix_type3D Id = static_matrix_type3D::Identity(); - const auto stress = - 2 * data.getMu() * this->m_estrain_prev + data.getLambda() * this->m_estrain_prev.trace() * Id; + const auto stress = 2 * data.getMu() * this->m_estrain_prev + + data.getLambda() * this->m_estrain_prev.trace() * Id; return stress; } - static_matrix_type - compute_stressPrev(const data_type& data) const - { + static_matrix_type compute_stressPrev( const data_type &data ) const { const static_matrix_type3D Id = static_matrix_type3D::Identity(); - const auto stress = - 2 * data.getMu() * this->m_estrain_prev + data.getLambda() * this->m_estrain_prev.trace() * Id; + const auto stress = 2 * data.getMu() * this->m_estrain_prev + + data.getLambda() * this->m_estrain_prev.trace() * Id; - return convertMatrix(stress); + return convertMatrix< scalar_type, DIM >( stress ); } - std::pair> - compute_whole3D(const static_matrix_type3D& strain_curr, const data_type& data, bool tangentmodulus = true) - { - this->m_estrain_curr = strain_curr; - const static_tensor C = this->elastic_modulus3D(data); + std::pair< static_matrix_type3D, static_tensor< scalar_type, 3 > > + compute_whole3D( const static_matrix_type3D &strain_curr, const data_type &data, + bool tangentmodulus = true ) { + this->m_estrain_curr = strain_curr; + const static_tensor< scalar_type, 3 > C = this->elastic_modulus3D( data ); // compute Cauchy stress - const static_matrix_type3D stress = this->compute_stress3D(data); + const static_matrix_type3D stress = this->compute_stress3D( data ); - return std::make_pair(stress, C); + return std::make_pair( stress, C ); } - std::pair> - compute_whole(const static_matrix_type& strain_curr, const data_type& data, bool tangentmodulus = true) - { - const static_matrix_type3D strain3D_curr = convertMatrix3D(strain_curr); - const auto behaviors3D = this->compute_whole3D(strain3D_curr, data, tangentmodulus); + std::pair< static_matrix_type, static_tensor< scalar_type, DIM > > + compute_whole( const static_matrix_type &strain_curr, const data_type &data, + bool tangentmodulus = true ) { + const static_matrix_type3D strain3D_curr = convertMatrix3D( strain_curr ); + const auto behaviors3D = this->compute_whole3D( strain3D_curr, data, tangentmodulus ); - const static_matrix_type stress = convertMatrix(behaviors3D.first); - const static_tensor Cep = convertTensor(behaviors3D.second); + const static_matrix_type stress = convertMatrix< scalar_type, DIM >( behaviors3D.first ); + const static_tensor< scalar_type, DIM > Cep = + convertTensor< scalar_type, DIM >( behaviors3D.second ); + + return std::make_pair( stress, Cep ); + } - return std::make_pair(stress, Cep); + static_matrix_type compute_stress( const static_matrix_type &strain_curr, + const data_type &data ) { + const static_matrix_type3D strain3D_curr = convertMatrix3D( strain_curr ); + const auto behaviors3D = this->compute_whole3D( strain3D_curr, data, false ); + + const static_matrix_type stress = convertMatrix< scalar_type, DIM >( behaviors3D.first ); + + return stress; } }; -} +} // namespace mechanics +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/LinearIsotropicAndKinematicHardening/LinearIsotropicAndKinematicHardening_qp.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/LinearIsotropicAndKinematicHardening/LinearIsotropicAndKinematicHardening_qp.hpp index 0a37fa89..14d236b9 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/LinearIsotropicAndKinematicHardening/LinearIsotropicAndKinematicHardening_qp.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/LinearIsotropicAndKinematicHardening/LinearIsotropicAndKinematicHardening_qp.hpp @@ -36,196 +36,176 @@ #define _USE_MATH_DEFINES #include -namespace disk -{ +namespace disk { +namespace mechanics { // Law for Linear Isotropic and Kinematic Hardening model with von Mises Criteria in small -template -class LinearIsotropicAndKinematicHardening_qp : public law_qp_bones -{ +template < typename T, int DIM > +class LinearIsotropicAndKinematicHardening_qp : public law_qp_bones< T, DIM > { public: - const static size_t dimension = DIM; - typedef T scalar_type; - typedef static_matrix static_matrix_type; - typedef static_matrix static_matrix_type3D; - typedef MaterialData data_type; + const static size_t dimension = DIM; + typedef T scalar_type; + typedef static_matrix< scalar_type, DIM, DIM > static_matrix_type; + typedef static_matrix< scalar_type, 3, 3 > static_matrix_type3D; + typedef MaterialData< scalar_type > data_type; private: // internal variables at previous step static_matrix_type3D m_pstrain_prev; // plastic strain - scalar_type m_p_prev; // cumulate plastic strain + scalar_type m_p_prev; // cumulate plastic strain // internal variables at current step - static_matrix_type3D m_pstrain_curr; // plastic strain - scalar_type m_p_curr; // cumulate plastic strain - bool m_is_plastic_curr; // the gauss point is plastic ? + static_matrix_type3D m_pstrain_curr; // plastic strain + scalar_type m_p_curr; // cumulate plastic strain + bool m_is_plastic_curr; // the gauss point is plastic ? public: - LinearIsotropicAndKinematicHardening_qp() : - law_qp_bones(), m_pstrain_prev(static_matrix_type3D::Zero()), m_p_prev(scalar_type(0)), - m_pstrain_curr(static_matrix_type3D::Zero()), m_p_curr(scalar_type(0)), m_is_plastic_curr(false) - { + LinearIsotropicAndKinematicHardening_qp() + : law_qp_bones< T, DIM >(), + m_pstrain_prev( static_matrix_type3D::Zero() ), + m_p_prev( scalar_type( 0 ) ), + m_pstrain_curr( static_matrix_type3D::Zero() ), + m_p_curr( scalar_type( 0 ) ), + m_is_plastic_curr( false ) {} + + LinearIsotropicAndKinematicHardening_qp( const point< scalar_type, DIM > &point, + scalar_type weight ) + : law_qp_bones< T, DIM >( point, weight ), + m_pstrain_prev( static_matrix_type3D::Zero() ), + m_p_prev( scalar_type( 0 ) ), + m_pstrain_curr( static_matrix_type3D::Zero() ), + m_p_curr( scalar_type( 0 ) ), + m_is_plastic_curr( false ) {} + + bool is_plastic() const { return m_is_plastic_curr; } + + static_matrix_type3D getPlasticStrain() const { return m_pstrain_curr; } + + static_matrix_type getTotalStrain() const { + return convertMatrix< scalar_type, DIM >( this->m_estrain_curr + this->m_pstrain_curr ); } - LinearIsotropicAndKinematicHardening_qp(const point& point, const scalar_type& weight) : - law_qp_bones(point, weight), m_pstrain_prev(static_matrix_type3D::Zero()), m_p_prev(scalar_type(0)), - m_pstrain_curr(static_matrix_type3D::Zero()), m_p_curr(scalar_type(0)), m_is_plastic_curr(false) - { + static_matrix_type getTotalStrainPrev() const { + return convertMatrix< scalar_type, DIM >( this->m_estrain_prev + this->m_pstrain_prev ); } - bool - is_plastic() const - { - return m_is_plastic_curr; - } - - static_matrix_type3D - getPlasticStrain() const - { - return m_pstrain_curr; - } - - static_matrix_type - getTotalStrain() const - { - return convertMatrix(this->m_estrain_curr + this->m_pstrain_curr); - } + scalar_type getEquivalentPlasticStrain() const { return m_p_curr; } - static_matrix_type - getTotalStrainPrev() const - { - return convertMatrix(this->m_estrain_prev + this->m_pstrain_prev); - } - - scalar_type - getEquivalentPlasticStrain() const - { - return m_p_curr; + void update() { + law_qp_bones< T, DIM >::update(); + m_pstrain_prev = m_pstrain_curr; + m_p_prev = m_p_curr; } - void - update() - { - law_qp_bones::update(); - m_pstrain_prev = m_pstrain_curr; - m_p_prev = m_p_curr; + void restore() { + law_qp_bones< T, DIM >::restore(); + m_pstrain_curr = m_pstrain_prev; + m_p_curr = m_p_prev; } - static_matrix_type3D - compute_stress3D(const data_type& data) const - { + static_matrix_type3D compute_stress3D( const data_type &data ) const { const static_matrix_type3D Id = static_matrix_type3D::Identity(); - const auto stress = - 2 * data.getMu() * this->m_estrain_curr + data.getLambda() * this->m_estrain_curr.trace() * Id; + const auto stress = 2 * data.getMu() * this->m_estrain_curr + + data.getLambda() * this->m_estrain_curr.trace() * Id; return stress; } - static_matrix_type - compute_stress(const data_type& data) const - { - return convertMatrix(compute_stress3D(data)); + static_matrix_type compute_stress( const data_type &data ) const { + return convertMatrix< scalar_type, DIM >( compute_stress3D( data ) ); } - static_matrix_type3D - compute_stress3DPrev(const data_type& data) const - { + static_matrix_type3D compute_stress3DPrev( const data_type &data ) const { const static_matrix_type3D Id = static_matrix_type3D::Identity(); - const auto stress = - 2 * data.getMu() * this->m_estrain_prev + data.getLambda() * this->m_estrain_prev.trace() * Id; + const auto stress = 2 * data.getMu() * this->m_estrain_prev + + data.getLambda() * this->m_estrain_prev.trace() * Id; return stress; } - static_matrix_type - compute_stressPrev(const data_type& data) const - { + static_matrix_type compute_stressPrev( const data_type &data ) const { const static_matrix_type3D Id = static_matrix_type3D::Identity(); - const auto stress = - 2 * data.getMu() * this->m_estrain_prev + data.getLambda() * this->m_estrain_prev.trace() * Id; + const auto stress = 2 * data.getMu() * this->m_estrain_prev + + data.getLambda() * this->m_estrain_prev.trace() * Id; - return convertMatrix(stress); + return convertMatrix< scalar_type, DIM >( stress ); } - std::pair> - compute_whole3D(const static_matrix_type3D& strain_curr, const data_type& data, bool tangentmodulus = true) - { - static_tensor Cep = this->elastic_modulus3D(data); + std::pair< static_matrix_type3D, static_tensor< scalar_type, 3 > > + compute_whole3D( const static_matrix_type3D &strain_curr, const data_type &data, + bool tangentmodulus = true ) { + static_tensor< scalar_type, 3 > Cep = this->elastic_modulus3D( data ); // prediction - const static_matrix_type3D incr_strain = strain_curr - convertMatrix3D(this->getTotalStrainPrev()); - const static_matrix_type3D estrain_trial = this->m_estrain_prev + incr_strain; // elastic strain trial - const static_matrix_type3D X_prev = data.getK() * m_pstrain_prev; // back-stress previous - const static_matrix_type3D se = 2 * data.getMu() * deviator(estrain_trial) - X_prev; - const scalar_type se_eq = this->sigmaeq(se); - const scalar_type Phi_trial = se_eq - data.getSigma_y0() - data.getH() * m_p_prev; - - if ((std::abs(X_prev.trace()) / X_prev.norm()) > 1E-8) - { - const std::string mess = "X_trace= " + std::to_string(X_prev.trace()) + " <= 0"; - throw std::invalid_argument(mess); + const static_matrix_type3D incr_strain = + strain_curr - convertMatrix3D( this->getTotalStrainPrev() ); + const static_matrix_type3D estrain_trial = + this->m_estrain_prev + incr_strain; // elastic strain trial + const static_matrix_type3D X_prev = data.getK() * m_pstrain_prev; // back-stress previous + const static_matrix_type3D se = 2 * data.getMu() * deviator( estrain_trial ) - X_prev; + const scalar_type se_eq = this->sigmaeq( se ); + const scalar_type Phi_trial = se_eq - data.getSigma_y0() - data.getH() * m_p_prev; + + if ( ( std::abs( X_prev.trace() ) / X_prev.norm() ) > 1E-8 ) { + const std::string mess = "X_trace= " + std::to_string( X_prev.trace() ) + " <= 0"; + throw std::invalid_argument( mess ); } - if ((std::abs(se.trace()) / se.norm()) > 1E-8) - { - const std::string mess = "Se_trace= " + std::to_string(se.trace()) + " <= 0"; - throw std::invalid_argument(mess); + if ( ( std::abs( se.trace() ) / se.norm() ) > 1E-8 ) { + const std::string mess = "Se_trace= " + std::to_string( se.trace() ) + " <= 0"; + throw std::invalid_argument( mess ); } // check - if (Phi_trial < scalar_type(0)) - { + if ( Phi_trial < scalar_type( 0 ) ) { // elastic evolution m_is_plastic_curr = false; - } - else - { + } else { // plastic evolution m_is_plastic_curr = true; } // corection - if (m_is_plastic_curr) - { - const scalar_type dem = 3 * data.getMu() + data.getH() + scalar_type(3.) * data.getK() / scalar_type(2.); - const static_matrix_type3D normal = scalar_type(3.) * se / (scalar_type(2.) * se_eq); - const scalar_type delta_p = Phi_trial / dem; + if ( m_is_plastic_curr ) { + const scalar_type dem = 3 * data.getMu() + data.getH() + + scalar_type( 3. ) * data.getK() / scalar_type( 2. ); + const static_matrix_type3D normal = + scalar_type( 3. ) * se / ( scalar_type( 2. ) * se_eq ); + const scalar_type delta_p = Phi_trial / dem; // std::cout << "n:" << std::endl; // std::cout << normal << std::endl; // update - m_p_curr = m_p_prev + delta_p; + m_p_curr = m_p_prev + delta_p; this->m_estrain_curr = estrain_trial - delta_p * normal; - m_pstrain_curr = m_pstrain_prev + delta_p * normal; + m_pstrain_curr = m_pstrain_prev + delta_p * normal; - if (tangentmodulus) - { + if ( tangentmodulus ) { // compute cep coherent - const static_tensor nxn = Kronecker(normal, normal); - const static_tensor Is = IdentitySymTensor4(); - const static_tensor Pdev = Is - IxI() / scalar_type(3); - const scalar_type mu2 = data.getMu() * data.getMu(); - - Cep += 4 * mu2 * (delta_p / se_eq - 1.0 / dem) * nxn - 6.0 * mu2 * delta_p / se_eq * Pdev; + const static_tensor< scalar_type, 3 > nxn = Kronecker( normal, normal ); + const static_tensor< scalar_type, 3 > Is = IdentitySymTensor4< scalar_type, 3 >(); + const static_tensor< scalar_type, 3 > Pdev = + Is - IxI< scalar_type, 3 >() / scalar_type( 3 ); + const scalar_type mu2 = data.getMu() * data.getMu(); + + Cep += 4 * mu2 * ( delta_p / se_eq - 1.0 / dem ) * nxn - + 6.0 * mu2 * delta_p / se_eq * Pdev; } - } - else - { + } else { // update this->m_estrain_curr = estrain_trial; - m_pstrain_curr = m_pstrain_prev; - m_p_curr = m_p_prev; + m_pstrain_curr = m_pstrain_prev; + m_p_curr = m_p_prev; } - if ((std::abs(m_pstrain_curr.trace()) / m_pstrain_curr.norm()) > 1E-8) - { - const std::string mess = "eps_p= " + std::to_string(m_pstrain_curr.trace()) + " <= 0"; - throw std::invalid_argument(mess); + if ( ( std::abs( m_pstrain_curr.trace() ) / m_pstrain_curr.norm() ) > 1E-8 ) { + const std::string mess = "eps_p= " + std::to_string( m_pstrain_curr.trace() ) + " <= 0"; + throw std::invalid_argument( mess ); } // std::cout << "ep:" << std::endl; @@ -236,7 +216,7 @@ class LinearIsotropicAndKinematicHardening_qp : public law_qp_bones // std::cout << m_estrain_curr + m_pstrain_curr << std::endl; // compute Cauchy stress - const static_matrix_type3D stress = this->compute_stress3D(data); + const static_matrix_type3D stress = this->compute_stress3D( data ); // std::cout << "stress:" << std::endl; // std::cout << stress << std::endl; @@ -248,19 +228,31 @@ class LinearIsotropicAndKinematicHardening_qp : public law_qp_bones // std::cout << "p:" << std::endl; // std::cout << m_p_curr << std::endl; - return std::make_pair(stress, Cep); + return std::make_pair( stress, Cep ); + } + + std::pair< static_matrix_type, static_tensor< scalar_type, DIM > > + compute_whole( const static_matrix_type &strain_curr, const data_type &data, + bool tangentmodulus = true ) { + const static_matrix_type3D strain3D_curr = convertMatrix3D( strain_curr ); + const auto behaviors3D = this->compute_whole3D( strain3D_curr, data, tangentmodulus ); + + const static_matrix_type stress = convertMatrix< scalar_type, DIM >( behaviors3D.first ); + const static_tensor< scalar_type, DIM > Cep = + convertTensor< scalar_type, DIM >( behaviors3D.second ); + + return std::make_pair( stress, Cep ); } - std::pair> - compute_whole(const static_matrix_type& strain_curr, const data_type& data, bool tangentmodulus = true) - { - const static_matrix_type3D strain3D_curr = convertMatrix3D(strain_curr); - const auto behaviors3D = this->compute_whole3D(strain3D_curr, data, tangentmodulus); + static_matrix_type compute_stress( const static_matrix_type &strain_curr, + const data_type &data ) { + const static_matrix_type3D strain3D_curr = convertMatrix3D( strain_curr ); + const auto behaviors3D = this->compute_whole3D( strain3D_curr, data, false ); - const static_matrix_type stress = convertMatrix(behaviors3D.first); - const static_tensor Cep = convertTensor(behaviors3D.second); + const static_matrix_type stress = convertMatrix< scalar_type, DIM >( behaviors3D.first ); - return std::make_pair(stress, Cep); + return stress; } }; -} +} // namespace mechanics +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/LinearLaw/LinearLaw_qp.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/LinearLaw/LinearLaw_qp.hpp index cf8c68b8..f163868e 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/LinearLaw/LinearLaw_qp.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/LinearLaw/LinearLaw_qp.hpp @@ -36,64 +36,60 @@ #define _USE_MATH_DEFINES #include -namespace disk -{ - +namespace disk { +namespace mechanics { // Law for LinearLaw (test of finite deformations) -template -class LinearLaw_qp : public law_qp_bones -{ +template < typename T, int DIM > +class LinearLaw_qp : public law_qp_bones< T, DIM > { public: - typedef T scalar_type; - typedef static_matrix static_matrix_type; - typedef static_matrix static_matrix_type3D; - const static size_t dimension = DIM; - typedef MaterialData data_type; + typedef T scalar_type; + typedef static_matrix< scalar_type, DIM, DIM > static_matrix_type; + typedef static_matrix< scalar_type, 3, 3 > static_matrix_type3D; + const static size_t dimension = DIM; + typedef MaterialData< scalar_type > data_type; public: - LinearLaw_qp() : law_qp_bones() {} + LinearLaw_qp() : law_qp_bones< T, DIM >() {} - LinearLaw_qp(const point& point, const scalar_type& weight) : law_qp_bones(point, weight) - { - } + LinearLaw_qp( const point< scalar_type, DIM > &point, scalar_type weight ) + : law_qp_bones< T, DIM >( point, weight ) {} - static_matrix_type3D - compute_stress3D(const data_type& data) const - { + static_matrix_type3D compute_stress3D( const data_type &data ) const { return data.getLambda() * this->m_estrain_curr; } - static_matrix_type - compute_stress(const data_type& data) const - { - return convertMatrix(compute_stress3D(data)); + static_matrix_type compute_stress( const data_type &data ) const { + return convertMatrix< scalar_type, DIM >( compute_stress3D( data ) ); } - std::pair> - compute_whole3D(const static_matrix_type3D& F_curr, const data_type& data, bool tangentmodulus = true) - { - static_tensor Cep = data.getLambda() * IdentityTensor4(); + std::pair< static_matrix_type3D, static_tensor< scalar_type, 3 > > + compute_whole3D( const static_matrix_type3D &F_curr, const data_type &data, + bool tangentmodulus = true ) { + static_tensor< scalar_type, 3 > Cep = + data.getLambda() * IdentityTensor4< scalar_type, 3 >(); // is always elastic this->m_estrain_curr = F_curr; // compute Cauchy stress - const static_matrix_type3D stress = this->compute_stress3D(data); + const static_matrix_type3D stress = this->compute_stress3D( data ); - return std::make_pair(stress, Cep); + return std::make_pair( stress, Cep ); } - std::pair> - compute_whole(const static_matrix_type& F_curr, const data_type& data, bool tangentmodulus = true) - { - const static_matrix_type3D F3D = convertMatrix3D(F_curr); - const auto behaviors3D = compute_whole3D(F3D, data, tangentmodulus); + std::pair< static_matrix_type, static_tensor< scalar_type, DIM > > + compute_whole( const static_matrix_type &F_curr, const data_type &data, + bool tangentmodulus = true ) { + const static_matrix_type3D F3D = convertMatrix3D( F_curr ); + const auto behaviors3D = compute_whole3D( F3D, data, tangentmodulus ); - const static_matrix_type stress = convertMatrix(behaviors3D.first); - const static_tensor Cep = convertTensor(behaviors3D.second); + const static_matrix_type stress = convertMatrix< scalar_type, DIM >( behaviors3D.first ); + const static_tensor< scalar_type, DIM > Cep = + convertTensor< scalar_type, DIM >( behaviors3D.second ); - return std::make_pair(stress, Cep); + return std::make_pair( stress, Cep ); } }; -} +} // namespace mechanics +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/Mfront/Mfront_law.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/Mfront/Mfront_law.hpp index d1a46015..7fd44ff1 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/Mfront/Mfront_law.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/Mfront/Mfront_law.hpp @@ -28,100 +28,80 @@ #ifdef HAVE_MGIS -#include - #include "MGIS/Behaviour/Behaviour.hxx" #include "diskpp/mechanics/behaviors/laws/Mfront/Mfront_law_cell.hpp" -namespace disk -{ +#include + +namespace disk { +namespace mechanics { // Law bones -template -class Mfront_law -{ +template < typename MeshType > +class Mfront_law { public: - typedef MeshType mesh_type; - typedef typename mesh_type::coordinate_type scalar_type; - typedef typename mesh_type::cell cell_type; - typedef MaterialData data_type; - typedef std::shared_ptr BehaviourPtr; + typedef MeshType mesh_type; + typedef typename mesh_type::coordinate_type scalar_type; + typedef typename mesh_type::cell cell_type; + typedef MaterialData< scalar_type > data_type; + typedef std::shared_ptr< mgis::behaviour::Behaviour > BehaviourPtr; private: - typedef Mfront_law_cell law_cell_type; + typedef Mfront_law_cell< mesh_type > law_cell_type; - size_t m_nb_qp; - std::vector m_list_cell_qp; - data_type m_data; - BehaviourPtr m_behav; + size_t m_nb_qp; + std::vector< law_cell_type > m_list_cell_qp; + data_type m_data; + BehaviourPtr m_behav; public: - Mfront_law() : m_nb_qp(0), m_behav(nullptr){}; + Mfront_law() : m_nb_qp( 0 ), m_behav( nullptr ) {}; - Mfront_law(const mesh_type& msh, const size_t degree, const BehaviourPtr& b) : m_behav(b) - { + Mfront_law( const mesh_type &msh, const size_t degree, const BehaviourPtr &b ) : m_behav( b ) { m_nb_qp = 0; m_list_cell_qp.clear(); - m_list_cell_qp.reserve(msh.cells_size()); + m_list_cell_qp.reserve( msh.cells_size() ); - for (auto& cl : msh) - { - law_cell_type cell_qp(msh, cl, degree, m_behav, m_data); + for ( auto &cl : msh ) { + law_cell_type cell_qp( msh, cl, degree, m_behav, m_data ); - m_list_cell_qp.push_back(cell_qp); + m_list_cell_qp.push_back( cell_qp ); m_nb_qp += cell_qp.getNumberOfQP(); } } - void - addMaterialData(const data_type materialData) - { + void addMaterialData( const data_type materialData ) { m_data = materialData; - for (auto& qp_cell : m_list_cell_qp) - { - qp_cell.addInitialMaterialParameters(m_data); + for ( auto &qp_cell : m_list_cell_qp ) { + qp_cell.addInitialMaterialParameters( m_data ); } } - data_type - getMaterialData() const - { - return m_data; - } + data_type getMaterialData() const { return m_data; } - int - getNumberOfQP() const - { - return m_nb_qp; - } + int getNumberOfQP() const { return m_nb_qp; } - void - update() - { - for (auto& qp_cell : m_list_cell_qp) - { - qp_cell.update(m_data); + void update() { + for ( auto &qp_cell : m_list_cell_qp ) { + qp_cell.update( m_data ); } } - law_cell_type& - getCellQPs(const int cell_id) - { - return m_list_cell_qp.at(cell_id); + void restore() { + for ( auto &qp_cell : m_list_cell_qp ) { + qp_cell.restore( m_data ); + } } - const law_cell_type& - getCellQPs(const int cell_id) const - { - return m_list_cell_qp.at(cell_id); - } + law_cell_type &getCellQPs( const int cell_id ) { return m_list_cell_qp.at( cell_id ); } - law_cell_type - getCellIVs(const int cell_id) const - { - return m_list_cell_qp.at(cell_id); + const law_cell_type &getCellQPs( const int cell_id ) const { + return m_list_cell_qp.at( cell_id ); } + + law_cell_type getCellIVs( const int cell_id ) const { return m_list_cell_qp.at( cell_id ); } }; -} +} // namespace mechanics +} // namespace disk #endif \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/Mfront/Mfront_law_cell.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/Mfront/Mfront_law_cell.hpp index 5474bb28..7c36dd2c 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/Mfront/Mfront_law_cell.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/Mfront/Mfront_law_cell.hpp @@ -28,114 +28,89 @@ #ifdef HAVE_MGIS +#include "MGIS/Behaviour/Behaviour.hxx" #include "diskpp/mechanics/behaviors/laws/Mfront/Mfront_qp.hpp" #include "diskpp/quadratures/quadratures.hpp" -#include "MGIS/Behaviour/Behaviour.hxx" - -namespace disk -{ +namespace disk { +namespace mechanics { /// Law cell bones -template -class Mfront_law_cell -{ +template < typename MeshType > +class Mfront_law_cell { public: - typedef MeshType mesh_type; + typedef MeshType mesh_type; typedef typename mesh_type::coordinate_type scalar_type; - typedef typename mesh_type::cell cell_type; + typedef typename mesh_type::cell cell_type; - typedef dynamic_matrix matrix_type; - typedef dynamic_vector vector_type; + typedef dynamic_matrix< scalar_type > matrix_type; + typedef dynamic_vector< scalar_type > vector_type; const static size_t dimension = mesh_type::dimension; - typedef Mfront_qp law_qp_type; - typedef typename law_qp_type::data_type data_type; + typedef Mfront_qp< typename MeshType::coordinate_type, MeshType::dimension > law_qp_type; + typedef typename law_qp_type::data_type data_type; private: - typedef std::shared_ptr BehaviourPtr; + typedef std::shared_ptr< mgis::behaviour::Behaviour > BehaviourPtr; BehaviourPtr m_behav; - std::vector m_list_qp; + std::vector< law_qp_type > m_list_qp; public: - Mfront_law_cell() : m_behav(nullptr) {} + Mfront_law_cell() : m_behav( nullptr ) {} - Mfront_law_cell(const mesh_type& msh, const cell_type& cl, const size_t degree, const BehaviourPtr& b, const data_type& data): - m_behav(b) - { - const auto qps = integrate(msh, cl, degree); + Mfront_law_cell( const mesh_type &msh, const cell_type &cl, const size_t degree, + const BehaviourPtr &b, const data_type &data ) + : m_behav( b ) { + const auto qps = integrate( msh, cl, degree ); m_list_qp.clear(); - m_list_qp.reserve(qps.size()); + m_list_qp.reserve( qps.size() ); - for (auto& qp : qps) - { - auto mqp = law_qp_type(qp.point(), qp.weight(), b); - mqp.addMaterialParameters(data); - m_list_qp.push_back(mqp); + for ( auto &qp : qps ) { + auto mqp = law_qp_type( qp.point(), qp.weight(), b ); + mqp.addMaterialParameters( data ); + m_list_qp.push_back( mqp ); } } - int - getNumberOfQP() const - { - return m_list_qp.size(); - } + int getNumberOfQP() const { return m_list_qp.size(); } - void - update(const data_type& data) - { - for (auto& qp : m_list_qp) - { + void update( const data_type &data ) { + for ( auto &qp : m_list_qp ) { qp.update(); - qp.addMaterialParameters(data); + qp.addMaterialParameters( data ); } } - void - addInitialMaterialParameters(const data_type& data) - { - for (auto& qp : m_list_qp) - { - qp.addMaterialParameters(data); - qp.addInitialMaterialParameters(data); + void restore( const data_type &data ) { + for ( auto &qp : m_list_qp ) { + qp.restore(); + qp.addMaterialParameters( data ); } } - std::vector& - getQPs() - { - return m_list_qp; + void addInitialMaterialParameters( const data_type &data ) { + for ( auto &qp : m_list_qp ) { + qp.addMaterialParameters( data ); + qp.addInitialMaterialParameters( data ); + } } - const std::vector& - getQPs() const - { - return m_list_qp; - } + std::vector< law_qp_type > &getQPs() { return m_list_qp; } - law_qp_type& - getQP(const size_t& qp_id) - { - return m_list_qp[qp_id]; - } + const std::vector< law_qp_type > &getQPs() const { return m_list_qp; } - const law_qp_type& - getQP(const size_t& qp_id) const - { - return m_list_qp[qp_id]; - } + law_qp_type &getQP( size_t qp_id ) { return m_list_qp[qp_id]; } - std::vector - getIVs() const - { - return m_list_qp; - } + const law_qp_type &getQP( size_t qp_id ) const { return m_list_qp[qp_id]; } + + std::vector< law_qp_type > getIVs() const { return m_list_qp; } }; -} +} // namespace mechanics +} // namespace disk #endif diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/Mfront/Mfront_qp.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/Mfront/Mfront_qp.hpp index e41477c2..84d31b2e 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/Mfront/Mfront_qp.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/Mfront/Mfront_qp.hpp @@ -27,8 +27,9 @@ #ifdef HAVE_MGIS -#include - +#include "MGIS/Behaviour/Behaviour.hxx" +#include "MGIS/Behaviour/BehaviourData.hxx" +#include "MGIS/Behaviour/Integrate.hxx" #include "diskpp/common/eigen.hpp" #include "diskpp/mechanics/behaviors/laws/law_qp_bones.hpp" #include "diskpp/mechanics/behaviors/laws/materialData.hpp" @@ -37,166 +38,153 @@ #include "diskpp/mechanics/behaviors/tensor_conversion.hpp" #include "diskpp/mesh/point.hpp" -#include "MGIS/Behaviour/Behaviour.hxx" -#include "MGIS/Behaviour/BehaviourData.hxx" -#include "MGIS/Behaviour/Integrate.hxx" +#include -namespace disk -{ +namespace disk { +namespace mechanics { // Law developped with Front interface // see http://tfel.sourceforge.net/index.html -template -class Mfront_qp : public law_qp_bones -{ +template < typename T, int DIM > +class Mfront_qp : public law_qp_bones< T, DIM > { public: - const static size_t dimension = DIM; - typedef T scalar_type; - typedef static_matrix static_matrix_type; - typedef static_matrix static_matrix_type3D; - typedef MaterialData data_type; - typedef std::shared_ptr BehaviourPtr; + const static size_t dimension = DIM; + typedef T scalar_type; + typedef static_matrix< scalar_type, DIM, DIM > static_matrix_type; + typedef static_matrix< scalar_type, 3, 3 > static_matrix_type3D; + typedef MaterialData< scalar_type > data_type; + typedef std::shared_ptr< mgis::behaviour::Behaviour > BehaviourPtr; private: - bool l_small_def; + bool l_small_def; std::string StressName; // shared pointer to mgis behaviour BehaviourPtr m_behav; // BehaviourDatat for Mfront computation - mgis::behaviour::BehaviourData m_behavData; + mgis::behaviour::BehaviourData m_behavData; mgis::behaviour::BehaviourDataView m_behavDataView; public: - Mfront_qp() : - law_qp_bones(), m_behav(nullptr), m_behavData(*m_behav), - m_behavDataView(mgis::behaviour::make_view(m_behavData)) - { - } - - Mfront_qp(const point& point, const scalar_type& weight, const BehaviourPtr& behav) : - law_qp_bones(point, weight), m_behav(behav), m_behavData(*m_behav), - m_behavDataView(mgis::behaviour::make_view(m_behavData)) - { - if ((*m_behav).kinematic == mgis::behaviour::Behaviour::SMALLSTRAINKINEMATIC) - { + Mfront_qp() + : law_qp_bones< T, DIM >(), + m_behav( nullptr ), + m_behavData( *m_behav ), + m_behavDataView( mgis::behaviour::make_view( m_behavData ) ) {} + + Mfront_qp( const point< scalar_type, DIM > &point, scalar_type weight, + const BehaviourPtr &behav ) + : law_qp_bones< T, DIM >( point, weight ), + m_behav( behav ), + m_behavData( *m_behav ), + m_behavDataView( mgis::behaviour::make_view( m_behavData ) ) { + if ( ( *m_behav ).kinematic == mgis::behaviour::Behaviour::SMALLSTRAINKINEMATIC ) { l_small_def = true; - StressName = "Stress"; - } - else if ((*m_behav).kinematic == mgis::behaviour::Behaviour::FINITESTRAINKINEMATIC_F_CAUCHY) - { + StressName = "Stress"; + } else if ( ( *m_behav ).kinematic == + mgis::behaviour::Behaviour::FINITESTRAINKINEMATIC_F_CAUCHY ) { l_small_def = false; - StressName = "FirstPiolaKirchhoffStress"; - } - else - throw std::runtime_error("Error"); + StressName = "FirstPiolaKirchhoffStress"; + } else + throw std::runtime_error( "Error" ); } - void - update() - { - law_qp_bones::update(); - mgis::behaviour::update(m_behavData); + void update() { + law_qp_bones< T, DIM >::update(); + mgis::behaviour::update( m_behavData ); } - scalar_type - getEquivalentPlasticStrain() const - { - try - { - const auto ePSPtr = mgis::behaviour::getInternalStateVariable(m_behavData.s1, "EquivalentPlasticStrain"); + void restore() { + law_qp_bones< T, DIM >::restore(); + mgis::behaviour::revert( m_behavData ); + } + + scalar_type getEquivalentPlasticStrain() const { + try { + const auto ePSPtr = mgis::behaviour::getInternalStateVariable( + m_behavData.s1, "EquivalentPlasticStrain" ); return *ePSPtr; + } catch ( ... ) { } - catch(...) - {} return 0.0; } - bool - is_plastic() const - { - if (getEquivalentPlasticStrain() != 0.0) + bool is_plastic() const { + if ( getEquivalentPlasticStrain() != 0.0 ) return true; return false; } - void - addMaterialParameters(const data_type& data) - { - const auto& mdata = data.getMfrontParameters(); - for (auto& [param, value] : mdata) - { - mgis::behaviour::setMaterialProperty(m_behavData.s1, param, value); + void addMaterialParameters( const data_type &data ) { + const auto &mdata = data.getMfrontParameters(); + for ( auto &[param, value] : mdata ) { + mgis::behaviour::setMaterialProperty( m_behavData.s1, param, value ); } } - void - addInitialMaterialParameters(const data_type& data) - { - const auto& mdata = data.getMfrontParameters(); - for (auto& [param, value] : mdata) - { - mgis::behaviour::setMaterialProperty(m_behavData.s0, param, value); + void addInitialMaterialParameters( const data_type &data ) { + const auto &mdata = data.getMfrontParameters(); + for ( auto &[param, value] : mdata ) { + mgis::behaviour::setMaterialProperty( m_behavData.s0, param, value ); } } - static_matrix_type3D - compute_stress3D(const data_type& data) const - { - const auto stressPtr = mgis::behaviour::getThermodynamicForce(m_behavData.s1, StressName); - if (stressPtr != &(m_behavData.s1.thermodynamic_forces[0])) - throw std::runtime_error("We assume that the stress is the first variable"); + static_matrix_type3D compute_stress3D( const data_type &data ) const { + const auto stressPtr = mgis::behaviour::getThermodynamicForce( m_behavData.s1, StressName ); + if ( stressPtr != &( m_behavData.s1.thermodynamic_forces[0] ) ) + throw std::runtime_error( "We assume that the stress is the first variable" ); static_matrix_type3D stress; - convertMatrixFromMgis(m_behavData.s1.thermodynamic_forces, stress); + convertMatrixFromMgis( m_behavData.s1.thermodynamic_forces, stress ); return stress; } - static_matrix_type - compute_stress(const data_type& data) const - { - return convertMatrix(compute_stress3D(data)); + static_matrix_type compute_stress( const data_type &data ) const { + return convertMatrix< scalar_type, DIM >( compute_stress3D( data ) ); } - std::pair> - compute_whole3D(const static_matrix_type3D& strain_curr, const data_type& data, bool tangentmodulus = true) - { + std::pair< static_matrix_type3D, static_tensor< scalar_type, 3 > > + compute_whole3D( const static_matrix_type3D &strain_curr, const data_type &data, + bool tangentmodulus = true, bool compute_modulus = true ) { this->m_estrain_curr = strain_curr; - if (tangentmodulus) - { - m_behavData.K[0] = 4; - } - else - { - m_behavData.K[0] = 1; + if ( compute_modulus ) { + if ( tangentmodulus ) { + m_behavData.K[0] = 4; + } else { + m_behavData.K[0] = 1; + } + } else { + m_behavData.K[0] = 0; } // Output: PK1, d PK1 / d F - if (!l_small_def) - { + if ( !l_small_def ) { m_behavData.K[1] = 2; m_behavData.K[2] = 2; } - // std::cout << "K: " << m_behavData.K[0] << ", " << m_behavData.K[1] << ", " << m_behavData.K[2] << std::endl; + // std::cout << "K: " << m_behavData.K[0] << ", " << m_behavData.K[1] << ", " << + // m_behavData.K[2] << std::endl; // mfront - convertMatrixToMgis(strain_curr, m_behavData.s1.gradients); - auto v = mgis::behaviour::make_view(m_behavData); - mgis::behaviour::integrate(v, *m_behav); + convertMatrixToMgis( strain_curr, m_behavData.s1.gradients ); + auto v = mgis::behaviour::make_view( m_behavData ); + mgis::behaviour::integrate( v, *m_behav ); // compute stress tensor depending on the choice - const static_matrix_type3D stress = compute_stress3D(data); + const static_matrix_type3D stress = compute_stress3D( data ); // compute tangent module (consistent with the stress tensor) - static_tensor Aep; - convertTensorFromMgis(m_behavData.K, Aep); + static_tensor< scalar_type, 3 > Aep; + if ( compute_modulus ) { + convertTensorFromMgis( m_behavData.K, Aep ); + } // std::cout << "MGIS" << std::endl; // for (auto& elem : m_behavData.K) @@ -208,35 +196,47 @@ class Mfront_qp : public law_qp_bones // printing // print_markdown(); - return std::make_pair(stress, Aep); + return std::make_pair( stress, Aep ); } // strain_curr is the symetric gradient for small deformation and F for finite def. - std::pair> - compute_whole(const static_matrix_type& strain_curr, const data_type& data, bool tangentmodulus = true) - { + std::pair< static_matrix_type, static_tensor< scalar_type, DIM > > + compute_whole( const static_matrix_type &strain_curr, const data_type &data, + bool tangentmodulus = true ) { static_matrix_type3D strain3D_curr; - if (l_small_def) - { - strain3D_curr = convertMatrix3D(strain_curr); - } - else - { - strain3D_curr = convertMatrix3DwithOne(strain_curr); + if ( l_small_def ) { + strain3D_curr = convertMatrix3D( strain_curr ); + } else { + strain3D_curr = convertMatrix3DwithOne( strain_curr ); } - const auto behaviors3D = this->compute_whole3D(strain3D_curr, data, tangentmodulus); + const auto behaviors3D = this->compute_whole3D( strain3D_curr, data, tangentmodulus ); + + const static_matrix_type stress = convertMatrix< scalar_type, DIM >( behaviors3D.first ); + const static_tensor< scalar_type, DIM > Cep = + convertTensor< scalar_type, DIM >( behaviors3D.second ); - const static_matrix_type stress = convertMatrix(behaviors3D.first); - const static_tensor Cep = convertTensor(behaviors3D.second); + return std::make_pair( stress, Cep ); + } - return std::make_pair(stress, Cep); + void print_markdown() const { + mgis::behaviour::print_markdown( std::cout, *m_behav, m_behavData, 1 ); } - void - print_markdown() const - { - mgis::behaviour::print_markdown(std::cout, *m_behav, m_behavData, 1); + static_matrix_type compute_stress( const static_matrix_type &strain_curr, + const data_type &data ) { + static_matrix_type3D strain3D_curr; + if ( l_small_def ) { + strain3D_curr = convertMatrix3D( strain_curr ); + } else { + strain3D_curr = convertMatrix3DwithOne( strain_curr ); + } + const auto behaviors3D = this->compute_whole3D( strain3D_curr, data, false, false ); + + const static_matrix_type stress = convertMatrix< scalar_type, DIM >( behaviors3D.first ); + + return stress; } }; #endif } +} \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/Neohookean/Neohookean_qp.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/Neohookean/Neohookean_qp.hpp index 56628c72..f1249e2d 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/Neohookean/Neohookean_qp.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/Neohookean/Neohookean_qp.hpp @@ -37,8 +37,8 @@ #define _USE_MATH_DEFINES #include -namespace disk -{ +namespace disk { +namespace mechanics { // Law for Linear Isotropic and Kinematic Hardening model with von Mises Criteria in small @@ -65,174 +65,185 @@ namespace disk * 6- U(J) = sqrt( ( J^2 -1 - 2 *ln(J)) /2) * */ -template -class Neohookean_qp : public law_qp_bones -{ +template < typename T, int DIM > +class Neohookean_qp : public law_qp_bones< T, DIM > { public: - typedef T scalar_type; - typedef static_matrix static_matrix_type; - typedef static_matrix static_matrix_type3D; - const static size_t dimension = DIM; - typedef MaterialData data_type; + typedef T scalar_type; + typedef static_matrix< scalar_type, DIM, DIM > static_matrix_type; + typedef static_matrix< scalar_type, 3, 3 > static_matrix_type3D; + const static size_t dimension = DIM; + typedef MaterialData< scalar_type > data_type; private: - scalar_type - compute_U(const data_type& data, scalar_type J) const - { - switch (data.getType()) - { - case 1: return log(J); - case 2: return (J - 1.0); - case 3: return log10(J); - case 4: return 1.0 / (1.0 - J); - case 5: return (J * J - 1.0); - case 6: return sqrt((J * J - 1.0 - 2.0 * log(J)) / 2.0); - - default: throw std::invalid_argument("NeoHookeanLaw: m_type have to be <= 6"); + scalar_type compute_U( const data_type &data, scalar_type J ) const { + switch ( data.getType() ) { + case 1: + return log( J ); + case 2: + return ( J - 1.0 ); + case 3: + return log10( J ); + case 4: + return 1.0 / ( 1.0 - J ); + case 5: + return ( J * J - 1.0 ); + case 6: + return sqrt( ( J * J - 1.0 - 2.0 * log( J ) ) / 2.0 ); + + default: + throw std::invalid_argument( "NeoHookeanLaw: m_type have to be <= 6" ); } } - scalar_type - compute_T1(const data_type& data, scalar_type J) const - { - switch (data.getType()) - { - case 1: return log(J); - case 2: return J * (J - 1.0); - case 3: return log(J) / (log(10) * log(10)); - case 4: return (J - 1.0) / (J * J); - case 5: return 2 * J * J * (J * J - 1.0); - case 6: return (J * J - 1.0) / 2.0; - - default: throw std::invalid_argument("NeoHookeanLaw: m_type have to be <= 6"); + scalar_type compute_T1( const data_type &data, scalar_type J ) const { + switch ( data.getType() ) { + case 1: + return log( J ); + case 2: + return J * ( J - 1.0 ); + case 3: + return log( J ) / ( log( 10 ) * log( 10 ) ); + case 4: + return ( J - 1.0 ) / ( J * J ); + case 5: + return 2 * J * J * ( J * J - 1.0 ); + case 6: + return ( J * J - 1.0 ) / 2.0; + + default: + throw std::invalid_argument( "NeoHookeanLaw: m_type have to be <= 6" ); } } - scalar_type - compute_T2(const data_type& data, scalar_type J) const - { - switch (data.getType()) - { - case 1: return 1.0; - case 2: return J * (2.0 * J - 1.0); - case 3: return 1.0 / (log(10) * log(10)); - case 4: return (2.0 - J) / (J * J); - case 5: return J * J * (8.0 * J * J - 4.0); - case 6: return J * J; - - default: throw std::invalid_argument("NeoHookeanLaw: m_type have to be <= 6"); + scalar_type compute_T2( const data_type &data, scalar_type J ) const { + switch ( data.getType() ) { + case 1: + return 1.0; + case 2: + return J * ( 2.0 * J - 1.0 ); + case 3: + return 1.0 / ( log( 10 ) * log( 10 ) ); + case 4: + return ( 2.0 - J ) / ( J * J ); + case 5: + return J * J * ( 8.0 * J * J - 4.0 ); + case 6: + return J * J; + + default: + throw std::invalid_argument( "NeoHookeanLaw: m_type have to be <= 6" ); } } - static_tensor - compute_tangent_moduli_A(const data_type& data) const - { + static_tensor< scalar_type, 3 > compute_tangent_moduli_A( const data_type &data ) const { const scalar_type J = this->m_estrain_curr.determinant(); - if (J <= 0.0) - { - const std::string mess = "J= " + std::to_string(J) + " <= 0"; - throw std::invalid_argument(mess); + if ( J <= 0.0 ) { + const std::string mess = "J= " + std::to_string( J ) + " <= 0"; + throw std::invalid_argument( mess ); } - const static_matrix_type3D invF = this->m_estrain_curr.inverse(); + const static_matrix_type3D invF = this->m_estrain_curr.inverse(); const static_matrix_type3D invFt = invF.transpose(); - const scalar_type T1 = compute_T1(data, J); - const scalar_type T2 = compute_T2(data, J); + const scalar_type T1 = compute_T1( data, J ); + const scalar_type T2 = compute_T2( data, J ); - const static_tensor I4 = IdentityTensor4(); - const static_tensor invFt_invF = ProductInf(invFt, invF); - const static_tensor invFt_invFt = Kronecker(invFt, invFt); + const static_tensor< scalar_type, 3 > I4 = IdentityTensor4< scalar_type, 3 >(); + const static_tensor< scalar_type, 3 > invFt_invF = ProductInf( invFt, invF ); + const static_tensor< scalar_type, 3 > invFt_invFt = Kronecker( invFt, invFt ); - return data.getMu() * (I4 + invFt_invF) + data.getLambda() * (T2 * invFt_invFt - T1 * invFt_invF); + return data.getMu() * ( I4 + invFt_invF ) + + data.getLambda() * ( T2 * invFt_invFt - T1 * invFt_invF ); } public: - Neohookean_qp() : law_qp_bones() {} + Neohookean_qp() : law_qp_bones< T, DIM >() {} - Neohookean_qp(const point& point, const scalar_type& weight) : law_qp_bones(point, weight) - { - } + Neohookean_qp( const point< scalar_type, DIM > &point, scalar_type weight ) + : law_qp_bones< T, DIM >( point, weight ) {} - static_matrix_type3D - compute_stress3D(const data_type& data) const - { + static_matrix_type3D compute_stress3D( const data_type &data ) const { const scalar_type J = this->m_estrain_curr.determinant(); - if (J <= 0.0) - { - const std::string mess = "J= " + std::to_string(J) + " <= 0"; - throw std::invalid_argument(mess); + if ( J <= 0.0 ) { + const std::string mess = "J= " + std::to_string( J ) + " <= 0"; + throw std::invalid_argument( mess ); } const static_matrix_type3D invF = this->m_estrain_curr.inverse(); - const scalar_type T1 = compute_T1(data, J); + const scalar_type T1 = compute_T1( data, J ); - return data.getMu() * this->m_estrain_curr + (data.getLambda() * T1 - data.getMu()) * invF.transpose(); + return data.getMu() * this->m_estrain_curr + + ( data.getLambda() * T1 - data.getMu() ) * invF.transpose(); } - static_matrix_type - compute_stress(const data_type& data) const - { - return convertMatrix(compute_stress3D(data)); + static_matrix_type compute_stress( const data_type &data ) const { + return convertMatrix< scalar_type, DIM >( compute_stress3D( data ) ); } - static_matrix_type3D - compute_stressPrev3D(const data_type& data) const - { + static_matrix_type3D compute_stressPrev3D( const data_type &data ) const { const scalar_type J = this->m_estrain_prev.determinant(); - if (J <= 0.0) - { - const std::string mess = "J= " + std::to_string(J) + " <= 0"; - throw std::invalid_argument(mess); + if ( J <= 0.0 ) { + const std::string mess = "J= " + std::to_string( J ) + " <= 0"; + throw std::invalid_argument( mess ); } const static_matrix_type3D invF = this->m_estrain_prev.inverse(); - const scalar_type T1 = compute_T1(data, J); + const scalar_type T1 = compute_T1( data, J ); - return data.getMu() * this->m_estrain_prev + (data.getLambda() * T1 - data.getMu()) * invF.transpose(); + return data.getMu() * this->m_estrain_prev + + ( data.getLambda() * T1 - data.getMu() ) * invF.transpose(); } - scalar_type - compute_energy(const data_type& data) const - { + scalar_type compute_energy( const data_type &data ) const { const scalar_type J = this->m_estrain_curr.determinant(); - if (J <= 0.0) - { - const std::string mess = "J= " + std::to_string(J) + " <= 0"; - throw std::invalid_argument(mess); + if ( J <= 0.0 ) { + const std::string mess = "J= " + std::to_string( J ) + " <= 0"; + throw std::invalid_argument( mess ); } - const static_matrix_type3D C = convertFtoCauchyGreenRight(this->m_estrain_curr); + const static_matrix_type3D C = convertFtoCauchyGreenRight( this->m_estrain_curr ); - const scalar_type Wiso = data.getMu() / 2.0 * (C.trace() - 3); + const scalar_type Wiso = data.getMu() / 2.0 * ( C.trace() - 3 ); const scalar_type Wvol = - data.getLambda() / 2.0 * compute_U(data, J) * compute_U(data, J) - data.getMu() * log(J); + data.getLambda() / 2.0 * compute_U( data, J ) * compute_U( data, J ) - + data.getMu() * log( J ); return Wiso + Wvol; } - std::pair> - compute_whole3D(const static_matrix_type3D& F_curr, const data_type& data, bool tangentmodulus = true) - { + std::pair< static_matrix_type3D, static_tensor< scalar_type, 3 > > + compute_whole3D( const static_matrix_type3D &F_curr, const data_type &data, + bool tangentmodulus = true ) { // is always elastic this->m_estrain_curr = F_curr; - const auto PK1 = this->compute_stress3D(data); - const auto A = this->compute_tangent_moduli_A(data); + const auto PK1 = this->compute_stress3D( data ); + const auto A = this->compute_tangent_moduli_A( data ); + + return std::make_pair( PK1, A ); + } + + std::pair< static_matrix_type, static_tensor< scalar_type, DIM > > + compute_whole( const static_matrix_type &F_curr, const data_type &data, + bool tangentmodulus = true ) { + const static_matrix_type3D F3D = convertMatrix3DwithOne( F_curr ); + const auto behaviors3D = compute_whole3D( F3D, data, tangentmodulus ); + + const static_matrix_type stress = convertMatrix< scalar_type, DIM >( behaviors3D.first ); + const static_tensor< scalar_type, DIM > Cep = + convertTensor< scalar_type, DIM >( behaviors3D.second ); - return std::make_pair(PK1, A); + return std::make_pair( stress, Cep ); } - std::pair> - compute_whole(const static_matrix_type& F_curr, const data_type& data, bool tangentmodulus = true) - { - const static_matrix_type3D F3D = convertMatrix3DwithOne(F_curr); - const auto behaviors3D = compute_whole3D(F3D, data, tangentmodulus); + static_matrix_type compute_stress( const static_matrix_type &F_curr, const data_type &data ) { + const static_matrix_type3D F3D = convertMatrix3DwithOne( F_curr ); + const auto behaviors3D = compute_whole3D( F3D, data, false ); - const static_matrix_type stress = convertMatrix(behaviors3D.first); - const static_tensor Cep = convertTensor(behaviors3D.second); + const static_matrix_type stress = convertMatrix< scalar_type, DIM >( behaviors3D.first ); - return std::make_pair(stress, Cep); + return stress; } }; -} +} // namespace mechanics +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/behaviorlaws.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/behaviorlaws.hpp old mode 100755 new mode 100644 index 1a067b26..c5f3450f --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/behaviorlaws.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/behaviorlaws.hpp @@ -43,54 +43,62 @@ #include "MGIS/Behaviour/Behaviour.hxx" #endif -namespace disk -{ +namespace disk { +namespace mechanics { -template +template < typename MeshType > using Cavitation = - LawTypeBones, false>; + LawTypeBones< MeshType, + Cavitation_qp< typename MeshType::coordinate_type, MeshType::dimension >, false >; -template +template < typename MeshType > using Neohookean = - LawTypeBones, false>; + LawTypeBones< MeshType, + Neohookean_qp< typename MeshType::coordinate_type, MeshType::dimension >, false >; -template -using HenckyMises = - LawTypeBones, false>; +template < typename MeshType > +using HenckyMises = LawTypeBones< + MeshType, HenckyMises_qp< typename MeshType::coordinate_type, MeshType::dimension >, false >; -template +template < typename MeshType > using LinearElasticityLaw = - LawTypeBones, false>; + LawTypeBones< MeshType, + LinearElasticity_qp< typename MeshType::coordinate_type, MeshType::dimension >, + false >; -template -using LinearLaw = LawTypeBones, false>; +template < typename MeshType > +using LinearLaw = + LawTypeBones< MeshType, LinearLaw_qp< typename MeshType::coordinate_type, MeshType::dimension >, + false >; -template +template < typename MeshType > using LinearIsotropicAndKinematicHardening = - LawTypeBones, - true>; + LawTypeBones< MeshType, + LinearIsotropicAndKinematicHardening_qp< typename MeshType::coordinate_type, + MeshType::dimension >, + true >; -template -using IsotropicHardeningVMis = - LawTypeBones, true>; +template < typename MeshType > +using IsotropicHardeningVMis = LawTypeBones< + MeshType, IsotropicHardeningVMis_qp< typename MeshType::coordinate_type, MeshType::dimension >, + true >; #ifdef HAVE_MGIS -template -using Mfront = Mfront_law; +template < typename MeshType > +using Mfront = Mfront_law< MeshType >; #endif -template -class Behavior -{ +template < typename MeshType > +class Behavior { private: typedef typename MeshType::coordinate_type scalar_type; - typedef typename MeshType::cell cell_type; - typedef MaterialData material_type; - typedef dynamic_vector vector_type; + typedef typename MeshType::cell cell_type; + typedef MaterialData< scalar_type > material_type; + typedef dynamic_vector< scalar_type > vector_type; - typedef static_matrix static_matrix_type; - typedef static_tensor static_tensor_type; + typedef static_matrix< scalar_type, MeshType::dimension, MeshType::dimension > + static_matrix_type; + typedef static_tensor< scalar_type, MeshType::dimension > static_tensor_type; size_t m_deformation; size_t m_law; @@ -99,429 +107,719 @@ class Behavior material_type m_data; #ifdef HAVE_MGIS - typedef std::shared_ptr BehaviourPtr; - BehaviourPtr m_behav; + typedef std::shared_ptr< mgis::behaviour::Behaviour > BehaviourPtr; + BehaviourPtr m_behav; #endif - Cavitation m_cavitation; - Neohookean m_neohokean; - HenckyMises m_henckymises; - LinearElasticityLaw m_elastic; - LinearIsotropicAndKinematicHardening m_linearHard; - IsotropicHardeningVMis m_nonlinearHard; + Cavitation< MeshType > m_cavitation; + Neohookean< MeshType > m_neohokean; + HenckyMises< MeshType > m_henckymises; + LinearElasticityLaw< MeshType > m_elastic; + LinearIsotropicAndKinematicHardening< MeshType > m_linearHard; + IsotropicHardeningVMis< MeshType > m_nonlinearHard; // - mechanics::LogarithmicStrain> m_log_elastic; - mechanics::LogarithmicStrain> m_log_linearHard; - mechanics::LogarithmicStrain> m_log_nonlinearHard; + mechanics::LogarithmicStrain< LinearElasticityLaw< MeshType > > m_log_elastic; + mechanics::LogarithmicStrain< LinearIsotropicAndKinematicHardening< MeshType > > + m_log_linearHard; + mechanics::LogarithmicStrain< IsotropicHardeningVMis< MeshType > > m_log_nonlinearHard; #ifdef HAVE_MGIS - Mfront m_mfront; + Mfront< MeshType > m_mfront; #endif - void - select_law(void) - { + void select_law( void ) { m_id = 0; - switch (m_deformation) - { - case DeformationMeasure::SMALL_DEF: - switch (m_law) - { - case LawType::ELASTIC: m_id = 100; break; - case LawType::LINEAR_HARDENING: m_id = 101; break; - case LawType::NONLINEAR_HARDENING: m_id = 102; break; - case LawType::HENCKY_MISES: m_id = 103; break; + switch ( m_deformation ) { + case DeformationMeasure::SMALL_DEF: + switch ( m_law ) { + case LawType::ELASTIC: + m_id = 100; + break; + case LawType::LINEAR_HARDENING: + m_id = 101; + break; + case LawType::NONLINEAR_HARDENING: + m_id = 102; + break; + case LawType::HENCKY_MISES: + m_id = 103; + break; #ifdef HAVE_MGIS - case LawType::MFRONT: m_id = 500; break; + case LawType::MFRONT: + m_id = 500; + break; #endif - default: throw std::invalid_argument("Incompatible law with SMALL_DEF"); - } + default: + throw std::invalid_argument( "Incompatible law with SMALL_DEF" ); + } + break; + case DeformationMeasure::F_DEF: + switch ( m_law ) { + case LawType::NEOHOKEAN: + m_id = 200; + break; + case LawType::CAVITATION: + m_id = 201; break; - case DeformationMeasure::F_DEF: - switch (m_law) - { - case LawType::NEOHOKEAN: m_id = 200; break; - case LawType::CAVITATION: m_id = 201; break; #ifdef HAVE_MGIS - case LawType::MFRONT: m_id = 500; break; + case LawType::MFRONT: + m_id = 500; + break; #endif - default: throw std::invalid_argument("Incompatible law with F_DEF"); - } + default: + throw std::invalid_argument( "Incompatible law with F_DEF" ); + } + break; + case DeformationMeasure::LOGARITHMIC_DEF: + switch ( m_law ) { + case LawType::ELASTIC: + m_id = 300; + break; + case LawType::LINEAR_HARDENING: + m_id = 301; + break; + case LawType::NONLINEAR_HARDENING: + m_id = 302; break; - case DeformationMeasure::LOGARITHMIC_DEF: - switch (m_law) - { - case LawType::ELASTIC: m_id = 300; break; - case LawType::LINEAR_HARDENING: m_id = 301; break; - case LawType::NONLINEAR_HARDENING: m_id = 302; break; #ifdef HAVE_MGIS - case LawType::MFRONT: m_id = 500; break; -#endif - default: throw std::invalid_argument("Incompatible law with LOGARITHMIC_DEF"); - } + case LawType::MFRONT: + m_id = 500; break; +#endif + default: + throw std::invalid_argument( "Incompatible law with LOGARITHMIC_DEF" ); + } + break; - default: throw std::invalid_argument("Unknown deformation"); + default: + throw std::invalid_argument( "Unknown deformation" ); } } public: - Behavior() : m_deformation(DeformationMeasure::SMALL_DEF), m_law(LawType::ELASTIC) { select_law(); } - - Behavior(const size_t deformation, const size_t law) : m_deformation(deformation), m_law(law) { select_law(); } + Behavior() : m_deformation( DeformationMeasure::SMALL_DEF ), m_law( LawType::ELASTIC ) { + select_law(); + } - Behavior(const MeshType& msh, const size_t degree, const size_t deformation, const size_t law) : - m_deformation(deformation), m_law(law) - { + Behavior( const size_t deformation, const size_t law ) + : m_deformation( deformation ), m_law( law ) { select_law(); - switch (m_id) - { - case 100: m_elastic = LinearElasticityLaw(msh, degree); break; - case 101: m_linearHard = LinearIsotropicAndKinematicHardening(msh, degree); break; - case 102: m_nonlinearHard = IsotropicHardeningVMis(msh, degree); break; - case 103: m_henckymises = HenckyMises(msh, degree); break; - case 200: m_neohokean = Neohookean(msh, degree); break; - case 201: - m_cavitation = Cavitation(msh, degree); - break; - // - case 300: m_log_elastic = mechanics::LogarithmicStrain>(msh, degree); break; - case 301: - m_log_linearHard = - mechanics::LogarithmicStrain>(msh, degree); - break; - case 302: - m_log_nonlinearHard = mechanics::LogarithmicStrain>(msh, degree); - break; + } - default: throw std::invalid_argument("Behavior error: Unknown id law"); + Behavior( const MeshType &msh, const size_t degree, const size_t deformation, const size_t law ) + : m_deformation( deformation ), m_law( law ) { + select_law(); + switch ( m_id ) { + case 100: + m_elastic = LinearElasticityLaw< MeshType >( msh, degree ); + break; + case 101: + m_linearHard = LinearIsotropicAndKinematicHardening< MeshType >( msh, degree ); + break; + case 102: + m_nonlinearHard = IsotropicHardeningVMis< MeshType >( msh, degree ); + break; + case 103: + m_henckymises = HenckyMises< MeshType >( msh, degree ); + break; + case 200: + m_neohokean = Neohookean< MeshType >( msh, degree ); + break; + case 201: + m_cavitation = Cavitation< MeshType >( msh, degree ); + break; + // + case 300: + m_log_elastic = + mechanics::LogarithmicStrain< LinearElasticityLaw< MeshType > >( msh, degree ); + break; + case 301: + m_log_linearHard = + mechanics::LogarithmicStrain< LinearIsotropicAndKinematicHardening< MeshType > >( + msh, degree ); + break; + case 302: + m_log_nonlinearHard = + mechanics::LogarithmicStrain< IsotropicHardeningVMis< MeshType > >( msh, degree ); + break; + + default: + throw std::invalid_argument( "Behavior error: Unknown id law" ); } } #ifdef HAVE_MGIS - Behavior(const MeshType& msh, - const size_t degree, - const std::string& filename, - const std::string& law, - const mgis::behaviour::Hypothesis h) : - m_law(LawType::MFRONT) - { + Behavior( const MeshType &msh, const size_t degree, const std::string &filename, + const std::string &law, const mgis::behaviour::Hypothesis h ) + : m_law( LawType::MFRONT ) { using namespace mgis::behaviour; std::cout << "Loading MFRONT law: " << law << std::endl; - if (isStandardFiniteStrainBehaviour(filename, law)) - { - m_deformation = DeformationMeasure::F_DEF; - auto opts = FiniteStrainBehaviourOptions{}; - opts.stress_measure = FiniteStrainBehaviourOptions::PK1; + if ( isStandardFiniteStrainBehaviour( filename, law ) ) { + m_deformation = DeformationMeasure::F_DEF; + auto opts = FiniteStrainBehaviourOptions {}; + opts.stress_measure = FiniteStrainBehaviourOptions::PK1; opts.tangent_operator = FiniteStrainBehaviourOptions::DPK1_DF; - m_behav = std::make_shared(load(opts, filename, law, h)); - } - else - { + m_behav = std::make_shared< Behaviour >( load( opts, filename, law, h ) ); + } else { m_deformation = DeformationMeasure::SMALL_DEF; - m_behav = std::make_shared(load(filename, law, h)); + m_behav = std::make_shared< Behaviour >( load( filename, law, h ) ); } - std::cout << "Behaviour type: " << (*m_behav).btype << std::endl; - std::cout << "Kinematic: " << (*m_behav).kinematic << std::endl; + std::cout << "Behaviour type: " << ( *m_behav ).btype << std::endl; + std::cout << "Kinematic: " << ( *m_behav ).kinematic << std::endl; std::cout << "Material properties: (name, type)" << std::endl; - for (const auto& mp : (*m_behav).mps) - std::cout << "* " << mp.name << ", " << MfrontVariableTypeName(mp.type) << std::endl; + for ( const auto &mp : ( *m_behav ).mps ) + std::cout << "* " << mp.name << ", " << MfrontVariableTypeName( mp.type ) << std::endl; std::cout << "Internal State Variables: (name, type)" << std::endl; - for (const auto& is : (*m_behav).isvs) - std::cout << "* " << is.name << ", " << MfrontVariableTypeName(is.type) << std::endl; + for ( const auto &is : ( *m_behav ).isvs ) + std::cout << "* " << is.name << ", " << MfrontVariableTypeName( is.type ) << std::endl; std::cout << "Thermodynamic forces: (name, type)" << std::endl; - for (const auto& fc : (*m_behav).thermodynamic_forces) - std::cout << "* " << fc.name << ", " << MfrontVariableTypeName(fc.type) << std::endl; + for ( const auto &fc : ( *m_behav ).thermodynamic_forces ) + std::cout << "* " << fc.name << ", " << MfrontVariableTypeName( fc.type ) << std::endl; select_law(); - switch (m_id) - { - case 500: m_mfront = Mfront(msh, degree, m_behav); break; - default: throw std::invalid_argument("Behavior error: Unknown id law"); + switch ( m_id ) { + case 500: + m_mfront = Mfront< MeshType >( msh, degree, m_behav ); + break; + default: + throw std::invalid_argument( "Behavior error: Unknown id law" ); } } #endif - size_t - getDeformation(void) const - { - return m_deformation; - } + size_t getDeformation( void ) const { return m_deformation; } - std::string - getDeformationName(void) const - { - return DeformationMeasureName(m_deformation); - } + std::string getDeformationName( void ) const { return DeformationMeasureName( m_deformation ); } - std::string - getLawName(void) const - { - return LawTypeName(m_law); - } + std::string getLawName( void ) const { return LawTypeName( m_law ); } - void - addMaterialData(const material_type& materialData) - { + void addMaterialData( const material_type &materialData ) { m_data = materialData; - switch (m_id) - { - case 100: m_elastic.addMaterialData(materialData); break; - case 101: m_linearHard.addMaterialData(materialData); break; - case 102: m_nonlinearHard.addMaterialData(materialData); break; - case 103: m_henckymises.addMaterialData(materialData); break; - case 200: m_neohokean.addMaterialData(materialData); break; - case 201: m_cavitation.addMaterialData(materialData); break; - case 300: m_log_elastic.addMaterialData(materialData); break; - case 301: m_log_linearHard.addMaterialData(materialData); break; - case 302: m_log_nonlinearHard.addMaterialData(materialData); break; + switch ( m_id ) { + case 100: + m_elastic.addMaterialData( materialData ); + break; + case 101: + m_linearHard.addMaterialData( materialData ); + break; + case 102: + m_nonlinearHard.addMaterialData( materialData ); + break; + case 103: + m_henckymises.addMaterialData( materialData ); + break; + case 200: + m_neohokean.addMaterialData( materialData ); + break; + case 201: + m_cavitation.addMaterialData( materialData ); + break; + case 300: + m_log_elastic.addMaterialData( materialData ); + break; + case 301: + m_log_linearHard.addMaterialData( materialData ); + break; + case 302: + m_log_nonlinearHard.addMaterialData( materialData ); + break; #ifdef HAVE_MGIS - case 500: m_mfront.addMaterialData(materialData); break; + case 500: + m_mfront.addMaterialData( materialData ); + break; #endif - default: throw std::invalid_argument("Behavior error: Unknown id law"); + default: + throw std::invalid_argument( "Behavior error: Unknown id law" ); } } - material_type - getMaterialData(void) - { - return m_data; - } + material_type getMaterialData( void ) { return m_data; } - const material_type& - getMaterialData(void) const - { - return m_data; - } + const material_type &getMaterialData( void ) const { return m_data; } /** * @brief Get number of quadrature points for the used law * * @return size_t number of quadrature law */ - size_t - numberOfQP(void) const - { - switch (m_id) - { - case 100: return m_elastic.getNumberOfQP(); break; - case 101: return m_linearHard.getNumberOfQP(); break; - case 102: return m_nonlinearHard.getNumberOfQP(); break; - case 103: return m_henckymises.getNumberOfQP(); break; - case 200: return m_neohokean.getNumberOfQP(); break; - case 201: return m_cavitation.getNumberOfQP(); break; - case 300: return m_log_elastic.getNumberOfQP(); break; - case 301: return m_log_linearHard.getNumberOfQP(); break; - case 302: return m_log_nonlinearHard.getNumberOfQP(); break; + size_t numberOfQP( void ) const { + switch ( m_id ) { + case 100: + return m_elastic.getNumberOfQP(); + break; + case 101: + return m_linearHard.getNumberOfQP(); + break; + case 102: + return m_nonlinearHard.getNumberOfQP(); + break; + case 103: + return m_henckymises.getNumberOfQP(); + break; + case 200: + return m_neohokean.getNumberOfQP(); + break; + case 201: + return m_cavitation.getNumberOfQP(); + break; + case 300: + return m_log_elastic.getNumberOfQP(); + break; + case 301: + return m_log_linearHard.getNumberOfQP(); + break; + case 302: + return m_log_nonlinearHard.getNumberOfQP(); + break; #ifdef HAVE_MGIS - case 500: return m_mfront.getNumberOfQP(); break; + case 500: + return m_mfront.getNumberOfQP(); + break; #endif - default: throw std::invalid_argument("Behavior error: Unknown id law"); + default: + throw std::invalid_argument( "Behavior error: Unknown id law" ); } } - size_t - numberOfQP(const size_t& cell_id) const - { - switch (m_id) - { - case 100: return m_elastic.getCellQPs(cell_id).getNumberOfQP(); break; - case 101: return m_linearHard.getCellQPs(cell_id).getNumberOfQP(); break; - case 102: return m_nonlinearHard.getCellQPs(cell_id).getNumberOfQP(); break; - case 103: return m_henckymises.getCellQPs(cell_id).getNumberOfQP(); break; - case 200: return m_neohokean.getCellQPs(cell_id).getNumberOfQP(); break; - case 201: return m_cavitation.getCellQPs(cell_id).getNumberOfQP(); break; - case 300: return m_log_elastic.getCellQPs(cell_id).getNumberOfQP(); break; - case 301: return m_log_linearHard.getCellQPs(cell_id).getNumberOfQP(); break; - case 302: return m_log_nonlinearHard.getCellQPs(cell_id).getNumberOfQP(); break; + size_t numberOfQP( size_t cell_id ) const { + switch ( m_id ) { + case 100: + return m_elastic.getCellQPs( cell_id ).getNumberOfQP(); + break; + case 101: + return m_linearHard.getCellQPs( cell_id ).getNumberOfQP(); + break; + case 102: + return m_nonlinearHard.getCellQPs( cell_id ).getNumberOfQP(); + break; + case 103: + return m_henckymises.getCellQPs( cell_id ).getNumberOfQP(); + break; + case 200: + return m_neohokean.getCellQPs( cell_id ).getNumberOfQP(); + break; + case 201: + return m_cavitation.getCellQPs( cell_id ).getNumberOfQP(); + break; + case 300: + return m_log_elastic.getCellQPs( cell_id ).getNumberOfQP(); + break; + case 301: + return m_log_linearHard.getCellQPs( cell_id ).getNumberOfQP(); + break; + case 302: + return m_log_nonlinearHard.getCellQPs( cell_id ).getNumberOfQP(); + break; #ifdef HAVE_MGIS - case 500: return m_mfront.getCellQPs(cell_id).getNumberOfQP(); break; + case 500: + return m_mfront.getCellQPs( cell_id ).getNumberOfQP(); + break; #endif - default: throw std::invalid_argument("Behavior error: Unknown id law"); + default: + throw std::invalid_argument( "Behavior error: Unknown id law" ); } } - size_t - numberOfQP(const MeshType& msh, const cell_type& cl) const - { - const auto cell_id = msh.lookup(cl); + size_t numberOfQP( const MeshType &msh, const cell_type &cl ) const { + const auto cell_id = msh.lookup( cl ); - return numberOfQP(cell_id); + return numberOfQP( cell_id ); } - auto - quadrature_point(const size_t& cell_id, const size_t& qp_id) const - { - switch (m_id) - { - case 100: return m_elastic.getCellQPs(cell_id).getQP(qp_id).quadrature_point(); break; - case 101: return m_linearHard.getCellQPs(cell_id).getQP(qp_id).quadrature_point(); break; - case 102: return m_nonlinearHard.getCellQPs(cell_id).getQP(qp_id).quadrature_point(); break; - case 103: return m_henckymises.getCellQPs(cell_id).getQP(qp_id).quadrature_point(); break; - case 200: return m_neohokean.getCellQPs(cell_id).getQP(qp_id).quadrature_point(); break; - case 201: return m_cavitation.getCellQPs(cell_id).getQP(qp_id).quadrature_point(); break; - case 300: return m_log_elastic.getCellQPs(cell_id).getQP(qp_id).quadrature_point(); break; - case 301: return m_log_linearHard.getCellQPs(cell_id).getQP(qp_id).quadrature_point(); break; - case 302: return m_log_nonlinearHard.getCellQPs(cell_id).getQP(qp_id).quadrature_point(); break; + auto quadrature_point( size_t cell_id, size_t qp_id ) const { + switch ( m_id ) { + case 100: + return m_elastic.getCellQPs( cell_id ).getQP( qp_id ).quadrature_point(); + break; + case 101: + return m_linearHard.getCellQPs( cell_id ).getQP( qp_id ).quadrature_point(); + break; + case 102: + return m_nonlinearHard.getCellQPs( cell_id ).getQP( qp_id ).quadrature_point(); + break; + case 103: + return m_henckymises.getCellQPs( cell_id ).getQP( qp_id ).quadrature_point(); + break; + case 200: + return m_neohokean.getCellQPs( cell_id ).getQP( qp_id ).quadrature_point(); + break; + case 201: + return m_cavitation.getCellQPs( cell_id ).getQP( qp_id ).quadrature_point(); + break; + case 300: + return m_log_elastic.getCellQPs( cell_id ).getQP( qp_id ).quadrature_point(); + break; + case 301: + return m_log_linearHard.getCellQPs( cell_id ).getQP( qp_id ).quadrature_point(); + break; + case 302: + return m_log_nonlinearHard.getCellQPs( cell_id ).getQP( qp_id ).quadrature_point(); + break; #ifdef HAVE_MGIS - case 500: return m_mfront.getCellQPs(cell_id).getQP(qp_id).quadrature_point(); break; + case 500: + return m_mfront.getCellQPs( cell_id ).getQP( qp_id ).quadrature_point(); + break; #endif - default: throw std::invalid_argument("Behavior error: Unknown id law"); + default: + throw std::invalid_argument( "Behavior error: Unknown id law" ); } } - std::pair - compute_whole(const size_t& cell_id, const size_t& qp_id, const static_matrix_type& RkT_iqn, bool tangent = true) - { - switch (m_id) - { - case 100: return m_elastic.getCellQPs(cell_id).getQP(qp_id).compute_whole(RkT_iqn, m_data, tangent); break; - case 101: - return m_linearHard.getCellQPs(cell_id).getQP(qp_id).compute_whole(RkT_iqn, m_data, tangent); - break; - case 102: - return m_nonlinearHard.getCellQPs(cell_id).getQP(qp_id).compute_whole(RkT_iqn, m_data, tangent); - break; - case 103: - return m_henckymises.getCellQPs(cell_id).getQP(qp_id).compute_whole(RkT_iqn, m_data, tangent); - break; - case 200: - return m_neohokean.getCellQPs(cell_id).getQP(qp_id).compute_whole(RkT_iqn, m_data, tangent); - break; - case 201: - return m_cavitation.getCellQPs(cell_id).getQP(qp_id).compute_whole(RkT_iqn, m_data, tangent); - break; - case 300: - return m_log_elastic.getCellQPs(cell_id).getQP(qp_id).compute_whole(RkT_iqn, m_data, tangent); - break; - case 301: - return m_log_linearHard.getCellQPs(cell_id).getQP(qp_id).compute_whole(RkT_iqn, m_data, tangent); - break; - case 302: - return m_log_nonlinearHard.getCellQPs(cell_id).getQP(qp_id).compute_whole(RkT_iqn, m_data, tangent); - break; + std::pair< static_matrix_type, static_tensor_type > + compute_whole( size_t cell_id, size_t qp_id, const static_matrix_type &RkT_iqn, + bool tangent = true ) { + switch ( m_id ) { + case 100: + return m_elastic.getCellQPs( cell_id ).getQP( qp_id ).compute_whole( RkT_iqn, m_data, + tangent ); + break; + case 101: + return m_linearHard.getCellQPs( cell_id ).getQP( qp_id ).compute_whole( RkT_iqn, m_data, + tangent ); + break; + case 102: + return m_nonlinearHard.getCellQPs( cell_id ).getQP( qp_id ).compute_whole( + RkT_iqn, m_data, tangent ); + break; + case 103: + return m_henckymises.getCellQPs( cell_id ).getQP( qp_id ).compute_whole( + RkT_iqn, m_data, tangent ); + break; + case 200: + return m_neohokean.getCellQPs( cell_id ).getQP( qp_id ).compute_whole( RkT_iqn, m_data, + tangent ); + break; + case 201: + return m_cavitation.getCellQPs( cell_id ).getQP( qp_id ).compute_whole( RkT_iqn, m_data, + tangent ); + break; + case 300: + return m_log_elastic.getCellQPs( cell_id ).getQP( qp_id ).compute_whole( + RkT_iqn, m_data, tangent ); + break; + case 301: + return m_log_linearHard.getCellQPs( cell_id ).getQP( qp_id ).compute_whole( + RkT_iqn, m_data, tangent ); + break; + case 302: + return m_log_nonlinearHard.getCellQPs( cell_id ).getQP( qp_id ).compute_whole( + RkT_iqn, m_data, tangent ); + break; +#ifdef HAVE_MGIS + case 500: + return m_mfront.getCellQPs( cell_id ).getQP( qp_id ).compute_whole( RkT_iqn, m_data, + tangent ); + break; +#endif + + default: + throw std::invalid_argument( "Behavior error: Unknown id law" ); + } + } + + static_matrix_type compute_stress( size_t cell_id, size_t qp_id, + const static_matrix_type &RkT_iqn ) { + switch ( m_id ) { + case 100: + return m_elastic.getCellQPs( cell_id ).getQP( qp_id ).compute_stress( RkT_iqn, m_data ); + break; + case 101: + return m_linearHard.getCellQPs( cell_id ).getQP( qp_id ).compute_stress( RkT_iqn, + m_data ); + break; + case 102: + return m_nonlinearHard.getCellQPs( cell_id ).getQP( qp_id ).compute_stress( RkT_iqn, + m_data ); + break; + case 103: + return m_henckymises.getCellQPs( cell_id ).getQP( qp_id ).compute_stress( RkT_iqn, + m_data ); + break; + case 200: + return m_neohokean.getCellQPs( cell_id ).getQP( qp_id ).compute_stress( RkT_iqn, + m_data ); + break; + case 201: + return m_cavitation.getCellQPs( cell_id ).getQP( qp_id ).compute_stress( RkT_iqn, + m_data ); + break; + case 300: + return m_log_elastic.getCellQPs( cell_id ).getQP( qp_id ).compute_stress( RkT_iqn, + m_data ); + break; + case 301: + return m_log_linearHard.getCellQPs( cell_id ).getQP( qp_id ).compute_stress( RkT_iqn, + m_data ); + break; + case 302: + return m_log_nonlinearHard.getCellQPs( cell_id ).getQP( qp_id ).compute_stress( + RkT_iqn, m_data ); + break; +#ifdef HAVE_MGIS + case 500: + return m_mfront.getCellQPs( cell_id ).getQP( qp_id ).compute_stress( RkT_iqn, m_data ); + break; +#endif + + default: + throw std::invalid_argument( "Behavior error: Unknown id law" ); + } + } + + static_matrix< scalar_type, 3, 3 > compute_stress3D( size_t cell_id, size_t qp_id ) const { + switch ( m_id ) { + case 100: + return m_elastic.getCellQPs( cell_id ).getQP( qp_id ).compute_stress3D( m_data ); + break; + case 101: + return m_linearHard.getCellQPs( cell_id ).getQP( qp_id ).compute_stress3D( m_data ); + break; + case 102: + return m_nonlinearHard.getCellQPs( cell_id ).getQP( qp_id ).compute_stress3D( m_data ); + break; + case 103: + return m_henckymises.getCellQPs( cell_id ).getQP( qp_id ).compute_stress3D( m_data ); + break; + case 200: + return m_neohokean.getCellQPs( cell_id ).getQP( qp_id ).compute_stress3D( m_data ); + break; + case 201: + return m_cavitation.getCellQPs( cell_id ).getQP( qp_id ).compute_stress3D( m_data ); + break; + case 300: + return m_log_elastic.getCellQPs( cell_id ).getQP( qp_id ).compute_stress3D( m_data ); + break; + case 301: + return m_log_linearHard.getCellQPs( cell_id ).getQP( qp_id ).compute_stress3D( m_data ); + break; + case 302: + return m_log_nonlinearHard.getCellQPs( cell_id ).getQP( qp_id ).compute_stress3D( + m_data ); + break; #ifdef HAVE_MGIS - case 500: return m_mfront.getCellQPs(cell_id).getQP(qp_id).compute_whole(RkT_iqn, m_data, tangent); break; + case 500: + return m_mfront.getCellQPs( cell_id ).getQP( qp_id ).compute_stress3D( m_data ); + break; #endif - default: throw std::invalid_argument("Behavior error: Unknown id law"); + default: + throw std::invalid_argument( "Behavior error: Unknown id law" ); } } - static_matrix - compute_stress3D(const size_t& cell_id, const size_t& qp_id) const - { - switch (m_id) - { - case 100: return m_elastic.getCellQPs(cell_id).getQP(qp_id).compute_stress3D(m_data); break; - case 101: return m_linearHard.getCellQPs(cell_id).getQP(qp_id).compute_stress3D(m_data); break; - case 102: return m_nonlinearHard.getCellQPs(cell_id).getQP(qp_id).compute_stress3D(m_data); break; - case 103: return m_henckymises.getCellQPs(cell_id).getQP(qp_id).compute_stress3D(m_data); break; - case 200: return m_neohokean.getCellQPs(cell_id).getQP(qp_id).compute_stress3D(m_data); break; - case 201: return m_cavitation.getCellQPs(cell_id).getQP(qp_id).compute_stress3D(m_data); break; - case 300: return m_log_elastic.getCellQPs(cell_id).getQP(qp_id).compute_stress3D(m_data); break; - case 301: return m_log_linearHard.getCellQPs(cell_id).getQP(qp_id).compute_stress3D(m_data); break; - case 302: return m_log_nonlinearHard.getCellQPs(cell_id).getQP(qp_id).compute_stress3D(m_data); break; + bool is_plastic( size_t cell_id, size_t qp_id ) const { + switch ( m_id ) { + case 100: + return m_elastic.getCellQPs( cell_id ).getQP( qp_id ).is_plastic(); + break; + case 101: + return m_linearHard.getCellQPs( cell_id ).getQP( qp_id ).is_plastic(); + break; + case 102: + return m_nonlinearHard.getCellQPs( cell_id ).getQP( qp_id ).is_plastic(); + break; + case 103: + return m_henckymises.getCellQPs( cell_id ).getQP( qp_id ).is_plastic(); + break; + case 200: + return m_neohokean.getCellQPs( cell_id ).getQP( qp_id ).is_plastic(); + break; + case 201: + return m_cavitation.getCellQPs( cell_id ).getQP( qp_id ).is_plastic(); + break; + case 300: + return m_log_elastic.getCellQPs( cell_id ).getQP( qp_id ).is_plastic(); + break; + case 301: + return m_log_linearHard.getCellQPs( cell_id ).getQP( qp_id ).is_plastic(); + break; + case 302: + return m_log_nonlinearHard.getCellQPs( cell_id ).getQP( qp_id ).is_plastic(); + break; #ifdef HAVE_MGIS - case 500: return m_mfront.getCellQPs(cell_id).getQP(qp_id).compute_stress3D(m_data); break; + case 500: + return m_mfront.getCellQPs( cell_id ).getQP( qp_id ).is_plastic(); + break; #endif - default: throw std::invalid_argument("Behavior error: Unknown id law"); + default: + throw std::invalid_argument( "Behavior error: Unknown id law" ); } } - bool - is_plastic(const size_t& cell_id, const size_t& qp_id) const - { - switch (m_id) - { - case 100: return m_elastic.getCellQPs(cell_id).getQP(qp_id).is_plastic(); break; - case 101: return m_linearHard.getCellQPs(cell_id).getQP(qp_id).is_plastic(); break; - case 102: return m_nonlinearHard.getCellQPs(cell_id).getQP(qp_id).is_plastic(); break; - case 103: return m_henckymises.getCellQPs(cell_id).getQP(qp_id).is_plastic(); break; - case 200: return m_neohokean.getCellQPs(cell_id).getQP(qp_id).is_plastic(); break; - case 201: return m_cavitation.getCellQPs(cell_id).getQP(qp_id).is_plastic(); break; - case 300: return m_log_elastic.getCellQPs(cell_id).getQP(qp_id).is_plastic(); break; - case 301: return m_log_linearHard.getCellQPs(cell_id).getQP(qp_id).is_plastic(); break; - case 302: return m_log_nonlinearHard.getCellQPs(cell_id).getQP(qp_id).is_plastic(); break; + scalar_type equivalentPlasticStrain( size_t cell_id, size_t qp_id ) const { + switch ( m_id ) { + case 100: + return m_elastic.getCellQPs( cell_id ).getQP( qp_id ).getEquivalentPlasticStrain(); + break; + case 101: + return m_linearHard.getCellQPs( cell_id ).getQP( qp_id ).getEquivalentPlasticStrain(); + break; + case 102: + return m_nonlinearHard.getCellQPs( cell_id ) + .getQP( qp_id ) + .getEquivalentPlasticStrain(); + break; + case 103: + return m_henckymises.getCellQPs( cell_id ).getQP( qp_id ).getEquivalentPlasticStrain(); + break; + case 200: + return m_neohokean.getCellQPs( cell_id ).getQP( qp_id ).getEquivalentPlasticStrain(); + break; + case 201: + return m_cavitation.getCellQPs( cell_id ).getQP( qp_id ).getEquivalentPlasticStrain(); + break; + case 300: + return m_log_elastic.getCellQPs( cell_id ).getQP( qp_id ).getEquivalentPlasticStrain(); + break; + case 301: + return m_log_linearHard.getCellQPs( cell_id ) + .getQP( qp_id ) + .getEquivalentPlasticStrain(); + break; + case 302: + return m_log_nonlinearHard.getCellQPs( cell_id ) + .getQP( qp_id ) + .getEquivalentPlasticStrain(); + break; #ifdef HAVE_MGIS - case 500: return m_mfront.getCellQPs(cell_id).getQP(qp_id).is_plastic(); break; + case 500: + return m_mfront.getCellQPs( cell_id ).getQP( qp_id ).getEquivalentPlasticStrain(); + break; #endif - default: throw std::invalid_argument("Behavior error: Unknown id law"); + default: + throw std::invalid_argument( "Behavior error: Unknown id law" ); } } - scalar_type - equivalentPlasticStrain(const size_t& cell_id, const size_t& qp_id) const - { - switch (m_id) - { - case 100: return m_elastic.getCellQPs(cell_id).getQP(qp_id).getEquivalentPlasticStrain(); break; - case 101: return m_linearHard.getCellQPs(cell_id).getQP(qp_id).getEquivalentPlasticStrain(); break; - case 102: return m_nonlinearHard.getCellQPs(cell_id).getQP(qp_id).getEquivalentPlasticStrain(); break; - case 103: return m_henckymises.getCellQPs(cell_id).getQP(qp_id).getEquivalentPlasticStrain(); break; - case 200: return m_neohokean.getCellQPs(cell_id).getQP(qp_id).getEquivalentPlasticStrain(); break; - case 201: return m_cavitation.getCellQPs(cell_id).getQP(qp_id).getEquivalentPlasticStrain(); break; - case 300: return m_log_elastic.getCellQPs(cell_id).getQP(qp_id).getEquivalentPlasticStrain(); break; - case 301: return m_log_linearHard.getCellQPs(cell_id).getQP(qp_id).getEquivalentPlasticStrain(); break; - case 302: return m_log_nonlinearHard.getCellQPs(cell_id).getQP(qp_id).getEquivalentPlasticStrain(); break; + void update( void ) { + switch ( m_id ) { + case 100: + return m_elastic.update(); + break; + case 101: + return m_linearHard.update(); + break; + case 102: + return m_nonlinearHard.update(); + break; + case 103: + return m_henckymises.update(); + break; + case 200: + return m_neohokean.update(); + break; + case 201: + return m_cavitation.update(); + break; + case 300: + return m_log_elastic.update(); + break; + case 301: + return m_log_linearHard.update(); + break; + case 302: + return m_log_nonlinearHard.update(); + break; #ifdef HAVE_MGIS - case 500: return m_mfront.getCellQPs(cell_id).getQP(qp_id).getEquivalentPlasticStrain(); break; + case 500: + return m_mfront.update(); + break; #endif - default: throw std::invalid_argument("Behavior error: Unknown id law"); + default: + throw std::invalid_argument( "Behavior error: Unknown id law" ); } } - void - update(void) - { - switch (m_id) - { - case 100: return m_elastic.update(); break; - case 101: return m_linearHard.update(); break; - case 102: return m_nonlinearHard.update(); break; - case 103: return m_henckymises.update(); break; - case 200: return m_neohokean.update(); break; - case 201: return m_cavitation.update(); break; - case 300: return m_log_elastic.update(); break; - case 301: return m_log_linearHard.update(); break; - case 302: return m_log_nonlinearHard.update(); break; + void restore( void ) { + switch ( m_id ) { + case 100: + return m_elastic.restore(); + break; + case 101: + return m_linearHard.restore(); + break; + case 102: + return m_nonlinearHard.restore(); + break; + case 103: + return m_henckymises.restore(); + break; + case 200: + return m_neohokean.restore(); + break; + case 201: + return m_cavitation.restore(); + break; + case 300: + return m_log_elastic.restore(); + break; + case 301: + return m_log_linearHard.restore(); + break; + case 302: + return m_log_nonlinearHard.restore(); + break; #ifdef HAVE_MGIS - case 500: return m_mfront.update(); break; + case 500: + return m_mfront.restore(); + break; #endif - default: throw std::invalid_argument("Behavior error: Unknown id law"); + default: + throw std::invalid_argument( "Behavior error: Unknown id law" ); } } - vector_type - projectStressOnCell(const MeshType& msh, const cell_type& cl, const hho_degree_info& hdi) const - { - switch (m_id) - { - case 100: return m_elastic.projectStressOnCell(msh, cl, hdi, m_data); break; - case 101: return m_linearHard.projectStressOnCell(msh, cl, hdi, m_data); break; - case 102: return m_nonlinearHard.projectStressOnCell(msh, cl, hdi, m_data); break; - case 103: return m_henckymises.projectStressOnCell(msh, cl, hdi, m_data); break; - case 200: return m_neohokean.projectStressOnCell(msh, cl, hdi, m_data); break; - case 201: return m_cavitation.projectStressOnCell(msh, cl, hdi, m_data); break; + vector_type projectStressOnCell( const MeshType &msh, const cell_type &cl, + const std::size_t grad_degree ) const { + + const auto cell_id = msh.lookup( cl ); + switch ( m_id ) { + case 100: + return m_elastic.getCellQPs( cell_id ).projectStressOnCell( msh, cl, grad_degree, + m_data ); + break; + case 101: + return m_linearHard.getCellQPs( cell_id ).projectStressOnCell( msh, cl, grad_degree, + m_data ); + break; + case 102: + return m_nonlinearHard.getCellQPs( cell_id ).projectStressOnCell( msh, cl, grad_degree, + m_data ); + break; + case 103: + return m_henckymises.getCellQPs( cell_id ).projectStressOnCell( msh, cl, grad_degree, + m_data ); + break; + case 200: + return m_neohokean.getCellQPs( cell_id ).projectStressOnCell( msh, cl, grad_degree, + m_data ); + break; + case 201: + return m_cavitation.getCellQPs( cell_id ).projectStressOnCell( msh, cl, grad_degree, + m_data ); + break; #ifdef HAVE_MGIS - case 500: return m_mfront.projectStressOnCell(msh, cl, hdi, m_data); break; + case 500: + throw std::runtime_error( "Not implemented for mfront" ); + break; #endif - default: throw std::invalid_argument("Behavior error: Unknown id law"); + default: + throw std::invalid_argument( "Behavior error: Unknown id law" ); } } @@ -541,4 +839,5 @@ class Behavior // } // } }; -} +} // namespace mechanics +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/behaviorlaws_names.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/behaviorlaws_names.hpp index 7e1c57e5..da00e41b 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/behaviorlaws_names.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/behaviorlaws_names.hpp @@ -28,78 +28,98 @@ #include -namespace disk -{ +namespace disk { +namespace mechanics { - -enum DeformationMeasure : size_t -{ - SMALL_DEF = 0, +enum DeformationMeasure : size_t { + SMALL_DEF = 0, LOGARITHMIC_DEF = 1, - F_DEF = 2, + F_DEF = 2, }; -enum LawType : size_t -{ - ELASTIC = 0, - LINEAR_HARDENING = 1, +enum LawType : size_t { + ELASTIC = 0, + LINEAR_HARDENING = 1, NONLINEAR_HARDENING = 2, - HENCKY_MISES = 3, - NEOHOKEAN = 4, - CAVITATION = 5, - MFRONT = 6 + HENCKY_MISES = 3, + NEOHOKEAN = 4, + CAVITATION = 5, + MFRONT = 6 }; -enum MfrontVariableType : size_t -{ - SCALAR = 0, - VECTOR = 1, +enum MfrontVariableType : size_t { + SCALAR = 0, + VECTOR = 1, STENSOR = 2, - TENSOR = 3, + TENSOR = 3, }; -std::string -DeformationMeasureName(const size_t& def) -{ - switch (def) - { - case DeformationMeasure::SMALL_DEF: return "SMALL_DEF"; break; - case DeformationMeasure::LOGARITHMIC_DEF: return "LOGARITHMIC_DEF"; break; - case DeformationMeasure::F_DEF: return "F_DEF"; break; - default: - throw std::invalid_argument("Unknown deformation"); - break; +std::string DeformationMeasureName( size_t def ) { + switch ( def ) { + case DeformationMeasure::SMALL_DEF: + return "SMALL_DEF"; + break; + case DeformationMeasure::LOGARITHMIC_DEF: + return "LOGARITHMIC_DEF"; + break; + case DeformationMeasure::F_DEF: + return "F_DEF"; + break; + default: + throw std::invalid_argument( "Unknown deformation" ); + break; } } -std::string -LawTypeName(const size_t& law) -{ - switch (law) - { - case LawType::ELASTIC: return "ELASTIC"; break; - case LawType::LINEAR_HARDENING: return "LINEAR_HARDENING"; break; - case LawType::NONLINEAR_HARDENING: return "NONLINEAR_HARDENING"; break; - case LawType::HENCKY_MISES: return "HENCKY_MISES"; break; - case LawType::NEOHOKEAN: return "NEOHOKEAN"; break; - case LawType::CAVITATION: return "CAVITATION"; break; - case LawType::MFRONT: return "MFRONT"; break; +std::string LawTypeName( size_t law ) { + switch ( law ) { + case LawType::ELASTIC: + return "ELASTIC"; + break; + case LawType::LINEAR_HARDENING: + return "LINEAR_HARDENING"; + break; + case LawType::NONLINEAR_HARDENING: + return "NONLINEAR_HARDENING"; + break; + case LawType::HENCKY_MISES: + return "HENCKY_MISES"; + break; + case LawType::NEOHOKEAN: + return "NEOHOKEAN"; + break; + case LawType::CAVITATION: + return "CAVITATION"; + break; + case LawType::MFRONT: + return "MFRONT"; + break; - default: throw std::invalid_argument("Not known law"); break; + default: + throw std::invalid_argument( "Not known law" ); + break; } } -std::string -MfrontVariableTypeName(const size_t& var) -{ - switch (var) - { - case MfrontVariableType::SCALAR: return "SCALAR"; break; - case MfrontVariableType::VECTOR: return "VECTOR"; break; - case MfrontVariableType::STENSOR: return "STENSOR"; break; - case MfrontVariableType::TENSOR: return "TENSOR"; break; +std::string MfrontVariableTypeName( size_t var ) { + switch ( var ) { + case MfrontVariableType::SCALAR: + return "SCALAR"; + break; + case MfrontVariableType::VECTOR: + return "VECTOR"; + break; + case MfrontVariableType::STENSOR: + return "STENSOR"; + break; + case MfrontVariableType::TENSOR: + return "TENSOR"; + break; - default: throw std::invalid_argument("Not known variable"); break; + default: + throw std::invalid_argument( "Not known variable" ); + break; } } -}; \ No newline at end of file +} // namespace mechanics +}; // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/law_bones.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/law_bones.hpp index ad12e2bb..00610306 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/law_bones.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/law_bones.hpp @@ -26,96 +26,76 @@ #pragma once -#include - #include "diskpp/common/eigen.hpp" #include "diskpp/mechanics/behaviors/laws/law_cell_bones.hpp" #include "diskpp/mechanics/behaviors/maths_tensor.hpp" #include "diskpp/mechanics/behaviors/maths_utils.hpp" -namespace disk -{ +#include + +namespace disk { + +namespace mechanics { // Law bones -template -class LawTypeBones -{ +template < typename MeshType, typename LawTypeQp, bool PlasticBehavior > +class LawTypeBones { public: - typedef MeshType mesh_type; + typedef MeshType mesh_type; typedef typename mesh_type::coordinate_type scalar_type; - typedef typename mesh_type::cell cell_type; - typedef LawTypeQp law_qp_type; - typedef typename law_qp_type::data_type data_type; + typedef typename mesh_type::cell cell_type; + typedef LawTypeQp law_qp_type; + typedef typename law_qp_type::data_type data_type; private: - typedef LawTypeCellBones law_cell_type; + typedef LawTypeCellBones< mesh_type, law_qp_type, PlasticBehavior > law_cell_type; - size_t m_nb_qp; - std::vector m_list_cell_qp; - data_type m_data; + size_t m_nb_qp; + std::vector< law_cell_type > m_list_cell_qp; + data_type m_data; public: - LawTypeBones() : m_nb_qp(0){}; + LawTypeBones() : m_nb_qp( 0 ) {}; - LawTypeBones(const mesh_type& msh, const size_t degree) - { + LawTypeBones( const mesh_type &msh, const size_t degree ) { m_nb_qp = 0; m_list_cell_qp.clear(); - m_list_cell_qp.reserve(msh.cells_size()); + m_list_cell_qp.reserve( msh.cells_size() ); - for (auto& cl : msh) - { - law_cell_type cell_qp(msh, cl, degree); + for ( auto &cl : msh ) { + law_cell_type cell_qp( msh, cl, degree ); - m_list_cell_qp.push_back(cell_qp); + m_list_cell_qp.push_back( cell_qp ); m_nb_qp += cell_qp.getNumberOfQP(); } } - void - addMaterialData(const data_type materialData) - { - m_data = materialData; - } + void addMaterialData( const data_type materialData ) { m_data = materialData; } - data_type - getMaterialData() const - { - return m_data; - } + data_type getMaterialData() const { return m_data; } - int - getNumberOfQP() const - { - return m_nb_qp; - } + int getNumberOfQP() const { return m_nb_qp; } - void - update() - { - for (auto& qp_cell : m_list_cell_qp) - { + void update() { + for ( auto &qp_cell : m_list_cell_qp ) { qp_cell.update(); } } - law_cell_type& - getCellQPs(const int cell_id) - { - return m_list_cell_qp.at(cell_id); + void restore() { + for ( auto &qp_cell : m_list_cell_qp ) { + qp_cell.restore(); + } } - const law_cell_type& - getCellQPs(const int cell_id) const - { - return m_list_cell_qp.at(cell_id); - } + law_cell_type &getCellQPs( const int cell_id ) { return m_list_cell_qp.at( cell_id ); } - law_cell_type - getCellIVs(const int cell_id) const - { - return m_list_cell_qp.at(cell_id); + const law_cell_type &getCellQPs( const int cell_id ) const { + return m_list_cell_qp.at( cell_id ); } + + law_cell_type getCellIVs( const int cell_id ) const { return m_list_cell_qp.at( cell_id ); } }; -} +} // namespace mechanics +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/law_cell_bones.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/law_cell_bones.hpp index fc6d49fc..bf56d9f2 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/law_cell_bones.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/law_cell_bones.hpp @@ -26,8 +26,6 @@ #pragma once -#include - #include "diskpp/bases/bases.hpp" #include "diskpp/common/eigen.hpp" #include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" @@ -36,169 +34,142 @@ #include "diskpp/methods/hho" #include "diskpp/quadratures/quadratures.hpp" -namespace disk -{ +#include +namespace disk { +namespace mechanics { /// Law cell bones -template -class LawTypeCellBones -{ +template < typename MeshType, typename LawTypeQp, bool PlasticBehavior > +class LawTypeCellBones { public: - typedef MeshType mesh_type; + typedef MeshType mesh_type; typedef typename mesh_type::coordinate_type scalar_type; - typedef typename mesh_type::cell cell_type; + typedef typename mesh_type::cell cell_type; - typedef LawTypeQp law_qp_type; + typedef LawTypeQp law_qp_type; typedef typename LawTypeQp::data_type data_type; - typedef dynamic_matrix matrix_type; - typedef dynamic_vector vector_type; + typedef dynamic_matrix< scalar_type > matrix_type; + typedef dynamic_vector< scalar_type > vector_type; const static size_t dimension = mesh_type::dimension; private: - std::vector m_list_qp; + std::vector< law_qp_type > m_list_qp; public: - LawTypeCellBones(const mesh_type& msh, const cell_type& cl, const size_t degree) - { - const auto qps = integrate(msh, cl, degree); + LawTypeCellBones( const mesh_type &msh, const cell_type &cl, const size_t degree ) { + const auto qps = integrate( msh, cl, degree ); m_list_qp.clear(); - m_list_qp.reserve(qps.size()); + m_list_qp.reserve( qps.size() ); - for (auto& qp : qps) - { - m_list_qp.push_back(law_qp_type(qp.point(), qp.weight())); + for ( auto &qp : qps ) { + m_list_qp.push_back( law_qp_type( qp.point(), qp.weight() ) ); } } - int - getNumberOfQP() const - { - return m_list_qp.size(); - } + int getNumberOfQP() const { return m_list_qp.size(); } - void - update() - { - for (auto& qp : m_list_qp) - { + void update() { + for ( auto &qp : m_list_qp ) { qp.update(); } } - std::vector& - getQPs() - { - return m_list_qp; + void restore() { + for ( auto &qp : m_list_qp ) { + qp.restore(); + } } - const std::vector& - getQPs() const - { - return m_list_qp; - } + std::vector< law_qp_type > &getQPs() { return m_list_qp; } - law_qp_type& - getQP(const size_t& qp_id) - { - return m_list_qp[qp_id]; - } + const std::vector< law_qp_type > &getQPs() const { return m_list_qp; } - const law_qp_type& - getQP(const size_t& qp_id) const - { - return m_list_qp[qp_id]; - } + law_qp_type &getQP( size_t qp_id ) { return m_list_qp[qp_id]; } - std::vector - getIVs() const - { - return m_list_qp; - } + const law_qp_type &getQP( size_t qp_id ) const { return m_list_qp[qp_id]; } + + std::vector< law_qp_type > getIVs() const { return m_list_qp; } - vector_type - projectStressOnCell(const mesh_type& msh, - const cell_type& cl, - const hho_degree_info& hdi, - const data_type& material_data) const - { - const auto grad_degree = hdi.grad_degree(); - const int grad_basis_size = matrix_basis_size(grad_degree, dimension, dimension); - const auto gb = make_matrix_monomial_basis(msh, cl, grad_degree); + vector_type projectStressOnCell( const mesh_type &msh, const cell_type &cl, + const size_t grad_degree, + const data_type &material_data ) const { + const int grad_basis_size = matrix_basis_size( grad_degree, dimension, dimension ); + const auto gb = make_matrix_monomial_basis( msh, cl, grad_degree ); - const matrix_type mass = make_mass_matrix(msh, cl, gb); - vector_type rhs = vector_type::Zero(grad_basis_size); + const matrix_type mass = make_mass_matrix( msh, cl, gb ); + vector_type rhs = vector_type::Zero( grad_basis_size ); - for (auto& qp : m_list_qp) - { - const auto stress = qp.compute_stress(material_data); - const auto gphi = gb.eval_functions(qp.point()); - assert(gphi.size() == grad_basis_size); + for ( auto &qp : m_list_qp ) { + const auto stress = qp.compute_stress( material_data ); + const auto gphi = gb.eval_functions( qp.point() ); + assert( gphi.size() == grad_basis_size ); - const auto qp_stress = priv::inner_product(qp.weight(), stress); + const auto qp_stress = disk::priv::inner_product( qp.weight(), stress ); - rhs += priv::outer_product(gphi, qp_stress); + rhs += disk::priv::outer_product( gphi, qp_stress ); } - return mass.ldlt().solve(rhs); + return mass.ldlt().solve( rhs ); + } + + vector_type projectStressOnCell( const mesh_type &msh, const cell_type &cl, + const hho_degree_info &hdi, + const data_type &material_data ) const { + const auto grad_degree = hdi.grad_degree(); + return this->projectStressOnCell( msh, cl, grad_degree, material_data ); } - vector_type - projectPOnCell(const mesh_type& msh, const cell_type& cl, const hho_degree_info& hdi) const - { + vector_type projectPOnCell( const mesh_type &msh, const cell_type &cl, + const hho_degree_info &hdi ) const { const auto grad_degree = hdi.grad_degree(); - const int pbs = scalar_basis_size(grad_degree, dimension); + const int pbs = scalar_basis_size( grad_degree, dimension ); - if (PlasticBehavior) - { - const auto pb = make_scalar_monomial_basis(msh, cl, grad_degree); + if ( PlasticBehavior ) { + const auto pb = make_scalar_monomial_basis( msh, cl, grad_degree ); - const matrix_type mass = make_mass_matrix(msh, cl, pb); - vector_type rhs = vector_type::Zero(pbs); + const matrix_type mass = make_mass_matrix( msh, cl, pb ); + vector_type rhs = vector_type::Zero( pbs ); - for (auto& qp : m_list_qp) - { - const auto pphi = pb.eval_functions(qp.point()); + for ( auto &qp : m_list_qp ) { + const auto pphi = pb.eval_functions( qp.point() ); rhs += qp.weight() * qp.getEquivalentPlasticStrain() * pphi; } - return mass.ldlt().solve(rhs); + return mass.ldlt().solve( rhs ); } - return vector_type::Zero(pbs); + return vector_type::Zero( pbs ); } - vector_type - projectStateOnCell(const mesh_type& msh, const cell_type& cl, const hho_degree_info& hdi) const - { + vector_type projectStateOnCell( const mesh_type &msh, const cell_type &cl, + const hho_degree_info &hdi ) const { const auto grad_degree = hdi.grad_degree(); - const int pbs = scalar_basis_size(grad_degree, dimension); + const int pbs = scalar_basis_size( grad_degree, dimension ); - if (PlasticBehavior) - { - const auto pb = make_scalar_monomial_basis(msh, cl, grad_degree); + if ( PlasticBehavior ) { + const auto pb = make_scalar_monomial_basis( msh, cl, grad_degree ); - const matrix_type mass = make_mass_matrix(msh, cl, pb); - vector_type rhs = vector_type::Zero(pbs); + const matrix_type mass = make_mass_matrix( msh, cl, pb ); + vector_type rhs = vector_type::Zero( pbs ); - for (auto& qp : m_list_qp) - { - const auto pphi = pb.eval_functions(qp.point()); - assert(pphi.size() == pbs); + for ( auto &qp : m_list_qp ) { + const auto pphi = pb.eval_functions( qp.point() ); + assert( pphi.size() == pbs ); - if (qp.is_plastic()) - { + if ( qp.is_plastic() ) { rhs += qp.weight() * pphi; } } - return mass.ldlt().solve(rhs); + return mass.ldlt().solve( rhs ); } - return vector_type::Zero(pbs); + return vector_type::Zero( pbs ); } }; -} +} // namespace mechanics +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/law_qp_bones.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/law_qp_bones.hpp index 0d0a6c9b..c30e1781 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/law_qp_bones.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/law_qp_bones.hpp @@ -34,8 +34,8 @@ #include "diskpp/mesh/point.hpp" #include "diskpp/quadratures/quadrature_point.hpp" -namespace disk -{ +namespace disk { +namespace mechanics { // Bones for the computation of a behavior law at a quadrature point @@ -50,15 +50,14 @@ using qpoint = quadrature_point; } -template -class law_qp_bones -{ +template < typename T, int DIM > +class law_qp_bones { public: - typedef T scalar_type; - typedef static_matrix static_matrix_type; - typedef static_matrix static_matrix_type3D; - const static size_t dimension = DIM; - typedef MaterialData data_type; + typedef T scalar_type; + typedef static_matrix< scalar_type, DIM, DIM > static_matrix_type; + typedef static_matrix< scalar_type, 3, 3 > static_matrix_type3D; + const static size_t dimension = DIM; + typedef MaterialData< scalar_type > data_type; protected: // coordinat and weight of considered gauss point. @@ -71,37 +70,33 @@ class law_qp_bones // internal variables at current step static_matrix_type3D m_estrain_curr; // elastic strain - static_tensor - elastic_modulus(const data_type& data) const - { + static_tensor< scalar_type, DIM > elastic_modulus( const data_type &data ) const { - return 2 * data.getMu() * IdentitySymTensor4() + data.getLambda() * IxI(); + return 2 * data.getMu() * IdentitySymTensor4< scalar_type, DIM >() + + data.getLambda() * IxI< scalar_type, DIM >(); } - static_tensor - elastic_modulus3D(const data_type& data) const - { + static_tensor< scalar_type, 3 > elastic_modulus3D( const data_type &data ) const { - return 2 * data.getMu() * IdentitySymTensor4() + data.getLambda() * IxI(); + return 2 * data.getMu() * IdentitySymTensor4< scalar_type, 3 >() + + data.getLambda() * IxI< scalar_type, 3 >(); } - scalar_type - sigmaeq(const static_matrix_type3D& dev) const - { - return sqrt(scalar_type(1.5) * dev.squaredNorm()); + scalar_type sigmaeq( const static_matrix_type3D &dev ) const { + return sqrt( scalar_type( 1.5 ) * dev.squaredNorm() ); } public: - law_qp_bones() : - m_weight(0), m_estrain_prev(static_matrix_type3D::Zero()), m_estrain_curr(static_matrix_type3D::Zero()) - { - } + law_qp_bones() + : m_weight( 0 ), + m_estrain_prev( static_matrix_type3D::Zero() ), + m_estrain_curr( static_matrix_type3D::Zero() ) {} - law_qp_bones(const point& point, const scalar_type& weight) : - m_point(point), m_weight(weight), m_estrain_prev(static_matrix_type3D::Zero()), - m_estrain_curr(static_matrix_type3D::Zero()) - { - } + law_qp_bones( const point< scalar_type, DIM > &point, scalar_type weight ) + : m_point( point ), + m_weight( weight ), + m_estrain_prev( static_matrix_type3D::Zero() ), + m_estrain_curr( static_matrix_type3D::Zero() ) {} priv::qpoint quadrature_point() const @@ -109,58 +104,25 @@ class law_qp_bones return make_qp(m_point, m_weight); } - priv::ppoint - point() const - { - return m_point; - } + auto point() const { return m_point; } - scalar_type - weight() const - { - return m_weight; - } + scalar_type weight() const { return m_weight; } - bool - is_plastic() const - { - return false; - } + bool is_plastic() const { return false; } - static_matrix_type3D - getElasticStrain() const - { - return m_estrain_curr; - } + static_matrix_type3D getElasticStrain() const { return m_estrain_curr; } - static_matrix_type3D - getPlasticStrain() const - { - return static_matrix_type3D::Zero(); - } + static_matrix_type3D getPlasticStrain() const { return static_matrix_type3D::Zero(); } - static_matrix_type - getTotalStrain() const - { - return m_estrain_curr.block(0, 0, DIM, DIM); - } + static_matrix_type getTotalStrain() const { return m_estrain_curr.block( 0, 0, DIM, DIM ); } - static_matrix_type - getTotalStrainPrev() const - { - return m_estrain_prev.block(0, 0, DIM, DIM); - } + static_matrix_type getTotalStrainPrev() const { return m_estrain_prev.block( 0, 0, DIM, DIM ); } - scalar_type - getEquivalentPlasticStrain() const - { - return scalar_type(0); - } + scalar_type getEquivalentPlasticStrain() const { return scalar_type( 0 ); } - void - update() - { - m_estrain_prev = m_estrain_curr; - } + void update() { m_estrain_prev = m_estrain_curr; } + + void restore() { m_estrain_curr = m_estrain_prev; } }; -} +} // namespace mechanics +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/laws/materialData.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/laws/materialData.hpp index fc5b9e7f..a594cf2d 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/laws/materialData.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/laws/materialData.hpp @@ -28,244 +28,145 @@ #define _USE_MATH_DEFINES #include -namespace disk -{ +namespace disk { -template -class curve_point -{ +namespace mechanics { + +template < typename T > +class curve_point { private: T m_p; T m_Rp; public: - curve_point() : m_p(T(0)), m_Rp(T(0)) {} + curve_point() : m_p( T( 0 ) ), m_Rp( T( 0 ) ) {} - curve_point(const T p, const T Rp) : m_p(p), m_Rp(Rp) {} + curve_point( const T p, const T Rp ) : m_p( p ), m_Rp( Rp ) {} - T - getP() const - { - return m_p; - } + T getP() const { return m_p; } - T - getRp() const - { - return m_Rp; - } + T getRp() const { return m_Rp; } }; -template -class MaterialData -{ - typedef std::pair MfrontType; +template < typename scalar_type > +class MaterialData { + typedef std::pair< std::string, scalar_type > MfrontType; private: - scalar_type m_lambda; - scalar_type m_mu; - scalar_type m_H; - scalar_type m_K; - scalar_type m_sigma_y0; - size_t m_type; - std::vector> m_Rp_curve; - std::vector m_mfront_param; + scalar_type m_lambda; + scalar_type m_mu; + scalar_type m_H; + scalar_type m_K; + scalar_type m_sigma_y0; + size_t m_type; + std::vector< curve_point< scalar_type > > m_Rp_curve; + std::vector< MfrontType > m_mfront_param; + scalar_type m_rho; public: - MaterialData() : - m_lambda(1.0), m_mu(1.0), m_H(0), m_K(0), m_sigma_y0(std::numeric_limits::max()), m_type(1) - { - } + MaterialData() + : m_lambda( 1.0 ), + m_mu( 1.0 ), + m_H( 0 ), + m_K( 0 ), + m_sigma_y0( std::numeric_limits< scalar_type >::max() ), + m_type( 1 ), + m_rho( 0.0 ) {} - MaterialData(const scalar_type& lambda, - const scalar_type& mu, - const scalar_type& H, - const scalar_type& K, - const scalar_type& sigma_y0) : - m_lambda(lambda), - m_mu(mu), m_H(H), m_K(K), m_sigma_y0(sigma_y0), m_type(0) - { - } + MaterialData( scalar_type lambda, scalar_type mu, scalar_type H, scalar_type K, + scalar_type sigma_y0 ) + : m_lambda( lambda ), m_mu( mu ), m_H( H ), m_K( K ), m_sigma_y0( sigma_y0 ), m_type( 0 ) {} - MaterialData(const scalar_type& lambda, const scalar_type& mu) : - m_lambda(lambda), m_mu(mu), m_H(0), m_K(0), m_sigma_y0(std::numeric_limits::max()), m_type(0) - { - } + MaterialData( scalar_type lambda, scalar_type mu ) + : m_lambda( lambda ), + m_mu( mu ), + m_H( 0 ), + m_K( 0 ), + m_sigma_y0( std::numeric_limits< scalar_type >::max() ), + m_type( 0 ) {} - void - setMu(const scalar_type mu) - { - m_mu = mu; - } + void setMu( const scalar_type mu ) { m_mu = mu; } - void - setMu(const scalar_type E, const scalar_type nu) - { - m_mu = E / (2.0 * (1.0 + nu)); - } + void setMu( const scalar_type E, const scalar_type nu ) { m_mu = E / ( 2.0 * ( 1.0 + nu ) ); } - void - setLambda(const scalar_type lambda) - { - m_lambda = lambda; - } + void setLambda( const scalar_type lambda ) { m_lambda = lambda; } - void - setLambda(const scalar_type E, const scalar_type nu) - { - m_lambda = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu)); + void setLambda( const scalar_type E, const scalar_type nu ) { + m_lambda = E * nu / ( ( 1.0 + nu ) * ( 1.0 - 2.0 * nu ) ); } - void - setH(const scalar_type H) - { - m_H = H; - } + void setH( const scalar_type H ) { m_H = H; } - void - setH(const scalar_type E, const scalar_type ET, const scalar_type K) - { - m_H = E * ET / (E - ET) - 1.5 * K; + void setH( const scalar_type E, const scalar_type ET, const scalar_type K ) { + m_H = E * ET / ( E - ET ) - 1.5 * K; } - void - setK(const scalar_type K) - { - m_K = K; - } + void setK( const scalar_type K ) { m_K = K; } - void - setSigma_y0(const scalar_type sigma_y0) - { - m_sigma_y0 = sigma_y0; - } + void setRho( const scalar_type rho ) { m_rho = rho; } - void - setType(const size_t type) - { - m_type = type; - } + void setSigma_y0( const scalar_type sigma_y0 ) { m_sigma_y0 = sigma_y0; } + + void setType( const size_t type ) { m_type = type; } - void - setRpCurve(const std::vector> RpCurve) - { + void setRpCurve( const std::vector< curve_point< scalar_type > > RpCurve ) { m_Rp_curve = RpCurve; } - void - addCurvePoint(const curve_point point) - { - m_Rp_curve.push_back(point); - } + void addCurvePoint( const curve_point< scalar_type > point ) { m_Rp_curve.push_back( point ); } - void - addCurvePoint(const scalar_type p, const scalar_type Rp) - { - m_Rp_curve.push_back(curve_point(p, Rp)); + void addCurvePoint( const scalar_type p, const scalar_type Rp ) { + m_Rp_curve.push_back( curve_point< scalar_type >( p, Rp ) ); } - scalar_type - getE() const - { - return m_mu * (3 * m_lambda + 2 * m_mu) / (m_lambda + m_mu); - } + scalar_type getE() const { return m_mu * ( 3 * m_lambda + 2 * m_mu ) / ( m_lambda + m_mu ); } - scalar_type - getNu() const - { - return m_lambda / (2 * (m_lambda + m_mu)); - } + scalar_type getNu() const { return m_lambda / ( 2 * ( m_lambda + m_mu ) ); } - scalar_type - getET() const - { + scalar_type getET() const { const scalar_type E = getE(); - return E * (m_H + 1.5 * m_K) / (m_H + 1.5 * m_K + E); + return E * ( m_H + 1.5 * m_K ) / ( m_H + 1.5 * m_K + E ); } - scalar_type - getLambda() const - { - return m_lambda; - } + scalar_type getLambda() const { return m_lambda; } - scalar_type - getMu() const - { - return m_mu; - } + scalar_type getMu() const { return m_mu; } - scalar_type - getH() const - { - return m_H; - } + scalar_type getH() const { return m_H; } - scalar_type - getK() const - { - return m_K; - } + scalar_type getK() const { return m_K; } - scalar_type - getSigma_y0() const - { - return m_sigma_y0; - } + scalar_type getSigma_y0() const { return m_sigma_y0; } - size_t - getType() const - { - return m_type; - } + scalar_type getRho() const { return m_rho; } - std::vector> - getRpCurve() const - { - return m_Rp_curve; - } + size_t getType() const { return m_type; } - void - checkRpCurve() - { - if (m_Rp_curve.size() > 0) - { - std::sort(m_Rp_curve.begin(), - m_Rp_curve.end(), - [](const auto& lhs, const auto& rhs) { return lhs.getP() < rhs.getP(); }); - - for (size_t i = 0; i < m_Rp_curve.size() - 1; i++) - { - if (std::abs(m_Rp_curve[i].getP() - m_Rp_curve[i + 1].getP()) < - std::numeric_limits::epsilon()) - { - throw std::invalid_argument("RpCurve: You have two values with the same p"); + std::vector< curve_point< scalar_type > > getRpCurve() const { return m_Rp_curve; } + + void checkRpCurve() { + if ( m_Rp_curve.size() > 0 ) { + std::sort( m_Rp_curve.begin(), m_Rp_curve.end(), + []( const auto &lhs, const auto &rhs ) { return lhs.getP() < rhs.getP(); } ); + + for ( size_t i = 0; i < m_Rp_curve.size() - 1; i++ ) { + if ( std::abs( m_Rp_curve[i].getP() - m_Rp_curve[i + 1].getP() ) < + std::numeric_limits< scalar_type >::epsilon() ) { + throw std::invalid_argument( "RpCurve: You have two values with the same p" ); } } } } - void - addMfrontParameter(const std::string& param, const scalar_type& value) - { - m_mfront_param.push_back((std::make_pair(param, value))); + void addMfrontParameter( const std::string ¶m, scalar_type value ) { + m_mfront_param.push_back( ( std::make_pair( param, value ) ) ); } - const std::vector& - getMfrontParameters() const - { - return m_mfront_param; - } + const std::vector< MfrontType > &getMfrontParameters() const { return m_mfront_param; } - std::vector - getMfrontParameters() - { - return m_mfront_param; - } + std::vector< MfrontType > getMfrontParameters() { return m_mfront_param; } - void - print() const - { + void print() const { std::cout << "Material parameters: " << std::endl; std::cout << "* E: " << getE() << std::endl; std::cout << "* Nu: " << getNu() << std::endl; @@ -275,14 +176,22 @@ class MaterialData std::cout << "* Sy0: " << getSigma_y0() << std::endl; std::cout << "* Lambda: " << getLambda() << std::endl; std::cout << "* Mu: " << getMu() << std::endl; - std::cout << "* Traction Curve:" << std::endl; - std::cout << "(p, R(p))" << std::endl; - for (auto& pt : m_Rp_curve) - std::cout << "( " << pt.getP() << ", " << pt.getRp() << " )" << std::endl; - std::cout << "* Mfront parameters:" << std::endl; - std::cout << "(parameter, value)" << std::endl; - for (auto& [param, value] : m_mfront_param) - std::cout << "( " << param << ", " << value << " )" << std::endl; + std::cout << "* Rho: " << getRho() << std::endl; + if ( !m_Rp_curve.empty() ) { + std::cout << "* Traction Curve:" << std::endl; + std::cout << "(p, R(p))" << std::endl; + for ( auto &pt : m_Rp_curve ) + std::cout << "( " << pt.getP() << ", " << pt.getRp() << " )" << std::endl; + } + if ( !m_mfront_param.empty() ) { + std::cout << "* Mfront parameters:" << std::endl; + std::cout << "(parameter, value)" << std::endl; + for ( auto &[param, value] : m_mfront_param ) + std::cout << "( " << param << ", " << value << " )" << std::endl; + } } }; -} \ No newline at end of file + +} // namespace mechanics + +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/logarithmic_strain/LogarithmicStrain.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/logarithmic_strain/LogarithmicStrain.hpp index 52356258..1055b63e 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/logarithmic_strain/LogarithmicStrain.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/logarithmic_strain/LogarithmicStrain.hpp @@ -25,18 +25,16 @@ #pragma once -#include - #include "diskpp/common/eigen.hpp" -#include "diskpp/mechanics/behaviors/logarithmic_strain/LogarithmicStrain_qp.hpp" #include "diskpp/mechanics/behaviors/laws/behaviorlaws.hpp" #include "diskpp/mechanics/behaviors/laws/law_cell_bones.hpp" +#include "diskpp/mechanics/behaviors/logarithmic_strain/LogarithmicStrain_qp.hpp" -namespace disk -{ +#include + +namespace disk { -namespace mechanics -{ +namespace mechanics { // Routine for Logarithmic Stain @@ -48,89 +46,66 @@ namespace mechanics * Comput. Methods Appl. Mech. Engrg. (2002) */ -template -class LogarithmicStrain -{ +template < typename LawType > +class LogarithmicStrain { public: - typedef LawType law_hpp_type; - typedef typename law_hpp_type::law_qp_type law_hpp_qp_type; - typedef typename law_hpp_type::mesh_type mesh_type; + typedef LawType law_hpp_type; + typedef typename law_hpp_type::law_qp_type law_hpp_qp_type; + typedef typename law_hpp_type::mesh_type mesh_type; typedef typename mesh_type::coordinate_type scalar_type; - typedef typename mesh_type::cell cell_type; + typedef typename mesh_type::cell cell_type; typedef typename law_hpp_qp_type::data_type data_type; - typedef LogarithmicStrain_qp law_qp_type; + typedef LogarithmicStrain_qp< law_hpp_qp_type > law_qp_type; - typedef LawTypeCellBones law_cell_type; + typedef LawTypeCellBones< mesh_type, law_qp_type, true > law_cell_type; private: - size_t m_nb_qp; - std::vector m_list_cell_qp; - data_type m_data; + size_t m_nb_qp; + std::vector< law_cell_type > m_list_cell_qp; + data_type m_data; public: - LogarithmicStrain() : m_nb_qp(0){}; + LogarithmicStrain() : m_nb_qp( 0 ) {}; - LogarithmicStrain(const mesh_type& msh, const size_t degree) - { + LogarithmicStrain( const mesh_type &msh, const size_t degree ) { m_nb_qp = 0; m_list_cell_qp.clear(); - m_list_cell_qp.reserve(msh.cells_size()); + m_list_cell_qp.reserve( msh.cells_size() ); - for (auto& cl : msh) - { - law_cell_type cell_qp(msh, cl, degree); + for ( auto &cl : msh ) { + law_cell_type cell_qp( msh, cl, degree ); - m_list_cell_qp.push_back(cell_qp); + m_list_cell_qp.push_back( cell_qp ); m_nb_qp += cell_qp.getNumberOfQP(); } } - void - addMaterialData(const data_type& material_data) - { - m_data = material_data; - } + void addMaterialData( const data_type &material_data ) { m_data = material_data; } - data_type - getMaterialData() const - { - return m_data; - } + data_type getMaterialData() const { return m_data; } - int - getNumberOfQP() const - { - return m_nb_qp; - } + int getNumberOfQP() const { return m_nb_qp; } - void - update() - { - for (auto& qp_cell : m_list_cell_qp) - { + void update() { + for ( auto &qp_cell : m_list_cell_qp ) { qp_cell.update(); } } - - law_cell_type& - getCellQPs(const int cell_id) - { - return m_list_cell_qp.at(cell_id); + void restore() { + for ( auto &qp_cell : m_list_cell_qp ) { + qp_cell.restore(); + } } - const law_cell_type& - getCellQPs(const int cell_id) const - { - return m_list_cell_qp.at(cell_id); - } + law_cell_type &getCellQPs( const int cell_id ) { return m_list_cell_qp.at( cell_id ); } - law_cell_type - getCellIVs(const int cell_id) const - { - return m_list_cell_qp.at(cell_id); + const law_cell_type &getCellQPs( const int cell_id ) const { + return m_list_cell_qp.at( cell_id ); } + + law_cell_type getCellIVs( const int cell_id ) const { return m_list_cell_qp.at( cell_id ); } }; -} -} \ No newline at end of file +} // namespace mechanics +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/logarithmic_strain/LogarithmicStrain_qp.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/logarithmic_strain/LogarithmicStrain_qp.hpp index 267d2590..085b8182 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/logarithmic_strain/LogarithmicStrain_qp.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/logarithmic_strain/LogarithmicStrain_qp.hpp @@ -35,11 +35,9 @@ #include "diskpp/mechanics/stress_tensors.hpp" #include "diskpp/mesh/point.hpp" -namespace disk -{ +namespace disk { -namespace mechanics -{ +namespace mechanics { namespace priv { /* squelch -fpermissive errors */ @@ -61,48 +59,44 @@ using qpoint = quadrature_point; * Comput. Methods Appl. Mech. Engrg. (2002) */ -template -class LogarithmicStrain_qp -{ +template < typename LawTypeQp > +class LogarithmicStrain_qp { public: - typedef LawTypeQp law_hpp_qp_type; - typedef typename law_hpp_qp_type::data_type data_type; + typedef LawTypeQp law_hpp_qp_type; + typedef typename law_hpp_qp_type::data_type data_type; typedef typename law_hpp_qp_type::scalar_type scalar_type; const static size_t DIM = LawTypeQp::dimension; - typedef static_matrix static_matrix_type; - typedef static_matrix static_matrix_type3D; - typedef static_tensor tensor_type; + typedef static_matrix< scalar_type, DIM, DIM > static_matrix_type; + typedef static_matrix< scalar_type, 3, 3 > static_matrix_type3D; + typedef static_tensor< scalar_type, DIM > tensor_type; private: // law hpp at qp law_hpp_qp_type m_law_hpp_qp; - static_tensor Pn; // Projector: to compute PK1 form T + static_tensor< scalar_type, 3 > Pn; // Projector: to compute PK1 form T - static_matrix_type3D - compute_stress3DPrev_T(const data_type& data) const - { - return m_law_hpp_qp.compute_stress3DPrev(data); + static_matrix_type3D compute_stress3DPrev_T( const data_type &data ) const { + return m_law_hpp_qp.compute_stress3DPrev( data ); } - std::pair> - compute_whole3D(const static_matrix_type3D& F_curr, const data_type& data, bool tangentmodulus = true) - { + std::pair< static_matrix_type3D, static_tensor< scalar_type, 3 > > + compute_whole3D( const static_matrix_type3D &F_curr, const data_type &data, + bool tangentmodulus = true ) { // std::cout << "F" << std::endl; // std::cout << F_curr << std::endl; const scalar_type J = F_curr.determinant(); - if (J <= 0.01) - { - const std::string mess = "J= " + std::to_string(J) + " <= 0"; - throw std::invalid_argument(mess); + if ( J <= 0.01 ) { + const std::string mess = "J= " + std::to_string( J ) + " <= 0"; + throw std::invalid_argument( mess ); } - const static_matrix_type3D C = convertFtoCauchyGreenRight(F_curr); - const auto ev_C = compute_eigenvalues(C); - const static_matrix_type3D Elog = compute_Elog(ev_C.first, ev_C.second); + const static_matrix_type3D C = convertFtoCauchyGreenRight( F_curr ); + const auto ev_C = compute_eigenvalues( C ); + const static_matrix_type3D Elog = compute_Elog( ev_C.first, ev_C.second ); // std::cout << "C" << std::endl; // std::cout << C << std::endl; @@ -111,11 +105,12 @@ class LogarithmicStrain_qp // std::cout << "Elog" << std::endl; // std::cout << Elog << std::endl; - const auto behavior3D_hpp = m_law_hpp_qp.compute_whole3D(Elog, data, tangentmodulus); - const auto projector = compute_projector(F_curr, behavior3D_hpp.first, ev_C.first, ev_C.second, false); + const auto behavior3D_hpp = m_law_hpp_qp.compute_whole3D( Elog, data, tangentmodulus ); + const auto projector = + compute_projector( F_curr, behavior3D_hpp.first, ev_C.first, ev_C.second, false ); - Pn = projector.first; - const static_matrix_type3D PK1 = this->compute_stress3D(data); + Pn = projector.first; + const static_matrix_type3D PK1 = this->compute_stress3D( data ); // std::cout << "T" << std::endl; // std::cout << behavior3D_hpp.first << std::endl; @@ -127,35 +122,35 @@ class LogarithmicStrain_qp // std::cout << convertPK1toPK2(PK1, F_curr) << std::endl; // std::cout << "dTdE" << std::endl; - // std::cout << convertTensorNotationMangel(behavior3D_hpp.second) << std::endl; + // std::cout << convertTensorNotationMangel(behavior3D_hpp.second) << + // std::endl; - if (!tangentmodulus) - { - return std::make_pair(PK1, behavior3D_hpp.second); + if ( !tangentmodulus ) { + return std::make_pair( PK1, behavior3D_hpp.second ); } - const auto projector2 = compute_projector_PK2(behavior3D_hpp.first, ev_C.first, ev_C.second, true); - const static_tensor CP2 = - ContractedProduct(behavior3D_hpp.second, projector2.first); - const static_tensor C2 = - ContractedProduct(transpose(projector2.first), CP2) + projector2.second; - const static_matrix_type3D PK2 = - ContractedProduct(this->compute_stress3D_T(data), projector2.first); - const static_tensor A = convertCtoA(C2, PK2, F_curr); + const auto projector2 = + compute_projector_PK2( behavior3D_hpp.first, ev_C.first, ev_C.second, true ); + const static_tensor< scalar_type, 3 > CP2 = + ContractedProduct< scalar_type, 3 >( behavior3D_hpp.second, projector2.first ); + const static_tensor< scalar_type, 3 > C2 = + ContractedProduct< scalar_type, 3 >( transpose< scalar_type, 3 >( projector2.first ), + CP2 ) + + projector2.second; + const static_matrix_type3D PK2 = ContractedProduct< scalar_type, 3 >( + this->compute_stress3D_T( data ), projector2.first ); + const static_tensor< scalar_type, 3 > A = convertCtoA( C2, PK2, F_curr ); // std::cout << "dTdE" << std::endl; - // std::cout << convertTensorNotationMangel(behavior3D_hpp.second) << std::endl; - // std::cout << "dPK2dC" << std::endl; - // std::cout << convertTensorNotationMangel(C) << std::endl; - // std::cout << "dPK1dF" << std::endl; - // std::cout << A << std::endl; - // std::cout << "dPK1dF" << std::endl; - // std::cout << convertTensorNotationMangel(A) << std::endl; - // std::cout << "dPK1dF alt" << std::endl; - // std::cout << convertTensorNotationMangel(convertCtoA(C, PK2 , F_curr)) << - // std::endl; + // std::cout << convertTensorNotationMangel(behavior3D_hpp.second) << + // std::endl; std::cout << "dPK2dC" << std::endl; std::cout << + // convertTensorNotationMangel(C) << std::endl; std::cout << "dPK1dF" << + // std::endl; std::cout << A << std::endl; std::cout << "dPK1dF" << std::endl; std::cout << + // convertTensorNotationMangel(A) << std::endl; std::cout << "dPK1dF alt" << + // std::endl; std::cout << convertTensorNotationMangel(convertCtoA(C, PK2 , F_curr)) << std::endl; - return std::make_pair(PK1, A); + return std::make_pair( PK1, A ); } public: @@ -165,107 +160,70 @@ class LogarithmicStrain_qp Pn = static_tensor::Zero(); } - priv::qpoint - quadrature_point() const - { - return make_qp(point(), weight()); - } + auto quadrature_point() const { return make_qp( point(), weight() ); } - priv::ppoint - point() const - { - return m_law_hpp_qp.point(); - } + auto point() const { return m_law_hpp_qp.point(); } - scalar_type - weight() const - { - return m_law_hpp_qp.weight(); - } + scalar_type weight() const { return m_law_hpp_qp.weight(); } - bool - is_plastic() const - { - return m_law_hpp_qp.is_plastic(); - } + bool is_plastic() const { return m_law_hpp_qp.is_plastic(); } - static_matrix_type3D - getElasticStrain() const - { - return m_law_hpp_qp.getElasticStrain(); - } + static_matrix_type3D getElasticStrain() const { return m_law_hpp_qp.getElasticStrain(); } - static_matrix_type3D - getPlasticStrain() const - { - return m_law_hpp_qp.getPlasticStrain(); - } + static_matrix_type3D getPlasticStrain() const { return m_law_hpp_qp.getPlasticStrain(); } - static_matrix_type - getTotalStrain() const - { - return m_law_hpp_qp.getTotalStrain(); - } + static_matrix_type getTotalStrain() const { return m_law_hpp_qp.getTotalStrain(); } - static_matrix_type - getTotalStrainPrev() const - { - return m_law_hpp_qp.getTotalStrainPrev(); - } + static_matrix_type getTotalStrainPrev() const { return m_law_hpp_qp.getTotalStrainPrev(); } - scalar_type - getEquivalentPlasticStrain() const - { + scalar_type getEquivalentPlasticStrain() const { return m_law_hpp_qp.getEquivalentPlasticStrain(); } - void - update() - { - m_law_hpp_qp.update(); + void update() { m_law_hpp_qp.update(); } + void restore() { m_law_hpp_qp.restore(); } + + static_matrix_type compute_stress( const data_type &data ) const { + return convertMatrix< scalar_type, DIM >( this->compute_stress3D( data ) ); } - static_matrix_type - compute_stress(const data_type& data) const - { - return convertMatrix(this->compute_stress3D(data)); + static_matrix_type compute_stressPrev_T( const data_type &data ) const { + return m_law_hpp_qp.compute_stressPrev( data ); } - static_matrix_type - compute_stressPrev_T(const data_type& data) const - { - return m_law_hpp_qp.compute_stressPrev(data); + static_matrix_type compute_stress_T( const data_type &data ) const { + return m_law_hpp_qp.compute_stress( data ); } - static_matrix_type - compute_stress_T(const data_type& data) const - { - return m_law_hpp_qp.compute_stress(data); + std::pair< static_matrix_type, tensor_type > compute_whole( const static_matrix_type &F_curr, + const data_type &data, + bool tangentmodulus = true ) { + const static_matrix_type3D F_curr_3D = convertMatrix3DwithOne( F_curr ); + const auto behaviors3D = compute_whole3D( F_curr_3D, data, tangentmodulus ); + + const static_matrix_type PK1 = convertMatrix< scalar_type, DIM >( behaviors3D.first ); + const static_tensor< scalar_type, DIM > A = + convertTensor< scalar_type, DIM >( behaviors3D.second ); + + return std::make_pair( PK1, A ); } - std::pair - compute_whole(const static_matrix_type& F_curr, const data_type& data, bool tangentmodulus = true) - { - const static_matrix_type3D F_curr_3D = convertMatrix3DwithOne(F_curr); - const auto behaviors3D = compute_whole3D(F_curr_3D, data, tangentmodulus); + static_matrix_type compute_stress( const static_matrix_type &F_curr, const data_type &data ) { + const static_matrix_type3D F_curr_3D = convertMatrix3DwithOne( F_curr ); + const auto behaviors3D = compute_whole3D( F_curr_3D, data, false ); - const static_matrix_type PK1 = convertMatrix(behaviors3D.first); - const static_tensor A = convertTensor(behaviors3D.second); + const static_matrix_type PK1 = convertMatrix< scalar_type, DIM >( behaviors3D.first ); - return std::make_pair(PK1, A); + return PK1; } - static_matrix_type3D - compute_stress3D(const data_type& data) const - { - return ContractedProduct(this->compute_stress3D_T(data), Pn); + static_matrix_type3D compute_stress3D( const data_type &data ) const { + return ContractedProduct< scalar_type, 3 >( this->compute_stress3D_T( data ), Pn ); } - static_matrix_type3D - compute_stress3D_T(const data_type& data) const - { - return m_law_hpp_qp.compute_stress3D(data); + static_matrix_type3D compute_stress3D_T( const data_type &data ) const { + return m_law_hpp_qp.compute_stress3D( data ); } }; -} -} +} // namespace mechanics +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/logarithmic_strain/logarithmic_tools.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/logarithmic_strain/logarithmic_tools.hpp index 32a81904..f4d64c4e 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/logarithmic_strain/logarithmic_tools.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/logarithmic_strain/logarithmic_tools.hpp @@ -26,6 +26,7 @@ #pragma once #include "diskpp/common/eigen.hpp" + #include #include @@ -37,51 +38,44 @@ * Comput. Methods Appl. Mech. Engrg. (2002) */ -namespace disk -{ +namespace disk { -namespace mechanics -{ +namespace mechanics { // compute eigenvalues and eigenvectors // ! Be careful Mat hes to be symmetric -template -std::pair, static_matrix> -compute_eigenvalues(const static_matrix& Mat) -{ - typedef static_matrix matrix_type; +template < typename T, int N > +std::pair< static_vector< T, N >, static_matrix< T, N, N > > +compute_eigenvalues( const static_matrix< T, N, N > &Mat ) { + typedef static_matrix< T, N, N > matrix_type; - SelfAdjointEigenSolver es(Mat); + SelfAdjointEigenSolver< matrix_type > es( Mat ); // std::cout << "eigenvalues:" << std::endl; // std::cout << es.eigenvalues() << std::endl; // std::cout << "eigenvectors:" << std::endl; // std::cout << es.eigenvectors() << std::endl; - return std::make_pair(es.eigenvalues(), es.eigenvectors()); + return std::make_pair( es.eigenvalues(), es.eigenvectors() ); } // compute ei -template -static_vector -compute_ei(const static_vector& lambda_i) -{ - static_vector ei; - - for (int i = 0; i < 3; i++) - { - ei(i) = std::log(lambda_i(i)) / T(2); +template < typename T > +static_vector< T, 3 > compute_ei( const static_vector< T, 3 > &lambda_i ) { + static_vector< T, 3 > ei; + + for ( int i = 0; i < 3; i++ ) { + ei( i ) = std::log( lambda_i( i ) ) / T( 2 ); } return ei; } // compute Elog Elog = P *log(D) * P^T -template -static_matrix -compute_Elog(const static_vector& lambda_i, const static_matrix& P) -{ - const static_vector ei = compute_ei(lambda_i); - const Eigen::DiagonalMatrix D = Eigen::DiagonalMatrix(ei[0], ei[1], ei[2]); +template < typename T > +static_matrix< T, 3, 3 > compute_Elog( const static_vector< T, 3 > &lambda_i, + const static_matrix< T, 3, 3 > &P ) { + const static_vector< T, 3 > ei = compute_ei( lambda_i ); + const Eigen::DiagonalMatrix< T, 3 > D = Eigen::DiagonalMatrix< T, 3 >( ei[0], ei[1], ei[2] ); return P * D * P.transpose(); } @@ -89,29 +83,24 @@ compute_Elog(const static_vector& lambda_i, const static_matrix& // compute coefficient for logarithmic strain // compute Ni -template -std::array, 3> -compute_Ni(const static_matrix& evec) -{ - std::array, 3> Ni; - - for (int i = 0; i < 3; i++) - { - Ni[i] = evec.col(i); +template < typename T > +std::array< static_vector< T, 3 >, 3 > compute_Ni( const static_matrix< T, 3, 3 > &evec ) { + std::array< static_vector< T, 3 >, 3 > Ni; + + for ( int i = 0; i < 3; i++ ) { + Ni[i] = evec.col( i ); } return Ni; } // compute ni = F * Ni -template -std::array, 3> -compute_ni(const static_matrix& F, const std::array, 3>& Ni) -{ - std::array, 3> ni; - - for (int i = 0; i < 3; i++) - { +template < typename T > +std::array< static_vector< T, 3 >, 3 > +compute_ni( const static_matrix< T, 3, 3 > &F, const std::array< static_vector< T, 3 >, 3 > &Ni ) { + std::array< static_vector< T, 3 >, 3 > ni; + + for ( int i = 0; i < 3; i++ ) { ni[i] = F * Ni[i]; } @@ -119,45 +108,36 @@ compute_ni(const static_matrix& F, const std::array } // compute di -template -static_vector -compute_di(const static_vector& lambda_i) -{ - static_vector di; - - for (int i = 0; i < 3; i++) - { - di(i) = T(1) / lambda_i(i); +template < typename T > +static_vector< T, 3 > compute_di( const static_vector< T, 3 > &lambda_i ) { + static_vector< T, 3 > di; + + for ( int i = 0; i < 3; i++ ) { + di( i ) = T( 1 ) / lambda_i( i ); } return di; } // compute fi -template -static_vector -compute_fi(const static_vector& lambda_i) -{ - static_vector fi; - - for (int i = 0; i < 3; i++) - { - fi(i) = -T(2) / (lambda_i(i) * lambda_i(i)); +template < typename T > +static_vector< T, 3 > compute_fi( const static_vector< T, 3 > &lambda_i ) { + static_vector< T, 3 > fi; + + for ( int i = 0; i < 3; i++ ) { + fi( i ) = -T( 2 ) / ( lambda_i( i ) * lambda_i( i ) ); } return fi; } // compute zeta -template -static_matrix -compute_zeta(const static_matrix& stress_T, const std::array, 3>& Ni) -{ - static_matrix zeta = static_matrix::Zero(); - - for (int j = 0; j < 3; j++) - { - for (int i = 0; i < 3; i++) - { - zeta(i, j) = InnerProduct(stress_T, Kronecker(Ni[i], Ni[j])); +template < typename T > +static_matrix< T, 3, 3 > compute_zeta( const static_matrix< T, 3, 3 > &stress_T, + const std::array< static_vector< T, 3 >, 3 > &Ni ) { + static_matrix< T, 3, 3 > zeta = static_matrix< T, 3, 3 >::Zero(); + + for ( int j = 0; j < 3; j++ ) { + for ( int i = 0; i < 3; i++ ) { + zeta( i, j ) = InnerProduct( stress_T, Kronecker( Ni[i], Ni[j] ) ); } } return zeta; @@ -165,74 +145,47 @@ compute_zeta(const static_matrix& stress_T, const std::array -static_matrix -compute_Mij(const std::array, 3>& Ni, - const std::array, 3>& ni, - const int i, - const int j) -{ - static_matrix Mij = static_matrix::Zero(); - - for (int a = 0; a < 3; a++) - { - for (int b = 0; b < 3; b++) - { - Mij(a, b) = ni[i](a) * Ni[j](b) + ni[j](a) * Ni[i](b); +template < typename T > +static_matrix< T, 3, 3 > compute_Mij( const std::array< static_vector< T, 3 >, 3 > &Ni, + const std::array< static_vector< T, 3 >, 3 > &ni, const int i, + const int j ) { + static_matrix< T, 3, 3 > Mij = static_matrix< T, 3, 3 >::Zero(); + + for ( int a = 0; a < 3; a++ ) { + for ( int b = 0; b < 3; b++ ) { + Mij( a, b ) = ni[i]( a ) * Ni[j]( b ) + ni[j]( a ) * Ni[i]( b ); } } return Mij; } -enum EigenCase -{ - THREE_EQUAL, - TWO_EQUAL01, - TWO_EQUAL02, - TWO_EQUAL12, - THREE_DIFF -}; - -namespace priv -{ -template -typename std::enable_if::is_integer, bool>::type -almost_equal(T x, T y, int ulp = 2) -{ +enum EigenCase { THREE_EQUAL, TWO_EQUAL01, TWO_EQUAL02, TWO_EQUAL12, THREE_DIFF }; + +namespace priv { +template < class T > +typename std::enable_if< !std::numeric_limits< T >::is_integer, bool >::type +almost_equal( T x, T y, int ulp = 2 ) { // the machine epsilon has to be scaled to the magnitude of the values used // and multiplied by the desired precision in ULPs (units in the last place) - return std::abs(x - y) <= std::numeric_limits::epsilon() * std::abs(x + y) * ulp + return std::abs( x - y ) <= std::numeric_limits< T >::epsilon() * std::abs( x + y ) * ulp // unless the result is subnormal - || std::abs(x - y) < std::numeric_limits::min(); + || std::abs( x - y ) < std::numeric_limits< T >::min(); } -template -int -selectCase(const static_vector& lambda_i) -{ - if (almost_equal(lambda_i(0), lambda_i(1))) - { - if (almost_equal(lambda_i(1), lambda_i(2))) - { +template < typename T > +int selectCase( const static_vector< T, 3 > &lambda_i ) { + if ( almost_equal( lambda_i( 0 ), lambda_i( 1 ) ) ) { + if ( almost_equal( lambda_i( 1 ), lambda_i( 2 ) ) ) { return THREE_EQUAL; - } - else - { + } else { return TWO_EQUAL01; } - } - else - { - if (almost_equal(lambda_i(1), lambda_i(2))) - { + } else { + if ( almost_equal( lambda_i( 1 ), lambda_i( 2 ) ) ) { return TWO_EQUAL12; - } - else if (almost_equal(lambda_i(0), lambda_i(2))) - { + } else if ( almost_equal( lambda_i( 0 ), lambda_i( 2 ) ) ) { return TWO_EQUAL02; - } - else - { + } else { return THREE_DIFF; } } @@ -241,211 +194,201 @@ selectCase(const static_vector& lambda_i) } // lambda_0 != lambda_1 != lambda_2 && lambda_0 < lambda_1 < lambda_2 -template -std::tuple, static_matrix, T> -compute_three_diff(const static_vector& lambda_i, const static_vector& ei, const static_vector& di) -{ - T eta = T(0); - static_matrix theta = static_matrix::Zero(); - static_matrix xi = static_matrix::Zero(); - - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 3; j++) - { - if (j != i) - { - const T lilj = lambda_i(i) - lambda_i(j); - theta(i, j) = (ei(i) - ei(j)) / lilj; - xi(i, j) = (theta(i, j) - di(j) / T(2)) / lilj; - - for (int k = 0; k < 3; k++) - { - if (k != i && k != j) - { - const T lilk = lambda_i(i) - lambda_i(k); - eta += ei(i) / (T(2) * lilj * lilk); +template < typename T > +std::tuple< static_matrix< T, 3, 3 >, static_matrix< T, 3, 3 >, T > +compute_three_diff( const static_vector< T, 3 > &lambda_i, const static_vector< T, 3 > &ei, + const static_vector< T, 3 > &di ) { + T eta = T( 0 ); + static_matrix< T, 3, 3 > theta = static_matrix< T, 3, 3 >::Zero(); + static_matrix< T, 3, 3 > xi = static_matrix< T, 3, 3 >::Zero(); + + for ( int i = 0; i < 3; i++ ) { + for ( int j = 0; j < 3; j++ ) { + if ( j != i ) { + const T lilj = lambda_i( i ) - lambda_i( j ); + theta( i, j ) = ( ei( i ) - ei( j ) ) / lilj; + xi( i, j ) = ( theta( i, j ) - di( j ) / T( 2 ) ) / lilj; + + for ( int k = 0; k < 3; k++ ) { + if ( k != i && k != j ) { + const T lilk = lambda_i( i ) - lambda_i( k ); + eta += ei( i ) / ( T( 2 ) * lilj * lilk ); } } } } } - return std::make_tuple(theta, xi, eta); + return std::make_tuple( theta, xi, eta ); } // lambda_0 == lambda_1 == lambda_2 -template -std::tuple, static_matrix, T> -compute_three_equal(const static_vector& di, const static_vector& fi) -{ - const T d = di(0) / T(2); - const T f = fi(0) / T(8); - - const T eta = f; - static_matrix theta = static_matrix::Zero(); - static_matrix xi = static_matrix::Zero(); - - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 3; j++) - { - if (j != i) - { - theta(i, j) = d; - xi(i, j) = f; +template < typename T > +std::tuple< static_matrix< T, 3, 3 >, static_matrix< T, 3, 3 >, T > +compute_three_equal( const static_vector< T, 3 > &di, const static_vector< T, 3 > &fi ) { + const T d = di( 0 ) / T( 2 ); + const T f = fi( 0 ) / T( 8 ); + + const T eta = f; + static_matrix< T, 3, 3 > theta = static_matrix< T, 3, 3 >::Zero(); + static_matrix< T, 3, 3 > xi = static_matrix< T, 3, 3 >::Zero(); + + for ( int i = 0; i < 3; i++ ) { + for ( int j = 0; j < 3; j++ ) { + if ( j != i ) { + theta( i, j ) = d; + xi( i, j ) = f; } } } - return std::make_tuple(theta, xi, eta); + return std::make_tuple( theta, xi, eta ); } // lambda_0 == lambda_1 != lambda_2 -template -std::tuple, static_matrix, T> -compute_two_equal(const static_vector& lambda_i, - const static_vector& ei, - const static_vector& di, - const static_vector& fi, - const int CASE) -{ - T eta = T(0); - static_matrix theta = static_matrix::Zero(); - static_matrix xi = static_matrix::Zero(); - - switch (CASE) - { - case TWO_EQUAL01: - { - theta(0, 1) = di(0) / T(2); - theta(1, 0) = theta(0, 1); - - theta(0, 2) = (ei(0) - ei(2)) / (lambda_i(0) - lambda_i(2)); - theta(2, 0) = theta(0, 2); - - theta(1, 2) = (ei(1) - ei(2)) / (lambda_i(1) - lambda_i(2)); - theta(2, 1) = theta(1, 2); - - xi(0, 1) = fi(0) / T(8); - xi(1, 0) = xi(0, 1); - - xi(0, 2) = (theta(0, 2) - di(2) / T(2)) / (lambda_i(0) - lambda_i(2)); - xi(2, 0) = (theta(2, 0) - di(0) / T(2)) / (lambda_i(2) - lambda_i(0)); - - xi(1, 2) = (theta(1, 2) - di(2) / T(2)) / (lambda_i(1) - lambda_i(2)); - xi(2, 1) = (theta(2, 1) - di(1) / T(2)) / (lambda_i(2) - lambda_i(1)); - - eta = xi(2, 0); - - break; - } - case TWO_EQUAL02: - { - theta(0, 1) = (ei(0) - ei(1)) / (lambda_i(0) - lambda_i(1)); - theta(1, 0) = theta(0, 1); +template < typename T > +std::tuple< static_matrix< T, 3, 3 >, static_matrix< T, 3, 3 >, T > +compute_two_equal( const static_vector< T, 3 > &lambda_i, const static_vector< T, 3 > &ei, + const static_vector< T, 3 > &di, const static_vector< T, 3 > &fi, + const int CASE ) { + T eta = T( 0 ); + static_matrix< T, 3, 3 > theta = static_matrix< T, 3, 3 >::Zero(); + static_matrix< T, 3, 3 > xi = static_matrix< T, 3, 3 >::Zero(); - theta(0, 2) = di(0) / T(2); - theta(2, 0) = theta(0, 2); + switch ( CASE ) { + case TWO_EQUAL01: { + theta( 0, 1 ) = di( 0 ) / T( 2 ); + theta( 1, 0 ) = theta( 0, 1 ); - theta(1, 2) = (ei(1) - ei(2)) / (lambda_i(1) - lambda_i(2)); - theta(2, 1) = theta(1, 2); + theta( 0, 2 ) = ( ei( 0 ) - ei( 2 ) ) / ( lambda_i( 0 ) - lambda_i( 2 ) ); + theta( 2, 0 ) = theta( 0, 2 ); - xi(0, 1) = (theta(0, 1) - di(1) / T(2)) / (lambda_i(0) - lambda_i(1)); - xi(1, 0) = (theta(1, 0) - di(0) / T(2)) / (lambda_i(1) - lambda_i(0)); + theta( 1, 2 ) = ( ei( 1 ) - ei( 2 ) ) / ( lambda_i( 1 ) - lambda_i( 2 ) ); + theta( 2, 1 ) = theta( 1, 2 ); - xi(0, 2) = fi(0) / T(8); - xi(2, 0) = xi(0, 2); + xi( 0, 1 ) = fi( 0 ) / T( 8 ); + xi( 1, 0 ) = xi( 0, 1 ); - xi(1, 2) = (theta(1, 2) - di(2) / T(2)) / (lambda_i(1) - lambda_i(2)); - xi(2, 1) = (theta(2, 1) - di(1) / T(2)) / (lambda_i(2) - lambda_i(1)); + xi( 0, 2 ) = ( theta( 0, 2 ) - di( 2 ) / T( 2 ) ) / ( lambda_i( 0 ) - lambda_i( 2 ) ); + xi( 2, 0 ) = ( theta( 2, 0 ) - di( 0 ) / T( 2 ) ) / ( lambda_i( 2 ) - lambda_i( 0 ) ); - eta = xi(0, 1); - break; - } - case TWO_EQUAL12: - { - theta(0, 1) = (ei(0) - ei(1)) / (lambda_i(0) - lambda_i(1)); - theta(1, 0) = theta(0, 1); + xi( 1, 2 ) = ( theta( 1, 2 ) - di( 2 ) / T( 2 ) ) / ( lambda_i( 1 ) - lambda_i( 2 ) ); + xi( 2, 1 ) = ( theta( 2, 1 ) - di( 1 ) / T( 2 ) ) / ( lambda_i( 2 ) - lambda_i( 1 ) ); - theta(0, 2) = (ei(0) - ei(2)) / (lambda_i(0) - lambda_i(2)); - theta(2, 0) = theta(0, 2); + eta = xi( 2, 0 ); - theta(1, 2) = di(0) / T(2); - theta(2, 1) = theta(1, 2); + break; + } + case TWO_EQUAL02: { + theta( 0, 1 ) = ( ei( 0 ) - ei( 1 ) ) / ( lambda_i( 0 ) - lambda_i( 1 ) ); + theta( 1, 0 ) = theta( 0, 1 ); - xi(0, 1) = (theta(0, 1) - di(1) / T(2)) / (lambda_i(0) - lambda_i(1)); - xi(1, 0) = (theta(1, 0) - di(0) / T(2)) / (lambda_i(1) - lambda_i(0)); + theta( 0, 2 ) = di( 0 ) / T( 2 ); + theta( 2, 0 ) = theta( 0, 2 ); - xi(0, 2) = (theta(0, 2) - di(2) / T(2)) / (lambda_i(0) - lambda_i(2)); - xi(2, 0) = (theta(2, 0) - di(0) / T(2)) / (lambda_i(2) - lambda_i(0)); + theta( 1, 2 ) = ( ei( 1 ) - ei( 2 ) ) / ( lambda_i( 1 ) - lambda_i( 2 ) ); + theta( 2, 1 ) = theta( 1, 2 ); - xi(1, 2) = fi(0) / T(8); - xi(2, 1) = xi(1, 2); + xi( 0, 1 ) = ( theta( 0, 1 ) - di( 1 ) / T( 2 ) ) / ( lambda_i( 0 ) - lambda_i( 1 ) ); + xi( 1, 0 ) = ( theta( 1, 0 ) - di( 0 ) / T( 2 ) ) / ( lambda_i( 1 ) - lambda_i( 0 ) ); - eta = xi(1, 2); - break; - } - default: std::invalid_argument("LogarithmicStrain: Wrong case"); + xi( 0, 2 ) = fi( 0 ) / T( 8 ); + xi( 2, 0 ) = xi( 0, 2 ); + + xi( 1, 2 ) = ( theta( 1, 2 ) - di( 2 ) / T( 2 ) ) / ( lambda_i( 1 ) - lambda_i( 2 ) ); + xi( 2, 1 ) = ( theta( 2, 1 ) - di( 1 ) / T( 2 ) ) / ( lambda_i( 2 ) - lambda_i( 1 ) ); + + eta = xi( 0, 1 ); + break; } + case TWO_EQUAL12: { + theta( 0, 1 ) = ( ei( 0 ) - ei( 1 ) ) / ( lambda_i( 0 ) - lambda_i( 1 ) ); + theta( 1, 0 ) = theta( 0, 1 ); - return std::make_tuple(theta, xi, eta); -} + theta( 0, 2 ) = ( ei( 0 ) - ei( 2 ) ) / ( lambda_i( 0 ) - lambda_i( 2 ) ); + theta( 2, 0 ) = theta( 0, 2 ); + + theta( 1, 2 ) = di( 0 ) / T( 2 ); + theta( 2, 1 ) = theta( 1, 2 ); + + xi( 0, 1 ) = ( theta( 0, 1 ) - di( 1 ) / T( 2 ) ) / ( lambda_i( 0 ) - lambda_i( 1 ) ); + xi( 1, 0 ) = ( theta( 1, 0 ) - di( 0 ) / T( 2 ) ) / ( lambda_i( 1 ) - lambda_i( 0 ) ); + + xi( 0, 2 ) = ( theta( 0, 2 ) - di( 2 ) / T( 2 ) ) / ( lambda_i( 0 ) - lambda_i( 2 ) ); + xi( 2, 0 ) = ( theta( 2, 0 ) - di( 0 ) / T( 2 ) ) / ( lambda_i( 2 ) - lambda_i( 0 ) ); + + xi( 1, 2 ) = fi( 0 ) / T( 8 ); + xi( 2, 1 ) = xi( 1, 2 ); + + eta = xi( 1, 2 ); + break; + } + default: + std::invalid_argument( "LogarithmicStrain: Wrong case" ); + } + + return std::make_tuple( theta, xi, eta ); } +} // namespace priv -template -std::tuple, static_matrix, T> -compute_coefficient(const static_vector& lambda_i, - const static_vector& ei, - const static_vector& di, - const static_vector& fi) -{ - const int evcase = priv::selectCase(lambda_i); +template < typename T > +std::tuple< static_matrix< T, 3, 3 >, static_matrix< T, 3, 3 >, T > +compute_coefficient( const static_vector< T, 3 > &lambda_i, const static_vector< T, 3 > &ei, + const static_vector< T, 3 > &di, const static_vector< T, 3 > &fi ) { + const int evcase = priv::selectCase( lambda_i ); // std::cout << "CASE: " << evcase << std::endl; - switch (evcase) - { - case THREE_DIFF: return priv::compute_three_diff(lambda_i, ei, di); break; - case TWO_EQUAL01: return priv::compute_two_equal(lambda_i, ei, di, fi, TWO_EQUAL01); break; - case TWO_EQUAL02: return priv::compute_two_equal(lambda_i, ei, di, fi, TWO_EQUAL02); break; - case TWO_EQUAL12: return priv::compute_two_equal(lambda_i, ei, di, fi, TWO_EQUAL12); break; - case THREE_EQUAL: return priv::compute_three_equal(di, fi); break; - default: std::invalid_argument("LogarithmicStrain: Wrong case"); + switch ( evcase ) { + case THREE_DIFF: + return priv::compute_three_diff( lambda_i, ei, di ); + break; + case TWO_EQUAL01: + return priv::compute_two_equal( lambda_i, ei, di, fi, TWO_EQUAL01 ); + break; + case TWO_EQUAL02: + return priv::compute_two_equal( lambda_i, ei, di, fi, TWO_EQUAL02 ); + break; + case TWO_EQUAL12: + return priv::compute_two_equal( lambda_i, ei, di, fi, TWO_EQUAL12 ); + break; + case THREE_EQUAL: + return priv::compute_three_equal( di, fi ); + break; + default: + std::invalid_argument( "LogarithmicStrain: Wrong case" ); } - return std::make_tuple(static_matrix::Zero(), static_matrix::Zero(), T(0)); + return std::make_tuple( static_matrix< T, 3, 3 >::Zero(), static_matrix< T, 3, 3 >::Zero(), + T( 0 ) ); } // compute projector tensor -template -std::pair, static_tensor> -compute_projector(const static_matrix& F, - const static_matrix& stress_T, - const static_vector& lambda_i, - const static_matrix& evec, - bool compute_TL = true) -{ - typedef static_tensor tensor_type; - typedef static_matrix matrix_type; - typedef static_vector vector_type; +template < typename T > +std::pair< static_tensor< T, 3 >, static_tensor< T, 3 > > +compute_projector( const static_matrix< T, 3, 3 > &F, const static_matrix< T, 3, 3 > &stress_T, + const static_vector< T, 3 > &lambda_i, const static_matrix< T, 3, 3 > &evec, + bool compute_TL = true ) { + typedef static_tensor< T, 3 > tensor_type; + typedef static_matrix< T, 3, 3 > matrix_type; + typedef static_vector< T, 3 > vector_type; // projector tensor - tensor_type P = tensor_type::Zero(); + tensor_type P = tensor_type::Zero(); tensor_type TL = tensor_type::Zero(); // compute Normal - const std::array Ni = compute_Ni(evec); - const std::array ni = compute_ni(F, Ni); + const std::array< vector_type, 3 > Ni = compute_Ni( evec ); + const std::array< vector_type, 3 > ni = compute_ni( F, Ni ); // compute quantites - const vector_type ei = compute_ei(lambda_i); - const vector_type di = compute_di(lambda_i); - const vector_type fi = compute_fi(lambda_i); - const matrix_type zeta = compute_zeta(stress_T, Ni); + const vector_type ei = compute_ei( lambda_i ); + const vector_type di = compute_di( lambda_i ); + const vector_type fi = compute_fi( lambda_i ); + const matrix_type zeta = compute_zeta( stress_T, Ni ); - const auto coefficient = compute_coefficient(lambda_i, ei, di, fi); - const matrix_type theta = std::get<0>(coefficient); - const matrix_type xi = std::get<1>(coefficient); - const T eta = std::get<2>(coefficient); + const auto coefficient = compute_coefficient( lambda_i, ei, di, fi ); + const matrix_type theta = std::get< 0 >( coefficient ); + const matrix_type xi = std::get< 1 >( coefficient ); + const T eta = std::get< 2 >( coefficient ); // std::cout << "T" << std::endl; // std::cout << stress_T << std::endl; @@ -467,48 +410,41 @@ compute_projector(const static_matrix& F, // std::cout << "xi" << std::endl; // std::cout << xi << std::endl; - for (int i = 0; i < 3; i++) - { - const matrix_type Mii = compute_Mij(Ni, ni, i, i); - const matrix_type di2_NiNi = di(i) / T(2) * Kronecker(Ni[i], Ni[i]); + for ( int i = 0; i < 3; i++ ) { + const matrix_type Mii = compute_Mij( Ni, ni, i, i ); + const matrix_type di2_NiNi = di( i ) / T( 2 ) * Kronecker( Ni[i], Ni[i] ); - P += Kronecker(di2_NiNi, Mii); + P += Kronecker( di2_NiNi, Mii ); - if (compute_TL) - { - const T fiZeta = fi(i) / T(4) * zeta(i, i); - TL += fiZeta * Kronecker(Mii, Mii); + if ( compute_TL ) { + const T fiZeta = fi( i ) / T( 4 ) * zeta( i, i ); + TL += fiZeta * Kronecker( Mii, Mii ); } - for (int j = 0; j < 3; j++) - { - if (j != i) - { - const matrix_type Mij = compute_Mij(Ni, ni, i, j); - const matrix_type theta_NiNj = theta(i, j) * Kronecker(Ni[i], Ni[j]); + for ( int j = 0; j < 3; j++ ) { + if ( j != i ) { + const matrix_type Mij = compute_Mij( Ni, ni, i, j ); + const matrix_type theta_NiNj = theta( i, j ) * Kronecker( Ni[i], Ni[j] ); - P += Kronecker(theta_NiNj, Mij); + P += Kronecker( theta_NiNj, Mij ); - if (compute_TL) - { + if ( compute_TL ) { // for TL - const matrix_type zeta_Mjj = zeta(i, j) * compute_Mij(Ni, ni, j, j); - const tensor_type zeta_MijMjj = Kronecker(Mij, zeta_Mjj); - const tensor_type zeta_MjjMij = Kronecker(zeta_Mjj, Mij); - const tensor_type MijMij = Kronecker(Mij, Mij); - const T twoxi = T(2) * xi(i, j); - - TL += twoxi * ((zeta_MijMjj + zeta_MjjMij) + zeta(j, j) * MijMij); - - for (int k = 0; k < 3; k++) - { - if (k != i && k != j) - { - const T etaZeta = T(2) * eta * zeta(i, j); - const matrix_type etaZeta_Mik = etaZeta * compute_Mij(Ni, ni, i, k); - const matrix_type Mjk = compute_Mij(Ni, ni, j, k); - - TL += Kronecker(etaZeta_Mik, Mjk); + const matrix_type zeta_Mjj = zeta( i, j ) * compute_Mij( Ni, ni, j, j ); + const tensor_type zeta_MijMjj = Kronecker( Mij, zeta_Mjj ); + const tensor_type zeta_MjjMij = Kronecker( zeta_Mjj, Mij ); + const tensor_type MijMij = Kronecker( Mij, Mij ); + const T twoxi = T( 2 ) * xi( i, j ); + + TL += twoxi * ( ( zeta_MijMjj + zeta_MjjMij ) + zeta( j, j ) * MijMij ); + + for ( int k = 0; k < 3; k++ ) { + if ( k != i && k != j ) { + const T etaZeta = T( 2 ) * eta * zeta( i, j ); + const matrix_type etaZeta_Mik = etaZeta * compute_Mij( Ni, ni, i, k ); + const matrix_type Mjk = compute_Mij( Ni, ni, j, k ); + + TL += Kronecker( etaZeta_Mik, Mjk ); } } } @@ -516,51 +452,48 @@ compute_projector(const static_matrix& F, } } - if (compute_TL) - { + if ( compute_TL ) { // last term partie symmetric - const matrix_type inv_F = F.inverse(); - const matrix_type invF_TP = inv_F * ContractedProduct(stress_T, P); - const matrix_type Id = matrix_type::Identity(); - TL += Odot(invF_TP, Id); + const matrix_type inv_F = F.inverse(); + const matrix_type invF_TP = inv_F * ContractedProduct( stress_T, P ); + const matrix_type Id = matrix_type::Identity(); + TL += Odot( invF_TP, Id ); } // std::cout << "P" << std::endl; // std::cout << P << std::endl; // std::cout << "TL" << std::endl; // std::cout << TL << std::endl; - return std::make_pair(P, TL); + return std::make_pair( P, TL ); } // compute projector tensor -template -std::pair, static_tensor> -compute_projector_PK2(const static_matrix& stress_T, - const static_vector& lambda_i, - const static_matrix& evec, - bool compute_TL = true) -{ - typedef static_tensor tensor_type; - typedef static_matrix matrix_type; - typedef static_vector vector_type; +template < typename T > +std::pair< static_tensor< T, 3 >, static_tensor< T, 3 > > +compute_projector_PK2( const static_matrix< T, 3, 3 > &stress_T, + const static_vector< T, 3 > &lambda_i, const static_matrix< T, 3, 3 > &evec, + bool compute_TL = true ) { + typedef static_tensor< T, 3 > tensor_type; + typedef static_matrix< T, 3, 3 > matrix_type; + typedef static_vector< T, 3 > vector_type; // projector tensor - tensor_type P = tensor_type::Zero(); + tensor_type P = tensor_type::Zero(); tensor_type TL = tensor_type::Zero(); // compute Normal - const std::array Ni = compute_Ni(evec); + const std::array< vector_type, 3 > Ni = compute_Ni( evec ); // compute quantites - const vector_type ei = compute_ei(lambda_i); - const vector_type di = compute_di(lambda_i); - const vector_type fi = compute_fi(lambda_i); - const matrix_type zeta = compute_zeta(stress_T, Ni); + const vector_type ei = compute_ei( lambda_i ); + const vector_type di = compute_di( lambda_i ); + const vector_type fi = compute_fi( lambda_i ); + const matrix_type zeta = compute_zeta( stress_T, Ni ); - const auto coefficient = compute_coefficient(lambda_i, ei, di, fi); - const matrix_type theta = std::get<0>(coefficient); - const matrix_type xi = std::get<1>(coefficient); - const T eta = std::get<2>(coefficient); + const auto coefficient = compute_coefficient( lambda_i, ei, di, fi ); + const matrix_type theta = std::get< 0 >( coefficient ); + const matrix_type xi = std::get< 1 >( coefficient ); + const T eta = std::get< 2 >( coefficient ); // std::cout << "T" << std::endl; // std::cout << stress_T << std::endl; @@ -570,45 +503,39 @@ compute_projector_PK2(const static_matrix& stress_T, // std::cout << "zeta" << std::endl; // std::cout << zeta << std::endl; - for (int i = 0; i < 3; i++) - { - const matrix_type Mii = compute_Mij(Ni, Ni, i, i); - const matrix_type NiNi = Kronecker(Ni[i], Ni[i]); + for ( int i = 0; i < 3; i++ ) { + const matrix_type Mii = compute_Mij( Ni, Ni, i, i ); + const matrix_type NiNi = Kronecker( Ni[i], Ni[i] ); - P += di(i) / T(2) * Kronecker(NiNi, Mii); + P += di( i ) / T( 2 ) * Kronecker( NiNi, Mii ); - if (compute_TL) - { - TL += fi(i) / T(4) * zeta(i, i) * Kronecker(Mii, Mii); + if ( compute_TL ) { + TL += fi( i ) / T( 4 ) * zeta( i, i ) * Kronecker( Mii, Mii ); } - for (int j = 0; j < 3; j++) - { - if (j != i) - { - const matrix_type Mij = compute_Mij(Ni, Ni, i, j); - const matrix_type NiNj = Kronecker(Ni[i], Ni[j]); + for ( int j = 0; j < 3; j++ ) { + if ( j != i ) { + const matrix_type Mij = compute_Mij( Ni, Ni, i, j ); + const matrix_type NiNj = Kronecker( Ni[i], Ni[j] ); - P += theta(i, j) * Kronecker(NiNj, Mij); + P += theta( i, j ) * Kronecker( NiNj, Mij ); - if (compute_TL) - { + if ( compute_TL ) { // for TL - const matrix_type Mjj = compute_Mij(Ni, Ni, j, j); - const tensor_type MijMjj = Kronecker(Mij, Mjj); - const tensor_type MjjMij = Kronecker(Mjj, Mij); - const tensor_type MijMij = Kronecker(Mij, Mij); + const matrix_type Mjj = compute_Mij( Ni, Ni, j, j ); + const tensor_type MijMjj = Kronecker( Mij, Mjj ); + const tensor_type MjjMij = Kronecker( Mjj, Mij ); + const tensor_type MijMij = Kronecker( Mij, Mij ); - TL += T(2) * xi(i, j) * (zeta(i, j) * (MijMjj + MjjMij) + zeta(j, j) * MijMij); + TL += T( 2 ) * xi( i, j ) * + ( zeta( i, j ) * ( MijMjj + MjjMij ) + zeta( j, j ) * MijMij ); - for (int k = 0; k < 3; k++) - { - if (k != i && k != j) - { - const matrix_type Mik = compute_Mij(Ni, Ni, i, k); - const matrix_type Mjk = compute_Mij(Ni, Ni, j, k); + for ( int k = 0; k < 3; k++ ) { + if ( k != i && k != j ) { + const matrix_type Mik = compute_Mij( Ni, Ni, i, k ); + const matrix_type Mjk = compute_Mij( Ni, Ni, j, k ); - TL += T(2) * eta * zeta(i, j) * Kronecker(Mik, Mjk); + TL += T( 2 ) * eta * zeta( i, j ) * Kronecker( Mik, Mjk ); } } } @@ -621,7 +548,7 @@ compute_projector_PK2(const static_matrix& stress_T, // std::cout << "TL" << std::endl; // std::cout << TL << std::endl; - return std::make_pair(P, TL); -} + return std::make_pair( P, TL ); } -} \ No newline at end of file +} // namespace mechanics +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/maths_jacobian_derivate.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/maths_jacobian_derivate.hpp old mode 100755 new mode 100644 index 3bf5d01b..b26ce3fa --- a/libdiskpp/include/diskpp/mechanics/behaviors/maths_jacobian_derivate.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/maths_jacobian_derivate.hpp @@ -28,8 +28,7 @@ #include "diskpp/common/eigen.hpp" #include "diskpp/mechanics/bevaviors/maths_tensor.hpp" -namespace disk -{ +namespace disk { // the fourth order tensor is stored like a Matrix // | A1111 A1112 A1211 A1212 | @@ -39,119 +38,109 @@ namespace disk // Compute \partial J / \partial M -template -void -JacobianFirstDerivate(const static_matrix& M) -{ - static_assert((DIM == 2 || DIM == 3), "Can not compute jacobian derivate for this dimension"); +template < typename T, int DIM > +void JacobianFirstDerivate( const static_matrix< T, DIM, DIM > &M ) { + static_assert( ( DIM == 2 || DIM == 3 ), + "Can not compute jacobian derivate for this dimension" ); } -template -static_matrix -JacobianFirstDerivate(const static_matrix& M) -{ - static_matrix ret = static_matrix::Zero(); +template < typename T > +static_matrix< T, 2, 2 > JacobianFirstDerivate( const static_matrix< T, 2, 2 > &M ) { + static_matrix< T, 2, 2 > ret = static_matrix< T, 2, 2 >::Zero(); - ret(0, 0) = M(1, 1); - ret(0, 1) = -M(1, 0); + ret( 0, 0 ) = M( 1, 1 ); + ret( 0, 1 ) = -M( 1, 0 ); - ret(1, 0) = -M(0, 1); - ret(1, 1) = M(0, 0); + ret( 1, 0 ) = -M( 0, 1 ); + ret( 1, 1 ) = M( 0, 0 ); return ret; } -template -static_matrix -JacobianFirstDerivate(const static_matrix& M) -{ - static_matrix ret = static_matrix::Zero(); +template < typename T > +static_matrix< T, 3, 3 > JacobianFirstDerivate( const static_matrix< T, 3, 3 > &M ) { + static_matrix< T, 3, 3 > ret = static_matrix< T, 3, 3 >::Zero(); - ret(0, 0) = M(1, 1) * M(2, 2) - M(2, 1) * M(1, 2); - ret(0, 1) = M(1, 2) * M(2, 0) - M(2, 2) * M(1, 0); - ret(0, 2) = M(1, 0) * M(2, 1) - M(1, 1) * M(2, 0); + ret( 0, 0 ) = M( 1, 1 ) * M( 2, 2 ) - M( 2, 1 ) * M( 1, 2 ); + ret( 0, 1 ) = M( 1, 2 ) * M( 2, 0 ) - M( 2, 2 ) * M( 1, 0 ); + ret( 0, 2 ) = M( 1, 0 ) * M( 2, 1 ) - M( 1, 1 ) * M( 2, 0 ); - ret(1, 0) = M(0, 2) * M(2, 1) - M(2, 2) * M(0, 1); - ret(1, 1) = M(0, 0) * M(2, 2) - M(0, 2) * M(2, 0); - ret(1, 2) = M(2, 0) * M(0, 1) - M(0, 0) * M(2, 1); + ret( 1, 0 ) = M( 0, 2 ) * M( 2, 1 ) - M( 2, 2 ) * M( 0, 1 ); + ret( 1, 1 ) = M( 0, 0 ) * M( 2, 2 ) - M( 0, 2 ) * M( 2, 0 ); + ret( 1, 2 ) = M( 2, 0 ) * M( 0, 1 ) - M( 0, 0 ) * M( 2, 1 ); - ret(2, 0) = M(0, 1) * M(1, 2) - M(1, 1) * M(0, 2); - ret(2, 1) = M(0, 2) * M(1, 0) - M(0, 0) * M(1, 2); - ret(2, 2) = M(0, 0) * M(1, 1) - M(0, 1) * M(1, 0); + ret( 2, 0 ) = M( 0, 1 ) * M( 1, 2 ) - M( 1, 1 ) * M( 0, 2 ); + ret( 2, 1 ) = M( 0, 2 ) * M( 1, 0 ) - M( 0, 0 ) * M( 1, 2 ); + ret( 2, 2 ) = M( 0, 0 ) * M( 1, 1 ) - M( 0, 1 ) * M( 1, 0 ); return ret; } // Compute \partial^2 J / \partial M^2 -template -void -JacobianSecondDerivate(const static_matrix& M) -{ - static_assert((DIM == 2 || DIM == 3), "Can not compute jacobian derivate for this dimension"); +template < typename T, int DIM > +void JacobianSecondDerivate( const static_matrix< T, DIM, DIM > &M ) { + static_assert( ( DIM == 2 || DIM == 3 ), + "Can not compute jacobian derivate for this dimension" ); } -template -static_tensor -JacobianSecondDerivate(const static_matrix& M) -{ - static_tensor ret = static_tensor::Zero(); - T one = T(1); +template < typename T > +static_tensor< T, 2 > JacobianSecondDerivate( const static_matrix< T, 2, 2 > &M ) { + static_tensor< T, 2 > ret = static_tensor< T, 2 >::Zero(); + T one = T( 1 ); - ret(1, 1) = one; - ret(1, 2) = -one; - ret(2, 1) = -one; - ret(2, 2) = one; + ret( 1, 1 ) = one; + ret( 1, 2 ) = -one; + ret( 2, 1 ) = -one; + ret( 2, 2 ) = one; return ret; } -template -static_tensor -JacobianSecondDerivate(const static_matrix& M) -{ - static_tensor ret = static_tensor::Zero(); - - ret(1, 1) = M(2, 2); - ret(1, 2) = -M(2, 1); - ret(1, 3) = -M(2, 2); - ret(2, 1) = -M(1, 2); - ret(2, 2) = M(1, 1); - ret(2, 3) = M(1, 2); - ret(3, 1) = -M(2, 2); - ret(3, 2) = M(2, 1); - ret(3, 3) = M(2, 2); - - ret(1, 5) = M(2, 0); - ret(1, 6) = M(2, 1); - ret(1, 7) = -M(2, 0); - ret(2, 5) = -M(1, 0); - ret(2, 6) = -M(1, 1); - ret(2, 7) = M(1, 0); - ret(3, 5) = -M(2, 0); - ret(3, 6) = -M(2, 1); - ret(3, 7) = M(2, 0); - - ret(5, 1) = M(0, 2); - ret(5, 2) = -M(0, 1); - ret(5, 3) = -M(0, 2); - ret(6, 1) = M(1, 2); - ret(6, 2) = -M(1, 1); - ret(6, 3) = -M(2, 1); - ret(7, 1) = -M(0, 2); - ret(7, 2) = M(0, 1); - ret(7, 3) = M(0, 2); - - ret(5, 5) = M(0, 0); - ret(5, 6) = M(0, 1); - ret(5, 7) = -M(0, 0); - ret(6, 5) = M(1, 0); - ret(6, 6) = M(1, 1); - ret(6, 7) = -M(1, 0); - ret(7, 5) = -M(0, 0); - ret(7, 6) = -M(0, 1); - ret(7, 7) = M(0, 0); +template < typename T > +static_tensor< T, 3 > JacobianSecondDerivate( const static_matrix< T, 3, 3 > &M ) { + static_tensor< T, 3 > ret = static_tensor< T, 3 >::Zero(); + + ret( 1, 1 ) = M( 2, 2 ); + ret( 1, 2 ) = -M( 2, 1 ); + ret( 1, 3 ) = -M( 2, 2 ); + ret( 2, 1 ) = -M( 1, 2 ); + ret( 2, 2 ) = M( 1, 1 ); + ret( 2, 3 ) = M( 1, 2 ); + ret( 3, 1 ) = -M( 2, 2 ); + ret( 3, 2 ) = M( 2, 1 ); + ret( 3, 3 ) = M( 2, 2 ); + + ret( 1, 5 ) = M( 2, 0 ); + ret( 1, 6 ) = M( 2, 1 ); + ret( 1, 7 ) = -M( 2, 0 ); + ret( 2, 5 ) = -M( 1, 0 ); + ret( 2, 6 ) = -M( 1, 1 ); + ret( 2, 7 ) = M( 1, 0 ); + ret( 3, 5 ) = -M( 2, 0 ); + ret( 3, 6 ) = -M( 2, 1 ); + ret( 3, 7 ) = M( 2, 0 ); + + ret( 5, 1 ) = M( 0, 2 ); + ret( 5, 2 ) = -M( 0, 1 ); + ret( 5, 3 ) = -M( 0, 2 ); + ret( 6, 1 ) = M( 1, 2 ); + ret( 6, 2 ) = -M( 1, 1 ); + ret( 6, 3 ) = -M( 2, 1 ); + ret( 7, 1 ) = -M( 0, 2 ); + ret( 7, 2 ) = M( 0, 1 ); + ret( 7, 3 ) = M( 0, 2 ); + + ret( 5, 5 ) = M( 0, 0 ); + ret( 5, 6 ) = M( 0, 1 ); + ret( 5, 7 ) = -M( 0, 0 ); + ret( 6, 5 ) = M( 1, 0 ); + ret( 6, 6 ) = M( 1, 1 ); + ret( 6, 7 ) = -M( 1, 0 ); + ret( 7, 5 ) = -M( 0, 0 ); + ret( 7, 6 ) = -M( 0, 1 ); + ret( 7, 7 ) = M( 0, 0 ); return ret; } -} \ No newline at end of file +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/maths_tensor.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/maths_tensor.hpp index 520bc850..ec8fb117 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/maths_tensor.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/maths_tensor.hpp @@ -27,10 +27,10 @@ #include "diskpp/common/eigen.hpp" -namespace disk -{ +namespace disk { -// See https://trilinos.org/docs/r11.14/packages/intrepid/doc/html/Intrepid__MiniTensor__Tensor4_8t_8h_source.html +// See +// https://trilinos.org/docs/r11.14/packages/intrepid/doc/html/Intrepid__MiniTensor__Tensor4_8t_8h_source.html // for details about operations // the fourth order tensor is stored like a Matrix @@ -40,60 +40,49 @@ namespace disk // | A2121 A2122 A2221 A2222 | // return Aijkl -template -T -coeff(const static_tensor& A, const int i, const int j, const int k, const int l) -{ - if (i < 0 || j < 0 || k < 0 || l < 0 || i >= DIM || j >= DIM || k >= DIM || l >= DIM) - throw std::invalid_argument("Invalid coefficient"); - - return A(i * DIM + k, j * DIM + l); +template < typename T, int DIM > +T coeff( const static_tensor< T, DIM > &A, const int i, const int j, const int k, const int l ) { + if ( i < 0 || j < 0 || k < 0 || l < 0 || i >= DIM || j >= DIM || k >= DIM || l >= DIM ) + throw std::invalid_argument( "Invalid coefficient" ); + + return A( i * DIM + k, j * DIM + l ); } -template -void -coeff(static_tensor& A, const int i, const int j, const int k, const int l, const T val) -{ - if (i < 0 || j < 0 || k < 0 || l < 0 || i >= DIM || j >= DIM || k >= DIM || l >= DIM) - throw std::invalid_argument("Invalid coefficient"); +template < typename T, int DIM > +void coeff( static_tensor< T, DIM > &A, const int i, const int j, const int k, const int l, + const T val ) { + if ( i < 0 || j < 0 || k < 0 || l < 0 || i >= DIM || j >= DIM || k >= DIM || l >= DIM ) + throw std::invalid_argument( "Invalid coefficient" ); - A(i * DIM + k, j * DIM + l) = val; + A( i * DIM + k, j * DIM + l ) = val; } // Product Tensor - Matrix // aij = Aijkl Bkl -template -static_matrix -tm_prod(const static_tensor& tens, const static_matrix& mat) -{ - static_matrix ret; - - for (int i = 0; i < DIM; i++) - { - for (int j = 0; j < DIM; j++) - { - ret(i, j) = (tens.block(i * DIM, j * DIM, DIM, DIM).cwiseProduct(mat)).sum(); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > tm_prod( const static_tensor< T, DIM > &tens, + const static_matrix< T, DIM, DIM > &mat ) { + static_matrix< T, DIM, DIM > ret; + + for ( int i = 0; i < DIM; i++ ) { + for ( int j = 0; j < DIM; j++ ) { + ret( i, j ) = ( tens.block( i * DIM, j * DIM, DIM, DIM ).cwiseProduct( mat ) ).sum(); } } return ret; } // aij = Bkl Aklij -template -static_matrix -tm_prod(const static_matrix& mat, const static_tensor& tens) -{ - static_matrix ret = static_matrix::Zero(); - - for (int i = 0; i < DIM; i++) - { - for (int j = 0; j < DIM; j++) - { - for (int k = 0; k < DIM; k++) - { - for (int l = 0; l < DIM; l++) - { - ret(i, j) += mat(k, l) * coeff(tens, k, l, i, j); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > tm_prod( const static_matrix< T, DIM, DIM > &mat, + const static_tensor< T, DIM > &tens ) { + static_matrix< T, DIM, DIM > ret = static_matrix< T, DIM, DIM >::Zero(); + + for ( int i = 0; i < DIM; i++ ) { + for ( int j = 0; j < DIM; j++ ) { + for ( int k = 0; k < DIM; k++ ) { + for ( int l = 0; l < DIM; l++ ) { + ret( i, j ) += mat( k, l ) * coeff< T, DIM >( tens, k, l, i, j ); } } } @@ -104,28 +93,24 @@ tm_prod(const static_matrix& mat, const static_tensor& tens // aij = Aijkl Bkl // optimization mat(row,col) neq 0, 0 else -template -static_matrix -tm_prod(const static_tensor& tens, const static_matrix& mat, const int row, const int col) -{ - static_matrix ret; - ret.setConstant(mat(row, col)); - - for (int i = 0; i < DIM; i++) - { - for (int j = 0; j < DIM; j++) - { - ret(i, j) *= coeff(tens, i, j, row, col); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > tm_prod( const static_tensor< T, DIM > &tens, + const static_matrix< T, DIM, DIM > &mat, const int row, + const int col ) { + static_matrix< T, DIM, DIM > ret; + ret.setConstant( mat( row, col ) ); + + for ( int i = 0; i < DIM; i++ ) { + for ( int j = 0; j < DIM; j++ ) { + ret( i, j ) *= coeff< T, DIM >( tens, i, j, row, col ); } } return ret; } -template -T -tm_prod(const T& tens, const T& mat) -{ +template < typename T > +T tm_prod( const T &tens, const T &mat ) { return tens * mat; } @@ -133,79 +118,62 @@ tm_prod(const T& tens, const T& mat) // T_ijkl = A_ij B_kl -template -static_tensor -Kronecker(const static_matrix& A, const static_matrix& B) -{ - static_tensor ret = static_tensor::Zero(); - - for (int j = 0; j < DIM; j++) - { - for (int i = 0; i < DIM; i++) - { - ret.block(i * DIM, j * DIM, DIM, DIM) = A(i, j) * B; +template < typename T, int DIM > +static_tensor< T, DIM > Kronecker( const static_matrix< T, DIM, DIM > &A, + const static_matrix< T, DIM, DIM > &B ) { + static_tensor< T, DIM > ret = static_tensor< T, DIM >::Zero(); + + for ( int j = 0; j < DIM; j++ ) { + for ( int i = 0; i < DIM; i++ ) { + ret.block( i * DIM, j * DIM, DIM, DIM ) = A( i, j ) * B; } } return ret; } -template -static_matrix -Kronecker(const static_vector& A, const static_vector& B) -{ +template < typename T, int DIM > +static_matrix< T, DIM, DIM > Kronecker( const static_vector< T, DIM > &A, + const static_vector< T, DIM > &B ) { return A * B.transpose(); } // contracted product -template -T -InnerProduct(const static_vector& A, const static_vector& B) -{ - return A.dot(B); +template < typename T, int DIM > +T InnerProduct( const static_vector< T, DIM > &A, const static_vector< T, DIM > &B ) { + return A.dot( B ); } -template -T -InnerProduct(const static_matrix& A, const static_matrix& B) -{ - return A.cwiseProduct(B).sum(); +template < typename T, int DIM > +T InnerProduct( const static_matrix< T, DIM, DIM > &A, const static_matrix< T, DIM, DIM > &B ) { + return A.cwiseProduct( B ).sum(); } -template -static_matrix -ContractedProduct(const static_tensor& Tens, const static_matrix& B) -{ - return tm_prod(Tens, B); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > ContractedProduct( const static_tensor< T, DIM > &Tens, + const static_matrix< T, DIM, DIM > &B ) { + return tm_prod( Tens, B ); } -template -static_matrix -ContractedProduct(const static_matrix& B, const static_tensor& Tens) -{ - return tm_prod(B, Tens); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > ContractedProduct( const static_matrix< T, DIM, DIM > &B, + const static_tensor< T, DIM > &Tens ) { + return tm_prod( B, Tens ); } // Cijkl = Aijpq Bpqkl -template -static_tensor -ContractedProduct(const static_tensor& A, const static_tensor& B) -{ - static_tensor ret = static_tensor::Zero(); - - for (int i = 0; i < DIM; i++) - { - for (int j = 0; j < DIM; j++) - { - for (int k = 0; k < DIM; k++) - { - for (int l = 0; l < DIM; l++) - { - for (int p = 0; p < DIM; p++) - { - for (int q = 0; q < DIM; q++) - { - ret(i * DIM + k, j * DIM + l) += - coeff(A, i, j, p, q) * coeff(B, p, q, k, l); +template < typename T, int DIM > +static_tensor< T, DIM > ContractedProduct( const static_tensor< T, DIM > &A, + const static_tensor< T, DIM > &B ) { + static_tensor< T, DIM > ret = static_tensor< T, DIM >::Zero(); + + for ( int i = 0; i < DIM; i++ ) { + for ( int j = 0; j < DIM; j++ ) { + for ( int k = 0; k < DIM; k++ ) { + for ( int l = 0; l < DIM; l++ ) { + for ( int p = 0; p < DIM; p++ ) { + for ( int q = 0; q < DIM; q++ ) { + ret( i * DIM + k, j * DIM + l ) += + coeff< T, DIM >( A, i, j, p, q ) * coeff< T, DIM >( B, p, q, k, l ); } } } @@ -218,21 +186,16 @@ ContractedProduct(const static_tensor& A, const static_tensor& B // T_ijkl = A_ik B_jl -template -static_tensor -ProductSup(const static_matrix& A, const static_matrix& B) -{ - static_tensor ret = static_tensor::Zero(); - - for (int i = 0; i < DIM; i++) - { - for (int j = 0; j < DIM; j++) - { - for (int k = 0; k < DIM; k++) - { - for (int l = 0; l < DIM; l++) - { - ret(i * DIM + k, j * DIM + l) = A(i, k) * B(j, l); +template < typename T, int DIM > +static_tensor< T, DIM > ProductSup( const static_matrix< T, DIM, DIM > &A, + const static_matrix< T, DIM, DIM > &B ) { + static_tensor< T, DIM > ret = static_tensor< T, DIM >::Zero(); + + for ( int i = 0; i < DIM; i++ ) { + for ( int j = 0; j < DIM; j++ ) { + for ( int k = 0; k < DIM; k++ ) { + for ( int l = 0; l < DIM; l++ ) { + ret( i * DIM + k, j * DIM + l ) = A( i, k ) * B( j, l ); } } } @@ -243,21 +206,16 @@ ProductSup(const static_matrix& A, const static_matrix // T_ijkl = A_il B_jk -template -static_tensor -ProductInf(const static_matrix& A, const static_matrix& B) -{ - static_tensor ret = static_tensor::Zero(); - - for (int i = 0; i < DIM; i++) - { - for (int j = 0; j < DIM; j++) - { - for (int k = 0; k < DIM; k++) - { - for (int l = 0; l < DIM; l++) - { - ret(i * DIM + k, j * DIM + l) = A(i, l) * B(j, k); +template < typename T, int DIM > +static_tensor< T, DIM > ProductInf( const static_matrix< T, DIM, DIM > &A, + const static_matrix< T, DIM, DIM > &B ) { + static_tensor< T, DIM > ret = static_tensor< T, DIM >::Zero(); + + for ( int i = 0; i < DIM; i++ ) { + for ( int j = 0; j < DIM; j++ ) { + for ( int k = 0; k < DIM; k++ ) { + for ( int l = 0; l < DIM; l++ ) { + ret( i * DIM + k, j * DIM + l ) = A( i, l ) * B( j, k ); } } } @@ -265,106 +223,86 @@ ProductInf(const static_matrix& A, const static_matrix return ret; } -template -static_tensor -IdentityTensor4() -{ - static_tensor ret = static_tensor::Zero(); - T one = T{1}; - - if (DIM == 1) - ret(0, 0) = one; // I1111 - else if (DIM == 2) - { - ret(0, 0) = one; // I1111 - ret(0, 3) = one; // I1212 - ret(3, 0) = one; // I2121 - ret(3, 3) = one; // I2222 - } - else if (DIM == 3) - { - ret(0, 0) = one; // I1111 - ret(0, 4) = one; // I1212 - ret(0, 8) = one; // I1313 - ret(4, 0) = one; // I2121 - ret(4, 4) = one; // I2222 - ret(4, 8) = one; // I2323 - ret(8, 0) = one; // I3131 - ret(8, 4) = one; // I3232 - ret(8, 8) = one; // I3333 - } - else - static_assert((DIM == 1 || DIM == 2 || DIM == 3), "Wrong dimension only 2 and 3"); +template < typename T, int DIM > +static_tensor< T, DIM > IdentityTensor4() { + static_tensor< T, DIM > ret = static_tensor< T, DIM >::Zero(); + T one = T { 1 }; + + if ( DIM == 1 ) + ret( 0, 0 ) = one; // I1111 + else if ( DIM == 2 ) { + ret( 0, 0 ) = one; // I1111 + ret( 0, 3 ) = one; // I1212 + ret( 3, 0 ) = one; // I2121 + ret( 3, 3 ) = one; // I2222 + } else if ( DIM == 3 ) { + ret( 0, 0 ) = one; // I1111 + ret( 0, 4 ) = one; // I1212 + ret( 0, 8 ) = one; // I1313 + ret( 4, 0 ) = one; // I2121 + ret( 4, 4 ) = one; // I2222 + ret( 4, 8 ) = one; // I2323 + ret( 8, 0 ) = one; // I3131 + ret( 8, 4 ) = one; // I3232 + ret( 8, 8 ) = one; // I3333 + } else + static_assert( ( DIM == 1 || DIM == 2 || DIM == 3 ), "Wrong dimension only 2 and 3" ); return ret; } -template -static_tensor -IdentitySymTensor4() -{ - static_tensor ret = static_tensor::Zero(); - T one = T{1}; - T half = one / T{2}; - - if (DIM == 1) - ret(0, 0) = one; // I1111 - else if (DIM == 2) - { - ret(0, 0) = one; // I1111 - ret(0, 3) = half; // I1212 - ret(1, 2) = half; // I1221 - ret(2, 1) = half; // I2112 - ret(3, 0) = half; // I2121 - ret(3, 3) = one; // I2222 - } - else if (DIM == 3) - { - ret(0, 0) = one; // I1111 - ret(0, 4) = half; // I1212 - ret(0, 8) = half; // I1331 - ret(1, 3) = half; // I1221 - ret(2, 6) = half; // I1331 - ret(3, 1) = half; // I2112 - ret(4, 0) = half; // I2121 - ret(4, 4) = one; // I2222 - ret(4, 8) = half; // I2323 - ret(5, 7) = half; // I2332 - ret(6, 2) = half; // I3113 - ret(8, 0) = half; // I3131 - ret(7, 5) = half; // I3223 - ret(8, 4) = half; // I3232 - ret(8, 8) = one; // I333 - } - else - static_assert((DIM == 1 || DIM == 2 || DIM == 3), "Wrong dimension only 2 and 3"); +template < typename T, int DIM > +static_tensor< T, DIM > IdentitySymTensor4() { + static_tensor< T, DIM > ret = static_tensor< T, DIM >::Zero(); + T one = T { 1 }; + T half = one / T { 2 }; + + if ( DIM == 1 ) + ret( 0, 0 ) = one; // I1111 + else if ( DIM == 2 ) { + ret( 0, 0 ) = one; // I1111 + ret( 0, 3 ) = half; // I1212 + ret( 1, 2 ) = half; // I1221 + ret( 2, 1 ) = half; // I2112 + ret( 3, 0 ) = half; // I2121 + ret( 3, 3 ) = one; // I2222 + } else if ( DIM == 3 ) { + ret( 0, 0 ) = one; // I1111 + ret( 0, 4 ) = half; // I1212 + ret( 0, 8 ) = half; // I1331 + ret( 1, 3 ) = half; // I1221 + ret( 2, 6 ) = half; // I1331 + ret( 3, 1 ) = half; // I2112 + ret( 4, 0 ) = half; // I2121 + ret( 4, 4 ) = one; // I2222 + ret( 4, 8 ) = half; // I2323 + ret( 5, 7 ) = half; // I2332 + ret( 6, 2 ) = half; // I3113 + ret( 8, 0 ) = half; // I3131 + ret( 7, 5 ) = half; // I3223 + ret( 8, 4 ) = half; // I3232 + ret( 8, 8 ) = one; // I333 + } else + static_assert( ( DIM == 1 || DIM == 2 || DIM == 3 ), "Wrong dimension only 2 and 3" ); return ret; } -template -static_tensor -IxI() -{ - return static_tensor::Identity(); +template < typename T, int DIM > +static_tensor< T, DIM > IxI() { + return static_tensor< T, DIM >::Identity(); } //(A^T)ijkl = Aklij -template -static_tensor -transpose(const static_tensor& tens) -{ - static_tensor ret; - - for (int i = 0; i < DIM; i++) - { - for (int j = 0; j < DIM; j++) - { - for (int k = 0; k < DIM; k++) - { - for (int l = 0; l < DIM; l++) - { - ret(i * DIM + k, j * DIM + l) = coeff(tens, k, l, i, j); +template < typename T, int DIM > +static_tensor< T, DIM > transpose( const static_tensor< T, DIM > &tens ) { + static_tensor< T, DIM > ret; + + for ( int i = 0; i < DIM; i++ ) { + for ( int j = 0; j < DIM; j++ ) { + for ( int k = 0; k < DIM; k++ ) { + for ( int l = 0; l < DIM; l++ ) { + ret( i * DIM + k, j * DIM + l ) = coeff< T, DIM >( tens, k, l, i, j ); } } } @@ -373,22 +311,17 @@ transpose(const static_tensor& tens) return ret; } -template -static_tensor -Odot(const static_matrix& A, const static_matrix& B) -{ - static_tensor ret = static_tensor::Zero(); - - for (int i = 0; i < DIM; i++) - { - for (int j = 0; j < DIM; j++) - { - for (int k = 0; k < DIM; k++) - { - for (int l = 0; l < DIM; l++) - { - T val = (A(i, k) * B(j, l) + A(i, l) * B(j, k)) / T(2); - coeff(ret, i, j, k, l, val); +template < typename T, int DIM > +static_tensor< T, DIM > Odot( const static_matrix< T, DIM, DIM > &A, + const static_matrix< T, DIM, DIM > &B ) { + static_tensor< T, DIM > ret = static_tensor< T, DIM >::Zero(); + + for ( int i = 0; i < DIM; i++ ) { + for ( int j = 0; j < DIM; j++ ) { + for ( int k = 0; k < DIM; k++ ) { + for ( int l = 0; l < DIM; l++ ) { + T val = ( A( i, k ) * B( j, l ) + A( i, l ) * B( j, k ) ) / T( 2 ); + coeff< T, DIM >( ret, i, j, k, l, val ); } } } @@ -396,4 +329,4 @@ Odot(const static_matrix& A, const static_matrix& B) return ret; } -} +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/maths_utils.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/maths_utils.hpp index d5aac1c2..2c99b3ce 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/maths_utils.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/maths_utils.hpp @@ -28,37 +28,30 @@ #include "diskpp/common/eigen.hpp" #include "diskpp/mechanics/behaviors/maths_tensor.hpp" -namespace disk -{ +namespace disk { // deviatoric part of mat -template -static_matrix -deviator(const static_matrix mat) -{ - return mat - mat.trace() / T(DIM) * static_matrix::Identity(); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > deviator( const static_matrix< T, DIM, DIM > mat ) { + return mat - mat.trace() / T( DIM ) * static_matrix< T, DIM, DIM >::Identity(); } // spheric part of mat -template -static_matrix -spheric(const static_matrix mat) -{ - return mat.trace() / T(DIM) * static_matrix::Identity(); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > spheric( const static_matrix< T, DIM, DIM > mat ) { + return mat.trace() / T( DIM ) * static_matrix< T, DIM, DIM >::Identity(); } // compute the first derivate of the Frobenius-norm of the deviatoric part of a matrix -template -static_matrix -NormFroFirstDerivate(const static_matrix& dev) -{ - const T normFrodev = dev.norm(); - const T normFrodev3_2 = normFrodev * std::sqrt(normFrodev); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > NormFroFirstDerivate( const static_matrix< T, DIM, DIM > &dev ) { + const T normFrodev = dev.norm(); + const T normFrodev3_2 = normFrodev * std::sqrt( normFrodev ); auto mat = dev; - mat.diagonal() *= (1 - 1.0 / T(DIM)); + mat.diagonal() *= ( 1 - 1.0 / T( DIM ) ); return -mat / normFrodev3_2; } -} // end disk \ No newline at end of file +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/behaviors/tensor_conversion.hpp b/libdiskpp/include/diskpp/mechanics/behaviors/tensor_conversion.hpp index 51d4cd93..2bbc862c 100644 --- a/libdiskpp/include/diskpp/mechanics/behaviors/tensor_conversion.hpp +++ b/libdiskpp/include/diskpp/mechanics/behaviors/tensor_conversion.hpp @@ -28,8 +28,7 @@ #include "diskpp/common/eigen.hpp" #include "diskpp/mechanics/behaviors/maths_tensor.hpp" -namespace disk -{ +namespace disk { // the fourth order tensor is stored like a Matrix // | A1111 A1112 A1211 A1212 | @@ -37,159 +36,136 @@ namespace disk // | A2111 A2112 A2211 A2212 | // | A2121 A2122 A2221 A2222 | -template -static_matrix -convertMatrix3D(const static_matrix& mat) -{ +template < typename T > +static_matrix< T, 3, 3 > convertMatrix3D( const static_matrix< T, 3, 3 > &mat ) { return mat; } -template -static_matrix -convertMatrix3D(const static_matrix& mat) -{ - static_matrix ret = static_matrix::Zero(); - ret.block(0, 0, 2, 2) = mat; +template < typename T > +static_matrix< T, 3, 3 > convertMatrix3D( const static_matrix< T, 2, 2 > &mat ) { + static_matrix< T, 3, 3 > ret = static_matrix< T, 3, 3 >::Zero(); + ret.block( 0, 0, 2, 2 ) = mat; return ret; } -template -static_matrix -convertMatrix3DwithOne(const static_matrix& mat) -{ +template < typename T > +static_matrix< T, 3, 3 > convertMatrix3DwithOne( const static_matrix< T, 3, 3 > &mat ) { return mat; } -template -static_matrix -convertMatrix3DwithOne(const static_matrix& mat) -{ - static_matrix ret = static_matrix::Identity(); - ret.block(0, 0, 2, 2) = mat; +template < typename T > +static_matrix< T, 3, 3 > convertMatrix3DwithOne( const static_matrix< T, 2, 2 > &mat ) { + static_matrix< T, 3, 3 > ret = static_matrix< T, 3, 3 >::Identity(); + ret.block( 0, 0, 2, 2 ) = mat; return ret; } -template -static_matrix -convertMatrix(const static_matrix& mat) -{ - static_assert((DIM == 2 || DIM == 3), "Can not compute conversion for this dimension"); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > convertMatrix( const static_matrix< T, 3, 3 > &mat ) { + static_assert( ( DIM == 2 || DIM == 3 ), "Can not compute conversion for this dimension" ); - return mat.block(0, 0, DIM, DIM); + return mat.block( 0, 0, DIM, DIM ); } -template -static_tensor -convertTensor(const static_tensor& tens) -{ - static_assert((DIM == 2 || DIM == 3), "Can not compute conversion for this dimension"); +template < typename T, int DIM > +static_tensor< T, DIM > convertTensor( const static_tensor< T, 3 > &tens ) { + static_assert( ( DIM == 2 || DIM == 3 ), "Can not compute conversion for this dimension" ); - if (DIM == 2) - { - static_tensor ret = static_tensor::Zero(); + if ( DIM == 2 ) { + static_tensor< T, 3 > ret = static_tensor< T, 3 >::Zero(); - ret.block(0, 0, 2, 2) = tens.block(0, 0, 2, 2); - ret.block(0, 2, 2, 2) = tens.block(0, 3, 2, 2); - ret.block(2, 0, 2, 2) = tens.block(3, 0, 2, 2); - ret.block(2, 2, 2, 2) = tens.block(3, 3, 2, 2); + ret.block( 0, 0, 2, 2 ) = tens.block( 0, 0, 2, 2 ); + ret.block( 0, 2, 2, 2 ) = tens.block( 0, 3, 2, 2 ); + ret.block( 2, 0, 2, 2 ) = tens.block( 3, 0, 2, 2 ); + ret.block( 2, 2, 2, 2 ) = tens.block( 3, 3, 2, 2 ); - return ret.block(0, 0, DIM * DIM, DIM * DIM); + return ret.block( 0, 0, DIM * DIM, DIM * DIM ); } - return tens.block(0, 0, DIM * DIM, DIM * DIM); + return tens.block( 0, 0, DIM * DIM, DIM * DIM ); } -template -static_matrix -convertTensorNotationMangel(const static_tensor& tens) -{ - static_assert((DIM == 2 || DIM == 3), "Can not compute conversion for this dimension"); - - static_matrix ret = static_matrix::Zero(); - - ret(0, 0) = coeff(tens, 0, 0, 0, 0); - ret(0, 1) = coeff(tens, 0, 0, 1, 1); - ret(1, 0) = coeff(tens, 1, 1, 0, 0); - ret(1, 1) = coeff(tens, 1, 1, 1, 1); - - ret(0, 3) = coeff(tens, 0, 0, 0, 1) * sqrt(T(2)); - ret(1, 3) = coeff(tens, 1, 1, 0, 1) * sqrt(T(2)); - ret(3, 0) = coeff(tens, 0, 1, 0, 0) * sqrt(T(2)); - ret(3, 1) = coeff(tens, 0, 1, 1, 1) * sqrt(T(2)); - ret(3, 3) = coeff(tens, 0, 1, 0, 1) * T(2); - - if (DIM == 3) - { - ret(0, 2) = coeff(tens, 0, 0, 2, 2); - ret(1, 2) = coeff(tens, 1, 1, 2, 2); - ret(2, 2) = coeff(tens, 2, 2, 2, 2); - ret(2, 0) = coeff(tens, 2, 2, 0, 0); - ret(2, 1) = coeff(tens, 2, 2, 1, 1); - - ret(2, 3) = coeff(tens, 2, 2, 0, 1) * sqrt(T(2)); - ret(3, 2) = coeff(tens, 0, 1, 2, 2) * sqrt(T(2)); - - ret(0, 5) = coeff(tens, 0, 0, 1, 2) * sqrt(T(2)); - ret(0, 4) = coeff(tens, 0, 0, 0, 2) * sqrt(T(2)); - ret(1, 5) = coeff(tens, 1, 1, 1, 2) * sqrt(T(2)); - ret(1, 4) = coeff(tens, 1, 1, 0, 2) * sqrt(T(2)); - ret(2, 5) = coeff(tens, 2, 2, 1, 2) * sqrt(T(2)); - ret(2, 4) = coeff(tens, 2, 2, 0, 2) * sqrt(T(2)); - - ret(4, 0) = coeff(tens, 0, 2, 0, 0) * sqrt(T(2)); - ret(4, 1) = coeff(tens, 0, 2, 1, 1) * sqrt(T(2)); - ret(4, 2) = coeff(tens, 0, 2, 2, 2) * sqrt(T(2)); - ret(5, 0) = coeff(tens, 1, 2, 0, 0) * sqrt(T(2)); - ret(5, 1) = coeff(tens, 1, 2, 1, 1) * sqrt(T(2)); - ret(5, 2) = coeff(tens, 1, 2, 2, 2) * sqrt(T(2)); - - ret(3, 5) = coeff(tens, 0, 1, 1, 2) * T(2); - ret(3, 4) = coeff(tens, 0, 1, 0, 2) * T(2); - ret(4, 3) = coeff(tens, 0, 2, 0, 1) * T(2); - ret(4, 5) = coeff(tens, 0, 2, 1, 2) * T(2); - ret(4, 4) = coeff(tens, 0, 2, 0, 2) * T(2); - ret(5, 3) = coeff(tens, 1, 2, 0, 1) * T(2); - ret(5, 5) = coeff(tens, 1, 2, 1, 2) * T(2); - ret(5, 4) = coeff(tens, 1, 2, 0, 2) * T(2); +template < typename T, int DIM > +static_matrix< T, 6, 6 > convertTensorNotationMangel( const static_tensor< T, DIM > &tens ) { + static_assert( ( DIM == 2 || DIM == 3 ), "Can not compute conversion for this dimension" ); + + static_matrix< T, 6, 6 > ret = static_matrix< T, 6, 6 >::Zero(); + + ret( 0, 0 ) = coeff< T, DIM >( tens, 0, 0, 0, 0 ); + ret( 0, 1 ) = coeff< T, DIM >( tens, 0, 0, 1, 1 ); + ret( 1, 0 ) = coeff< T, DIM >( tens, 1, 1, 0, 0 ); + ret( 1, 1 ) = coeff< T, DIM >( tens, 1, 1, 1, 1 ); + + ret( 0, 3 ) = coeff< T, DIM >( tens, 0, 0, 0, 1 ) * sqrt( T( 2 ) ); + ret( 1, 3 ) = coeff< T, DIM >( tens, 1, 1, 0, 1 ) * sqrt( T( 2 ) ); + ret( 3, 0 ) = coeff< T, DIM >( tens, 0, 1, 0, 0 ) * sqrt( T( 2 ) ); + ret( 3, 1 ) = coeff< T, DIM >( tens, 0, 1, 1, 1 ) * sqrt( T( 2 ) ); + ret( 3, 3 ) = coeff< T, DIM >( tens, 0, 1, 0, 1 ) * T( 2 ); + + if ( DIM == 3 ) { + ret( 0, 2 ) = coeff< T, DIM >( tens, 0, 0, 2, 2 ); + ret( 1, 2 ) = coeff< T, DIM >( tens, 1, 1, 2, 2 ); + ret( 2, 2 ) = coeff< T, DIM >( tens, 2, 2, 2, 2 ); + ret( 2, 0 ) = coeff< T, DIM >( tens, 2, 2, 0, 0 ); + ret( 2, 1 ) = coeff< T, DIM >( tens, 2, 2, 1, 1 ); + + ret( 2, 3 ) = coeff< T, DIM >( tens, 2, 2, 0, 1 ) * sqrt( T( 2 ) ); + ret( 3, 2 ) = coeff< T, DIM >( tens, 0, 1, 2, 2 ) * sqrt( T( 2 ) ); + + ret( 0, 5 ) = coeff< T, DIM >( tens, 0, 0, 1, 2 ) * sqrt( T( 2 ) ); + ret( 0, 4 ) = coeff< T, DIM >( tens, 0, 0, 0, 2 ) * sqrt( T( 2 ) ); + ret( 1, 5 ) = coeff< T, DIM >( tens, 1, 1, 1, 2 ) * sqrt( T( 2 ) ); + ret( 1, 4 ) = coeff< T, DIM >( tens, 1, 1, 0, 2 ) * sqrt( T( 2 ) ); + ret( 2, 5 ) = coeff< T, DIM >( tens, 2, 2, 1, 2 ) * sqrt( T( 2 ) ); + ret( 2, 4 ) = coeff< T, DIM >( tens, 2, 2, 0, 2 ) * sqrt( T( 2 ) ); + + ret( 4, 0 ) = coeff< T, DIM >( tens, 0, 2, 0, 0 ) * sqrt( T( 2 ) ); + ret( 4, 1 ) = coeff< T, DIM >( tens, 0, 2, 1, 1 ) * sqrt( T( 2 ) ); + ret( 4, 2 ) = coeff< T, DIM >( tens, 0, 2, 2, 2 ) * sqrt( T( 2 ) ); + ret( 5, 0 ) = coeff< T, DIM >( tens, 1, 2, 0, 0 ) * sqrt( T( 2 ) ); + ret( 5, 1 ) = coeff< T, DIM >( tens, 1, 2, 1, 1 ) * sqrt( T( 2 ) ); + ret( 5, 2 ) = coeff< T, DIM >( tens, 1, 2, 2, 2 ) * sqrt( T( 2 ) ); + + ret( 3, 5 ) = coeff< T, DIM >( tens, 0, 1, 1, 2 ) * T( 2 ); + ret( 3, 4 ) = coeff< T, DIM >( tens, 0, 1, 0, 2 ) * T( 2 ); + ret( 4, 3 ) = coeff< T, DIM >( tens, 0, 2, 0, 1 ) * T( 2 ); + ret( 4, 5 ) = coeff< T, DIM >( tens, 0, 2, 1, 2 ) * T( 2 ); + ret( 4, 4 ) = coeff< T, DIM >( tens, 0, 2, 0, 2 ) * T( 2 ); + ret( 5, 3 ) = coeff< T, DIM >( tens, 1, 2, 0, 1 ) * T( 2 ); + ret( 5, 5 ) = coeff< T, DIM >( tens, 1, 2, 1, 2 ) * T( 2 ); + ret( 5, 4 ) = coeff< T, DIM >( tens, 1, 2, 0, 2 ) * T( 2 ); } return ret; } -template -static_tensor -convertCtoA(const static_tensor& C, const static_matrix& PK2, const static_matrix& F) -{ - static_tensor A = static_tensor::Zero(); - - for (int i = 0; i < 3; i++) - { - for (int J = 0; J < 3; J++) - { - for (int k = 0; k < 3; k++) - { - for (int L = 0; L < 3; L++) - { - T sum = T(0); - for (int M = 0; M < 3; M++) - { - T sum1 = T(0); - for (int N = 0; N < 3; N++) - { - sum1 += coeff(C, M, J, N, L) * F(k, N); +template < typename T > +static_tensor< T, 3 > convertCtoA( const static_tensor< T, 3 > &C, + const static_matrix< T, 3, 3 > &PK2, + const static_matrix< T, 3, 3 > &F ) { + static_tensor< T, 3 > A = static_tensor< T, 3 >::Zero(); + + for ( int i = 0; i < 3; i++ ) { + for ( int J = 0; J < 3; J++ ) { + for ( int k = 0; k < 3; k++ ) { + for ( int L = 0; L < 3; L++ ) { + T sum = T( 0 ); + for ( int M = 0; M < 3; M++ ) { + T sum1 = T( 0 ); + for ( int N = 0; N < 3; N++ ) { + sum1 += coeff< T, 3 >( C, M, J, N, L ) * F( k, N ); } - sum += sum1 * F(i, M); + sum += sum1 * F( i, M ); } - if (i == k) - { - sum += PK2(J, L); + if ( i == k ) { + sum += PK2( J, L ); } - coeff(A, i, J, k, L, sum); - coeff(A, k, L, i, J, sum); + coeff< T, 3 >( A, i, J, k, L, sum ); + coeff< T, 3 >( A, k, L, i, J, sum ); } } } @@ -198,384 +174,369 @@ convertCtoA(const static_tensor& C, const static_matrix& PK2, con return A; } -template -void -convertMatrixToMgis(const static_matrix& mat, std::vector& mat_vec) -{ - switch (mat_vec.size()) - { - case 4: - { - mat_vec[0] = mat(0, 0); - mat_vec[1] = mat(1, 1); - mat_vec[2] = mat(2, 2); - mat_vec[3] = sqrt(2.) * mat(0, 1); - break; - } - case 5: - { - mat_vec[0] = mat(0, 0); - mat_vec[1] = mat(1, 1); - mat_vec[2] = mat(2, 2); - mat_vec[3] = mat(0, 1); - mat_vec[4] = mat(1, 0); - break; - } - case 6: - { - const T rac2 = sqrt(2.); - mat_vec[0] = mat(0, 0); - mat_vec[1] = mat(1, 1); - mat_vec[2] = mat(2, 2); - mat_vec[3] = rac2 * mat(0, 1); - mat_vec[4] = rac2 * mat(0, 2); - mat_vec[5] = rac2 * mat(1, 2); - break; - } - case 9: - { - mat_vec[0] = mat(0, 0); - mat_vec[1] = mat(1, 1); - mat_vec[2] = mat(2, 2); - mat_vec[3] = mat(0, 1); - mat_vec[4] = mat(1, 0); - mat_vec[5] = mat(0, 2); - mat_vec[6] = mat(2, 0); - mat_vec[7] = mat(1, 2); - mat_vec[8] = mat(2, 1); - break; - } +template < typename T, typename T2 > +void convertMatrixToMgis( const static_matrix< T, 3, 3 > &mat, std::vector< T2 > &mat_vec ) { + switch ( mat_vec.size() ) { + case 4: { + mat_vec[0] = mat( 0, 0 ); + mat_vec[1] = mat( 1, 1 ); + mat_vec[2] = mat( 2, 2 ); + mat_vec[3] = sqrt( 2. ) * mat( 0, 1 ); + break; + } + case 5: { + mat_vec[0] = mat( 0, 0 ); + mat_vec[1] = mat( 1, 1 ); + mat_vec[2] = mat( 2, 2 ); + mat_vec[3] = mat( 0, 1 ); + mat_vec[4] = mat( 1, 0 ); + break; + } + case 6: { + const T rac2 = sqrt( 2. ); + mat_vec[0] = mat( 0, 0 ); + mat_vec[1] = mat( 1, 1 ); + mat_vec[2] = mat( 2, 2 ); + mat_vec[3] = rac2 * mat( 0, 1 ); + mat_vec[4] = rac2 * mat( 0, 2 ); + mat_vec[5] = rac2 * mat( 1, 2 ); + break; + } + case 9: { + mat_vec[0] = mat( 0, 0 ); + mat_vec[1] = mat( 1, 1 ); + mat_vec[2] = mat( 2, 2 ); + mat_vec[3] = mat( 0, 1 ); + mat_vec[4] = mat( 1, 0 ); + mat_vec[5] = mat( 0, 2 ); + mat_vec[6] = mat( 2, 0 ); + mat_vec[7] = mat( 1, 2 ); + mat_vec[8] = mat( 2, 1 ); + break; + } - default: throw std::runtime_error("wrong size"); break; + default: + throw std::runtime_error( "wrong size" ); + break; } } -template -void -convertMatrixFromMgis(const std::vector& mat_vec, static_matrix& mat) -{ +template < typename T, typename T2 > +void convertMatrixFromMgis( const std::vector< T2 > &mat_vec, static_matrix< T, 3, 3 > &mat ) { mat.setZero(); - switch (mat_vec.size()) - { - case 4: - { - mat(0, 0) = mat_vec[0]; - mat(1, 1) = mat_vec[1]; - mat(2, 2) = mat_vec[2]; - mat(0, 1) = mat_vec[3] / sqrt(2.); - mat(1, 0) = mat(0, 1); - break; - } - case 5: - { - mat(0, 0) = mat_vec[0]; - mat(1, 1) = mat_vec[1]; - mat(2, 2) = mat_vec[2]; - mat(0, 1) = mat_vec[3]; - mat(1, 0) = mat_vec[4]; - break; - } - case 6: - { - const T rac2 = sqrt(2.); - mat(0, 0) = mat_vec[0]; - mat(1, 1) = mat_vec[1]; - mat(2, 2) = mat_vec[2]; - mat(0, 1) = mat_vec[3] / sqrt(2.); - mat(1, 0) = mat(0, 1); - mat(0, 2) = mat_vec[4] / sqrt(2.); - mat(2, 0) = mat(0, 2); - mat(0, 1) = mat_vec[5] / sqrt(2.); - mat(2, 1) = mat(1, 2); - break; - } - case 9: - { - mat(0, 0) = mat_vec[0]; - mat(1, 1) = mat_vec[1]; - mat(2, 2) = mat_vec[2]; - mat(0, 1) = mat_vec[3]; - mat(1, 0) = mat_vec[4]; - mat(0, 2) = mat_vec[5]; - mat(2, 0) = mat_vec[6]; - mat(1, 2) = mat_vec[7]; - mat(2, 1) = mat_vec[8]; - break; - } + switch ( mat_vec.size() ) { + case 4: { + mat( 0, 0 ) = mat_vec[0]; + mat( 1, 1 ) = mat_vec[1]; + mat( 2, 2 ) = mat_vec[2]; + mat( 0, 1 ) = mat_vec[3] / sqrt( 2. ); + mat( 1, 0 ) = mat( 0, 1 ); + break; + } + case 5: { + mat( 0, 0 ) = mat_vec[0]; + mat( 1, 1 ) = mat_vec[1]; + mat( 2, 2 ) = mat_vec[2]; + mat( 0, 1 ) = mat_vec[3]; + mat( 1, 0 ) = mat_vec[4]; + break; + } + case 6: { + const T rac2 = sqrt( 2. ); + mat( 0, 0 ) = mat_vec[0]; + mat( 1, 1 ) = mat_vec[1]; + mat( 2, 2 ) = mat_vec[2]; + mat( 0, 1 ) = mat_vec[3] / sqrt( 2. ); + mat( 1, 0 ) = mat( 0, 1 ); + mat( 0, 2 ) = mat_vec[4] / sqrt( 2. ); + mat( 2, 0 ) = mat( 0, 2 ); + mat( 0, 1 ) = mat_vec[5] / sqrt( 2. ); + mat( 2, 1 ) = mat( 1, 2 ); + break; + } + case 9: { + mat( 0, 0 ) = mat_vec[0]; + mat( 1, 1 ) = mat_vec[1]; + mat( 2, 2 ) = mat_vec[2]; + mat( 0, 1 ) = mat_vec[3]; + mat( 1, 0 ) = mat_vec[4]; + mat( 0, 2 ) = mat_vec[5]; + mat( 2, 0 ) = mat_vec[6]; + mat( 1, 2 ) = mat_vec[7]; + mat( 2, 1 ) = mat_vec[8]; + break; + } - default: throw std::runtime_error("wrong size"); break; + default: + throw std::runtime_error( "wrong size" ); + break; } } -template -void -convertTensorFromMgis(const std::vector& tens_vec, static_tensor& tens) -{ +template < typename T, typename T2 > +void convertTensorFromMgis( const std::vector< T2 > &tens_vec, static_tensor< T, 3 > &tens ) { tens.setZero(); // std::cout << "SIZE: " << tens_vec.size() << std::endl; // for (int i = 0; i < tens_vec.size(); i++) // std::cout << i << ": " << tens_vec[i] << std::endl; - switch (tens_vec.size()) - { - case 16: - { - const T rac2 = sqrt(2.); - coeff(tens, 0, 0, 0, 0, tens_vec[0]); - coeff(tens, 0, 0, 1, 1, tens_vec[1]); - coeff(tens, 0, 0, 2, 2, tens_vec[2]); - coeff(tens, 0, 0, 0, 1, tens_vec[3] / rac2); - coeff(tens, 0, 0, 1, 0, coeff(tens, 0, 0, 0, 1)); - // - coeff(tens, 1, 1, 0, 0, tens_vec[4]); - coeff(tens, 1, 1, 1, 1, tens_vec[5]); - coeff(tens, 1, 1, 2, 2, tens_vec[6]); - coeff(tens, 1, 1, 0, 1, tens_vec[7] / rac2); - coeff(tens, 1, 1, 1, 0, coeff(tens, 1, 1, 0, 1)); - // - coeff(tens, 2, 2, 0, 0, tens_vec[8]); - coeff(tens, 2, 2, 1, 1, tens_vec[9]); - coeff(tens, 2, 2, 2, 2, tens_vec[10]); - coeff(tens, 2, 2, 0, 1, tens_vec[11] / rac2); - coeff(tens, 2, 2, 1, 0, coeff(tens, 2, 2, 0, 1)); - // - coeff(tens, 0, 1, 0, 0, tens_vec[12] / rac2); - coeff(tens, 0, 1, 1, 1, tens_vec[13] / rac2); - coeff(tens, 0, 1, 2, 2, tens_vec[14] / rac2); - coeff(tens, 0, 1, 0, 1, tens_vec[15] / 2.0); - coeff(tens, 0, 1, 1, 0, coeff(tens, 0, 1, 0, 1)); - // - coeff(tens, 1, 0, 0, 0, coeff(tens, 0, 1, 0, 0)); - coeff(tens, 1, 0, 1, 1, coeff(tens, 0, 1, 1, 1)); - coeff(tens, 1, 0, 2, 2, coeff(tens, 0, 1, 2, 2)); - coeff(tens, 1, 0, 1, 0, coeff(tens, 0, 1, 1, 0)); - coeff(tens, 1, 0, 0, 1, coeff(tens, 0, 1, 0, 1)); - break; - } + switch ( tens_vec.size() ) { + case 16: { + const T rac2 = sqrt( 2. ); + coeff< T, 3 >( tens, 0, 0, 0, 0, tens_vec[0] ); + coeff< T, 3 >( tens, 0, 0, 1, 1, tens_vec[1] ); + coeff< T, 3 >( tens, 0, 0, 2, 2, tens_vec[2] ); + coeff< T, 3 >( tens, 0, 0, 0, 1, tens_vec[3] / rac2 ); + coeff< T, 3 >( tens, 0, 0, 1, 0, coeff< T, 3 >( tens, 0, 0, 0, 1 ) ); + // + coeff< T, 3 >( tens, 1, 1, 0, 0, tens_vec[4] ); + coeff< T, 3 >( tens, 1, 1, 1, 1, tens_vec[5] ); + coeff< T, 3 >( tens, 1, 1, 2, 2, tens_vec[6] ); + coeff< T, 3 >( tens, 1, 1, 0, 1, tens_vec[7] / rac2 ); + coeff< T, 3 >( tens, 1, 1, 1, 0, coeff< T, 3 >( tens, 1, 1, 0, 1 ) ); + // + coeff< T, 3 >( tens, 2, 2, 0, 0, tens_vec[8] ); + coeff< T, 3 >( tens, 2, 2, 1, 1, tens_vec[9] ); + coeff< T, 3 >( tens, 2, 2, 2, 2, tens_vec[10] ); + coeff< T, 3 >( tens, 2, 2, 0, 1, tens_vec[11] / rac2 ); + coeff< T, 3 >( tens, 2, 2, 1, 0, coeff< T, 3 >( tens, 2, 2, 0, 1 ) ); + // + coeff< T, 3 >( tens, 0, 1, 0, 0, tens_vec[12] / rac2 ); + coeff< T, 3 >( tens, 0, 1, 1, 1, tens_vec[13] / rac2 ); + coeff< T, 3 >( tens, 0, 1, 2, 2, tens_vec[14] / rac2 ); + coeff< T, 3 >( tens, 0, 1, 0, 1, tens_vec[15] / 2.0 ); + coeff< T, 3 >( tens, 0, 1, 1, 0, coeff< T, 3 >( tens, 0, 1, 0, 1 ) ); + // + coeff< T, 3 >( tens, 1, 0, 0, 0, coeff< T, 3 >( tens, 0, 1, 0, 0 ) ); + coeff< T, 3 >( tens, 1, 0, 1, 1, coeff< T, 3 >( tens, 0, 1, 1, 1 ) ); + coeff< T, 3 >( tens, 1, 0, 2, 2, coeff< T, 3 >( tens, 0, 1, 2, 2 ) ); + coeff< T, 3 >( tens, 1, 0, 1, 0, coeff< T, 3 >( tens, 0, 1, 1, 0 ) ); + coeff< T, 3 >( tens, 1, 0, 0, 1, coeff< T, 3 >( tens, 0, 1, 0, 1 ) ); + break; + } - case 25: - { - coeff(tens, 0, 0, 0, 0, tens_vec[0]); - coeff(tens, 0, 0, 1, 1, tens_vec[1]); - coeff(tens, 0, 0, 2, 2, tens_vec[2]); - coeff(tens, 0, 0, 0, 1, tens_vec[3]); - coeff(tens, 0, 0, 1, 0, tens_vec[4]); - // - coeff(tens, 1, 1, 0, 0, tens_vec[5]); - coeff(tens, 1, 1, 1, 1, tens_vec[6]); - coeff(tens, 1, 1, 2, 2, tens_vec[7]); - coeff(tens, 1, 1, 0, 1, tens_vec[8]); - coeff(tens, 1, 1, 1, 0, tens_vec[9]); - // - coeff(tens, 2, 2, 0, 0, tens_vec[10]); - coeff(tens, 2, 2, 1, 1, tens_vec[11]); - coeff(tens, 2, 2, 2, 2, tens_vec[12]); - coeff(tens, 2, 2, 0, 1, tens_vec[13]); - coeff(tens, 2, 2, 1, 0, tens_vec[14]); - // - coeff(tens, 0, 1, 0, 0, tens_vec[15]); - coeff(tens, 0, 1, 1, 1, tens_vec[16]); - coeff(tens, 0, 1, 2, 2, tens_vec[17]); - coeff(tens, 0, 1, 0, 1, tens_vec[18]); - coeff(tens, 0, 1, 1, 0, tens_vec[19]); - // - coeff(tens, 1, 0, 0, 0, tens_vec[20]); - coeff(tens, 1, 0, 1, 1, tens_vec[21]); - coeff(tens, 1, 0, 2, 2, tens_vec[22]); - coeff(tens, 1, 0, 0, 1, tens_vec[23]); - coeff(tens, 1, 0, 1, 0, tens_vec[24]); - break; - } + case 25: { + coeff< T, 3 >( tens, 0, 0, 0, 0, tens_vec[0] ); + coeff< T, 3 >( tens, 0, 0, 1, 1, tens_vec[1] ); + coeff< T, 3 >( tens, 0, 0, 2, 2, tens_vec[2] ); + coeff< T, 3 >( tens, 0, 0, 0, 1, tens_vec[3] ); + coeff< T, 3 >( tens, 0, 0, 1, 0, tens_vec[4] ); + // + coeff< T, 3 >( tens, 1, 1, 0, 0, tens_vec[5] ); + coeff< T, 3 >( tens, 1, 1, 1, 1, tens_vec[6] ); + coeff< T, 3 >( tens, 1, 1, 2, 2, tens_vec[7] ); + coeff< T, 3 >( tens, 1, 1, 0, 1, tens_vec[8] ); + coeff< T, 3 >( tens, 1, 1, 1, 0, tens_vec[9] ); + // + coeff< T, 3 >( tens, 2, 2, 0, 0, tens_vec[10] ); + coeff< T, 3 >( tens, 2, 2, 1, 1, tens_vec[11] ); + coeff< T, 3 >( tens, 2, 2, 2, 2, tens_vec[12] ); + coeff< T, 3 >( tens, 2, 2, 0, 1, tens_vec[13] ); + coeff< T, 3 >( tens, 2, 2, 1, 0, tens_vec[14] ); + // + coeff< T, 3 >( tens, 0, 1, 0, 0, tens_vec[15] ); + coeff< T, 3 >( tens, 0, 1, 1, 1, tens_vec[16] ); + coeff< T, 3 >( tens, 0, 1, 2, 2, tens_vec[17] ); + coeff< T, 3 >( tens, 0, 1, 0, 1, tens_vec[18] ); + coeff< T, 3 >( tens, 0, 1, 1, 0, tens_vec[19] ); + // + coeff< T, 3 >( tens, 1, 0, 0, 0, tens_vec[20] ); + coeff< T, 3 >( tens, 1, 0, 1, 1, tens_vec[21] ); + coeff< T, 3 >( tens, 1, 0, 2, 2, tens_vec[22] ); + coeff< T, 3 >( tens, 1, 0, 0, 1, tens_vec[23] ); + coeff< T, 3 >( tens, 1, 0, 1, 0, tens_vec[24] ); + break; + } - case 36: - { - const T rac2 = sqrt(2.); - coeff(tens, 0, 0, 0, 0, tens_vec[0]); - coeff(tens, 0, 0, 1, 1, tens_vec[1]); - coeff(tens, 0, 0, 2, 2, tens_vec[2]); - coeff(tens, 0, 0, 1, 2, tens_vec[3] / rac2); - coeff(tens, 0, 0, 2, 1, coeff(tens, 0, 0, 1, 2)); - coeff(tens, 0, 0, 2, 0, tens_vec[4] / rac2); - coeff(tens, 0, 0, 0, 2, coeff(tens, 0, 0, 2, 0)); - coeff(tens, 0, 0, 0, 1, tens_vec[5] / rac2); - coeff(tens, 0, 0, 1, 0, coeff(tens, 0, 0, 0, 1)); - // - coeff(tens, 1, 1, 0, 0, tens_vec[6]); - coeff(tens, 1, 1, 1, 1, tens_vec[7]); - coeff(tens, 1, 1, 2, 2, tens_vec[8]); - coeff(tens, 1, 1, 1, 2, tens_vec[9] / rac2); - coeff(tens, 1, 1, 2, 1, coeff(tens, 1, 1, 1, 2)); - coeff(tens, 1, 1, 2, 0, tens_vec[10] / rac2); - coeff(tens, 1, 1, 0, 2, coeff(tens, 1, 1, 2, 0)); - coeff(tens, 1, 1, 0, 1, tens_vec[11] / rac2); - coeff(tens, 1, 1, 1, 0, coeff(tens, 1, 1, 0, 1)); - // - coeff(tens, 2, 2, 0, 0, tens_vec[12]); - coeff(tens, 2, 2, 1, 1, tens_vec[13]); - coeff(tens, 2, 2, 2, 2, tens_vec[14]); - coeff(tens, 2, 2, 1, 2, tens_vec[15] / rac2); - coeff(tens, 2, 2, 2, 1, coeff(tens, 2, 2, 1, 2)); - coeff(tens, 2, 2, 2, 0, tens_vec[16] / rac2); - coeff(tens, 2, 2, 0, 2, coeff(tens, 2, 2, 2, 0)); - coeff(tens, 2, 2, 0, 1, tens_vec[17] / rac2); - coeff(tens, 2, 2, 1, 0, coeff(tens, 2, 2, 0, 1)); - // - coeff(tens, 1, 2, 0, 0, tens_vec[18] / rac2); - coeff(tens, 1, 2, 1, 1, tens_vec[19] / rac2); - coeff(tens, 1, 2, 2, 2, tens_vec[20] / rac2); - coeff(tens, 1, 2, 1, 2, tens_vec[21] / 2.); - coeff(tens, 1, 2, 2, 1, coeff(tens, 1, 2, 1, 2)); - coeff(tens, 1, 2, 2, 0, tens_vec[22] / 2.); - coeff(tens, 1, 2, 0, 2, coeff(tens, 1, 2, 2, 0)); - coeff(tens, 1, 2, 0, 1, tens_vec[23] / 2.); - coeff(tens, 1, 2, 1, 0, coeff(tens, 1, 2, 0, 1)); - // - coeff(tens, 2, 0, 0, 0, tens_vec[24] / rac2); - coeff(tens, 2, 0, 1, 1, tens_vec[25] / rac2); - coeff(tens, 2, 0, 2, 2, tens_vec[26] / rac2); - coeff(tens, 2, 0, 1, 2, tens_vec[27] / 2.); - coeff(tens, 2, 0, 2, 1, coeff(tens, 2, 0, 1, 2)); - coeff(tens, 2, 0, 2, 0, tens_vec[28] / 2.); - coeff(tens, 2, 0, 0, 2, coeff(tens, 2, 0, 2, 0)); - coeff(tens, 2, 0, 0, 1, tens_vec[29] / 2.); - coeff(tens, 2, 0, 1, 0, coeff(tens, 2, 0, 0, 1)); - // - coeff(tens, 0, 1, 0, 0, tens_vec[30] / rac2); - coeff(tens, 0, 1, 1, 1, tens_vec[31] / rac2); - coeff(tens, 0, 1, 2, 2, tens_vec[32] / 2.); - coeff(tens, 0, 1, 1, 2, tens_vec[33] / 2.); - coeff(tens, 0, 1, 2, 1, coeff(tens, 0, 1, 1, 2)); - coeff(tens, 0, 1, 2, 0, tens_vec[34] / rac2); - coeff(tens, 0, 1, 0, 2, coeff(tens, 0, 1, 2, 0)); - coeff(tens, 0, 1, 0, 1, tens_vec[35] / 2.); - coeff(tens, 0, 1, 1, 0, coeff(tens, 0, 1, 0, 1)); - // - coeff(tens, 2, 1, 0, 0, coeff(tens, 1, 2, 0, 0)); - coeff(tens, 2, 1, 1, 1, coeff(tens, 1, 2, 1, 1)); - coeff(tens, 2, 1, 2, 2, coeff(tens, 1, 2, 2, 2)); - coeff(tens, 2, 1, 1, 2, coeff(tens, 1, 2, 1, 2)); - coeff(tens, 2, 1, 2, 1, coeff(tens, 1, 2, 2, 1)); - coeff(tens, 2, 1, 2, 0, coeff(tens, 1, 2, 2, 0)); - coeff(tens, 2, 1, 0, 2, coeff(tens, 1, 2, 0, 2)); - coeff(tens, 2, 1, 0, 1, coeff(tens, 1, 2, 0, 1)); - coeff(tens, 2, 1, 1, 0, coeff(tens, 1, 2, 1, 0)); - // - coeff(tens, 0, 2, 0, 0, coeff(tens, 2, 0, 0, 0)); - coeff(tens, 0, 2, 1, 1, coeff(tens, 2, 0, 1, 1)); - coeff(tens, 0, 2, 2, 2, coeff(tens, 2, 0, 2, 2)); - coeff(tens, 0, 2, 1, 2, coeff(tens, 2, 0, 1, 2)); - coeff(tens, 0, 2, 2, 1, coeff(tens, 2, 0, 2, 1)); - coeff(tens, 0, 2, 2, 0, coeff(tens, 2, 0, 2, 0)); - coeff(tens, 0, 2, 0, 2, coeff(tens, 2, 0, 0, 2)); - coeff(tens, 0, 2, 0, 1, coeff(tens, 2, 0, 0, 1)); - coeff(tens, 0, 2, 1, 0, coeff(tens, 2, 0, 1, 0)); - // - coeff(tens, 1, 0, 0, 0, coeff(tens, 0, 1, 0, 0)); - coeff(tens, 1, 0, 1, 1, coeff(tens, 0, 1, 1, 1)); - coeff(tens, 1, 0, 2, 2, coeff(tens, 0, 1, 2, 2)); - coeff(tens, 1, 0, 1, 2, coeff(tens, 0, 1, 1, 2)); - coeff(tens, 1, 0, 2, 1, coeff(tens, 0, 1, 2, 1)); - coeff(tens, 1, 0, 2, 0, coeff(tens, 0, 1, 2, 0)); - coeff(tens, 1, 0, 0, 2, coeff(tens, 0, 1, 0, 2)); - coeff(tens, 1, 0, 0, 1, coeff(tens, 0, 1, 0, 1)); - coeff(tens, 1, 0, 1, 0, coeff(tens, 0, 1, 1, 0)); - break; - } + case 36: { + const T rac2 = sqrt( 2. ); + coeff< T, 3 >( tens, 0, 0, 0, 0, tens_vec[0] ); + coeff< T, 3 >( tens, 0, 0, 1, 1, tens_vec[1] ); + coeff< T, 3 >( tens, 0, 0, 2, 2, tens_vec[2] ); + coeff< T, 3 >( tens, 0, 0, 1, 2, tens_vec[3] / rac2 ); + coeff< T, 3 >( tens, 0, 0, 2, 1, coeff< T, 3 >( tens, 0, 0, 1, 2 ) ); + coeff< T, 3 >( tens, 0, 0, 2, 0, tens_vec[4] / rac2 ); + coeff< T, 3 >( tens, 0, 0, 0, 2, coeff< T, 3 >( tens, 0, 0, 2, 0 ) ); + coeff< T, 3 >( tens, 0, 0, 0, 1, tens_vec[5] / rac2 ); + coeff< T, 3 >( tens, 0, 0, 1, 0, coeff< T, 3 >( tens, 0, 0, 0, 1 ) ); + // + coeff< T, 3 >( tens, 1, 1, 0, 0, tens_vec[6] ); + coeff< T, 3 >( tens, 1, 1, 1, 1, tens_vec[7] ); + coeff< T, 3 >( tens, 1, 1, 2, 2, tens_vec[8] ); + coeff< T, 3 >( tens, 1, 1, 1, 2, tens_vec[9] / rac2 ); + coeff< T, 3 >( tens, 1, 1, 2, 1, coeff< T, 3 >( tens, 1, 1, 1, 2 ) ); + coeff< T, 3 >( tens, 1, 1, 2, 0, tens_vec[10] / rac2 ); + coeff< T, 3 >( tens, 1, 1, 0, 2, coeff< T, 3 >( tens, 1, 1, 2, 0 ) ); + coeff< T, 3 >( tens, 1, 1, 0, 1, tens_vec[11] / rac2 ); + coeff< T, 3 >( tens, 1, 1, 1, 0, coeff< T, 3 >( tens, 1, 1, 0, 1 ) ); + // + coeff< T, 3 >( tens, 2, 2, 0, 0, tens_vec[12] ); + coeff< T, 3 >( tens, 2, 2, 1, 1, tens_vec[13] ); + coeff< T, 3 >( tens, 2, 2, 2, 2, tens_vec[14] ); + coeff< T, 3 >( tens, 2, 2, 1, 2, tens_vec[15] / rac2 ); + coeff< T, 3 >( tens, 2, 2, 2, 1, coeff< T, 3 >( tens, 2, 2, 1, 2 ) ); + coeff< T, 3 >( tens, 2, 2, 2, 0, tens_vec[16] / rac2 ); + coeff< T, 3 >( tens, 2, 2, 0, 2, coeff< T, 3 >( tens, 2, 2, 2, 0 ) ); + coeff< T, 3 >( tens, 2, 2, 0, 1, tens_vec[17] / rac2 ); + coeff< T, 3 >( tens, 2, 2, 1, 0, coeff< T, 3 >( tens, 2, 2, 0, 1 ) ); + // + coeff< T, 3 >( tens, 1, 2, 0, 0, tens_vec[18] / rac2 ); + coeff< T, 3 >( tens, 1, 2, 1, 1, tens_vec[19] / rac2 ); + coeff< T, 3 >( tens, 1, 2, 2, 2, tens_vec[20] / rac2 ); + coeff< T, 3 >( tens, 1, 2, 1, 2, tens_vec[21] / 2. ); + coeff< T, 3 >( tens, 1, 2, 2, 1, coeff< T, 3 >( tens, 1, 2, 1, 2 ) ); + coeff< T, 3 >( tens, 1, 2, 2, 0, tens_vec[22] / 2. ); + coeff< T, 3 >( tens, 1, 2, 0, 2, coeff< T, 3 >( tens, 1, 2, 2, 0 ) ); + coeff< T, 3 >( tens, 1, 2, 0, 1, tens_vec[23] / 2. ); + coeff< T, 3 >( tens, 1, 2, 1, 0, coeff< T, 3 >( tens, 1, 2, 0, 1 ) ); + // + coeff< T, 3 >( tens, 2, 0, 0, 0, tens_vec[24] / rac2 ); + coeff< T, 3 >( tens, 2, 0, 1, 1, tens_vec[25] / rac2 ); + coeff< T, 3 >( tens, 2, 0, 2, 2, tens_vec[26] / rac2 ); + coeff< T, 3 >( tens, 2, 0, 1, 2, tens_vec[27] / 2. ); + coeff< T, 3 >( tens, 2, 0, 2, 1, coeff< T, 3 >( tens, 2, 0, 1, 2 ) ); + coeff< T, 3 >( tens, 2, 0, 2, 0, tens_vec[28] / 2. ); + coeff< T, 3 >( tens, 2, 0, 0, 2, coeff< T, 3 >( tens, 2, 0, 2, 0 ) ); + coeff< T, 3 >( tens, 2, 0, 0, 1, tens_vec[29] / 2. ); + coeff< T, 3 >( tens, 2, 0, 1, 0, coeff< T, 3 >( tens, 2, 0, 0, 1 ) ); + // + coeff< T, 3 >( tens, 0, 1, 0, 0, tens_vec[30] / rac2 ); + coeff< T, 3 >( tens, 0, 1, 1, 1, tens_vec[31] / rac2 ); + coeff< T, 3 >( tens, 0, 1, 2, 2, tens_vec[32] / 2. ); + coeff< T, 3 >( tens, 0, 1, 1, 2, tens_vec[33] / 2. ); + coeff< T, 3 >( tens, 0, 1, 2, 1, coeff< T, 3 >( tens, 0, 1, 1, 2 ) ); + coeff< T, 3 >( tens, 0, 1, 2, 0, tens_vec[34] / rac2 ); + coeff< T, 3 >( tens, 0, 1, 0, 2, coeff< T, 3 >( tens, 0, 1, 2, 0 ) ); + coeff< T, 3 >( tens, 0, 1, 0, 1, tens_vec[35] / 2. ); + coeff< T, 3 >( tens, 0, 1, 1, 0, coeff< T, 3 >( tens, 0, 1, 0, 1 ) ); + // + coeff< T, 3 >( tens, 2, 1, 0, 0, coeff< T, 3 >( tens, 1, 2, 0, 0 ) ); + coeff< T, 3 >( tens, 2, 1, 1, 1, coeff< T, 3 >( tens, 1, 2, 1, 1 ) ); + coeff< T, 3 >( tens, 2, 1, 2, 2, coeff< T, 3 >( tens, 1, 2, 2, 2 ) ); + coeff< T, 3 >( tens, 2, 1, 1, 2, coeff< T, 3 >( tens, 1, 2, 1, 2 ) ); + coeff< T, 3 >( tens, 2, 1, 2, 1, coeff< T, 3 >( tens, 1, 2, 2, 1 ) ); + coeff< T, 3 >( tens, 2, 1, 2, 0, coeff< T, 3 >( tens, 1, 2, 2, 0 ) ); + coeff< T, 3 >( tens, 2, 1, 0, 2, coeff< T, 3 >( tens, 1, 2, 0, 2 ) ); + coeff< T, 3 >( tens, 2, 1, 0, 1, coeff< T, 3 >( tens, 1, 2, 0, 1 ) ); + coeff< T, 3 >( tens, 2, 1, 1, 0, coeff< T, 3 >( tens, 1, 2, 1, 0 ) ); + // + coeff< T, 3 >( tens, 0, 2, 0, 0, coeff< T, 3 >( tens, 2, 0, 0, 0 ) ); + coeff< T, 3 >( tens, 0, 2, 1, 1, coeff< T, 3 >( tens, 2, 0, 1, 1 ) ); + coeff< T, 3 >( tens, 0, 2, 2, 2, coeff< T, 3 >( tens, 2, 0, 2, 2 ) ); + coeff< T, 3 >( tens, 0, 2, 1, 2, coeff< T, 3 >( tens, 2, 0, 1, 2 ) ); + coeff< T, 3 >( tens, 0, 2, 2, 1, coeff< T, 3 >( tens, 2, 0, 2, 1 ) ); + coeff< T, 3 >( tens, 0, 2, 2, 0, coeff< T, 3 >( tens, 2, 0, 2, 0 ) ); + coeff< T, 3 >( tens, 0, 2, 0, 2, coeff< T, 3 >( tens, 2, 0, 0, 2 ) ); + coeff< T, 3 >( tens, 0, 2, 0, 1, coeff< T, 3 >( tens, 2, 0, 0, 1 ) ); + coeff< T, 3 >( tens, 0, 2, 1, 0, coeff< T, 3 >( tens, 2, 0, 1, 0 ) ); + // + coeff< T, 3 >( tens, 1, 0, 0, 0, coeff< T, 3 >( tens, 0, 1, 0, 0 ) ); + coeff< T, 3 >( tens, 1, 0, 1, 1, coeff< T, 3 >( tens, 0, 1, 1, 1 ) ); + coeff< T, 3 >( tens, 1, 0, 2, 2, coeff< T, 3 >( tens, 0, 1, 2, 2 ) ); + coeff< T, 3 >( tens, 1, 0, 1, 2, coeff< T, 3 >( tens, 0, 1, 1, 2 ) ); + coeff< T, 3 >( tens, 1, 0, 2, 1, coeff< T, 3 >( tens, 0, 1, 2, 1 ) ); + coeff< T, 3 >( tens, 1, 0, 2, 0, coeff< T, 3 >( tens, 0, 1, 2, 0 ) ); + coeff< T, 3 >( tens, 1, 0, 0, 2, coeff< T, 3 >( tens, 0, 1, 0, 2 ) ); + coeff< T, 3 >( tens, 1, 0, 0, 1, coeff< T, 3 >( tens, 0, 1, 0, 1 ) ); + coeff< T, 3 >( tens, 1, 0, 1, 0, coeff< T, 3 >( tens, 0, 1, 1, 0 ) ); + break; + } - case 81: - { - coeff(tens, 0, 0, 0, 0, tens_vec[0]); - coeff(tens, 0, 0, 1, 1, tens_vec[1]); - coeff(tens, 0, 0, 2, 2, tens_vec[2]); - coeff(tens, 0, 0, 0, 1, tens_vec[3]); - coeff(tens, 0, 0, 1, 0, tens_vec[4]); - coeff(tens, 0, 0, 0, 2, tens_vec[5]); - coeff(tens, 0, 0, 2, 0, tens_vec[6]); - coeff(tens, 0, 0, 1, 2, tens_vec[7]); - coeff(tens, 0, 0, 2, 1, tens_vec[8]); - // - coeff(tens, 1, 1, 0, 0, tens_vec[9]); - coeff(tens, 1, 1, 1, 1, tens_vec[10]); - coeff(tens, 1, 1, 2, 2, tens_vec[11]); - coeff(tens, 1, 1, 0, 1, tens_vec[12]); - coeff(tens, 1, 1, 1, 0, tens_vec[13]); - coeff(tens, 1, 1, 0, 2, tens_vec[14]); - coeff(tens, 1, 1, 2, 0, tens_vec[15]); - coeff(tens, 1, 1, 1, 2, tens_vec[16]); - coeff(tens, 1, 1, 2, 1, tens_vec[17]); - // - coeff(tens, 2, 2, 0, 0, tens_vec[18]); - coeff(tens, 2, 2, 1, 1, tens_vec[19]); - coeff(tens, 2, 2, 2, 2, tens_vec[20]); - coeff(tens, 2, 2, 0, 1, tens_vec[21]); - coeff(tens, 2, 2, 1, 0, tens_vec[22]); - coeff(tens, 2, 2, 0, 2, tens_vec[23]); - coeff(tens, 2, 2, 2, 0, tens_vec[24]); - coeff(tens, 2, 2, 1, 2, tens_vec[25]); - coeff(tens, 2, 2, 2, 1, tens_vec[26]); - // - coeff(tens, 0, 1, 0, 0, tens_vec[27]); - coeff(tens, 0, 1, 1, 1, tens_vec[28]); - coeff(tens, 0, 1, 2, 2, tens_vec[29]); - coeff(tens, 0, 1, 0, 1, tens_vec[30]); - coeff(tens, 0, 1, 1, 0, tens_vec[31]); - coeff(tens, 0, 1, 0, 2, tens_vec[32]); - coeff(tens, 0, 1, 2, 0, tens_vec[33]); - coeff(tens, 0, 1, 1, 2, tens_vec[34]); - coeff(tens, 0, 1, 2, 1, tens_vec[35]); - // - coeff(tens, 1, 0, 0, 0, tens_vec[36]); - coeff(tens, 1, 0, 1, 1, tens_vec[37]); - coeff(tens, 1, 0, 2, 2, tens_vec[38]); - coeff(tens, 1, 0, 0, 1, tens_vec[39]); - coeff(tens, 1, 0, 1, 0, tens_vec[40]); - coeff(tens, 1, 0, 0, 2, tens_vec[41]); - coeff(tens, 1, 0, 2, 0, tens_vec[42]); - coeff(tens, 1, 0, 1, 2, tens_vec[43]); - coeff(tens, 1, 0, 2, 1, tens_vec[44]); - // - coeff(tens, 0, 2, 0, 0, tens_vec[45]); - coeff(tens, 0, 2, 1, 1, tens_vec[46]); - coeff(tens, 0, 2, 2, 2, tens_vec[47]); - coeff(tens, 0, 2, 0, 1, tens_vec[48]); - coeff(tens, 0, 2, 1, 0, tens_vec[49]); - coeff(tens, 0, 2, 0, 2, tens_vec[50]); - coeff(tens, 0, 2, 2, 0, tens_vec[51]); - coeff(tens, 0, 2, 1, 2, tens_vec[52]); - coeff(tens, 0, 2, 2, 1, tens_vec[53]); - // - coeff(tens, 2, 0, 0, 0, tens_vec[54]); - coeff(tens, 2, 0, 1, 1, tens_vec[55]); - coeff(tens, 2, 0, 2, 2, tens_vec[56]); - coeff(tens, 2, 0, 0, 1, tens_vec[57]); - coeff(tens, 2, 0, 1, 0, tens_vec[58]); - coeff(tens, 2, 0, 0, 2, tens_vec[59]); - coeff(tens, 2, 0, 2, 0, tens_vec[60]); - coeff(tens, 2, 0, 1, 2, tens_vec[61]); - coeff(tens, 2, 0, 2, 1, tens_vec[62]); - // - coeff(tens, 1, 2, 0, 0, tens_vec[63]); - coeff(tens, 1, 2, 1, 1, tens_vec[64]); - coeff(tens, 1, 2, 2, 2, tens_vec[65]); - coeff(tens, 1, 2, 0, 1, tens_vec[66]); - coeff(tens, 1, 2, 1, 0, tens_vec[67]); - coeff(tens, 1, 2, 0, 2, tens_vec[68]); - coeff(tens, 1, 2, 2, 0, tens_vec[69]); - coeff(tens, 1, 2, 1, 2, tens_vec[70]); - coeff(tens, 1, 2, 2, 1, tens_vec[71]); - // - coeff(tens, 2, 1, 0, 0, tens_vec[72]); - coeff(tens, 2, 1, 1, 1, tens_vec[73]); - coeff(tens, 2, 1, 2, 2, tens_vec[74]); - coeff(tens, 2, 1, 0, 1, tens_vec[75]); - coeff(tens, 2, 1, 1, 0, tens_vec[76]); - coeff(tens, 2, 1, 0, 2, tens_vec[77]); - coeff(tens, 2, 1, 2, 0, tens_vec[78]); - coeff(tens, 2, 1, 1, 2, tens_vec[79]); - coeff(tens, 2, 1, 2, 1, tens_vec[80]); - break; - } + case 81: { + coeff< T, 3 >( tens, 0, 0, 0, 0, tens_vec[0] ); + coeff< T, 3 >( tens, 0, 0, 1, 1, tens_vec[1] ); + coeff< T, 3 >( tens, 0, 0, 2, 2, tens_vec[2] ); + coeff< T, 3 >( tens, 0, 0, 0, 1, tens_vec[3] ); + coeff< T, 3 >( tens, 0, 0, 1, 0, tens_vec[4] ); + coeff< T, 3 >( tens, 0, 0, 0, 2, tens_vec[5] ); + coeff< T, 3 >( tens, 0, 0, 2, 0, tens_vec[6] ); + coeff< T, 3 >( tens, 0, 0, 1, 2, tens_vec[7] ); + coeff< T, 3 >( tens, 0, 0, 2, 1, tens_vec[8] ); + // + coeff< T, 3 >( tens, 1, 1, 0, 0, tens_vec[9] ); + coeff< T, 3 >( tens, 1, 1, 1, 1, tens_vec[10] ); + coeff< T, 3 >( tens, 1, 1, 2, 2, tens_vec[11] ); + coeff< T, 3 >( tens, 1, 1, 0, 1, tens_vec[12] ); + coeff< T, 3 >( tens, 1, 1, 1, 0, tens_vec[13] ); + coeff< T, 3 >( tens, 1, 1, 0, 2, tens_vec[14] ); + coeff< T, 3 >( tens, 1, 1, 2, 0, tens_vec[15] ); + coeff< T, 3 >( tens, 1, 1, 1, 2, tens_vec[16] ); + coeff< T, 3 >( tens, 1, 1, 2, 1, tens_vec[17] ); + // + coeff< T, 3 >( tens, 2, 2, 0, 0, tens_vec[18] ); + coeff< T, 3 >( tens, 2, 2, 1, 1, tens_vec[19] ); + coeff< T, 3 >( tens, 2, 2, 2, 2, tens_vec[20] ); + coeff< T, 3 >( tens, 2, 2, 0, 1, tens_vec[21] ); + coeff< T, 3 >( tens, 2, 2, 1, 0, tens_vec[22] ); + coeff< T, 3 >( tens, 2, 2, 0, 2, tens_vec[23] ); + coeff< T, 3 >( tens, 2, 2, 2, 0, tens_vec[24] ); + coeff< T, 3 >( tens, 2, 2, 1, 2, tens_vec[25] ); + coeff< T, 3 >( tens, 2, 2, 2, 1, tens_vec[26] ); + // + coeff< T, 3 >( tens, 0, 1, 0, 0, tens_vec[27] ); + coeff< T, 3 >( tens, 0, 1, 1, 1, tens_vec[28] ); + coeff< T, 3 >( tens, 0, 1, 2, 2, tens_vec[29] ); + coeff< T, 3 >( tens, 0, 1, 0, 1, tens_vec[30] ); + coeff< T, 3 >( tens, 0, 1, 1, 0, tens_vec[31] ); + coeff< T, 3 >( tens, 0, 1, 0, 2, tens_vec[32] ); + coeff< T, 3 >( tens, 0, 1, 2, 0, tens_vec[33] ); + coeff< T, 3 >( tens, 0, 1, 1, 2, tens_vec[34] ); + coeff< T, 3 >( tens, 0, 1, 2, 1, tens_vec[35] ); + // + coeff< T, 3 >( tens, 1, 0, 0, 0, tens_vec[36] ); + coeff< T, 3 >( tens, 1, 0, 1, 1, tens_vec[37] ); + coeff< T, 3 >( tens, 1, 0, 2, 2, tens_vec[38] ); + coeff< T, 3 >( tens, 1, 0, 0, 1, tens_vec[39] ); + coeff< T, 3 >( tens, 1, 0, 1, 0, tens_vec[40] ); + coeff< T, 3 >( tens, 1, 0, 0, 2, tens_vec[41] ); + coeff< T, 3 >( tens, 1, 0, 2, 0, tens_vec[42] ); + coeff< T, 3 >( tens, 1, 0, 1, 2, tens_vec[43] ); + coeff< T, 3 >( tens, 1, 0, 2, 1, tens_vec[44] ); + // + coeff< T, 3 >( tens, 0, 2, 0, 0, tens_vec[45] ); + coeff< T, 3 >( tens, 0, 2, 1, 1, tens_vec[46] ); + coeff< T, 3 >( tens, 0, 2, 2, 2, tens_vec[47] ); + coeff< T, 3 >( tens, 0, 2, 0, 1, tens_vec[48] ); + coeff< T, 3 >( tens, 0, 2, 1, 0, tens_vec[49] ); + coeff< T, 3 >( tens, 0, 2, 0, 2, tens_vec[50] ); + coeff< T, 3 >( tens, 0, 2, 2, 0, tens_vec[51] ); + coeff< T, 3 >( tens, 0, 2, 1, 2, tens_vec[52] ); + coeff< T, 3 >( tens, 0, 2, 2, 1, tens_vec[53] ); + // + coeff< T, 3 >( tens, 2, 0, 0, 0, tens_vec[54] ); + coeff< T, 3 >( tens, 2, 0, 1, 1, tens_vec[55] ); + coeff< T, 3 >( tens, 2, 0, 2, 2, tens_vec[56] ); + coeff< T, 3 >( tens, 2, 0, 0, 1, tens_vec[57] ); + coeff< T, 3 >( tens, 2, 0, 1, 0, tens_vec[58] ); + coeff< T, 3 >( tens, 2, 0, 0, 2, tens_vec[59] ); + coeff< T, 3 >( tens, 2, 0, 2, 0, tens_vec[60] ); + coeff< T, 3 >( tens, 2, 0, 1, 2, tens_vec[61] ); + coeff< T, 3 >( tens, 2, 0, 2, 1, tens_vec[62] ); + // + coeff< T, 3 >( tens, 1, 2, 0, 0, tens_vec[63] ); + coeff< T, 3 >( tens, 1, 2, 1, 1, tens_vec[64] ); + coeff< T, 3 >( tens, 1, 2, 2, 2, tens_vec[65] ); + coeff< T, 3 >( tens, 1, 2, 0, 1, tens_vec[66] ); + coeff< T, 3 >( tens, 1, 2, 1, 0, tens_vec[67] ); + coeff< T, 3 >( tens, 1, 2, 0, 2, tens_vec[68] ); + coeff< T, 3 >( tens, 1, 2, 2, 0, tens_vec[69] ); + coeff< T, 3 >( tens, 1, 2, 1, 2, tens_vec[70] ); + coeff< T, 3 >( tens, 1, 2, 2, 1, tens_vec[71] ); + // + coeff< T, 3 >( tens, 2, 1, 0, 0, tens_vec[72] ); + coeff< T, 3 >( tens, 2, 1, 1, 1, tens_vec[73] ); + coeff< T, 3 >( tens, 2, 1, 2, 2, tens_vec[74] ); + coeff< T, 3 >( tens, 2, 1, 0, 1, tens_vec[75] ); + coeff< T, 3 >( tens, 2, 1, 1, 0, tens_vec[76] ); + coeff< T, 3 >( tens, 2, 1, 0, 2, tens_vec[77] ); + coeff< T, 3 >( tens, 2, 1, 2, 0, tens_vec[78] ); + coeff< T, 3 >( tens, 2, 1, 1, 2, tens_vec[79] ); + coeff< T, 3 >( tens, 2, 1, 2, 1, tens_vec[80] ); + break; + } - default: throw std::runtime_error("wrong size"); break; + default: + throw std::runtime_error( "wrong size" ); + break; } } -} +} // namespace disk diff --git a/libdiskpp/include/diskpp/mechanics/deformation_tensors.hpp b/libdiskpp/include/diskpp/mechanics/deformation_tensors.hpp old mode 100755 new mode 100644 index c984050d..c8d4effa --- a/libdiskpp/include/diskpp/mechanics/deformation_tensors.hpp +++ b/libdiskpp/include/diskpp/mechanics/deformation_tensors.hpp @@ -29,96 +29,76 @@ #include "diskpp/common/eigen.hpp" -namespace disk -{ +namespace disk { -namespace mechanics -{ +namespace mechanics { // G: gradient -template -static_matrix -convertGtoLinearizedStrain(const static_matrix& Gradient) -{ +template < typename T, int DIM > +static_matrix< T, DIM, DIM > +convertGtoLinearizedStrain( const static_matrix< T, DIM, DIM > &Gradient ) { return 0.5 * Gradient * Gradient.transpose(); } // Compute F = G + I -template -static_matrix -convertGtoF(const static_matrix& Gradient) -{ - return Gradient + static_matrix::Identity(); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > convertGtoF( const static_matrix< T, DIM, DIM > &Gradient ) { + return Gradient + static_matrix< T, DIM, DIM >::Identity(); } -template -static_matrix -convertFtoG(const static_matrix& F) -{ - return F - static_matrix::Identity(); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > convertFtoG( const static_matrix< T, DIM, DIM > &F ) { + return F - static_matrix< T, DIM, DIM >::Identity(); } // Compute C = F^T * F -template -static_matrix -convertFtoCauchyGreenRight(const static_matrix& F) -{ +template < typename T, int DIM > +static_matrix< T, DIM, DIM > convertFtoCauchyGreenRight( const static_matrix< T, DIM, DIM > &F ) { return F.transpose() * F; } -template -static_matrix -convertGtoCauchyGreenRight(const static_matrix& G) -{ - const auto F = convertGtoF(G); - return convertFtoCauchyGreenRight(F); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > convertGtoCauchyGreenRight( const static_matrix< T, DIM, DIM > &G ) { + const auto F = convertGtoF( G ); + return convertFtoCauchyGreenRight( F ); } // Compute b = F * F^t -template -static_matrix -convertFtoCauchyGreenLeft(const static_matrix& F) -{ +template < typename T, int DIM > +static_matrix< T, DIM, DIM > convertFtoCauchyGreenLeft( const static_matrix< T, DIM, DIM > &F ) { return F * F.transpose(); } -template -static_matrix -convertGtoCauchyGreenLeft(const static_matrix& G) -{ - const auto F = convertGtoF(G); - return convertFtoCauchyGreenLeft(F); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > convertGtoCauchyGreenLeft( const static_matrix< T, DIM, DIM > &G ) { + const auto F = convertGtoF( G ); + return convertFtoCauchyGreenLeft( F ); } // Compute E = 1/2 *( C - I) -template -static_matrix -convertCauchyGreenRighttoGreenLagrange(const static_matrix& CauchyGreenRight) -{ - return T(0.5) * (CauchyGreenRight - static_matrix::Identity()); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > +convertCauchyGreenRighttoGreenLagrange( const static_matrix< T, DIM, DIM > &CauchyGreenRight ) { + return T( 0.5 ) * ( CauchyGreenRight - static_matrix< T, DIM, DIM >::Identity() ); } -template -static_matrix -convertFtoGreenLagrange(const static_matrix& F) -{ - const auto CauchyGreenRight = convertFtoCauchyGreenRight(F); - return convertCauchyGreenRighttoGreenLagrange(CauchyGreenRight); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > convertFtoGreenLagrange( const static_matrix< T, DIM, DIM > &F ) { + const auto CauchyGreenRight = convertFtoCauchyGreenRight( F ); + return convertCauchyGreenRighttoGreenLagrange( CauchyGreenRight ); } -template -static_matrix -convertGtoGreenLagrange(const static_matrix& G) -{ - const auto CauchyGreenRight = convertGtoCauchyGreenRight(G); - return convertCauchyGreenRighttoGreenLagrange(CauchyGreenRight); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > convertGtoGreenLagrange( const static_matrix< T, DIM, DIM > &G ) { + const auto CauchyGreenRight = convertGtoCauchyGreenRight( G ); + return convertCauchyGreenRighttoGreenLagrange( CauchyGreenRight ); } -} // end mechanics +} // namespace mechanics -} // end disk \ No newline at end of file +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/mechanics/stress_tensors.hpp b/libdiskpp/include/diskpp/mechanics/stress_tensors.hpp old mode 100755 new mode 100644 index 4b3f4459..706c3781 --- a/libdiskpp/include/diskpp/mechanics/stress_tensors.hpp +++ b/libdiskpp/include/diskpp/mechanics/stress_tensors.hpp @@ -33,71 +33,61 @@ // Function to convert Stress to an other // F is the deformation gradient -namespace disk -{ +namespace disk { -namespace mechanics -{ +namespace mechanics { // PK2 = F^{-1} * PK1 -template -static_matrix -convertPK1toPK2(const static_matrix& PK1, const static_matrix& F) -{ - return (F.inverse()) * PK1; +template < typename T, int DIM > +static_matrix< T, DIM, DIM > convertPK1toPK2( const static_matrix< T, DIM, DIM > &PK1, + const static_matrix< T, DIM, DIM > &F ) { + return ( F.inverse() ) * PK1; } // PK1 = F * PK2 -template -static_matrix -convertPK2toPK1(const static_matrix& PK2, const static_matrix& F) -{ +template < typename T, int DIM > +static_matrix< T, DIM, DIM > convertPK2toPK1( const static_matrix< T, DIM, DIM > &PK2, + const static_matrix< T, DIM, DIM > &F ) { return F * PK2; } // Cauchy = J^{-1} * P * F^{T} -template -static_matrix -convertPK1toCauchy(const static_matrix& PK1, const static_matrix& F) -{ - return (PK1 * F.transpose()) / F.determinant(); +template < typename T, int DIM > +static_matrix< T, DIM, DIM > convertPK1toCauchy( const static_matrix< T, DIM, DIM > &PK1, + const static_matrix< T, DIM, DIM > &F ) { + return ( PK1 * F.transpose() ) / F.determinant(); } // PK1 = J * Cauchy * F^{-T} -template -static_matrix -convertCauchytoPK1(const static_matrix& Cauchy, const static_matrix& F) -{ +template < typename T, int DIM > +static_matrix< T, DIM, DIM > convertCauchytoPK1( const static_matrix< T, DIM, DIM > &Cauchy, + const static_matrix< T, DIM, DIM > &F ) { const auto invF = F.inverse(); return F.determinant() * Cauchy * invF.transpose(); } // PK2 = J * F^{-1} * Cauchy * F^{-T} -template -static_matrix -convertCauchytoPK2(const static_matrix& Cauchy, const static_matrix& F) -{ +template < typename T, int DIM > +static_matrix< T, DIM, DIM > convertCauchytoPK2( const static_matrix< T, DIM, DIM > &Cauchy, + const static_matrix< T, DIM, DIM > &F ) { const auto invF = F.inverse(); return F.determinant() * invF * Cauchy * invF.transpose(); } // Cauchy = J^-1 * F * Cauchy * F^{T} -template -static_matrix -convertPK2toCauchy(const static_matrix& PK2, const static_matrix& F) -{ +template < typename T, int DIM > +static_matrix< T, DIM, DIM > convertPK2toCauchy( const static_matrix< T, DIM, DIM > &PK2, + const static_matrix< T, DIM, DIM > &F ) { return F * PK2 * F.transpose() / F.determinant(); } // Compute criteria of Von Mises -template -T -VonMisesCriteria(const static_matrix mat) -{ - const auto dev = deviator(mat); - return sqrt(T(1.5) * dev.squaredNorm()); +template < typename T, int DIM > +T VonMisesCriteria( const static_matrix< T, DIM, DIM > mat ) { + const auto dev = deviator( mat ); + return sqrt( T( 1.5 ) * dev.squaredNorm() ); } -} // end mechanics +} // namespace mechanics } // end namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/methods/implementation_hho/assembler_hho.hpp b/libdiskpp/include/diskpp/methods/implementation_hho/assembler_hho.hpp index 6ed23c3c..a5d6ea41 100644 --- a/libdiskpp/include/diskpp/methods/implementation_hho/assembler_hho.hpp +++ b/libdiskpp/include/diskpp/methods/implementation_hho/assembler_hho.hpp @@ -1307,7 +1307,7 @@ class assembler_mechanics template void - assemble(const mesh_type& msh, const cell_type& cl, const bnd_type& bnd, const LocalContrib& lc, int di = 0) + assemble(const mesh_type& msh, const cell_type& cl, const bnd_type& bnd, const LocalContrib& lc, size_t di = 0) { const size_t face_degree = m_hdi.face_degree(); const auto num_face_dofs = vector_basis_size(face_degree, dimension - 1, dimension); @@ -1698,7 +1698,7 @@ class assembler_mechanics } vector_type - expand_solution(const mesh_type& msh, const bnd_type& bnd, const vector_type& solution, int di = 0) + expand_solution(const mesh_type& msh, const bnd_type& bnd, const vector_type& solution, size_t di = 0) { assert(solution.size() == m_num_unknowns); const auto face_degree = m_hdi.face_degree(); @@ -2837,14 +2837,7 @@ class vector_primal_hho_assembler compress_table[face_id] = compressed_offset; - if (!bnd.is_contact_face(face_id)) - { - compressed_offset += n_face_dofs - bnd.dirichlet_imposed_dofs(face_id, face_degree); - } - else if (bnd.contact_boundary_type(face_id) == SIGNORINI_FACE) - { - compressed_offset += n_face_dofs; - } + compressed_offset += n_face_dofs - bnd.dirichlet_imposed_dofs( face_id, face_degree ); m_total_dofs += n_face_dofs; } @@ -2879,14 +2872,8 @@ class vector_primal_hho_assembler const auto face_degree = faces_degree[face_id].degree(); const auto n_face_dofs = num_face_dofs(face_id); - if (!bnd.is_contact_face(face_id)) - { - compressed_offset += n_face_dofs - bnd.dirichlet_imposed_dofs(face_id, face_degree); - } - else if (bnd.contact_boundary_type(face_id) == SIGNORINI_FACE) - { - compressed_offset += n_face_dofs; - } + compressed_offset += + n_face_dofs - bnd.dirichlet_imposed_dofs( face_id, face_degree ); m_total_dofs += n_face_dofs; } @@ -3334,7 +3321,7 @@ class vector_primal_hho_assembler } vector_type - expand_solution(const mesh_type& msh, const boundary_type& bnd, const vector_type& solution, int di = 0) const + expand_solution(const mesh_type& msh, const boundary_type& bnd, const vector_type& solution, size_t di = 0) const { assert(solution.size() == system_size); @@ -4113,6 +4100,10 @@ class vector_mechanics_hho_assembler const auto fcj = fcs[face_j]; const auto n_face_dofs_j = num_face_dofs(fcs_id[face_j]); + if ( lhs.rows() == 0 || lhs.cols() == 0 ) { + throw std::runtime_error( "Empty matrix" ); + } + matrix_type mat_Fj = lhs.block(offset_faces[face_j], offset_faces[face_i], n_face_dofs_j, n_face_dofs); @@ -4286,6 +4277,194 @@ class vector_mechanics_hho_assembler return std::make_tuple(rhs_bc, asm_map); } + std::tuple> + create_local_connectivity_lin(const mesh_type &msh, const cell_type &cl, + const boundary_type &bnd, const matrix_type &lhs, + const vector_type &rhs, size_t di = 1) const { + const auto fcs_id = faces_id(msh, cl); + const auto fcs = faces(msh, cl); + const auto n_faces_dofs = num_faces_dofs(msh, cl); + + std::vector asm_map; + asm_map.reserve(n_faces_dofs); + + vector_type rhs_bc = vector_type::Zero(n_faces_dofs); + + const auto offset_faces = faces_offset(msh, cl); + + for (size_t face_i = 0; face_i < fcs_id.size(); face_i++) { + const auto face_id = fcs_id[face_i]; + const auto fc = fcs[face_i]; + const auto face_degree = faces_degree[face_id].degree(); + const auto n_face_dofs = num_face_dofs(face_id); + + const bool fc_is_dirichlet_boundary = bnd.is_dirichlet_face(face_id); + const auto face_offset = compress_table.at(face_id); + + if (!fc_is_dirichlet_boundary) { + for (size_t i = 0; i < n_face_dofs; i++) { + asm_map.push_back(assembly_index(face_offset + i, true)); + } + } else { + size_t ind_sol = 0; + + const vector_type proj_bcf = project_function( + msh, fc, face_degree, bnd.dirichlet_boundary_func(face_id), di); + + vector_type incr = proj_bcf; + bool ind_ok = false; + for (size_t face_j = 0; face_j < fcs.size(); face_j++) { + const auto fcj = fcs[face_j]; + const auto n_face_dofs_j = num_face_dofs(fcs_id[face_j]); + + if ( lhs.rows() == 0 || lhs.cols() == 0 ) { + throw std::runtime_error( "Empty matrix" ); + } + + matrix_type mat_Fj = lhs.block(offset_faces[face_j], offset_faces[face_i], + n_face_dofs_j, n_face_dofs); + + switch (bnd.dirichlet_boundary_type(face_id)) { + case DIRICHLET: { + if (!ind_ok) { + for (size_t i = 0; i < n_face_dofs; i++) { + asm_map.push_back(assembly_index(face_offset + i, false)); + } + ind_ok = true; + } + break; + } + case CLAMPED: { + incr.setZero(); + if (!ind_ok) { + for (size_t i = 0; i < n_face_dofs; i++) { + asm_map.push_back(assembly_index(face_offset + i, false)); + } + ind_ok = true; + } + break; + } + case DX: { + for (size_t i = 0; i < n_face_dofs; i += Mesh::dimension) { + mat_Fj.col(i + 1).setZero(); + incr(i + 1) = scalar_type(0); + if (Mesh::dimension == 3) { + mat_Fj.col(i + 2).setZero(); + incr(i + 2) = scalar_type(0); + } + + if (!ind_ok) { + asm_map.push_back(assembly_index(face_offset + i, false)); + asm_map.push_back(assembly_index(face_offset + ind_sol++, true)); + if (Mesh::dimension == 3) { + asm_map.push_back( + assembly_index(face_offset + ind_sol++, true)); + } + } + } + ind_ok = true; + break; + } + case DY: { + for (size_t i = 0; i < n_face_dofs; i += Mesh::dimension) { + mat_Fj.col(i).setZero(); + incr(i) = scalar_type(0); + if (Mesh::dimension == 3) { + mat_Fj.col(i + 2).setZero(); + incr(i + 2) = scalar_type(0); + } + if (!ind_ok) { + asm_map.push_back(assembly_index(face_offset + ind_sol++, true)); + asm_map.push_back(assembly_index(face_offset + i, false)); + + if (Mesh::dimension == 3) { + asm_map.push_back( + assembly_index(face_offset + ind_sol++, true)); + } + } + } + ind_ok = true; + break; + } + case DZ: { + if (Mesh::dimension != 3) + throw std::invalid_argument("You are not in 3D"); + for (size_t i = 0; i < n_face_dofs; i += Mesh::dimension) { + mat_Fj.col(i).setZero(); + incr(i) = scalar_type(0); + mat_Fj.col(i + 1).setZero(); + incr(i + 1) = scalar_type(0); + if (!ind_ok) { + asm_map.push_back(assembly_index(face_offset + ind_sol++, true)); + asm_map.push_back(assembly_index(face_offset + ind_sol++, true)); + asm_map.push_back(assembly_index(face_offset + i, false)); + } + } + ind_ok = true; + break; + } + case DXDY: { + for (size_t i = 0; i < n_face_dofs; i += Mesh::dimension) { + if (Mesh::dimension == 3) { + mat_Fj.col(i + 2).setZero(); + incr(i + 2) = scalar_type(0); + } + if (!ind_ok) { + asm_map.push_back(assembly_index(face_offset + i, false)); + asm_map.push_back(assembly_index(face_offset + i, false)); + if (Mesh::dimension == 3) { + asm_map.push_back( + assembly_index(face_offset + ind_sol++, true)); + } + } + } + ind_ok = true; + break; + } + case DXDZ: { + if (Mesh::dimension != 3) + throw std::invalid_argument("You are not in 3D"); + for (size_t i = 0; i < n_face_dofs; i += Mesh::dimension) { + mat_Fj.col(i + 1).setZero(); + incr(i + 1) = scalar_type(0); + if (!ind_ok) { + asm_map.push_back(assembly_index(face_offset + i, false)); + asm_map.push_back(assembly_index(face_offset + ind_sol++, true)); + asm_map.push_back(assembly_index(face_offset + i, false)); + } + } + ind_ok = true; + break; + } + case DYDZ: { + if (Mesh::dimension != 3) + throw std::invalid_argument("You are not in 3D"); + for (size_t i = 0; i < n_face_dofs; i += Mesh::dimension) { + mat_Fj.col(i).setZero(); + incr(i) = scalar_type(0); + if (!ind_ok) { + asm_map.push_back(assembly_index(face_offset + ind_sol++, true)); + asm_map.push_back(assembly_index(face_offset + i, false)); + asm_map.push_back(assembly_index(face_offset + i, false)); + } + } + ind_ok = true; + break; + } + default: { + throw std::logic_error("Unknown Dirichlet Conditions"); + break; + } + } + + rhs_bc.segment(offset_faces[face_j], n_face_dofs_j) += mat_Fj * incr; + } + } + } + + return std::make_tuple(rhs_bc, asm_map); + } + public: SparseMatrix LHS; vector_type RHS; @@ -4320,14 +4499,7 @@ class vector_mechanics_hho_assembler compress_table[face_id] = compressed_offset; - if (!bnd.is_contact_face(face_id)) - { - compressed_offset += n_face_dofs - bnd.dirichlet_imposed_dofs(face_id, face_degree); - } - else if (bnd.contact_boundary_type(face_id) == SIGNORINI_FACE) - { - compressed_offset += n_face_dofs; - } + compressed_offset += n_face_dofs - bnd.dirichlet_imposed_dofs( face_id, face_degree ); m_total_dofs += n_face_dofs; } @@ -4362,14 +4534,8 @@ class vector_mechanics_hho_assembler const auto face_degree = faces_degree[face_id].degree(); const auto n_face_dofs = num_face_dofs(face_id); - if (!bnd.is_contact_face(face_id)) - { - compressed_offset += n_face_dofs - bnd.dirichlet_imposed_dofs(face_id, face_degree); - } - else if (bnd.contact_boundary_type(face_id) == SIGNORINI_FACE) - { - compressed_offset += n_face_dofs; - } + compressed_offset += + n_face_dofs - bnd.dirichlet_imposed_dofs( face_id, face_degree ); m_total_dofs += n_face_dofs; } @@ -4420,14 +4586,14 @@ class vector_mechanics_hho_assembler assert(lhs.rows() == rhs.size()); assert(rhs.size() == rhs_bc.size()); + const auto size = rhs.size(); + #ifdef FILL_COLMAJOR - for (size_t j = 0; j < lhs.rows(); j++) - { + for ( size_t j = 0; j < size; j++ ) { if (!asm_map[j].assemble()) continue; - for (size_t i = 0; i < lhs.cols(); i++) - { + for ( size_t i = 0; i < size; i++ ) { if (asm_map[i].assemble()) triplets.push_back(Triplet(asm_map[i], asm_map[j], lhs(i, j))); } @@ -4435,13 +4601,11 @@ class vector_mechanics_hho_assembler duos.push_back(std::make_pair(asm_map[i], rhs(i) - rhs_bc(i))); } #else - for (size_t i = 0; i < lhs.rows(); i++) - { + for ( size_t i = 0; i < size; i++ ) { if (!asm_map[i].assemble()) continue; - for (size_t j = 0; j < lhs.cols(); j++) - { + for ( size_t j = 0; j < size; j++ ) { if (asm_map[j].assemble()) triplets.push_back(Triplet(asm_map[i], asm_map[j], lhs(i, j))); } @@ -4451,6 +4615,77 @@ class vector_mechanics_hho_assembler #endif } + void assemble(const mesh_type &msh, const cell_type &cl, const boundary_type &bnd, + const matrix_type &lhs, const vector_type &rhs, size_t di = 1) { + const auto [rhs_bc, asm_map] = create_local_connectivity_lin(msh, cl, bnd, lhs, rhs, di); + + assert(lhs.rows() == lhs.cols()); + assert(lhs.rows() == rhs.size()); + assert(rhs.size() == rhs_bc.size()); + + const auto size = lhs.rows(); + +#ifdef FILL_COLMAJOR + for ( size_t j = 0; j < size; j++ ) { + if (!asm_map[j].assemble()) + continue; + + for ( size_t i = 0; i < size; i++ ) { + if (asm_map[i].assemble()) + triplets.push_back(Triplet(asm_map[i], asm_map[j], lhs(i, j))); + } + + duos.push_back(std::make_pair(asm_map[i], rhs(i) - rhs_bc(i))); + } +#else + for ( size_t i = 0; i < size; i++ ) { + if (!asm_map[i].assemble()) + continue; + + for ( size_t j = 0; j < size; j++ ) { + if (asm_map[j].assemble()) + triplets.push_back(Triplet(asm_map[i], asm_map[j], lhs(i, j))); + } + + duos.push_back(std::make_pair(asm_map[i], rhs(i) - rhs_bc(i))); + } +#endif + } + + void assemble_rhs(const mesh_type &msh, const cell_type &cl, const boundary_type &bnd, + const matrix_type &lhs, const vector_type &rhs, size_t di = 1) { + const auto [rhs_bc, asm_map] = create_local_connectivity_lin(msh, cl, bnd, lhs, rhs, di); + + const auto size = rhs.size(); + assert( rhs.size() == rhs_bc.size() ); + + for ( size_t i = 0; i < size; i++ ) { + if (!asm_map[i].assemble()) + continue; + + duos.push_back(std::make_pair(asm_map[i], rhs(i) - rhs_bc(i))); + } + } + + void assemble_nonlinear_rhs( const mesh_type &msh, const cell_type &cl, + const boundary_type &bnd, const matrix_type &lhs, + const vector_type &rhs, const std::vector< vector_type > &sol_F, + size_t di = 1 ) { + const auto [rhs_bc, asm_map] = + create_local_connectivity( msh, cl, bnd, lhs, rhs, sol_F, di ); + + assert( rhs.size() == rhs_bc.size() ); + + const auto size = rhs.size(); + + for ( int i = 0; i < size; i++ ) { + if ( !asm_map[i].assemble() ) + continue; + + duos.push_back( std::make_pair( asm_map[i], rhs( i ) - rhs_bc( i ) ) ); + } + } + vector_type take_local_solution_nonlinear(const Mesh& msh, const typename Mesh::cell_type& cl, @@ -4482,6 +4717,31 @@ class vector_mechanics_hho_assembler return ret; } + vector_type take_local_solution(const Mesh &msh, const typename Mesh::cell_type &cl, + const boundary_type &bnd, const vector_type &solution, + size_t di = 1) const { + const auto fcs = faces(msh, cl); + const auto fcs_id = faces_id(msh, cl); + + const auto n_faces_dofs = num_faces_dofs(msh, cl); + + vector_type ret = vector_type::Zero(n_faces_dofs); + + size_t face_offset = 0; + for (size_t face_i = 0; face_i < fcs.size(); face_i++) { + const auto fc = fcs[face_i]; + const auto face_id = fcs_id[face_i]; + + const auto n_face_dofs = num_face_dofs(face_id); + + ret.segment(face_offset, n_face_dofs) = take_local_solution(msh, fc, bnd, solution, di); + + face_offset += n_face_dofs; + } + + return ret; + } + vector_type take_local_solution_nonlinear(const Mesh& msh, const typename Mesh::face_type& fc, @@ -4614,18 +4874,120 @@ class vector_mechanics_hho_assembler return ret; } - vector_type - expand_solution_nonlinear(const mesh_type& msh, - const boundary_type& bnd, - const vector_type& solution, - const std::vector& sol_F, - int di = 1) const - { + vector_type take_local_solution(const Mesh &msh, const typename Mesh::face_type &fc, + const boundary_type &bnd, const vector_type &solution, + size_t di = 1) const { + const auto face_id = msh.lookup(fc); + + const auto n_face_dofs = num_face_dofs(face_id); + + vector_type ret = vector_type::Zero(n_face_dofs); + + if (n_face_dofs == 0) { + return ret; + } + + const auto compress_offset = compress_table[face_id]; + + if (bnd.is_dirichlet_face(face_id)) { + size_t sol_ind = 0; + + const vector_type proj_bcf = project_function(msh, fc, faces_degree[face_id].degree(), + bnd.dirichlet_boundary_func(face_id), di); + const vector_type incr = proj_bcf; + assert(proj_bcf.size() == n_face_dofs); + + switch (bnd.dirichlet_boundary_type(face_id)) { + case DIRICHLET: { + return incr; + break; + } + case CLAMPED: { + return vector_type::Zero(incr.size()); + break; + } + case DX: { + for (size_t i = 0; i < n_face_dofs; i += Mesh::dimension) { + ret(i) = incr(i); + ret(i + 1) = solution(compress_offset + sol_ind++); + if (Mesh::dimension == 3) { + ret(i + 2) = solution(compress_offset + sol_ind++); + } + } + break; + } + case DY: { + for (size_t i = 0; i < n_face_dofs; i += Mesh::dimension) { + ret(i) = solution(compress_offset + sol_ind++); + ret(i + 1) = incr(i + 1); + if (Mesh::dimension == 3) { + ret(i + 2) = solution(compress_offset + sol_ind++); + } + } + break; + } + case DZ: { + if (Mesh::dimension != 3) + throw std::invalid_argument("You are not in 3D"); + for (size_t i = 0; i < n_face_dofs; i += Mesh::dimension) { + ret(i) = solution(compress_offset + sol_ind++); + ret(i + 1) = solution(compress_offset + sol_ind++); + ret(i + 2) = incr(i + 2); + } + break; + } + case DXDY: { + for (size_t i = 0; i < n_face_dofs; i += Mesh::dimension) { + ret(i) = incr(i); + ret(i + 1) = incr(i + 1); + if (Mesh::dimension == 3) { + ret(i + 2) = solution(compress_offset + sol_ind++); + } + } + break; + } + case DXDZ: { + if (Mesh::dimension != 3) + throw std::invalid_argument("You are not in 3D"); + for (size_t i = 0; i < n_face_dofs; i += Mesh::dimension) { + ret(i) = incr(i); + ret(i + 1) = solution(compress_offset + sol_ind++); + ret(i + 2) = incr(i + 2); + } + break; + } + case DYDZ: { + if (Mesh::dimension != 3) + throw std::invalid_argument("You are not in 3D"); + for (size_t i = 0; i < n_face_dofs; i += Mesh::dimension) { + ret(i) = solution(compress_offset + sol_ind++); + ret(i + 1) = incr(i + 1); + ret(i + 2) = incr(i + 2); + } + break; + } + default: { + throw std::logic_error("Unknown Dirichlet Conditions"); + break; + } + } + } else { + return solution.segment(compress_offset, n_face_dofs); + } + + return ret; + } + + std::pair< vector_type, dynamic_vector< size_t > > + expand_solution_nonlinear( const mesh_type &msh, const boundary_type &bnd, + const vector_type &solution, const std::vector< vector_type > &sol_F, + size_t di = 1 ) const { assert(solution.size() == system_size); assert(sol_F.size() == msh.faces_size()); vector_type ret = vector_type::Zero(m_total_dofs); - size_t face_offset = 0; + dynamic_vector< size_t > idx = dynamic_vector< size_t >::Zero( msh.faces_size() + 1 ); + size_t face_offset = 0, face_i = 0; for (auto itor = msh.faces_begin(); itor != msh.faces_end(); itor++) { @@ -4636,6 +4998,30 @@ class vector_mechanics_hho_assembler ret.segment(face_offset, n_face_dofs) = take_local_solution_nonlinear(msh, bfc, bnd, solution, sol_F, di); + face_offset += n_face_dofs; + face_i++; + idx( face_i ) = idx( face_i - 1 ) + n_face_dofs; + } + + return std::make_pair( ret, idx ); + } + + vector_type expand_solution(const mesh_type &msh, const boundary_type &bnd, + const vector_type &solution, size_t di = 1) const { + assert(solution.size() == system_size); + + vector_type ret = vector_type::Zero(m_total_dofs); + size_t face_offset = 0; + + for (auto itor = msh.faces_begin(); itor != msh.faces_end(); itor++) { + const auto bfc = *itor; + const auto face_id = msh.lookup(bfc); + + const auto n_face_dofs = num_face_dofs(face_id); + + ret.segment(face_offset, n_face_dofs) = + take_local_solution(msh, bfc, bnd, solution, di); + face_offset += n_face_dofs; } diff --git a/libdiskpp/include/diskpp/methods/implementation_hho/utils_hho.hpp b/libdiskpp/include/diskpp/methods/implementation_hho/utils_hho.hpp index 1d899455..36ad8d49 100644 --- a/libdiskpp/include/diskpp/methods/implementation_hho/utils_hho.hpp +++ b/libdiskpp/include/diskpp/methods/implementation_hho/utils_hho.hpp @@ -225,6 +225,16 @@ class hho_degree_info } }; +template < typename Mesh > +size_t vector_cell_dofs( const Mesh &msh, size_t cell_degree ) { + return vector_basis_size(cell_degree, Mesh::dimension, Mesh::dimension); +} + +template +size_t vector_cell_dofs(const Mesh &msh, const CellDegreeInfo &cell_infos) { + return vector_basis_size(cell_infos.cell_degree(), Mesh::dimension, Mesh::dimension); +} + // const MeshDegreeInfo& degree_infos template size_t diff --git a/libdiskpp/include/diskpp/methods/implementation_hho/vector_hho_laplacian.hpp b/libdiskpp/include/diskpp/methods/implementation_hho/vector_hho_laplacian.hpp index efc2e1f9..352177e7 100644 --- a/libdiskpp/include/diskpp/methods/implementation_hho/vector_hho_laplacian.hpp +++ b/libdiskpp/include/diskpp/methods/implementation_hho/vector_hho_laplacian.hpp @@ -40,14 +40,27 @@ namespace disk namespace priv { -inline size_t -nb_lag(const size_t dim) -{ - size_t lag = 1; - if (dim == 3) - lag = 3; - return lag; -} + template + inline size_t + nb_lag() + { + static_assert(N != 1); + return 0; + } + + template <> + constexpr size_t + nb_lag<2>() + { + return 1; + } + + template <> + constexpr size_t + nb_lag<3>() + { + return 3; + } } template @@ -77,13 +90,13 @@ make_vector_hho_symmetric_laplacian(const Mesh& msh, const size_t rbs_ho = rbs - N; const size_t num_total_dofs = cbs + num_faces_dofs; - const size_t nb_lag = priv::nb_lag(N); + constexpr size_t nb_lag = priv::nb_lag(); matrix_type stiff = matrix_type::Zero(rbs, rbs); matrix_type gr_lhs = matrix_type::Zero(rbs_ho + nb_lag, rbs_ho + nb_lag); matrix_type gr_rhs = matrix_type::Zero(rbs_ho + nb_lag, num_total_dofs); - const auto qps = integrate(msh, cl, 2 * (recdeg - 1)); + const auto qps = integrate(msh, cl, 2 * (recdeg-1)); for (auto& qp : qps) { const auto dphi = rb.eval_sgradients(qp.point()); @@ -130,10 +143,43 @@ make_vector_hho_symmetric_laplacian(const Mesh& msh, const auto qps_2 = integrate(msh, cl, recdeg); + const auto lb = make_scalar_monomial_basis(msh, cl, recdeg); + + matrix_type::Zero(rbs, nb_lag); + matrix_type rot = matrix_type::Zero(rbs, nb_lag); for (auto& qp : qps_2) { - const auto rphi = rb.eval_curls(qp.point()); + const function_type dphi = lb.eval_gradients(qp.point()); + Matrix rphi = Matrix::Zero(rbs, nb_lag); + + int j = 0; + for (size_t i = 0; i < lb.size(); i++) + { + const auto dphi_i = dphi.row(i); + if (N == 2) + { + rphi(j++) = dphi_i(1); + rphi(j++) = -dphi_i(0); + } + else + { + // row 1 + rphi(j, 0) = dphi_i(1); + rphi(j, 1) = dphi_i(2); + j++; + // row 2 + rphi(j, 0) = -dphi_i(0); + rphi(j, 2) = dphi_i(2); + j++; + // row 3 + rphi(j, 1) = -dphi_i(0); + rphi(j, 2) = -dphi_i(1); + j++; + } + } + assert(rbs == j); + rot += qp.weight() * rphi; } gr_lhs.block(0, rbs_ho, rbs_ho, nb_lag) += rot.bottomLeftCorner(rbs_ho, nb_lag); diff --git a/libdiskpp/include/diskpp/output/plotOverTime.hpp b/libdiskpp/include/diskpp/output/plotOverTime.hpp new file mode 100644 index 00000000..4addbc05 --- /dev/null +++ b/libdiskpp/include/diskpp/output/plotOverTime.hpp @@ -0,0 +1,169 @@ +/* + * /\ Matteo Cicuttin (C) 2016, 2017 + * /__\ matteo.cicuttin@enpc.fr + * /_\/_\ École Nationale des Ponts et Chaussées - CERMICS + * /\ /\ + * /__\ /__\ DISK++, a template library for DIscontinuous SKeletal + * /_\/_\/_\/_\ methods. + * + * This file is copyright of the following authors: + * Nicolas Pignet (C) 2025 nicolas.pignet@enpc.fr + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * If you use this code or parts of it for scientific publications, you + * are required to cite it as following: + * + * Implementation of Discontinuous Skeletal methods on arbitrary-dimensional, + * polytopal meshes using generic programming. + * M. Cicuttin, D. A. Di Pietro, A. Ern. + * Journal of Computational and Applied Mathematics. + * DOI: 10.1016/j.cam.2017.09.017 + */ + +#pragma once + +#include "diskpp/common/eigen.hpp" +#include "diskpp/geometry/geometry.hpp" +#include "diskpp/mesh/point.hpp" + +#include +#include +#include +#include +#include + +namespace disk { + +template < typename Mesh > +class PlotPointOverTime { + private: + typedef Mesh mesh_type; + typedef typename mesh_type::point_type point_type; + + typedef std::pair< double, std::vector< double > > vale_type; + + int _c_id; + point_type _point; + + std::vector< vale_type > _vale; + std::vector< std::string > _comp; + + std::string _filename; + + public: + PlotPointOverTime() : _c_id( -1 ) {} + + PlotPointOverTime( const Mesh &mesh, const point_type &point ) : _point( point ) { + // Find cell id; + + bool find = false; + + for ( auto &cl : mesh ) { + if ( is_inside( mesh, cl, _point ) ) { + _c_id = mesh.lookup( cl ); + find = true; + break; + } + } + + if ( !find ) { + throw std::runtime_error( "Point not find in the mesh" ); + } + } + + int getCellId() const { return _c_id; } + auto getPoint() const { return _point; } + + void setFilename( const std::string &filename ) { _filename = filename; } + + void addComponents( const std::vector< std::string > &comp ) { _comp = comp; } + void addValues( const double &time, const std::vector< double > &vals ) { + _vale.push_back( std::make_pair( time, vals ) ); + } + + template < typename T, int N > + void addValues( const double &time, const static_vector< T, N > &vals ) { + std::vector< double > val( N ); + + for ( int i = 0; i < N; i++ ) { + val[i] = vals[i]; + } + + _vale.push_back( std::make_pair( time, val ) ); + } + + template < typename T, int N > + void addValues( const double &time, const int &n_iter, + const std::vector< static_vector< T, N > > &vals ) { + std::vector< double > val; + val.push_back( n_iter ); + + for ( auto &vec : vals ) { + for ( int i = 0; i < N; i++ ) { + val.push_back( vec[i] ); + } + } + + _vale.push_back( std::make_pair( time, val ) ); + } + + template < typename T, int N > + void addValues( const double &time, const std::vector< static_vector< T, N > > &vals ) { + std::vector< double > val; + + for ( auto &vec : vals ) { + for ( int i = 0; i < N; i++ ) { + val.push_back( vec[i] ); + } + } + + _vale.push_back( std::make_pair( time, val ) ); + } + + void addValues( const double &time, const std::map< std::string, double > &vals ) { + std::vector< double > val; + + bool write_cmp = _comp.empty(); + + for ( auto &[key, value] : vals ) { + if ( write_cmp ) { + _comp.push_back( key ); + } + val.push_back( value ); + } + + _vale.push_back( std::make_pair( time, val ) ); + } + + void write() const { + + std::ofstream fio( _filename, std::ofstream::trunc ); + + if ( fio.is_open() ) { + + fio << "Time "; + for ( auto &cmp : _comp ) { + fio << "; " << cmp; + } + fio << std::endl; + + for ( auto &[time, vals] : _vale ) { + fio << time; + for ( auto &val : vals ) { + fio << "; " << val; + } + fio << std::endl; + } + + } else { + throw std::runtime_error( "Error when opening the file." ); + } + + fio.close(); + } +}; + +} // namespace disk \ No newline at end of file diff --git a/libdiskpp/include/diskpp/quadratures/bits/quad_phys_generic.hpp b/libdiskpp/include/diskpp/quadratures/bits/quad_phys_generic.hpp index ce4683d9..47ac4acc 100644 --- a/libdiskpp/include/diskpp/quadratures/bits/quad_phys_generic.hpp +++ b/libdiskpp/include/diskpp/quadratures/bits/quad_phys_generic.hpp @@ -47,11 +47,20 @@ integrate_convex(const disk::generic_mesh& msh, { auto pts = points(msh, cl); assert(pts.size() > 2); + std::vector< quadrature_point< T, 2 > > ret; + + if ( pts.size() == 3 ) { + auto p0 = pts[0]; + auto p1 = pts[1]; + auto p2 = pts[2]; + auto qps = triangle_gauss( degree, p0, p1, p2 ); + ret.insert( ret.end(), qps.begin(), qps.end() ); + return ret; + } + auto center = std::accumulate(pts.begin(), pts.end(), point(0, 0)); center = center / T(pts.size()); - std::vector> ret; - for (size_t i = 0; i < pts.size(); i++) { auto p0 = pts[i]; @@ -83,6 +92,177 @@ integrate_nonconvex(const disk::generic_mesh& msh, return ret; } +template < typename T > +bool is_ortho_quad( const disk::generic_mesh< T, 2 > &msh, + const typename disk::generic_mesh< T, 2 >::cell_type &cl ) { + const auto pts = points( msh, cl ); + + if ( pts.size() != 4 ) { + return false; + }; + + const T thrs = 1e-8; + + const auto v02 = ( pts[2] - pts[0] ).to_vector(); + + const auto p2_test = pts[1] + ( pts[3] - pts[0] ); + + const auto dist = ( pts[2] - p2_test ).to_vector().norm(); + + return dist < thrs * v02.norm(); +} + +template < typename T > +bool is_hexa( const disk::generic_mesh< T, 3 > &msh, + const typename disk::generic_mesh< T, 3 >::cell_type &cl ) { + + if ( cl.point_ids().size() != 8 ) { + return false; + } + + const auto fcs = faces( msh, cl ); + if ( fcs.size() != 6 ) { + return false; + } + + for ( auto &fc : fcs ) { + if ( fc.point_ids().size() != 4 ) { + return false; + } + } + + return true; +} + +template < typename T > +bool is_ortho_hexa( const disk::generic_mesh< T, 3 > &msh, + const typename disk::generic_mesh< T, 3 >::cell_type &cl ) { + + const auto fcs = faces( msh, cl ); + if ( fcs.size() != 6 ) { + return false; + } + + const auto bT = barycenter( msh, cl ); + + for ( auto &fc : fcs ) { + const auto n = normal( msh, cl, fc ); + const auto bF = barycenter( msh, fc ); + + const auto vFT = ( bF - bT ).to_vector().normalized(); + + if ( n.dot( vFT ) < ( 1. - 1e-8 ) ) { + return false; + } + } + + return true; +} + +template < typename T > +bool is_extruted_hexa( const std::array< point< T, 3 >, 8 > &pts ) { + + const T thrs = 1e-8; + + const auto n = pts[4] - pts[0]; + const T n_norm = n.to_vector().norm(); + + for ( int i = 0; i < 3; i++ ) { + const auto p_test = pts[i] + n; + const auto dist = ( pts[i + 4] - p_test ).to_vector().norm(); + + if ( dist > thrs * n_norm ) { + return false; + } + } + + return true; +} + +template < typename T > +std::array< point< T, 3 >, 8 > +renumber_hexa( const disk::generic_mesh< T, 3 > &msh, + const typename disk::generic_mesh< T, 3 >::cell_type &cl ) { + + using point_id = point_identifier< 3 >; + + const auto pts = points( msh, cl ); + const auto pts_ids = cl.point_ids(); + + std::map< point_id, point< T, 3 > > map_cl; + + int i = 0; + for ( auto &pt : pts ) { + map_cl[pts_ids[i++]] = pt; + } + + const auto fcs = faces( msh, cl ); + assert( fcs.size() == 6 ); + + std::map< point_id, std::vector< point_id > > map_fc0; + auto pts_fc0 = fcs[0].point_ids(); + auto pts2_fc0 = points( msh, fcs[0] ); + + const auto n0 = normal( msh, cl, fcs[0] ); + + auto v0 = ( pts2_fc0[1] - pts2_fc0[0] ).to_vector(); + auto v1 = ( pts2_fc0[2] - pts2_fc0[1] ).to_vector(); + auto n = v0.cross( v1 ); + + if ( n.dot( n0 ) <= 0 ) { + point_id pt = pts_fc0[1]; + pts_fc0[1] = pts_fc0[3]; + pts_fc0[3] = pt; + } + + for ( auto &pt : pts_fc0 ) { + map_fc0[pt] = std::vector< point_id >(); + } + + for ( int i = 1; i < fcs.size(); i++ ) { + const auto fc = fcs[i]; + const auto pts_fc = fc.point_ids(); + + for ( auto &pt : pts_fc ) { + if ( map_fc0.contains( pt ) ) { + for ( auto &pt2 : pts_fc ) { + if ( !map_fc0.contains( pt2 ) ) { + map_fc0[pt].push_back( pt2 ); + } + } + } + } + } + + std::array< point< T, 3 >, 8 > new_num; + int j = 0; + for ( auto &pt : pts_fc0 ) { + const auto vect = map_fc0[pt]; + point_id pt_corr = -1; + for ( auto &val : vect ) { + const auto nb_elem = std::count( vect.begin(), vect.end(), val ); + if ( nb_elem == 2 ) { + pt_corr = val; + break; + } + } + if ( pt_corr < 0 ) { + throw std::runtime_error( "Error" ); + }; + + new_num[j] = map_cl[pt]; + new_num[j + 4] = map_cl[pt_corr]; + j++; + } + + // std::cout << "(" << new_num[0] << ", " << new_num[1] << ", " << new_num[2] << ", " << + // new_num[3] + // << ", " << new_num[4] << ", " << new_num[5] << ", " << new_num[6] << ", " + // << new_num[7] << ")" << std::endl; + + return new_num; +} + } // namespace priv } // namespace quadrature @@ -100,15 +280,13 @@ integrate(const disk::generic_mesh& msh, const typename disk::generic_mesh return disk::quadrature::triangle_gauss(degree, pts[0], pts[1], pts[2]); } - bool convex = is_convex(msh, cl); - - if (pts.size() == 4 and convex) - { + /* The coordinate transformation could become non-linear, so use tensorized Gauss + * points only on quadrilaterals which are almost square. */ + if ( pts.size() == 4 and quadrature::priv::is_ortho_quad( msh, cl ) ) { return disk::quadrature::tensorized_gauss_legendre(degree, pts[0], pts[1], pts[2], pts[3]); } - if (convex) - { + if ( is_convex( msh, cl ) ) { return quadrature::priv::integrate_convex(msh, cl, degree); } @@ -137,8 +315,7 @@ integrate_polyhedron(const disk::generic_mesh& msh, const auto rss = split_in_raw_tetrahedra(msh, cl); - std::vector ret; - //ret.reserve(tetrahedron_arbq_size(degree) * rss.size()); + std::vector< quadpoint_type > ret; for (auto& rs : rss) { const auto pts = rs.points(); @@ -174,6 +351,75 @@ integrate_polyhedron_face(const disk::generic_mesh& msh, return ret; } +template < typename T > +std::vector< disk::quadrature_point< T, 3 > > +integrate_hexahedron_extruded( const std::array< point< T, 3 >, 8 > &pts, const size_t degree ) { + using quadpoint_type = disk::quadrature_point< T, 3 >; + + // compute quadrature on the basis + std::vector< quadpoint_type > quad_basis; + quad_basis.reserve( quadrature::priv::triangle_gauss_rules[degree].num_points * 2 ); + + const auto quad_tri0 = disk::quadrature::triangle_gauss( degree, pts[0], pts[1], pts[2] ); + quad_basis.insert( quad_basis.end(), quad_tri0.begin(), quad_tri0.end() ); + + const auto quad_tri1 = disk::quadrature::triangle_gauss( degree, pts[2], pts[3], pts[0] ); + quad_basis.insert( quad_basis.end(), quad_tri1.begin(), quad_tri1.end() ); + + // compute quad on axis + const auto axis = pts[4] - pts[0]; + const T dist = distance( pts[0], pts[4] ); + + const auto quad_axis = disk::quadrature::gauss_legendre( degree, 0.0, 1.0 ); + + std::vector< quadpoint_type > quad_extr; + quad_extr.reserve( quad_axis.size() * quad_basis.size() ); + + for ( auto &qp_a : quad_axis ) { + const auto weight = dist * qp_a.weight(); + const auto a = qp_a.point().x() * axis; + for ( auto &qp_b : quad_basis ) { + quad_extr.push_back( { qp_b.point() + a, qp_b.weight() * weight } ); + } + } + + return quad_extr; +} + +template < typename T > +std::vector< disk::quadrature_point< T, 3 > > +integrate_hexahedron( const disk::generic_mesh< T, 3 > &msh, + const typename disk::generic_mesh< T, 3 >::cell &cl, const size_t degree ) { + using quadpoint_type = disk::quadrature_point< T, 3 >; + using raw_simplex_type = raw_simplex< typename disk::generic_mesh< T, 3 >::point_type, 3 >; + + const auto pts = quadrature::priv::renumber_hexa( msh, cl ); + + if ( quadrature::priv::is_ortho_hexa( msh, cl ) ) { + return disk::quadrature::tensorized_gauss_legendre( degree, pts ); + } else if ( quadrature::priv::is_extruted_hexa( pts ) ) { + return priv::integrate_hexahedron_extruded( pts, degree ); + } + + std::vector< raw_simplex_type > rss; + rss.push_back( raw_simplex_type( { pts[0], pts[1], pts[3], pts[4] } ) ); + rss.push_back( raw_simplex_type( { pts[1], pts[2], pts[3], pts[6] } ) ); + rss.push_back( raw_simplex_type( { pts[1], pts[3], pts[4], pts[6] } ) ); + rss.push_back( raw_simplex_type( { pts[1], pts[4], pts[5], pts[6] } ) ); + rss.push_back( raw_simplex_type( { pts[3], pts[4], pts[6], pts[7] } ) ); + + std::vector< quadpoint_type > ret; + for ( auto &rs : rss ) { + const auto pts_rs = rs.points(); + assert( pts_rs.size() == 4 ); + const auto quad_tet = disk::quadrature::grundmann_moeller( degree, pts_rs[0], pts_rs[1], + pts_rs[2], pts_rs[3] ); + ret.insert( ret.end(), quad_tet.begin(), quad_tet.end() ); + } + + return ret; +} + } // end priv template @@ -186,17 +432,17 @@ integrate(const disk::generic_mesh& msh, const typename disk::generic_mesh } const auto pts = points(msh, cl); - switch (pts.size()) - { - case 0: - case 1: - case 2: - case 3: - throw std::invalid_argument("A 3D cell cannot have less than four points. " - "This looks like a nice bug."); - default: return priv::integrate_polyhedron(msh, cl, degree); + if ( pts.size() < 4 ) { + throw std::invalid_argument( "A 3D cell cannot have less than four points. " + "This looks like a nice bug." ); } + + if ( quadrature::priv::is_hexa( msh, cl ) ) { + return priv::integrate_hexahedron( msh, cl, degree ); + } + + return priv::integrate_polyhedron( msh, cl, degree ); } template diff --git a/libdiskpp/include/diskpp/quadratures/bits/quad_raw_tetra.hpp b/libdiskpp/include/diskpp/quadratures/bits/quad_raw_tetra.hpp index f39cfe0f..aecd896d 100644 --- a/libdiskpp/include/diskpp/quadratures/bits/quad_raw_tetra.hpp +++ b/libdiskpp/include/diskpp/quadratures/bits/quad_raw_tetra.hpp @@ -10,9 +10,11 @@ #pragma once +#include + +#include "diskpp/common/simplicial_formula.hpp" #include "diskpp/mesh/point.hpp" #include "diskpp/quadratures/quadrature_point.hpp" -#include #include "jburkardt/simplex_gm_rule.hpp" #include "jburkardt/tetrahedron_arbq_rule.hpp" @@ -26,18 +28,9 @@ namespace quadrature namespace priv { -template -inline T -tetra_volume(const Eigen::Matrix& v0, const Eigen::Matrix& v1, const Eigen::Matrix& v2) -{ - return std::abs(v0.dot(v1.cross(v2))) / 6.; -} - -static const double arbq_to_ref_A[3][3] = { - { 0.500000000000000, -0.288675134594813, -0.204124145231932 }, - { 0.000000000000000, 0.577350269189626, -0.204124145231932 }, - { 0.000000000000000, 0.000000000000000, 0.612372435695795 } -}; +static const double arbq_to_ref_A[3][3] = {{0.500000000000000, -0.288675134594813, -0.204124145231932}, + {0.000000000000000, 0.577350269189626, -0.204124145231932}, + {0.000000000000000, 0.000000000000000, 0.612372435695795}}; static const double arbq_to_ref_b[3] = {-1.000000000000000, -0.577350269189626, -0.408248290463863}; @@ -61,7 +54,7 @@ arbq(size_t degree, const point& p0, const point& p1, const point,N>& rs) return bar / T(pts.size()); } +template < typename T > +bool is_inside( const raw_simplex< point< T, 3 >, 3 > &rs, const point< T, 3 > &pt ) { + const auto pts = rs.points(); + const auto bar = barycenter( rs ); + + const std::vector< std::array< int, 3 > > faces = { + { 0, 1, 2 }, { 1, 2, 3 }, { 0, 2, 3 }, { 0, 1, 3 } + }; + + auto f_face = [&bar, &pts, &faces]( const int &face_id ) { + const auto pts_id = faces[face_id]; + const auto p0 = pts[pts_id[0]]; + const auto p1 = pts[pts_id[1]]; + const auto p2 = pts[pts_id[2]]; + + const auto bar_f = ( p0 + p1 + p2 ) / 3.0; + + const auto v01 = to_vector( pts[1] - pts[0] ); + const auto v02 = to_vector( pts[2] - pts[0] ); + + const auto n0 = v01.cross( v02 ); + const auto n0n = n0.normalized(); + + const auto ddot = n0n.dot( to_vector( bar_f - bar ) ); + + T sign = 1.0; + if ( ddot < 0 ) { + sign = -1.0; + } + + return std::make_pair( bar_f, sign * n0n ); + }; + + for ( int i = 0; i < 4; i++ ) { + const auto [bar_f, n] = f_face( i ); + const T dist = n.dot( to_vector( bar_f - pt ).normalized() ); + + if ( dist < 0. ) { + return false; + } + } + + return true; +} + /** * @brief Map a point from the reference tetrahedra to the physical tetrahedra * diff --git a/libdiskpp/include/diskpp/solvers/direct_solvers.hpp b/libdiskpp/include/diskpp/solvers/direct_solvers.hpp index 5b36407d..4b0cfe6a 100644 --- a/libdiskpp/include/diskpp/solvers/direct_solvers.hpp +++ b/libdiskpp/include/diskpp/solvers/direct_solvers.hpp @@ -139,4 +139,159 @@ sparse_ldlt(Eigen::SparseMatrix& A, return direct_solver_status::ok; } +template < typename T, int _Options = Eigen::ColMajor, typename _Index = int > +class sparse_solver { + private: + using spmat_t = Eigen::SparseMatrix< T, _Options, _Index >; + template < _Index nrhs > + using dense_matrix_t = Eigen::Matrix< T, Eigen::Dynamic, nrhs >; + direct_solver _solver_type; + bool _isFacto; + +#ifdef HAVE_MUMPS + mumps_solver< T > _mumps_solver; +#endif + Eigen::SparseLU< spmat_t > _sparselu_solver; + +#ifdef HAVE_PARDISO + Eigen::PardisoLU< spmat_t > _pardisolu_solver; +#endif + + public: + explicit sparse_solver( direct_solver solver = direct_solver::autosel ) + : _solver_type( solver ), _isFacto( false ) { + /* + * Automatic solver selection: + * + * 1. MUMPS, if available; + * 2. PARDISO, if available; + * 3. Eigen::SparseLU otherwise. + */ + if ( _solver_type == direct_solver::autosel ) { +#if defined( HAVE_MUMPS ) + _solver_type = direct_solver::mumps; +#elif defined( HAVE_PARDISO ) + _solver_type = direct_solver::pardiso; +#else + _solver_type = direct_solver::sparselu; +#endif + } + } + + [[nodiscard]] + direct_solver solver_type() const noexcept { + return _solver_type; + } + + [[nodiscard]] + bool is_factorized() const noexcept { + return _isFacto; + } + + void reset() noexcept { _isFacto = false; } + + direct_solver_status factorize( spmat_t &A ) { + _isFacto = false; + switch ( _solver_type ) { +#ifdef HAVE_MUMPS + case direct_solver::mumps: + _mumps_solver.compute( A ); + if ( _mumps_solver.failure() ) { + return direct_solver_status::failure; + } + break; +#endif + case direct_solver::sparselu: + _sparselu_solver.compute( A ); + if ( _sparselu_solver.info() != Eigen::Success ) { + return direct_solver_status::failure; + } + break; + +#ifdef HAVE_PARDISO + case direct_solver::pardiso: + _pardisolu_solver.compute( A ); + if ( _pardisolu_solver.info() != Eigen::Success ) { + return direct_solver_status::failure; + } + break; +#endif + case direct_solver::autosel: + throw std::logic_error( "sparse_solver::factorize: unresolved automatic selection" ); + default: + throw std::invalid_argument( "sparse_solver::factorize: unknown solver" ); + } + + _isFacto = true; + return direct_solver_status::ok; + } + + template < _Index nrhs > + direct_solver_status solve( const dense_matrix_t< nrhs > &b, dense_matrix_t< nrhs > &x ) { + if ( !_isFacto ) { + throw std::runtime_error( "Factorize matrix before solving." ); + } + + switch ( _solver_type ) { +#ifdef HAVE_MUMPS + case direct_solver::mumps: + x = _mumps_solver.solve( b ); + if ( _mumps_solver.failure() ) { + return direct_solver_status::failure; + } + break; +#endif + case direct_solver::sparselu: + x = _sparselu_solver.solve( b ); + if ( _sparselu_solver.info() != Eigen::Success ) { + return direct_solver_status::failure; + } + break; + +#ifdef HAVE_PARDISO + case direct_solver::pardiso: + x = _pardisolu_solver.solve( b ); + if ( _pardisolu_solver.info() != Eigen::Success ) { + return direct_solver_status::failure; + } + break; +#endif + case direct_solver::autosel: + throw std::logic_error( "sparse_solver::solve: unresolved automatic selection" ); + default: + throw std::invalid_argument( "sparse_solver::solve: unknown solver" ); + } + return direct_solver_status::ok; + } + + template < _Index nrhs > + [[nodiscard]] + std::pair< direct_solver_status, dense_matrix_t< nrhs > > + solve( const dense_matrix_t< nrhs > &b ) { + dense_matrix_t< nrhs > x; + const auto status = solve( b, x ); + return { status, std::move( x ) }; + } + + template < _Index nrhs > + [[nodiscard]] + std::pair< direct_solver_status, dense_matrix_t< nrhs > > + solve( const spmat_t &A, const dense_matrix_t< nrhs > &b ) { + const auto factorisation_status = factorize( A ); + if ( factorisation_status != direct_solver_status::ok ) { + return { factorisation_status, dense_matrix_t< nrhs > {} }; + } + return solve( b ); + } + + template < _Index nrhs > + direct_solver_status solve( spmat_t &A, const dense_matrix_t< nrhs > &b, + dense_matrix_t< nrhs > &x ) { + const auto factorisation_status = factorize( A ); + if ( factorisation_status != direct_solver_status::ok ) { + return factorisation_status; + } + return solve( b, x ); + } +}; }; \ No newline at end of file diff --git a/libdiskpp/include/diskpp/solvers/eigensolvers/feast.hpp b/libdiskpp/include/diskpp/solvers/eigensolvers/feast.hpp index 8cb9f210..67a6a185 100644 --- a/libdiskpp/include/diskpp/solvers/eigensolvers/feast.hpp +++ b/libdiskpp/include/diskpp/solvers/eigensolvers/feast.hpp @@ -161,8 +161,9 @@ feast(const feast_eigensolver_params& params, Qe = solver.solve(Yc); } break; + case feast_inner_solver::mumps: #ifdef HAVE_MUMPS - case feast_inner_solver::mumps: { + { disk::solvers::mumps_solver solver; solver.compute(lhs); if (solver.failure()) { @@ -172,6 +173,7 @@ feast(const feast_eigensolver_params& params, Qe = solver.solve(Yc); } #endif /* HAVE_MUMPS */ + default: throw std::runtime_error("Feast solver not available"); } cdm T = r * std::exp(std::complex(0.0, theta_e)) * Qe; diff --git a/refactor_old_diskpp_code/utils/med2poly.py b/refactor_old_diskpp_code/utils/med2poly.py index 93810938..2cefec74 100644 --- a/refactor_old_diskpp_code/utils/med2poly.py +++ b/refactor_old_diskpp_code/utils/med2poly.py @@ -47,6 +47,13 @@ def __init__(self): self.faces = [] +def reorder(liste): + minpos = liste.index(min(liste)) + list_tmp = liste[minpos:] + liste[:minpos] + + return tuple(list_tmp) + + def rotate(liste): minpos = liste.index(min(liste)) list_tmp = liste[minpos:] + liste[:minpos] @@ -56,6 +63,12 @@ def rotate(liste): return tuple(list_tmp) + +def intersection(lst1, lst2): + lst = set(lst1) & set(lst2) + return len(lst) > 0 + + class CellConverter: def __init__(self): _med_types = 'POINT1 SEG2 TRI3 QUAD4 TETRA4 HEXA8 PYRA5 PENTA6 SEG3 TRI6 QUAD8 TETRA10 HEXA20 PYRA13 PENTA15 SEG4 TRI7 QUAD9 PENTA18 HEXA27'.split() @@ -91,37 +104,37 @@ def getDim(self, typeC): return self.mdim[typeC] def addCell(self, mtype, nodes, edges, faces, volumes): + mnodes = rotate(nodes[0 : self.mnodes[mtype]]) + nodes_r = reorder(nodes[0 : self.mnodes[mtype]]) + if self.mdim[mtype] == 0: logging.info("0D-cell are not supported. We skip them...") elif self.mdim[mtype] == 1: - mnodes = rotate(nodes[0:self.mnodes[mtype]]) if mnodes in self.list_edges: return self.list_edges[mnodes] else: edge = Edge() - edge.nodes = mnodes + edge.nodes = nodes_r edges.append(edge) - self.list_edges[edge.nodes] = len(edges)-1 + self.list_edges[mnodes] = len(edges) - 1 return len(edges)-1 elif self.mdim[mtype] == 2: - mnodes = rotate(nodes[0:self.mnodes[mtype]]) if mnodes in self.list_faces: return self.list_faces[mnodes] else: face = Face() - face.nodes = mnodes + face.nodes = nodes_r list_egdes = self.mfaces[self.mstype[mtype]] for edge in list_egdes: enodes = [nodes[edge[0]], nodes[edge[1]]] eid = self.addCell("SEG2", enodes, edges, faces, volumes) face.edges.append(eid) faces.append(face) - self.list_faces[face.nodes] = len(faces)-1 + self.list_faces[mnodes] = len(faces) - 1 return len(faces)-1 elif self.mdim[mtype] == 3: - mnodes = rotate(nodes[0:self.mnodes[mtype]]) volu = Volume() - volu.nodes = mnodes + volu.nodes = nodes_r list_faces = self.mfaces[self.mstype[mtype]] for face in list_faces: fnodes = [] @@ -150,7 +163,6 @@ def __init__(self, level=logging.INFO): self.volumes_grp = [] self.nodes_grp = [] - def createMesh(self, args): medmesh = medcoupling.MEDFileUMesh(args.fileNameInput) self.dimension = 0 @@ -187,19 +199,18 @@ def createMesh(self, args): val = [loc_glo_ind[cid] for cid in ids.getValues()] if mdim == 0: logging.info("0D-groups are not supported. We skip them...") - if mdim == 1: + elif mdim == 1: self.edges_grp.append([group, val]) elif mdim == 2: self.faces_grp.append([group, val]) elif mdim == 3: self.volumes_grp.append([group, val]) else: - raise RuntimeError("Should not be here") + raise RuntimeError(f"Should not be here: {mdim}") cells_shift+=mesh_lev.getNumberOfCells() - - #clean nodes + # clean nodes nodes_to_keep = {} for edge in self.edges: for node in edge.nodes: @@ -320,35 +331,55 @@ def writeMesh(self, args): f.write("\n") if len(self.edges_grp) > 0: + lst = [] f.write("*Edges->Groups %d\n"%len(self.edges_grp)) for grp in self.edges_grp: logging.info("Group naming: %s (med name) -> %d (internal id)"%(grp[0], i_grp)) - f.write("%s %d %d "%(grp[0], i_grp, len(grp[1]))) - for cell in grp[1]: + eds = sorted(grp[1]) + if intersection(lst, eds): + raise RuntimeError( + f"At least one element of group {grp[0]} is already in an other group" + ) + f.write("%s %d %d " % (grp[0], i_grp, len(eds))) + for cell in eds: f.write("%d "%cell) i_grp+=1 f.write("\n") + lst.extend(eds) if len(self.faces_grp) > 0: + lst = [] f.write("*Faces->Groups %d\n"%len(self.faces_grp)) for grp in self.faces_grp: logging.info("Group naming: %s (med name) -> %d (internal id)"%(grp[0], i_grp)) - f.write("%s %d %d "%(grp[0], i_grp, len(grp[1]))) - for cell in grp[1]: - f.write("%d "%cell) + fcs = sorted(grp[1]) + if intersection(lst, fcs): + raise RuntimeError( + f"At least one element of group {grp[0]} is already in an other group" + ) + f.write("%s %d %d " % (grp[0], i_grp, len(fcs))) + for fc in fcs: + f.write("%d " % fc) i_grp+=1 f.write("\n") + lst.extend(fcs) if len(self.volumes_grp) > 0: + lst = [] f.write("*Volumes->Groups %d\n"%len(self.volumes_grp)) for grp in self.volumes_grp: logging.info("Group naming: %s (med name) -> %d (internal id)"%(grp[0], i_grp)) - f.write("%s %d %d "%(grp[0], i_grp, len(grp[1]))) - for cell in grp[1]: + vols = sorted(grp[1]) + if intersection(lst, vols): + raise RuntimeError( + f"At least one element of group {grp[0]} is already in an other group" + ) + f.write("%s %d %d " % (grp[0], i_grp, len(vols))) + for cell in vols: f.write("%d "%cell) i_grp+=1 f.write("\n") - + lst.extend(vols) f.write("**EndMesh") f.close() diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt index 286e3770..beca1ea9 100644 --- a/unit_tests/CMakeLists.txt +++ b/unit_tests/CMakeLists.txt @@ -70,3 +70,7 @@ add_test(NAME dga_geom COMMAND dga_geom) add_executable(dga_matrices dga_matrices.cpp) target_link_libraries(dga_matrices ${LINK_LIBS}) add_test(NAME dga_matrices COMMAND dga_matrices) + +add_executable(kahan_formulas kahan_formulas.cpp) +target_link_libraries(kahan_formulas ${LINK_LIBS}) +add_test(NAME kahan_formulas COMMAND kahan_formulas) \ No newline at end of file diff --git a/unit_tests/kahan_formulas.cpp b/unit_tests/kahan_formulas.cpp new file mode 100644 index 00000000..b9886b57 --- /dev/null +++ b/unit_tests/kahan_formulas.cpp @@ -0,0 +1,62 @@ +#include + +#include "diskpp/common/simplicial_formula.hpp" +#include "diskpp/geometry/geometry.hpp" +#include "diskpp/mesh/mesh.hpp" +#include "diskpp/mesh/meshgen.hpp" + +#define THRESH 1e-14 + +bool test_kahan_2d(void) +{ + using T = double; + disk::triangular_mesh msh; + auto mesher = disk::make_simple_mesher(msh); + mesher.refine(); + mesher.refine(); + + T area = 0.0; + for (auto& cl : msh) { + auto pts = points(msh, cl); + area += disk::area_triangle_kahan(pts[0], pts[1], pts[2]); + } + + auto numelemes = msh.cells_size(); + auto error = std::abs(area - 1.0); + std::cout << "Elements: " << numelemes << ", area error: " << error << std::endl; + + return error < THRESH; +} + +bool test_kahan_3d(void) +{ + using T = double; + disk::tetrahedral_mesh msh; + auto mesher = disk::make_simple_mesher(msh); + mesher.refine(); + mesher.refine(); + + T volume = 0.0; + for (auto& cl : msh) { + auto pts = points(msh, cl); + volume += disk::volume_tetrahedron_kahan(pts[0], pts[1], pts[2], pts[3]); + } + + auto numelemes = msh.cells_size(); + auto error = std::abs(volume - 1.0); + std::cout << "Elements: " << numelemes << ", volume error: " << error << std::endl; + + return error < THRESH; +} + +int main(void) +{ + using T = double; + + bool success = true; + + success &= test_kahan_2d(); + success &= test_kahan_3d(); + + return (success == false); +} \ No newline at end of file