v0.16.3
Loading...
Searching...
No Matches
Classes | Typedefs | Functions | Variables
schur_test_diag_mat.cpp File Reference
#include <MoFEM.hpp>

Go to the source code of this file.

Classes

struct  ElementsAndOps< DIM >
 [Operators_definition] More...
 
struct  ElementsAndOps< 2 >
 
struct  ElementsAndOps< 3 >
 

Typedefs

using EntData = EntitiesFieldData::EntData
 
using DomainEle = ElementsAndOps< SPACE_DIM >::DomainEle
 
using DomainEleOp = DomainEle::UserDataOperator
 

Functions

int main (int argc, char *argv[])
 

Variables

static char help [] = "...\n\n"
 
constexpr int SPACE_DIM = 3
 [Define dimension]
 
constexpr int FIELD_DIM = SPACE_DIM
 
constexpr AssemblyType A
 
constexpr IntegrationType I
 
SmartPetscObj< Mat > petsc_mat
 
SmartPetscObj< Mat > block_mat
 
constexpr bool debug = false
 

Typedef Documentation

◆ DomainEle

Definition at line 35 of file schur_test_diag_mat.cpp.

◆ DomainEleOp

Definition at line 36 of file schur_test_diag_mat.cpp.

◆ EntData

Definition at line 34 of file schur_test_diag_mat.cpp.

Function Documentation

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 85 of file schur_test_diag_mat.cpp.

