850 {
854
855 auto dm =
simple->getDM();
856 auto ts = pipeline_mng->createTSIM();
857
858 auto add_extra_finite_elements_to_solver_pipelines = [&]() {
860
861 auto pre_proc_ptr = boost::make_shared<FEMethod>();
862 auto post_proc_rhs_ptr = boost::make_shared<FEMethod>();
863 auto post_proc_lhs_ptr = boost::make_shared<FEMethod>();
864
865 auto time_scale = boost::make_shared<ExampleTimeScale>();
866
867 auto get_bc_hook_rhs = [this, pre_proc_ptr, time_scale]() {
869 CHKERR EssentialPreProc<DisplacementCubitBcData>(
mField, pre_proc_ptr,
870 {time_scale}, false)();
872 };
873
874 pre_proc_ptr->preProcessHook = get_bc_hook_rhs;
875
876 auto get_post_proc_hook_rhs = [this, post_proc_rhs_ptr]() {
878 CHKERR EssentialPreProcReaction<DisplacementCubitBcData>(
879 mField, post_proc_rhs_ptr,
nullptr, Sev::verbose)();
880 CHKERR EssentialPostProcRhs<DisplacementCubitBcData>(
881 mField, post_proc_rhs_ptr, 1.)();
883 };
884 auto get_post_proc_hook_lhs = [this, post_proc_lhs_ptr]() {
886 CHKERR EssentialPostProcLhs<DisplacementCubitBcData>(
887 mField, post_proc_lhs_ptr, 1.)();
889 };
890 post_proc_rhs_ptr->postProcessHook = get_post_proc_hook_rhs;
891 post_proc_lhs_ptr->postProcessHook = get_post_proc_hook_lhs;
892
893
895 ts_ctx_ptr->getPreProcessIFunction().push_front(pre_proc_ptr);
896 ts_ctx_ptr->getPreProcessIJacobian().push_front(pre_proc_ptr);
897 ts_ctx_ptr->getPostProcessIFunction().push_back(post_proc_rhs_ptr);
898 ts_ctx_ptr->getPostProcessIJacobian().push_back(post_proc_lhs_ptr);
900 };
901
902
903
904 CHKERR add_extra_finite_elements_to_solver_pipelines();
905
906 auto create_monitor_fe = [dm](auto &&post_proc_fe) {
907 return boost::make_shared<Monitor>(dm.get(), post_proc_fe);
908 };
909
910
911 boost::shared_ptr<FEMethod> null_fe;
918 auto monitor_ptr =
921 null_fe, monitor_ptr);
922
923
924 double ftime = 1;
925 CHKERR TSSetMaxTime(ts, ftime);
926 CHKERR TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP);
927
929 CHKERR TSSetI2Jacobian(ts,
B,
B, PETSC_NULLPTR, PETSC_NULLPTR);
932 CHKERR TSSetFromOptions(ts);
933
934 PetscBool test_steps = PETSC_FALSE;
935 PetscBool test_piola_stress = PETSC_FALSE;
937 &test_piola_stress, nullptr);
939 nullptr);
940
941 const bool check_steps = test_steps || test_piola_stress;
942
943 auto check_piola_stress = [this](PetscReal time) {
946
951
952 auto displacement_ptr = boost::make_shared<MatrixDouble>();
953
954
955 const double applied_F_zz = 1. - 0.1 * time;
956
957 t_P_expected(
i,
J) = 0.;
958 auto set_linear_elastic_piola = [&](const double strain_zz,
959 const double d_strain_d_F_zz) {
960 constexpr double E = 1.;
961 constexpr double nu = 0.3;
962 const double lambda =
E * nu / ((1. + nu) * (1. - 2. * nu));
963 const double mu =
E / (2. * (1. + nu));
965 t_P_expected(d, d) =
lambda * strain_zz;
967 (
lambda + 2. *
mu) * strain_zz * d_strain_d_F_zz;
968 };
969
970#ifndef AXISYMMETRIC
971 auto set_neohookean_piola = [&](
const double F_zz,
const double J) {
972 constexpr double c10 = 1.;
973 constexpr double K = 1.;
974 double I1 = (
SPACE_DIM - 1) + F_zz * F_zz;
976 I1 += 1.;
977 const double J_to_minus_two_thirds = std::pow(
J, -2. / 3.);
979 const double F_dd =
d ==
SPACE_DIM - 1 ? F_zz : 1.;
980 const double inv_F_dd = 1. / F_dd;
981 t_P_expected(d, d) =
982 2. * c10 * J_to_minus_two_thirds * (F_dd - (I1 / 3.) * inv_F_dd) +
983 K *
J * (
J - 1.) * inv_F_dd;
984 }
985 };
986
987#endif
988
989 auto eval_piola_at_point = [&](boost::shared_ptr<MatrixDouble> &mat_p,
990 std::array<double, 3> field_eval_coords) {
993 ->addFieldEvaluator<SPACE_DIM>(
995 field_eval_coords, [&](auto &pipeline) {
997 CHKERR AddHOOps<SPACE_DIM, SPACE_DIM, SPACE_DIM>::add(
998 pipeline, {
H1},
"GEOMETRY");
999
1000 pipeline.push_back(new OpCalculateVectorFieldValues<SPACE_DIM>(
1001 "U", displacement_ptr));
1002
1004 auto common_ptr =
1005 commonDataFactory<SPACE_DIM, GAUSS, DomainEleOp>(
1006 mField, pipeline,
"U",
"MAT_ELASTIC", Sev::inform);
1007 mat_p = common_ptr->getMatFirstPiolaStress();
1008 } else {
1009#ifdef WITH_ADOL_C
1015 "P");
1016#else
1018 "ADOL-C support is not enabled. Please reconfigure with "
1019 "-DWITH_ADOL_C=ON and recompile to use MatOps material model.");
1020#endif
1021 }
1023 });
1025 };
1026
1027 boost::shared_ptr<MatrixDouble> mat_p;
1028 using DL = DataLayoutTraits<DataLayout::GaussByCoeffs>;
1029
1030
1031 std::string material_name = "Hencky";
1032#ifdef WITH_ADOL_C
1035 bool found_range = false;
1038 if (range.empty())
1039 continue;
1040 if (found_range && tag != material_tag)
1042 "The analytical fixture requires a homogeneous material");
1043 material_tag = tag;
1044 found_range = true;
1045 }
1046 }
1048 }
1049#endif
1050
1051#ifdef AXISYMMETRIC
1052 if (material_name != "MetaPiolaResponse")
1053 SETERRQ(
1055 "The axisymmetric analytical fixture requires Neo-Hookean material");
1056#endif
1057
1058 if (material_name == "Hencky") {
1059
1060 set_linear_elastic_piola(std::log(applied_F_zz), 1. / applied_F_zz);
1061 } else if (material_name == "MetaPiolaResponse") {
1062#ifdef AXISYMMETRIC
1063
1064
1065 const double stretch = 1. + 0.01 * time;
1066 const double jacobian = stretch * stretch * stretch;
1069 t_P_expected(
i,
J) = piola *
delta(
i,
J);
1070 CHKERR eval_piola_at_point(mat_p, {1.37, 0.41, 0.});
1072 *displacement_ptr, 1)();
1073 const double u_err = std::hypot(t_u(0) - (stretch - 1.) * 1.37,
1074 t_u(1) - (stretch - 1.) * 0.41);
1076 ->checkError<TestType::POINTWISE>("axisymmetric displacement", u_err,
1077 0., {1e-8, 0.});
1078#else
1079 set_neohookean_piola(applied_F_zz, applied_F_zz);
1080#endif
1081 } else if (material_name == "Umat") {
1082
1083 char strain_type[32] = "small";
1085 strain_type, sizeof(strain_type), nullptr);
1086 if (std::string(strain_type) != "small")
1088 "The analytical UMAT fixture requires small strain");
1089 set_linear_elastic_piola(applied_F_zz - 1., 1.);
1090 } else {
1092 "No analytical fixture for material %s", material_name.c_str());
1093 }
1094
1095 if (!mat_p)
1096 CHKERR eval_piola_at_point(mat_p, {0.123, -0.087, 0.193});
1097 auto t_P =
1099 DL>::get(*mat_p, 1)();
1100 t_P_diff(
i,
J) = t_P(
i,
J) - t_P_expected(
i,
J);
1101 const double p_err = std::sqrt(t_P_diff(
i,
J) * t_P_diff(
i,
J));
1105 <<
"Piola stress (" << material_name <<
") P(" <<
r <<
", " <<
c
1106 <<
") actual " << std::scientific << t_P(r,
c) <<
" expected "
1107 << t_P_expected(r,
c) <<
" diff " << t_P_diff(r,
c);
1108 MOFEM_LOG(
"EXAMPLE", Sev::inform) <<
"Piola stress (" << material_name
1109 << ") error " << std::scientific << p_err;
1111 ->checkError<TestType::POINTWISE>("Piola stress", p_err, 0.,
1112 {1e-8, 0.});
1113
1115 };
1116
1117 if (check_steps) {
1119 ts, [this, check_piola_stress](TS, PetscInt step, PetscReal time,
1120 Vec solution) {
1123 CHKERR VecGhostUpdateBegin(solution, INSERT_VALUES, SCATTER_FORWARD);
1124 CHKERR VecGhostUpdateEnd(solution, INSERT_VALUES, SCATTER_FORWARD);
1126 INSERT_VALUES, SCATTER_REVERSE);
1127 CHKERR check_piola_stress(time);
1129 << "Numerical checks passed at TS step " << step << ", time "
1130 << time;
1132 });
1133 }
1134
1138 const auto solve_error = TSSolve(ts, nullptr);
1141
1142
1143
1144
1145 {
1146 PetscReal expected_time;
1147 CHKERR TSGetMaxTime(ts, &expected_time);
1149 CHKERR testing->checkSolver(ts, expected_time, {1e-12, 1e-12},
1150 "nonlinear elasticity");
1151 }
1152
1153 CHKERR TSGetTime(ts, &ftime);
1154
1155 PetscInt steps, snesfails, rejects, nonlinits, linits;
1156 CHKERR TSGetStepNumber(ts, &steps);
1157 CHKERR TSGetSNESFailures(ts, &snesfails);
1158 CHKERR TSGetStepRejections(ts, &rejects);
1159 CHKERR TSGetSNESIterations(ts, &nonlinits);
1160 CHKERR TSGetKSPIterations(ts, &linits);
1162 "steps %d (%d rejected, %d SNES fails), ftime %g, nonlinits "
1163 "%d, linits %d",
1164 steps, rejects, snesfails, ftime, nonlinits, linits);
1165
1167}
SmartPetscObj< Mat > jacobian
#define FTENSOR_INDEX(DIM, I)
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
@ MOFEM_ATOM_TEST_INVALID
#define MoFEMFunctionBeginHot
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
auto createDMMatrix(DM dm)
Get smart matrix from DM.
FTensor::Index< 'i', SPACE_DIM > i
const double c
speed of light (cm/ns)
FTensor::Index< 'J', DIM1 > J
DataLayoutTraits< DataLayout::GaussByCoeffs > DL
PetscErrorCode DMMoFEMTSSetMonitor(DM dm, TS ts, const std::string fe_name, boost::shared_ptr< MoFEM::FEMethod > method, boost::shared_ptr< MoFEM::BasicMethod > pre_only, boost::shared_ptr< MoFEM::BasicMethod > post_only)
Set Monitor To TS solver.
auto getDMTsCtx(DM dm)
Get TS context data structure used by DM.
decltype(GetFTensor1FromMatImpl< Tensor_Dim, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor1FromMatType
PetscErrorCode PetscOptionsGetString(PetscOptions *, const char pre[], const char name[], char str[], size_t size, PetscBool *set)
decltype(GetFTensor2FromMatImpl< Tensor_Dim0, Tensor_Dim1, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor2FromMatType
static constexpr double delta
static MoFEMErrorCode postStepFun(TS ts)
static MoFEMErrorCode postStepInitialise(NonlinearElasticExample *example_ptr)
static MoFEMErrorCode postStepDestroy()
static MoFEMErrorCode preStepFun(TS ts)
static constexpr int MAT_DIM