996 {
1000
1001 auto dm =
simple->getDM();
1004
1005 auto set_section_monitor = [&](auto solver) {
1007 SNES snes;
1008 CHKERR TSGetSNES(solver, &snes);
1009 CHKERR SNESMonitorSet(snes,
1012 (void *)(snes_ctx_ptr.get()), nullptr);
1014 };
1015
1016 auto create_post_process_element = [&]() {
1017 auto post_proc_fe = boost::make_shared<PostProcEle>(
mField);
1018
1019 auto block_params = boost::make_shared<BlockedParameters>();
1020 auto mD_ptr = block_params->getDPtr();
1022 "MAT_FLUID", block_params, Sev::verbose);
1024 post_proc_fe->getOpPtrVector(), {H1, HDIV});
1025
1026 auto mat_grad_ptr = boost::make_shared<MatrixDouble>();
1027 auto mat_strain_ptr = boost::make_shared<MatrixDouble>();
1028 auto mat_stress_ptr = boost::make_shared<MatrixDouble>();
1029
1030 auto p_ptr = boost::make_shared<VectorDouble>();
1031 auto mat_flux_ptr = boost::make_shared<MatrixDouble>();
1032
1033 post_proc_fe->getOpPtrVector().push_back(
1035 post_proc_fe->getOpPtrVector().push_back(
1037
1038 auto u_ptr = boost::make_shared<MatrixDouble>();
1039 post_proc_fe->getOpPtrVector().push_back(
1041 post_proc_fe->getOpPtrVector().push_back(
1043 mat_grad_ptr));
1044 post_proc_fe->getOpPtrVector().push_back(
1046 post_proc_fe->getOpPtrVector().push_back(
1048 mat_strain_ptr, mat_stress_ptr, mD_ptr));
1049
1051
1052 post_proc_fe->getOpPtrVector().push_back(
1053
1055
1056 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
1057
1058 {{"P", p_ptr}},
1059
1060 {{"U", u_ptr}, {"FLUX", mat_flux_ptr}},
1061
1062 {},
1063
1064 {{"STRAIN", mat_strain_ptr}, {"STRESS", mat_stress_ptr}}
1065
1066 )
1067
1068 );
1069
1070 return post_proc_fe;
1071 };
1072
1073 auto create_creaction_fe = [&]() {
1074 auto fe_ptr = boost::make_shared<DomainEle>(
mField);
1075 fe_ptr->getRuleHook = [](
int,
int,
int o) {
return 2 * o; };
1076
1077 auto &pip = fe_ptr->getOpPtrVector();
1078
1079 auto block_params = boost::make_shared<BlockedParameters>();
1080 auto mD_ptr = block_params->getDPtr();
1082 Sev::verbose);
1084
1085 auto u_grad_ptr = boost::make_shared<MatrixDouble>();
1086 auto strain_ptr = boost::make_shared<MatrixDouble>();
1087 auto stress_ptr = boost::make_shared<MatrixDouble>();
1088
1090 "U", u_grad_ptr));
1092
1093
1095 strain_ptr, stress_ptr, mD_ptr));
1097
1098 fe_ptr->postProcessHook =
1100
1101 return fe_ptr;
1102 };
1103
1104 auto monitor_ptr = boost::make_shared<FEMethod>();
1105 auto post_proc_fe = create_post_process_element();
1107 auto rections_fe = create_creaction_fe();
1108
1109 auto set_time_monitor = [&](auto dm, auto solver) {
1111 monitor_ptr->preProcessHook = [&]() {
1113
1115
1117 post_proc_fe,
1118 monitor_ptr->getCacheWeakPtr());
1119 CHKERR post_proc_fe->writeFile(
1120 "out_" + boost::lexical_cast<std::string>(monitor_ptr->ts_step) +
1121 ".h5m");
1122 }
1123
1124 rections_fe->f = res;
1126 rections_fe,
1127 monitor_ptr->getCacheWeakPtr());
1128
1129 CHKERR VecAssemblyBegin(res);
1130 CHKERR VecAssemblyEnd(res);
1131 double nrm;
1132 CHKERR VecNorm(res, NORM_2, &nrm);
1134 << "Residual norm " << nrm << " at time step "
1135 << monitor_ptr->ts_step;
1136
1137 struct AtomTestResult {
1138 bool fail = false;
1139 std::string msg = "";
1140 };
1141
1142 AtomTestResult atom_test_result;
1143
1144 auto fail_atom_test = [&atom_test_result](const std::string &msg) {
1145 if (!atom_test_result.fail) {
1146 atom_test_result.fail = true;
1147 atom_test_result.msg = msg;
1148 }
1149 };
1150
1151
1152 struct AtomTestData {
1153 double expected = 0.0;
1155 };
1156
1157
1159
1161 ->evalFEAtThePoint<SPACE_DIM>(
1166
1168 auto eval_num_vec =
1170 CHKERR VecZeroEntries(eval_num_vec);
1172 CHKERR VecSetValue(eval_num_vec, 0, 1, ADD_VALUES);
1173 }
1174 CHKERR VecAssemblyBegin(eval_num_vec);
1175 CHKERR VecAssemblyEnd(eval_num_vec);
1176
1177 double eval_num;
1178 CHKERR VecSum(eval_num_vec, &eval_num);
1179 if (!(int)eval_num) {
1180 fail_atom_test(
1181 "did not find elements to evaluate the field, check the "
1182 "coordinates");
1183 }
1184 }
1185
1186 if (
atom_test && fabs(monitor_ptr->ts_t - 0.1) < 1e-12 &&
1192 << "Eval point P: " << t_pressure;
1193 double pressure = 0.0;
1194
1196 auto t_flux = getFTensor1FromMat<SPACE_DIM>(*
fluxFieldPtr);
1197 auto flux_mag = sqrt(t_flux(
i) * t_flux(
i));
1199 << "Eval point FLUX magnitude: " << flux_mag;
1200 double flux = 0.0;
1201
1202 auto t_disp = getFTensor1FromMat<SPACE_DIM>(*
dispFieldPtr);
1203 auto disp_mag = sqrt(t_disp(
i) * t_disp(
i));
1205 << "Eval point U magnitude: " << disp_mag;
1206 double disp = 0.0;
1207
1208 auto t_strain = getFTensor2SymmetricFromMat<SPACE_DIM>(*
strainFieldPtr);
1209 auto t_strain_trace = t_strain(
i,
i);
1211 << "Eval point trace of strain: " << t_strain_trace;
1212 double strain = 0.0;
1213
1214 double von_mises_stress;
1215 auto getVonMisesStress = [&](auto t_stress) {
1217 von_mises_stress = std::sqrt(
1218 0.5 *
1219 ((t_stress(0, 0) - t_stress(1, 1)) *
1220 (t_stress(0, 0) - t_stress(1, 1)) +
1221 (
SPACE_DIM == 3 ? (t_stress(1, 1) - t_stress(2, 2)) *
1222 (t_stress(1, 1) - t_stress(2, 2))
1223 : 0) +
1224 (
SPACE_DIM == 3 ? (t_stress(2, 2) - t_stress(0, 0)) *
1225 (t_stress(2, 2) - t_stress(0, 0))
1226 : 0) +
1227 6 * (t_stress(0, 1) * t_stress(0, 1) +
1228 (
SPACE_DIM == 3 ? t_stress(1, 2) * t_stress(1, 2) : 0) +
1229 (
SPACE_DIM == 3 ? t_stress(2, 0) * t_stress(2, 0) : 0))));
1231 };
1232 auto t_stress = getFTensor2SymmetricFromMat<SPACE_DIM>(*
stressFieldPtr);
1233 CHKERR getVonMisesStress(t_stress);
1235 << "Eval point von Mises Stress: " << von_mises_stress;
1236 double stress = 0.0;
1237
1239 case 1:
1240 pressure = 0.0002681;
1241 flux = 0.0001734;
1242 disp = 0.0009;
1243 strain = 0.0009;
1244 stress = 53.037;
1245 break;
1246
1247 case 2:
1248 pressure = 0.0063046;
1249 flux = 0.000093771;
1250 disp = 0.000859577;
1251 strain = 0.0009;
1252 stress = 75.00;
1253 break;
1254
1255 case 3:
1256 pressure = 0.31473;
1257 flux = 0.0009216;
1258 disp = 0.0135;
1259 strain = 0.036392;
1260 stress = 356.956;
1261 break;
1262
1263 default:
1264 fail_atom_test("unknown atom test number");
1265 }
1266 if (fabs(t_pressure + pressure) > 1e-4) {
1267 fail_atom_test("wrong pressure value");
1268 }
1269 if (fabs(flux_mag - flux) > 1e-6) {
1270 fail_atom_test("wrong flux value");
1271 }
1272 if (fabs(disp_mag - disp) > 1e-2) {
1273 fail_atom_test("wrong displacement value");
1274 }
1275 if (fabs(t_strain_trace + strain) > 1e-3) {
1276 fail_atom_test("wrong strain value");
1277 }
1278 if (fabs(von_mises_stress - stress) > 1e-2) {
1279 fail_atom_test("wrong stress value");
1280 }
1281 }
1282
1283 PetscReal current_time;
1284 CHKERR TSGetTime(solver, ¤t_time);
1285 (void)current_time;
1286
1288
1300 <<
"Eval point elasticity matrix: " << *
mDPtr;
1301 }
1303 }
1304
1305 int fail_flag = atom_test_result.fail ? 1 : 0;
1306 MPI_Allreduce(MPI_IN_PLACE, &fail_flag, 1, MPI_INT, MPI_MAX,
mField.
get_comm());
1307
1308 if (fail_flag) {
1309 const int root = 0;
1310 const int MAX_MSG = 512;
1311
1312 char msg_buf[MAX_MSG];
1313 msg_buf[0] = '\0';
1314
1315 if (atom_test_result.fail) {
1316 std::snprintf(msg_buf, MAX_MSG, "%s", atom_test_result.msg.c_str());
1317 }
1319 int send_rank = atom_test_result.fail ? my_rank : INT_MAX;
1320 MPI_Allreduce(MPI_IN_PLACE, &send_rank, 1, MPI_INT, MPI_MIN,
mField.
get_comm());
1321 MPI_Bcast(msg_buf, MAX_MSG, MPI_CHAR, send_rank,
mField.
get_comm());
1322
1323 if (my_rank == root) {
1325 "atom test %d failed: %s",
atom_test, msg_buf);
1326 }
1327
1329 "Atom test failed");
1330 }
1331
1333 };
1334
1335 auto null = boost::shared_ptr<FEMethod>();
1337 monitor_ptr, null);
1339 };
1340
1341 auto set_fieldsplit_preconditioner = [&](auto solver) {
1343
1344 SNES snes;
1345 CHKERR TSGetSNES(solver, &snes);
1346 KSP ksp;
1347 CHKERR SNESGetKSP(snes, &ksp);
1348 PC pc;
1349 CHKERR KSPGetPC(ksp, &pc);
1350 PetscBool is_pcfs = PETSC_FALSE;
1351 PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &is_pcfs);
1352
1353
1354 if (is_pcfs == PETSC_TRUE) {
1357 auto name_prb =
simple->getProblemName();
1358
1360 CHKERR is_mng->isCreateProblemFieldAndRank(name_prb,
ROW,
"U", 0,
1363 CHKERR is_mng->isCreateProblemFieldAndRank(name_prb,
ROW,
"FLUX", 0, 0,
1364 is_flux);
1366 CHKERR is_mng->isCreateProblemFieldAndRank(name_prb,
ROW,
"P", 0, 0,
1367 is_P);
1368 IS is_tmp;
1369 CHKERR ISExpand(is_P, is_flux, &is_tmp);
1371
1372 auto is_all_bc = bc_mng->getBlockIS(name_prb, "FLUIDFLUX", "FLUX", 0, 0);
1373 int is_all_bc_size;
1374 CHKERR ISGetSize(is_all_bc, &is_all_bc_size);
1376 << "Field split block size " << is_all_bc_size;
1377 if (is_all_bc_size) {
1378 IS is_tmp2;
1379 CHKERR ISDifference(is_Flux, is_all_bc, &is_tmp2);
1381 CHKERR PCFieldSplitSetIS(pc, PETSC_NULLPTR,
1382 is_all_bc);
1383 }
1384
1387 CHKERR PCFieldSplitSetIS(pc, PETSC_NULLPTR, is_Flux);
1388 CHKERR PCFieldSplitSetIS(pc, PETSC_NULLPTR, is_u);
1389 }
1390
1392 };
1393
1394 auto pre_proc_ptr = boost::make_shared<FEMethod>();
1395 auto post_proc_rhs_ptr = boost::make_shared<FEMethod>();
1396 auto post_proc_lhs_ptr = boost::make_shared<FEMethod>();
1397 auto time_scale = boost::make_shared<TimeScale>();
1398
1399 auto get_bc_hook_rhs = [this, pre_proc_ptr, time_scale]() {
1401 {time_scale}, false);
1402 return hook;
1403 };
1404
1405 auto get_post_proc_hook_rhs = [this, post_proc_rhs_ptr]() {
1408 mField, post_proc_rhs_ptr,
nullptr, Sev::verbose)();
1410 mField, post_proc_rhs_ptr, 1.)();
1412 };
1413 auto get_post_proc_hook_lhs = [this, post_proc_lhs_ptr]() {
1415 post_proc_lhs_ptr, 1.);
1416 };
1417
1418 pre_proc_ptr->preProcessHook = get_bc_hook_rhs();
1419 post_proc_rhs_ptr->postProcessHook = get_post_proc_hook_rhs;
1420 post_proc_lhs_ptr->postProcessHook = get_post_proc_hook_lhs();
1421
1423 ts_ctx_ptr->getPreProcessIFunction().push_front(pre_proc_ptr);
1424 ts_ctx_ptr->getPreProcessIJacobian().push_front(pre_proc_ptr);
1425 ts_ctx_ptr->getPostProcessIFunction().push_back(post_proc_rhs_ptr);
1426 ts_ctx_ptr->getPostProcessIJacobian().push_back(post_proc_lhs_ptr);
1427
1429 CHKERR TSSetIJacobian(solver,
B,
B, PETSC_NULLPTR, PETSC_NULLPTR);
1431 CHKERR TSSetSolution(solver,
D);
1432 CHKERR TSSetFromOptions(solver);
1433
1434 CHKERR set_section_monitor(solver);
1435 CHKERR set_fieldsplit_preconditioner(solver);
1436 CHKERR set_time_monitor(dm, solver);
1437
1439 CHKERR TSSolve(solver, NULL);
1440
1442}
@ MOFEM_ATOM_TEST_INVALID
#define MoFEMFunctionBeginHot
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
PetscErrorCode DMoFEMLoopFiniteElements(DM dm, const char fe_name[], MoFEM::FEMethod *method, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
auto createDMMatrix(DM dm)
Get smart matrix from DM.
SmartPetscObj< TS > createTSIM(SmartPetscObj< DM > dm=nullptr)
Create TS (time) implicit solver.
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.
MoFEMErrorCode MoFEMSNESMonitorFields(SNES snes, PetscInt its, PetscReal fgnorm, SnesCtx *ctx)
Sens monitor printing residual field by field.
auto createVectorMPI(MPI_Comm comm, PetscInt n, PetscInt N)
Create MPI Vector.
static auto getFTensor0FromVec(V &data)
Get tensor rank 0 (scalar) form data vector.
auto getDMSnesCtx(DM dm)
Get SNES context data structure used by DM.
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
Class (Function) to enforce essential constrains on the left hand side diagonal.
Class (Function) to enforce essential constrains on the right hand side diagonal.
Class (Function) to calculate residual side diagonal.
Class (Function) to enforce essential constrains.
Section manager is used to create indexes and sections.
Post post-proc data at points from hash maps.
intrusive_ptr for managing petsc objects