85 {
86
87 // initialize petsc
88 MoFEM::Core::Initialize(&argc, &argv, (char *)0, help);
89
90 try {
91
92 // Create MoAB database
93 moab::Core moab_core;
94 moab::Interface &moab = moab_core;
95
96 // Create MoFEM database and link it to MoAB
97 MoFEM::Core mofem_core(moab);
98 MoFEM::Interface &m_field = mofem_core;
99
100 // Register DM Manager
101 DMType dm_name = "DMMOFEM";
102 CHKERR DMRegister_MoFEM(dm_name);
103
104 // Add logging channel for example
105 auto core_log = logging::core::get();
106 core_log->add_sink(
108 LogManager::setLog("Timeline");
109 MOFEM_LOG_TAG("Timeline", "Timeline");
110
111 // Simple interface
112 auto simple = m_field.getInterface<Simple>();
113
114 // get options from command line
116 // load mesh file
117 CHKERR simple->loadFile();
118
119 CHKERR simple->addDomainField("V", H1, AINSWORTH_LEGENDRE_BASE, FIELD_DIM);
120 CHKERR simple->addDomainField("T", L2, AINSWORTH_LEGENDRE_BASE, FIELD_DIM);
121 CHKERR simple->addDomainField("S", L2, AINSWORTH_LEGENDRE_BASE, FIELD_DIM);
122 CHKERR simple->addDomainField("O", L2, AINSWORTH_LEGENDRE_BASE, FIELD_DIM);
123
124 // set fields order, i.e. for most first cases order is sufficient.
125 int order = 3;
126 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &order,
127 PETSC_NULLPTR);
128 // without preconditioner blocks A00 element matrices are factorised in
129 // place, that tests cached factors in mult, mult transpose and solve
130 PetscBool no_preconditioner_block = PETSC_FALSE;
131 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-no_preconditioner_block",
132 &no_preconditioner_block, PETSC_NULLPTR);
133 // block pattern of A00 with uncoupled pair of fields (S, O are not
134 // coupled), and with empty diagonal block (O, O is listed but not
135 // assembled), that tests block elimination of A00 elements
136 PetscBool uncoupled_so = PETSC_FALSE;
137 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-uncoupled_so",
138 &uncoupled_so, PETSC_NULLPTR);
139 PetscBool empty_oo = PETSC_FALSE;
140 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-empty_oo", &empty_oo,
141 PETSC_NULLPTR);
142 // diagonal block (S, S) scaled to 1e-300 and couplings (S, T), (T, S)
143 // scaled by 1e10, such that block elimination of S overflows. A00 is
144 // regular, and dense factorisation with pivoting is accurate. With
145 // -overflow_pivot_element only the last owned element on each process is
146 // scaled, the first one is the probe of block elimination, thus block
147 // elimination is accepted and the scaled element has to fall back to
148 // dense factorisation.
149 PetscBool overflow_pivot = PETSC_FALSE;
150 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-overflow_pivot",
151 &overflow_pivot, PETSC_NULLPTR);
152 PetscBool overflow_pivot_element = PETSC_FALSE;
153 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-overflow_pivot_element",
154 &overflow_pivot_element, PETSC_NULLPTR);
155 if (overflow_pivot_element)
156 overflow_pivot = PETSC_TRUE;
157 CHKERR simple->setFieldOrder("V", order);
158 CHKERR simple->setFieldOrder("T", order);
159 CHKERR simple->setFieldOrder("S", order - 1);
160 CHKERR simple->setFieldOrder("O", order - 2);
161
162 // setup problem
163 CHKERR simple->setUp();
164
165 // If block "VOL" exist, first index is removed from "T" field. That test
166 // blocks handling when some DOFs are removed.
167 auto bc_mng = m_field.getInterface<BcManager>();
168 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "VOL",
169 "T", 0, 1);
170
171 auto schur_dm = createDM(m_field.get_comm(), "DMMOFEM");
172 CHKERR DMMoFEMCreateSubDM(schur_dm, simple->getDM(), "SCHUR");
173 CHKERR DMMoFEMSetSquareProblem(schur_dm, PETSC_TRUE);
174 CHKERR DMMoFEMAddElement(schur_dm, simple->getDomainFEName());
175 CHKERR DMMoFEMAddSubFieldRow(schur_dm, "V");
176 CHKERR DMMoFEMAddSubFieldCol(schur_dm, "V");
177 CHKERR DMSetUp(schur_dm);
178
179 auto block_dm = createDM(m_field.get_comm(), "DMMOFEM");
180 CHKERR DMMoFEMCreateSubDM(block_dm, simple->getDM(), "BLOCK");
181 CHKERR DMMoFEMSetSquareProblem(block_dm, PETSC_TRUE);
182 CHKERR DMMoFEMAddElement(block_dm, simple->getDomainFEName());
183 CHKERR DMMoFEMAddSubFieldRow(block_dm, "T");
184 CHKERR DMMoFEMAddSubFieldCol(block_dm, "T");
185 CHKERR DMMoFEMAddSubFieldRow(block_dm, "S");
186 CHKERR DMMoFEMAddSubFieldCol(block_dm, "S");
187 CHKERR DMMoFEMAddSubFieldRow(block_dm, "O");
188 CHKERR DMMoFEMAddSubFieldCol(block_dm, "O");
189 CHKERR DMSetUp(block_dm);
190
191 petsc_mat = createDMMatrix(simple->getDM());
192 auto S = createDMMatrix(schur_dm);
193
194 std::vector<SchurFieldPair> block_pairs{
195 {"V", "V"}, {"T", "T"}, {"S", "S"}, {"O", "O"}, {"V", "T"},
196 {"T", "V"}, {"S", "T"}, {"T", "S"}, {"T", "O"}, {"O", "T"}};
197 if (!uncoupled_so) {
198 block_pairs.push_back({"S", "O"});
199 block_pairs.push_back({"O", "S"});
200 }
201
202 auto shell_data = createBlockMat(
203 simple->getDM(),
205 {{simple->getDomainFEName(), block_pairs}}));
206
207 auto [mat, block_data_ptr] = shell_data;
208 block_mat = mat;
209
210 std::vector<std::string> fields{"T", "S", "O"};
211
212 auto [nested_mat, nested_data_ptr] = createSchurNestedMatrix(
213
215
216 {schur_dm, block_dm}, block_data_ptr,
217
218 fields, {nullptr, nullptr, nullptr},
219 no_preconditioner_block ? false : true
220
221 )
222
223 );
224
225 using OpMassPETSCAssemble = FormsIntegrators<DomainEleOp>::Assembly<
227 using OpMassBlockAssemble = FormsIntegrators<DomainEleOp>::Assembly<
229 using OpMassBlockPreconditionerAssemble =
231 BiLinearForm<GAUSS>::OpMass<1, FIELD_DIM>;
232
233 // get operators tester
234 auto pip_mng = m_field.getInterface<PipelineManager>(); // get interface to
235 // pipeline manager
236
237 auto close_zero = [](double, double, double) { return 1; };
238 auto beta = [](double, double, double) { return -1. / 2; };
239 auto gamma = [](double, double, double) { return -1. / 4; };
240 // vertices of scaled element, if only one element is scaled
241 std::array<double, 12> bad_tet;
242 if (overflow_pivot_element) {
243 auto prb = m_field.get_problem(simple->getProblemName());
244 Range owned;
245 for (auto &fe : *prb->numeredFiniteElementsPtr)
246 if (fe->getPart() == m_field.get_comm_rank() &&
247 fe->getName() == simple->getDomainFEName())
248 owned.insert(fe->getEnt());
249 if (owned.empty())
250 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID, "No elements");
251 const EntityHandle *conn;
252 int num_nodes;
253 CHKERR moab.get_connectivity(owned.back(), conn, num_nodes, true);
254 CHKERR moab.get_coords(conn, 4, bad_tet.data());
255 }
256 // point inside scaled element (Gauss points are interior points)
257 auto in_bad = [&](double x, double y, double z) {
258 if (!overflow_pivot)
259 return false;
260 if (!overflow_pivot_element)
261 return true;
263 FTensor::Tensor1<double, 3> t_p{x - bad_tet[0], y - bad_tet[1],
264 z - bad_tet[2]};
265 for (int i = 0; i != 3; ++i)
266 for (int j = 0; j != 3; ++j)
267 t_jac(i, j) = bad_tet[3 * (j + 1) + i] - bad_tet[i];
269 double det;
270 CHK_THROW_MESSAGE(determinantTensor3by3(t_jac, det), "det");
271 CHK_THROW_MESSAGE(invertTensor3by3(t_jac, det, t_inv), "inv");
272 double sum = 0;
273 for (int i = 0; i != 3; ++i) {
274 double l = 0;
275 for (int j = 0; j != 3; ++j)
276 l += t_inv(i, j) * t_p(j);
277 if (l < -1e-10)
278 return false;
279 sum += l;
280 }
281 return sum < 1 + 1e-10;
282 };
283 auto ss_coeff = [&](double x, double y, double z) {
284 return in_bad(x, y, z) ? 1e-300 : 1.;
285 };
286 auto st_coeff = [&](double x, double y, double z) {
287 return in_bad(x, y, z) ? -1e10 / 2 : -1. / 2;
288 };
289
290 pip_mng->setDomainLhsIntegrationRule([](int, int, int o) { return 2 * o; });
291 auto &pip_lhs = pip_mng->getOpDomainLhsPipeline();
292
293 pip_lhs.push_back(new OpMassPETSCAssemble("V", "V"));
294 // (T, T) block is assembled as preconditioner block, unless
295 // preconditioner blocks are not allocated
296 if (no_preconditioner_block)
297 pip_lhs.push_back(new OpMassPETSCAssemble("T", "T"));
298 pip_lhs.push_back(new OpMassPETSCAssemble("V", "T"));
299 pip_lhs.push_back(new OpMassPETSCAssemble("T", "V"));
300 pip_lhs.push_back(new OpMassPETSCAssemble("S", "S", ss_coeff));
301 pip_lhs.push_back(new OpMassPETSCAssemble("S", "T", st_coeff));
302 pip_lhs.push_back(new OpMassPETSCAssemble("T", "S", st_coeff));
303 if (!empty_oo)
304 pip_lhs.push_back(new OpMassPETSCAssemble("O", "O", close_zero));
305 pip_lhs.push_back(new OpMassPETSCAssemble("T", "O", beta));
306 pip_lhs.push_back(new OpMassPETSCAssemble("O", "T", beta));
307 if (!uncoupled_so) {
308 pip_lhs.push_back(new OpMassPETSCAssemble("S", "O", gamma));
309 pip_lhs.push_back(new OpMassPETSCAssemble("O", "S", beta));
310 }
311
312 pip_lhs.push_back(createOpSchurAssembleBegin());
313 pip_lhs.push_back(new OpMassBlockAssemble("V", "V"));
314 if (no_preconditioner_block)
315 pip_lhs.push_back(new OpMassBlockAssemble("T", "T"));
316 pip_lhs.push_back(new OpMassBlockAssemble("V", "T"));
317 pip_lhs.push_back(new OpMassBlockAssemble("T", "V"));
318 pip_lhs.push_back(new OpMassBlockAssemble("S", "S", ss_coeff));
319 pip_lhs.push_back(new OpMassBlockAssemble("S", "T", st_coeff));
320 pip_lhs.push_back(new OpMassBlockAssemble("T", "S", st_coeff));
321 if (!empty_oo)
322 pip_lhs.push_back(new OpMassBlockAssemble("O", "O", close_zero));
323 pip_lhs.push_back(new OpMassBlockAssemble("T", "O", beta));
324 pip_lhs.push_back(new OpMassBlockAssemble("O", "T", beta));
325 if (!uncoupled_so) {
326 pip_lhs.push_back(new OpMassBlockAssemble("S", "O", gamma));
327 pip_lhs.push_back(new OpMassBlockAssemble("O", "S", beta));
328 }
329 if (!no_preconditioner_block)
330 pip_lhs.push_back(new OpMassBlockPreconditionerAssemble("T", "T"));
331
332 auto schur_is = getDMSubData(schur_dm)->getSmartRowIs();
333 auto ao_up = createAOMappingIS(schur_is, PETSC_NULLPTR);
334
335 pip_lhs.push_back(createOpSchurAssembleEnd(
336
337 fields, {nullptr, nullptr, nullptr}, ao_up, S, false, false)
338
339 );
340
341 {
342 MOFEM_LOG_CHANNEL("Timeline");
343 MOFEM_LOG_TAG("Timeline", "timer");
344 BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
345 MOFEM_LOG("Timeline", Sev::inform) << "Assemble start";
347 simple->getDomainFEName(),
348 pip_mng->getDomainLhsFE());
349 MOFEM_LOG("Timeline", Sev::inform) << "Assemble end";
350 }
351 {
352 MOFEM_LOG_CHANNEL("Timeline");
353 MOFEM_LOG_TAG("Timeline", "timer");
354 BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
355 MOFEM_LOG("Timeline", Sev::inform) << "Mat assemble start";
356 CHKERR MatAssemblyBegin(petsc_mat, MAT_FINAL_ASSEMBLY);
357 CHKERR MatAssemblyEnd(petsc_mat, MAT_FINAL_ASSEMBLY);
358 MOFEM_LOG("Timeline", Sev::inform) << "Mat assemble end";
359 }
360
361 auto get_random_vector = [&](auto dm) {
362 auto v = createDMVector(dm);
363 PetscRandom rctx;
364 PetscRandomCreate(PETSC_COMM_WORLD, &rctx);
365 CHK_MOAB_THROW(VecSetRandom(v, rctx), "generate rand vector");
366 PetscRandomDestroy(&rctx);
367 return v;
368 };
369 auto v = get_random_vector(simple->getDM());
370
371 auto y_petsc = createDMVector(simple->getDM());
372 auto y_block = createDMVector(simple->getDM());
373
374 auto test = [](auto msg, auto y, double norm0) {
376
377 double eps = 1e-10;
378 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-eps", &eps,
379 PETSC_NULLPTR);
380
381 PetscReal norm;
382 CHKERR VecNorm(y, NORM_2, &norm);
383 norm = norm / norm0;
384 MOFEM_LOG_CHANNEL("WORLD");
385 MOFEM_TAG_AND_LOG("WORLD", Sev::inform, "TestBlockMat")
386 << msg << ": norm of difference: " << norm;
387 if (norm > eps || std::isnan(norm) || std::isinf(norm)) {
388 SETERRQ(PETSC_COMM_WORLD, 1, "norm of difference is too big");
389 }
391 };
392
393 std::vector<int> zero_rows_and_cols = {
394 0, 1, 10, 20,
395 500}; // not to remove dofs for TENSOR field, inverse will not work
396 CHKERR MatZeroRowsColumns(petsc_mat, zero_rows_and_cols.size(),
397 &*zero_rows_and_cols.begin(), 1, PETSC_NULLPTR,
398 PETSC_NULLPTR);
399 CHKERR MatZeroRowsColumns(block_mat, zero_rows_and_cols.size(),
400 &*zero_rows_and_cols.begin(), 1, PETSC_NULLPTR,
401 PETSC_NULLPTR);
402
403 // test mult
404 {
405 MOFEM_LOG_CHANNEL("Timeline");
406 MOFEM_LOG_TAG("Timeline", "timer");
407 BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
408 MOFEM_LOG("Timeline", Sev::inform)
409 << "MatMult(petsc_mat, v, y_petsc) star";
410 CHKERR MatMult(petsc_mat, v, y_petsc);
411 MOFEM_LOG("Timeline", Sev::inform)
412 << "MatMult(petsc_mat, v, y_petsc) end";
413 }
414 double nrm0;
415 CHKERR VecNorm(y_petsc, NORM_2, &nrm0);
416
417 {
418 MOFEM_LOG_CHANNEL("Timeline");
419 MOFEM_LOG_TAG("Timeline", "timer");
420 BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
421 MOFEM_LOG("Timeline", Sev::inform)
422 << "MatMult(block_mat, v, y_block) star";
423 CHKERR MatMult(block_mat, v, y_block);
424 MOFEM_LOG("Timeline", Sev::inform)
425 << "MatMult(block_mat, v, y_block) end";
426 }
427 CHKERR VecAXPY(y_petsc, -1.0, y_block);
428 CHKERR test("mult", y_petsc, nrm0);
429
430 // tets mult add
431
432 MOFEM_LOG_CHANNEL("Timeline");
433 MOFEM_LOG_TAG("Timeline", "timer");
434
435 CHKERR MatMult(petsc_mat, v, y_petsc);
436 CHKERR MatMult(block_mat, v, y_block);
437 CHKERR MatMultAdd(petsc_mat, v, y_petsc, y_petsc);
438 CHKERR MatMultAdd(block_mat, v, y_block, y_block);
439 CHKERR VecAXPY(y_petsc, -1.0, y_block);
440 CHKERR test("mult add", y_petsc, nrm0);
441
442 // test mult transpose
443 CHKERR MatMultTranspose(petsc_mat, v, y_petsc);
444 CHKERR MatMultTranspose(block_mat, v, y_block);
445 CHKERR VecAXPY(y_petsc, -1.0, y_block);
446 CHKERR test("mult transpose", y_petsc, nrm0);
447
448 // tets mult add transpose
449 CHKERR MatMultTranspose(petsc_mat, v, y_petsc);
450 CHKERR MatMultTranspose(block_mat, v, y_block);
451 CHKERR MatMultTransposeAdd(petsc_mat, v, y_petsc, y_petsc);
452 CHKERR MatMultTransposeAdd(block_mat, v, y_block, y_block);
453 CHKERR VecAXPY(y_petsc, -1.0, y_block);
454 CHKERR test("mult add transpose", y_petsc, nrm0);
455
456 // test schur nested mat with preconditioner
457 if (!no_preconditioner_block)
458 CHKERR schurSwitchPreconditioner(std::get<1>(*nested_data_ptr)[3]);
459 auto y_nested = createDMVector(simple->getDM());
460 CHKERR MatMult(petsc_mat, v, y_petsc);
461 CHKERR MatMult(nested_mat, v, y_nested);
462 CHKERR VecAXPY(y_petsc, -1.0, y_nested);
463 CHKERR test("mult nested", y_petsc, nrm0);
464
465 if (!no_preconditioner_block)
466 CHKERR schurSwitchPreconditioner(std::get<1>(*nested_data_ptr)[3]);
467 auto diag_mat = std::get<0>(*nested_data_ptr)[3];
468 auto diag_block_x = get_random_vector(block_dm);
469 auto diag_block_f = createDMVector(block_dm);
470 auto block_solved_x = createDMVector(block_dm);
471 CHKERR MatMult(diag_mat, diag_block_x, diag_block_f);
472
473 // That is if one like to use MatSolve directly, not though PC, as it is
474 // below
475 CHKERR MatSolve(diag_mat, diag_block_f, block_solved_x);
476 auto diag_block_f_test = createDMVector(block_dm);
477 CHKERR MatMult(diag_mat, block_solved_x, diag_block_f_test);
478 CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
479 CHKERR test("diag solve", diag_block_f_test, nrm0);
480 // Transpose solve test
481 CHKERR MatSolveTranspose(diag_mat, diag_block_f, block_solved_x);
482 CHKERR MatMultTranspose(diag_mat, block_solved_x, diag_block_f_test);
483 CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
484 CHKERR test("diag transpose solve", diag_block_f_test, nrm0);
485
486 // set matrix type to shell, set data
487 CHKERR DMSetMatType(block_dm, MATSHELL);
488 CHKERR DMMoFEMSetBlocMatData(block_dm, std::get<1>(*nested_data_ptr)[3]);
489 // set empty operator, since block data are already calculated
490 CHKERR DMKSPSetComputeOperators(
491 block_dm,
492 [](KSP, Mat, Mat, void *) {
493 MOFEM_LOG("WORLD", Sev::inform) << "empty operator";
494 return 0;
495 },
496 nullptr);
497
498 auto ksp = createKSP(m_field.get_comm());
499 CHKERR KSPSetDM(ksp, block_dm);
500 CHKERR KSPSetFromOptions(ksp);
501
502 // set preconditioner to block mat
503 auto get_pc = [](auto ksp) {
504 PC pc_raw;
505 CHKERR KSPGetPC(ksp, &pc_raw);
506 return SmartPetscObj<PC>(pc_raw, true); // bump reference
507 };
509 CHKERR KSPSetUp(ksp);
510
511 CHKERR VecZeroEntries(block_solved_x);
512 CHKERR KSPSolve(ksp, diag_block_f, block_solved_x);
513
514 CHKERR MatMult(diag_mat, block_solved_x, diag_block_f_test);
515 CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
516 CHKERR test("diag solve", diag_block_f_test, nrm0);
517
518 // solve transpose system
519 CHKERR VecZeroEntries(block_solved_x);
520 CHKERR KSPSolveTranspose(ksp, diag_block_f, block_solved_x);
521 CHKERR MatMultTranspose(diag_mat, block_solved_x, diag_block_f_test);
522 CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
523 CHKERR test("diag transpose solve", diag_block_f_test, nrm0);
524
525 // block matrix after cached solves. Without preconditioner blocks A00
526 // factors are stored in place and mult has to apply them.
527 CHKERR MatMult(petsc_mat, v, y_petsc);
528 CHKERR MatMult(block_mat, v, y_block);
529 CHKERR VecAXPY(y_petsc, -1.0, y_block);
530 CHKERR test("mult after solve", y_petsc, nrm0);
531 CHKERR MatMultTranspose(petsc_mat, v, y_petsc);
532 CHKERR MatMultTranspose(block_mat, v, y_block);
533 CHKERR VecAXPY(y_petsc, -1.0, y_block);
534 CHKERR test("mult transpose after solve", y_petsc, nrm0);
535 if (no_preconditioner_block) {
536 CHKERR MatMult(petsc_mat, v, y_petsc);
537 CHKERR MatMult(nested_mat, v, y_nested);
538 CHKERR VecAXPY(y_petsc, -1.0, y_nested);
539 CHKERR test("mult nested after solve", y_petsc, nrm0);
540 }
541
542 // Schur complement assembled from block matrix is compared with Schur
543 // complement assembled element by element (S)
544 auto test_schur = [&](auto msg, std::vector<boost::shared_ptr<Range>> ents,
545 Mat s_ref) {
547 auto s = matDuplicate(s_ref, MAT_DO_NOT_COPY_VALUES);
548 CHKERR assembleBlockMatSchur(m_field, block_mat, s, fields, ents, ao_up);
549 CHKERR MatAssemblyBegin(s, MAT_FINAL_ASSEMBLY);
550 CHKERR MatAssemblyEnd(s, MAT_FINAL_ASSEMBLY);
551 double nrm_ref;
552 CHKERR MatNorm(s_ref, NORM_FROBENIUS, &nrm_ref);
553 CHKERR MatAXPY(s, -1.0, s_ref, DIFFERENT_NONZERO_PATTERN);
554 double nrm;
555 CHKERR MatNorm(s, NORM_FROBENIUS, &nrm);
556 nrm /= nrm_ref;
557 double eps = 1e-10;
558 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-eps", &eps,
559 PETSC_NULLPTR);
560 MOFEM_LOG_CHANNEL("WORLD");
561 MOFEM_TAG_AND_LOG("WORLD", Sev::inform, "TestBlockMat")
562 << msg << ": norm of difference: " << nrm;
563 if (nrm > eps || std::isnan(nrm) || std::isinf(nrm))
564 SETERRQ(PETSC_COMM_WORLD, 1, "norm of difference is too big");
566 };
567
568 // zero matrices and assemble again with different values (two assembly
569 // passes double the values), factors have to be recomputed
570 auto reassemble = [&]() {
572 CHKERR MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY);
573 CHKERR MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY);
574 CHKERR MatZeroEntries(petsc_mat);
575 CHKERR MatZeroEntries(block_mat);
576 CHKERR MatZeroEntries(S);
577 for (int i = 0; i != 2; ++i)
579 simple->getDomainFEName(),
580 pip_mng->getDomainLhsFE());
581 CHKERR MatAssemblyBegin(petsc_mat, MAT_FINAL_ASSEMBLY);
582 CHKERR MatAssemblyEnd(petsc_mat, MAT_FINAL_ASSEMBLY);
583 CHKERR MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY);
584 CHKERR MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY);
586 };
587
588 CHKERR reassemble();
589 std::vector<boost::shared_ptr<Range>> all_ents = {nullptr, nullptr,
590 nullptr};
591 // element level Schur complement includes (T, T) preconditioner block,
592 // thus block matrix has to include preconditioner blocks as well
593 if (!no_preconditioner_block)
594 CHKERR schurSwitchPreconditioner(block_data_ptr);
595 CHKERR test_schur("schur from block", all_ents, S);
596
597 // half of elements eliminated, that is not consistent with nested matrix
598 Range vols, part_vols;
599 CHKERR moab.get_entities_by_dimension(0, 3, vols, true);
600 int nb_vols = 0;
601 for (auto e : vols)
602 if (nb_vols++ % 2 == 0)
603 part_vols.insert(e);
604 auto part_ptr = boost::make_shared<Range>(part_vols);
605 std::vector<boost::shared_ptr<Range>> part_ents = {part_ptr, part_ptr,
606 part_ptr};
607
608 {
609 // A00 is factorised in place by Schur assembly (in data, or in
610 // preconditioner blocks), elimination of different set of entities is
611 // not possible until matrix is zeroed
612 PetscPushErrorHandler(PetscIgnoreErrorHandler, PETSC_NULLPTR);
613 auto ierr = assembleBlockMatSchur(m_field, block_mat, S, fields,
614 part_ents, ao_up);
615 PetscPopErrorHandler();
616 if (!ierr)
617 SETERRQ(PETSC_COMM_WORLD, 1,
618 "Schur assembly with different elimination set should fail "
619 "on factorised matrix");
620 MOFEM_TAG_AND_LOG("WORLD", Sev::inform, "TestBlockMat")
621 << "schur assembly with inconsistent elimination set rejected";
622 }
623 if (!no_preconditioner_block)
624 CHKERR schurSwitchPreconditioner(block_data_ptr);
625
626 CHKERR MatMult(petsc_mat, v, y_petsc);
627 CHKERR VecNorm(y_petsc, NORM_2, &nrm0);
628 CHKERR MatMult(block_mat, v, y_block);
629 CHKERR VecAXPY(y_petsc, -1.0, y_block);
630 CHKERR test("mult after reassembly", y_petsc, nrm0);
631
632 CHKERR MatMult(diag_mat, diag_block_x, diag_block_f);
633 CHKERR MatSolve(diag_mat, diag_block_f, block_solved_x);
634 CHKERR MatMult(diag_mat, block_solved_x, diag_block_f_test);
635 CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
636 CHKERR test("diag solve after reassembly", diag_block_f_test, nrm0);
637
638 CHKERR MatMult(petsc_mat, v, y_petsc);
639 CHKERR MatMult(block_mat, v, y_block);
640 CHKERR VecAXPY(y_petsc, -1.0, y_block);
641 CHKERR test("mult after reassembly and solve", y_petsc, nrm0);
642 CHKERR MatMultTranspose(petsc_mat, v, y_petsc);
643 CHKERR MatMultTranspose(block_mat, v, y_block);
644 CHKERR VecAXPY(y_petsc, -1.0, y_block);
645 CHKERR test("mult transpose after reassembly and solve", y_petsc, nrm0);
646
647 CHKERR VecZeroEntries(block_solved_x);
648 CHKERR KSPSolve(ksp, diag_block_f, block_solved_x);
649 CHKERR MatMult(diag_mat, block_solved_x, diag_block_f_test);
650 CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
651 CHKERR test("ksp solve after reassembly", diag_block_f_test, nrm0);
652
653 // Without preconditioner blocks element level reference can be assembled
654 // with part of A00 eliminated.
655 if (no_preconditioner_block) {
656 // Schur complement with part of A00 eliminated. Element level reference
657 // uses the same entities. Block matrix can not use factors stored in
658 // place, scratch memory is used.
659 pip_lhs.pop_back();
660 pip_lhs.push_back(
661 createOpSchurAssembleEnd(fields, part_ents, ao_up, S, false, false));
662 CHKERR reassemble();
663 CHKERR test_schur("schur from block, part of A00 eliminated", part_ents,
664 S);
665 CHKERR MatMult(petsc_mat, v, y_petsc);
666 CHKERR VecNorm(y_petsc, NORM_2, &nrm0);
667 CHKERR MatMult(block_mat, v, y_block);
668 CHKERR VecAXPY(y_petsc, -1.0, y_block);
669 CHKERR test("mult after partial schur assembly", y_petsc, nrm0);
670 }
671
672 if (m_field.get_comm_rank() == 0) {
673 CHKERR schurSaveBlockMesh(block_data_ptr, "block_mesh.vtk");
674 }
675
676 petsc_mat.reset();
677 block_mat.reset();
678 }
680
681 // finish work cleaning memory, getting statistics, etc.
683
684 return 0;
685}
SmartPetscObj< KSP > ksp
#define MOFEM_TAG_AND_LOG(channel, severity, tag)
Tag and log in channel.
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
static const double eps
#define CATCH_ERRORS
Catch errors.
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
@ L2
field with C-1 continuity
Definition definitions.h:88
@ H1
continuous field
Definition definitions.h:85
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define CHK_MOAB_THROW(err, msg)
Check error code of MoAB function and throw MoFEM exception.
@ MOFEM_ATOM_TEST_INVALID
Definition definitions.h:40
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
constexpr int order
PetscErrorCode DMMoFEMCreateSubDM(DM subdm, DM dm, const char problem_name[])
Must be called by user to set Sub DM MoFEM data structures.
Definition DMMoFEM.cpp:244
PetscErrorCode DMMoFEMAddElement(DM dm, std::string fe_name)
add element to dm
Definition DMMoFEM.cpp:517
PetscErrorCode DMMoFEMSetSquareProblem(DM dm, PetscBool square_problem)
set squared problem
Definition DMMoFEM.cpp:479
PetscErrorCode DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
Definition DMMoFEM.cpp:267
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
Definition DMMoFEM.cpp:43
PetscErrorCode DMoFEMLoopFiniteElements(DM dm, const char fe_name[], MoFEM::FEMethod *method, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
Definition DMMoFEM.cpp:605
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
Definition DMMoFEM.hpp:1250
PetscErrorCode DMMoFEMAddSubFieldCol(DM dm, const char field_name[])
Definition DMMoFEM.cpp:309
auto createDMMatrix(DM dm)
Get smart matrix from DM.
Definition DMMoFEM.hpp:1207
virtual const Problem * get_problem(const std::string problem_name) const =0
Get the problem object.
@ PETSC
Standard PETSc assembly.
@ BLOCK_PRECONDITIONER_SCHUR
Block preconditioner Schur assembly.
@ BLOCK_SCHUR
Block Schur assembly.
static LoggerType & setLog(const std::string channel)
Set ans resset chanel logger.
#define MOFEM_LOG(channel, severity)
Log.
#define MOFEM_LOG_TAG(channel, tag)
Tag channel.
#define MOFEM_LOG_CHANNEL(channel)
Set and reset channel.
MoFEMErrorCode removeBlockDOFsOnEntities(const std::string problem_name, const std::string block_name, const std::string field_name, int lo, int hi, bool get_low_dim_ents=true, bool is_distributed_mesh=true)
Remove DOFs from problem based on block entities.
Definition BcManager.cpp:72
FTensor::Index< 'i', SPACE_DIM > i
const double v
phase velocity of light in medium (cm/ns)
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
static MoFEMErrorCodeGeneric< PetscErrorCode > ierr
auto createKSP(MPI_Comm comm)
OpSchurAssembleBase * createOpSchurAssembleEnd(std::vector< std::string > fields_name, std::vector< boost::shared_ptr< Range > > field_ents, SmartPetscObj< AO > ao, SmartPetscObj< Mat > schur, bool sym_schur, bool symm_op)
Construct a new Op Schur Assemble End object.
Definition Schur.cpp:4196
PetscErrorCode PetscOptionsGetInt(PetscOptions *, const char pre[], const char name[], PetscInt *ivalue, PetscBool *set)
MoFEMErrorCode schurSwitchPreconditioner(boost::shared_ptr< BlockStructure > block_mat_data)
Switch preconditioner.
Definition Schur.cpp:4385
MoFEMErrorCode setSchurA00MatSolvePC(SmartPetscObj< PC > pc)
Set PC for A00 block.
Definition Schur.cpp:4238
std::pair< SmartPetscObj< Mat >, boost::shared_ptr< NestSchurData > > createSchurNestedMatrix(boost::shared_ptr< NestSchurData > schur_net_data_ptr)
Create a Mat Diag Blocks object.
Definition Schur.cpp:4163
PetscErrorCode PetscOptionsGetBool(PetscOptions *, const char pre[], const char name[], PetscBool *bval, PetscBool *set)
PetscErrorCode PetscOptionsGetScalar(PetscOptions *, const char pre[], const char name[], PetscScalar *dval, PetscBool *set)
MoFEMErrorCode invertTensor3by3(ublas::matrix< T, L, A > &jac_data, ublas::vector< T, A > &det_data, ublas::matrix< T, L, A > &inv_jac_data)
Calculate inverse of tensor rank 2 at integration points.
auto getDMSubData(DM dm)
Get sub problem data structure.
Definition DMMoFEM.hpp:1308
MoFEMErrorCode DMMoFEMSetBlocMatData(DM dm, boost::shared_ptr< BlockStructure >)
Set data for block mat.
Definition DMMoFEM.cpp:1555
boost::shared_ptr< BlockStructure > createBlockMatStructure(DM dm, SchurFEOpsFEandFields schur_fe_op_vec)
Create block matrix structure.
Definition Schur.cpp:2415
boost::shared_ptr< NestSchurData > createSchurNestedMatrixStruture(std::pair< SmartPetscObj< DM >, SmartPetscObj< DM > > dms, boost::shared_ptr< BlockStructure > block_mat_data_ptr, std::vector< std::string > fields_names, std::vector< boost::shared_ptr< Range > > field_ents, bool add_preconditioner_block)
Create structure of nested matrix [A11 A10; A01 A00].
Definition Schur.cpp:3667
auto createAOMappingIS(IS isapp, IS ispetsc)
Creates an application mapping using two index sets.
MoFEMErrorCode schurSaveBlockMesh(boost::shared_ptr< BlockStructure > block_mat_data, std::string filename)
Save block matrix as a mesh.
Definition Schur.cpp:4400
SmartPetscObj< Mat > matDuplicate(Mat mat, MatDuplicateOption op)
static auto determinantTensor3by3(T &t)
Calculate the determinant of a 3x3 matrix or a tensor of rank 2.
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
SchurShellMatData createBlockMat(DM dm, boost::shared_ptr< BlockStructure > data)
Create a Schur Mat object.
Definition Schur.cpp:3072
MoFEMErrorCode assembleBlockMatSchur(MoFEM::Interface &m_field, Mat B, Mat S, std::vector< std::string > fields_name, std::vector< boost::shared_ptr< Range > > field_ents, SmartPetscObj< AO > ao)
Assemble Schur complement S = A11 - A10 A00^{-1} A01 from block matrix.
Definition Schur.cpp:3107
OpSchurAssembleBase * createOpSchurAssembleBegin()
Definition Schur.cpp:4191
static char help[]
SmartPetscObj< Mat > block_mat
constexpr int FIELD_DIM
SmartPetscObj< Mat > petsc_mat
Boundary condition manager for finite element problem setup.
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
Core (interface) class.
Definition Core.hpp:83
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
Definition Core.cpp:68
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Definition Core.cpp:123
Deprecated interface functions.
static boost::shared_ptr< SinkType > createSink(boost::shared_ptr< std::ostream > stream_ptr, std::string comm_filter)
Create a sink object.
static boost::shared_ptr< std::ostream > getStrmWorld()
Get the strm world object.
PipelineManager interface.
Simple interface for fast problem set-up.
Definition Simple.hpp:27
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.

Variable Documentation

◆ A

constexpr AssemblyType A
constexpr
Initial value:
=
AssemblyType::BLOCK_MAT

Definition at line 29 of file schur_test_diag_mat.cpp.

◆ block_mat

SmartPetscObj<Mat> block_mat

◆ debug

constexpr bool debug = false
constexpr

Definition at line 83 of file schur_test_diag_mat.cpp.

◆ FIELD_DIM

constexpr int FIELD_DIM = SPACE_DIM
constexpr

Definition at line 27 of file schur_test_diag_mat.cpp.

◆ help

char help[] = "...\n\n"
static

Definition at line 13 of file schur_test_diag_mat.cpp.

◆ I

constexpr IntegrationType I
constexpr
Initial value:
=
IntegrationType::GAUSS

Definition at line 31 of file schur_test_diag_mat.cpp.

◆ petsc_mat

SmartPetscObj<Mat> petsc_mat

◆ SPACE_DIM

constexpr int SPACE_DIM = 3
constexpr

[Define dimension]

Definition at line 26 of file schur_test_diag_mat.cpp.