Test block matrix and Schur complement matrix.
Test block matrix and Schur complement matrix.
static char help[] =
"...\n\n";
};
};
AssemblyType::BLOCK_MAT;
IntegrationType::GAUSS;
template <>
return MatSetValues<AssemblyTypeSelector<PETSC>>(
};
template <>
return MatSetValues<AssemblyTypeSelector<BLOCK_MAT>>(
};
template <>
return MatSetValues<AssemblyTypeSelector<BLOCK_SCHUR>>(
};
template <>
return MatSetValues<AssemblyTypeSelector<BLOCK_PRECONDITIONER_SCHUR>>(
};
[[maybe_unused]]
constexpr bool debug =
false;
int main(
int argc,
char *argv[]) {
try {
moab::Core moab_core;
moab::Interface &moab = moab_core;
DMType dm_name = "DMMOFEM";
auto core_log = logging::core::get();
core_log->add_sink(
LogManager::createSink(LogManager::getStrmWorld(), "Timeline"));
LogManager::setLog("Timeline");
PETSC_NULLPTR);
PetscBool no_preconditioner_block = PETSC_FALSE;
&no_preconditioner_block, PETSC_NULLPTR);
PetscBool uncoupled_so = PETSC_FALSE;
&uncoupled_so, PETSC_NULLPTR);
PetscBool empty_oo = PETSC_FALSE;
PETSC_NULLPTR);
PetscBool overflow_pivot = PETSC_FALSE;
&overflow_pivot, PETSC_NULLPTR);
PetscBool overflow_pivot_element = PETSC_FALSE;
&overflow_pivot_element, PETSC_NULLPTR);
if (overflow_pivot_element)
overflow_pivot = PETSC_TRUE;
"T", 0, 1);
std::vector<SchurFieldPair> block_pairs{
{"V", "V"}, {"T", "T"}, {"S", "S"}, {"O", "O"}, {"V", "T"},
{"T", "V"}, {"S", "T"}, {"T", "S"}, {"T", "O"}, {"O", "T"}};
if (!uncoupled_so) {
block_pairs.push_back({"S", "O"});
block_pairs.push_back({"O", "S"});
}
{{simple->getDomainFEName(), block_pairs}}));
auto [mat, block_data_ptr] = shell_data;
std::vector<std::string> fields{"T", "S", "O"};
{schur_dm, block_dm}, block_data_ptr,
fields, {nullptr, nullptr, nullptr},
no_preconditioner_block ? false : true
)
);
using OpMassBlockPreconditionerAssemble =
std::array<double, 12> bad_tet;
if (overflow_pivot_element) {
for (auto &fe : *prb->numeredFiniteElementsPtr)
if (fe->getPart() == m_field.get_comm_rank() &&
fe->getName() ==
simple->getDomainFEName())
owned.insert(fe->getEnt());
if (owned.empty())
const EntityHandle *conn;
int num_nodes;
CHKERR moab.get_connectivity(owned.back(), conn, num_nodes,
true);
CHKERR moab.get_coords(conn, 4, bad_tet.data());
}
auto in_bad = [&](double x, double y, double z) {
if (!overflow_pivot)
return false;
if (!overflow_pivot_element)
return true;
z - bad_tet[2]};
for (
int i = 0;
i != 3; ++
i)
for (
int j = 0;
j != 3; ++
j)
t_jac(
i,
j) = bad_tet[3 * (
j + 1) +
i] - bad_tet[
i];
double det;
double sum = 0;
for (
int i = 0;
i != 3; ++
i) {
for (
int j = 0;
j != 3; ++
j)
l += t_inv(
i,
j) * t_p(
j);
return false;
}
return sum < 1 + 1e-10;
};
auto ss_coeff = [&](double x, double y, double z) {
return in_bad(x, y, z) ? 1e-300 : 1.;
};
auto st_coeff = [&](double x, double y, double z) {
return in_bad(x, y, z) ? -1e10 / 2 : -1. / 2;
};
pip_mng->setDomainLhsIntegrationRule([](int, int, int o) { return 2 * o; });
auto &pip_lhs = pip_mng->getOpDomainLhsPipeline();
pip_lhs.push_back(new OpMassPETSCAssemble("V", "V"));
if (no_preconditioner_block)
pip_lhs.push_back(new OpMassPETSCAssemble("T", "T"));
pip_lhs.push_back(new OpMassPETSCAssemble("V", "T"));
pip_lhs.push_back(new OpMassPETSCAssemble("T", "V"));
pip_lhs.push_back(new OpMassPETSCAssemble("S", "S", ss_coeff));
pip_lhs.push_back(new OpMassPETSCAssemble("S", "T", st_coeff));
pip_lhs.push_back(new OpMassPETSCAssemble("T", "S", st_coeff));
if (!empty_oo)
pip_lhs.push_back(new OpMassPETSCAssemble("O", "O", close_zero));
pip_lhs.push_back(new OpMassPETSCAssemble("T", "O", beta));
pip_lhs.push_back(new OpMassPETSCAssemble("O", "T", beta));
if (!uncoupled_so) {
pip_lhs.push_back(new OpMassPETSCAssemble("S", "O", gamma));
pip_lhs.push_back(new OpMassPETSCAssemble("O", "S", beta));
}
pip_lhs.push_back(new OpMassBlockAssemble("V", "V"));
if (no_preconditioner_block)
pip_lhs.push_back(new OpMassBlockAssemble("T", "T"));
pip_lhs.push_back(new OpMassBlockAssemble("V", "T"));
pip_lhs.push_back(new OpMassBlockAssemble("T", "V"));
pip_lhs.push_back(new OpMassBlockAssemble("S", "S", ss_coeff));
pip_lhs.push_back(new OpMassBlockAssemble("S", "T", st_coeff));
pip_lhs.push_back(new OpMassBlockAssemble("T", "S", st_coeff));
if (!empty_oo)
pip_lhs.push_back(new OpMassBlockAssemble("O", "O", close_zero));
pip_lhs.push_back(new OpMassBlockAssemble("T", "O", beta));
pip_lhs.push_back(new OpMassBlockAssemble("O", "T", beta));
if (!uncoupled_so) {
pip_lhs.push_back(new OpMassBlockAssemble("S", "O", gamma));
pip_lhs.push_back(new OpMassBlockAssemble("O", "S", beta));
}
if (!no_preconditioner_block)
pip_lhs.push_back(new OpMassBlockPreconditionerAssemble("T", "T"));
fields, {nullptr, nullptr, nullptr}, ao_up, S, false, false)
);
{
BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
MOFEM_LOG(
"Timeline", Sev::inform) <<
"Assemble start";
pip_mng->getDomainLhsFE());
MOFEM_LOG(
"Timeline", Sev::inform) <<
"Assemble end";
}
{
BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
MOFEM_LOG(
"Timeline", Sev::inform) <<
"Mat assemble start";
MOFEM_LOG(
"Timeline", Sev::inform) <<
"Mat assemble end";
}
auto get_random_vector = [&](auto dm) {
PetscRandom rctx;
PetscRandomCreate(PETSC_COMM_WORLD, &rctx);
PetscRandomDestroy(&rctx);
};
auto v = get_random_vector(
simple->getDM());
auto test = [](auto msg, auto y, double norm0) {
PETSC_NULLPTR);
PetscReal norm;
CHKERR VecNorm(y, NORM_2, &norm);
norm = norm / norm0;
<< msg << ": norm of difference: " << norm;
if (norm >
eps || std::isnan(norm) || std::isinf(norm)) {
SETERRQ(PETSC_COMM_WORLD, 1, "norm of difference is too big");
}
};
std::vector<int> zero_rows_and_cols = {
0, 1, 10, 20,
500};
&*zero_rows_and_cols.begin(), 1, PETSC_NULLPTR,
PETSC_NULLPTR);
&*zero_rows_and_cols.begin(), 1, PETSC_NULLPTR,
PETSC_NULLPTR);
{
BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
<< "MatMult(petsc_mat, v, y_petsc) star";
<< "MatMult(petsc_mat, v, y_petsc) end";
}
double nrm0;
CHKERR VecNorm(y_petsc, NORM_2, &nrm0);
{
BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
<< "MatMult(block_mat, v, y_block) star";
<< "MatMult(block_mat, v, y_block) end";
}
CHKERR VecAXPY(y_petsc, -1.0, y_block);
CHKERR test(
"mult", y_petsc, nrm0);
CHKERR VecAXPY(y_petsc, -1.0, y_block);
CHKERR test(
"mult add", y_petsc, nrm0);
CHKERR VecAXPY(y_petsc, -1.0, y_block);
CHKERR test(
"mult transpose", y_petsc, nrm0);
CHKERR VecAXPY(y_petsc, -1.0, y_block);
CHKERR test(
"mult add transpose", y_petsc, nrm0);
if (!no_preconditioner_block)
CHKERR MatMult(nested_mat,
v, y_nested);
CHKERR VecAXPY(y_petsc, -1.0, y_nested);
CHKERR test(
"mult nested", y_petsc, nrm0);
if (!no_preconditioner_block)
auto diag_mat = std::get<0>(*nested_data_ptr)[3];
auto diag_block_x = get_random_vector(block_dm);
CHKERR MatMult(diag_mat, diag_block_x, diag_block_f);
CHKERR MatSolve(diag_mat, diag_block_f, block_solved_x);
CHKERR MatMult(diag_mat, block_solved_x, diag_block_f_test);
CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
CHKERR test(
"diag solve", diag_block_f_test, nrm0);
CHKERR MatSolveTranspose(diag_mat, diag_block_f, block_solved_x);
CHKERR MatMultTranspose(diag_mat, block_solved_x, diag_block_f_test);
CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
CHKERR test(
"diag transpose solve", diag_block_f_test, nrm0);
CHKERR DMSetMatType(block_dm, MATSHELL);
CHKERR DMKSPSetComputeOperators(
block_dm,
[](KSP, Mat, Mat, void *) {
MOFEM_LOG(
"WORLD", Sev::inform) <<
"empty operator";
return 0;
},
nullptr);
auto get_pc = [](
auto ksp) {
PC pc_raw;
};
CHKERR VecZeroEntries(block_solved_x);
CHKERR KSPSolve(
ksp, diag_block_f, block_solved_x);
CHKERR MatMult(diag_mat, block_solved_x, diag_block_f_test);
CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
CHKERR test(
"diag solve", diag_block_f_test, nrm0);
CHKERR VecZeroEntries(block_solved_x);
CHKERR KSPSolveTranspose(
ksp, diag_block_f, block_solved_x);
CHKERR MatMultTranspose(diag_mat, block_solved_x, diag_block_f_test);
CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
CHKERR test(
"diag transpose solve", diag_block_f_test, nrm0);
CHKERR VecAXPY(y_petsc, -1.0, y_block);
CHKERR test(
"mult after solve", y_petsc, nrm0);
CHKERR VecAXPY(y_petsc, -1.0, y_block);
CHKERR test(
"mult transpose after solve", y_petsc, nrm0);
if (no_preconditioner_block) {
CHKERR MatMult(nested_mat,
v, y_nested);
CHKERR VecAXPY(y_petsc, -1.0, y_nested);
CHKERR test(
"mult nested after solve", y_petsc, nrm0);
}
auto test_schur = [&](auto msg, std::vector<boost::shared_ptr<Range>> ents,
Mat s_ref) {
CHKERR MatAssemblyBegin(s, MAT_FINAL_ASSEMBLY);
CHKERR MatAssemblyEnd(s, MAT_FINAL_ASSEMBLY);
double nrm_ref;
CHKERR MatNorm(s_ref, NORM_FROBENIUS, &nrm_ref);
CHKERR MatAXPY(s, -1.0, s_ref, DIFFERENT_NONZERO_PATTERN);
double nrm;
CHKERR MatNorm(s, NORM_FROBENIUS, &nrm);
nrm /= nrm_ref;
PETSC_NULLPTR);
<< msg << ": norm of difference: " << nrm;
if (nrm >
eps || std::isnan(nrm) || std::isinf(nrm))
SETERRQ(PETSC_COMM_WORLD, 1, "norm of difference is too big");
};
auto reassemble = [&]() {
CHKERR MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY);
CHKERR MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY);
for (
int i = 0;
i != 2; ++
i)
pip_mng->getDomainLhsFE());
CHKERR MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY);
CHKERR MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY);
};
std::vector<boost::shared_ptr<Range>> all_ents = {nullptr, nullptr,
nullptr};
if (!no_preconditioner_block)
CHKERR test_schur(
"schur from block", all_ents, S);
CHKERR moab.get_entities_by_dimension(0, 3, vols,
true);
int nb_vols = 0;
for (auto e : vols)
if (nb_vols++ % 2 == 0)
part_vols.insert(e);
auto part_ptr = boost::make_shared<Range>(part_vols);
std::vector<boost::shared_ptr<Range>> part_ents = {part_ptr, part_ptr,
part_ptr};
{
PetscPushErrorHandler(PetscIgnoreErrorHandler, PETSC_NULLPTR);
part_ents, ao_up);
PetscPopErrorHandler();
SETERRQ(PETSC_COMM_WORLD, 1,
"Schur assembly with different elimination set should fail "
"on factorised matrix");
<< "schur assembly with inconsistent elimination set rejected";
}
if (!no_preconditioner_block)
CHKERR VecNorm(y_petsc, NORM_2, &nrm0);
CHKERR VecAXPY(y_petsc, -1.0, y_block);
CHKERR test(
"mult after reassembly", y_petsc, nrm0);
CHKERR MatMult(diag_mat, diag_block_x, diag_block_f);
CHKERR MatSolve(diag_mat, diag_block_f, block_solved_x);
CHKERR MatMult(diag_mat, block_solved_x, diag_block_f_test);
CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
CHKERR test(
"diag solve after reassembly", diag_block_f_test, nrm0);
CHKERR VecAXPY(y_petsc, -1.0, y_block);
CHKERR test(
"mult after reassembly and solve", y_petsc, nrm0);
CHKERR VecAXPY(y_petsc, -1.0, y_block);
CHKERR test(
"mult transpose after reassembly and solve", y_petsc, nrm0);
CHKERR VecZeroEntries(block_solved_x);
CHKERR KSPSolve(
ksp, diag_block_f, block_solved_x);
CHKERR MatMult(diag_mat, block_solved_x, diag_block_f_test);
CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
CHKERR test(
"ksp solve after reassembly", diag_block_f_test, nrm0);
if (no_preconditioner_block) {
pip_lhs.pop_back();
pip_lhs.push_back(
CHKERR test_schur(
"schur from block, part of A00 eliminated", part_ents,
S);
CHKERR VecNorm(y_petsc, NORM_2, &nrm0);
CHKERR VecAXPY(y_petsc, -1.0, y_block);
CHKERR test(
"mult after partial schur assembly", y_petsc, nrm0);
}
}
}
return 0;
}
#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)
static PetscErrorCode ierr
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
#define CATCH_ERRORS
Catch errors.
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
@ L2
field with C-1 continuity
#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
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
PetscErrorCode DMMoFEMCreateSubDM(DM subdm, DM dm, const char problem_name[])
Must be called by user to set Sub DM MoFEM data structures.
PetscErrorCode DMMoFEMAddElement(DM dm, std::string fe_name)
add element to dm
PetscErrorCode DMMoFEMSetSquareProblem(DM dm, PetscBool square_problem)
set squared problem
PetscErrorCode DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
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.
PetscErrorCode DMMoFEMAddSubFieldCol(DM dm, const char field_name[])
auto createDMMatrix(DM dm)
Get smart matrix from DM.
virtual const Problem * get_problem(const std::string problem_name) const =0
Get the problem object.
#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.
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
UBlasMatrix< double > MatrixDouble
implementation of Data Operators for Forces and Sources
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.
PetscErrorCode PetscOptionsGetInt(PetscOptions *, const char pre[], const char name[], PetscInt *ivalue, PetscBool *set)
MoFEMErrorCode schurSwitchPreconditioner(boost::shared_ptr< BlockStructure > block_mat_data)
Switch preconditioner.
MoFEMErrorCode setSchurA00MatSolvePC(SmartPetscObj< PC > pc)
Set PC for A00 block.
std::pair< SmartPetscObj< Mat >, boost::shared_ptr< NestSchurData > > createSchurNestedMatrix(boost::shared_ptr< NestSchurData > schur_net_data_ptr)
Create a Mat Diag Blocks object.
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.
MoFEMErrorCode DMMoFEMSetBlocMatData(DM dm, boost::shared_ptr< BlockStructure >)
Set data for block mat.
boost::shared_ptr< BlockStructure > createBlockMatStructure(DM dm, SchurFEOpsFEandFields schur_fe_op_vec)
Create block matrix structure.
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].
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.
SmartPetscObj< Mat > matDuplicate(Mat mat, MatDuplicateOption op)
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
MoFEMErrorCode determinantTensor3by3(T1 &t, T2 &det)
Calculate determinant 3 by 3.
SchurShellMatData createBlockMat(DM dm, boost::shared_ptr< BlockStructure > data)
Create a Schur Mat object.
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.
OpSchurAssembleBase * createOpSchurAssembleBegin()
constexpr IntegrationType I
SmartPetscObj< Mat > block_mat
SmartPetscObj< Mat > petsc_mat
FTensor::Index< 'm', 3 > m
Boundary condition manager for finite element problem setup.
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Deprecated interface functions.
Data on single entity (This is passed as argument to DataOperator::doWork)
boost::function< MoFEMErrorCode(ForcesAndSourcesCore::UserDataOperator *op_ptr, const EntitiesFieldData::EntData &row_data, const EntitiesFieldData::EntData &col_data, MatrixDouble &m)> MatSetValuesHook
PipelineManager interface.
Simple interface for fast problem set-up.
MoFEMErrorCode getOptions()
get options
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
Volume finite element base.