v0.14.0
Loading...
Searching...
No Matches
test_broken_space.cpp

Testing broken spaces. Implementations works for 2d and 3d meshes, is aiming to test H-div broken base functions, and L2 base on skeleton.

Also, it test block matrix with Schur complement.

/**
* \example test_broken_space.cpp
*
* Testing broken spaces. Implementations works for 2d and 3d meshes, is aiming
* to test H-div broken base functions, and L2 base on skeleton.
*
* Also, it test block matrix with Schur complement.
*
*/
#include <MoFEM.hpp>
using namespace MoFEM;
static char help[] = "...\n\n";
constexpr bool debug = false;
constexpr AssemblyType AT =
(SCHUR_ASSEMBLE) ? AssemblyType::BLOCK_SCHUR
: AssemblyType::PETSC; //< selected assembly type
constexpr IntegrationType IT =
IntegrationType::GAUSS; //< selected integration type
constexpr int SPACE_DIM =
EXECUTABLE_DIMENSION; //< Space dimension of problem, mesh
using BoundaryEle =
using DomainEleOp = DomainEle::UserDataOperator;
using BdyEleOp = BoundaryEle::UserDataOperator;
using SideEleOp = EleOnSide::UserDataOperator;
struct SetUpSchur {
static boost::shared_ptr<SetUpSchur>
protected:
SetUpSchur() = default;
virtual ~SetUpSchur() = default;
};
int approx_order = 1;
int main(int argc, char *argv[]) {
MoFEM::Core::Initialize(&argc, &argv, (char *)0, help);
try {
//! [Register MoFEM discrete manager in PETSc]
DMType dm_name = "DMMOFEM";
CHKERR DMRegister_MoFEM(dm_name);
DMType dm_name_mg = "DMMOFEM_MG";
CHKERR DMRegister_MGViaApproxOrders(dm_name_mg);
//! [Register MoFEM discrete manager in PETSc
moab::Core mb_instance;
moab::Interface &moab = mb_instance;
// Add logging channel for example
auto core_log = logging::core::get();
core_log->add_sink(
LogManager::createSink(LogManager::getStrmWorld(), "AT"));
core_log->add_sink(
LogManager::createSink(LogManager::getStrmWorld(), "TIMER"));
LogManager::setLog("AT");
LogManager::setLog("TIMER");
MOFEM_LOG_TAG("AT", "atom_test");
MOFEM_LOG_TAG("TIMER", "timer");
// Create MoFEM instance
MoFEM::Core core(moab);
MoFEM::Interface &m_field = core;
auto *simple = m_field.getInterface<Simple>();
CHKERR simple->getOptions();
simple->getAddBoundaryFE() = true;
CHKERR simple->loadFile();
auto add_shared_entities_on_skeleton = [&]() {
auto boundary_meshset = simple->getBoundaryMeshSet();
auto skeleton_meshset = simple->getSkeletonMeshSet();
Range bdy_ents;
CHKERR m_field.get_moab().get_entities_by_handle(boundary_meshset,
bdy_ents, true);
Range skeleton_ents;
CHKERR m_field.get_moab().get_entities_by_dimension(
0, simple->getDim() - 1, skeleton_ents, true);
skeleton_ents = subtract(skeleton_ents, bdy_ents);
CHKERR m_field.get_moab().clear_meshset(&skeleton_meshset, 1);
CHKERR m_field.get_moab().add_entities(skeleton_meshset, skeleton_ents);
};
CHKERR add_shared_entities_on_skeleton();
// Declare elements
enum bases {
AINSWORTH,
AINSWORTH_LOBATTO,
DEMKOWICZ,
BERNSTEIN,
LASBASETOP
};
const char *list_bases[] = {"ainsworth", "ainsworth_lobatto", "demkowicz",
"bernstein"};
PetscBool flg;
PetscInt choice_base_value = AINSWORTH;
CHKERR PetscOptionsGetEList(PETSC_NULL, NULL, "-base", list_bases,
LASBASETOP, &choice_base_value, &flg);
if (flg != PETSC_TRUE)
SETERRQ(PETSC_COMM_SELF, MOFEM_IMPOSSIBLE_CASE, "base not set");
if (choice_base_value == AINSWORTH)
if (choice_base_value == AINSWORTH_LOBATTO)
else if (choice_base_value == DEMKOWICZ)
else if (choice_base_value == BERNSTEIN)
enum spaces { hdiv, hcurl, last_space };
const char *list_spaces[] = {"hdiv", "hcurl"};
PetscInt choice_space_value = hdiv;
CHKERR PetscOptionsGetEList(PETSC_NULL, NULL, "-space", list_spaces,
last_space, &choice_space_value, &flg);
if (flg != PETSC_TRUE)
SETERRQ(PETSC_COMM_SELF, MOFEM_IMPOSSIBLE_CASE, "space not set");
FieldSpace space = HDIV;
if (choice_space_value == hdiv)
space = HDIV;
else if (choice_space_value == hcurl)
space = HCURL;
CHKERR PetscOptionsGetInt(PETSC_NULL, "", "-order", &approx_order,
PETSC_NULL);
CHKERR simple->addDomainBrokenField("BROKEN", space, base, 1);
CHKERR simple->addDomainField("U", L2, base, 1);
CHKERR simple->addSkeletonField("HYBRID", L2, base, 1);
CHKERR simple->setFieldOrder("BROKEN", approx_order);
CHKERR simple->setFieldOrder("U", approx_order - 1);
CHKERR simple->setFieldOrder("HYBRID", approx_order - 1);
CHKERR simple->setUp();
auto bc_mng = m_field.getInterface<BcManager>();
CHKERR bc_mng->removeSideDOFs(simple->getProblemName(), "ZERO_FLUX",
"BROKEN", SPACE_DIM, 0, 1, true);
auto integration_rule = [](int, int, int p) { return 2 * p; };
auto assemble_domain_lhs = [&](auto &pip) {
IT>::OpMixDivTimesScalar<SPACE_DIM>;
auto beta = [](const double, const double, const double) constexpr {
return 1;
};
pip.push_back(new OpHdivHdiv("BROKEN", "BROKEN", beta));
auto unity = []() constexpr { return 1; };
pip.push_back(new OpHdivU("BROKEN", "U", unity, true));
// First: Iterate over skeleton FEs adjacent to Domain FEs
// Note: BoundaryEle, i.e. uses skeleton interation rule
auto op_loop_skeleton_side = new OpLoopSide<BoundaryEle>(
m_field, simple->getSkeletonFEName(), SPACE_DIM - 1, Sev::noisy);
op_loop_skeleton_side->getSideFEPtr()->getRuleHook = integration_rule;
op_loop_skeleton_side->getOpPtrVector(), {});
// Second: Iterate over domain FEs adjacent to skelton, particularly one
// domain element.
auto broken_data_ptr =
boost::make_shared<std::vector<BrokenBaseSideData>>();
// Note: EleOnSide, i.e. uses on domain projected skeleton rule
auto op_loop_domain_side = new OpBrokenLoopSide<EleOnSide>(
m_field, simple->getDomainFEName(), SPACE_DIM, Sev::noisy);
op_loop_domain_side->getOpPtrVector(), {HDIV});
op_loop_domain_side->getOpPtrVector().push_back(
new OpGetBrokenBaseSideData<SideEleOp>("BROKEN", broken_data_ptr));
op_loop_skeleton_side->getOpPtrVector().push_back(op_loop_domain_side);
IT>::OpBrokenSpaceConstrain<1>;
op_loop_skeleton_side->getOpPtrVector().push_back(
new OpC("HYBRID", broken_data_ptr, 1., true, false));
if (debug) {
// print skeleton elements on partition
constexpr int partition = 1;
auto op_print = new BdyEleOp(NOSPACE, BdyEleOp::OPSPACE);
op_print->doWorkRhsHook = [&](DataOperator *base_op_ptr, int side,
EntityType type,
if (auto op_ptr = dynamic_cast<BdyEleOp *>(base_op_ptr)) {
auto fe_method = op_ptr->getFEMethod();
auto num_fe = fe_method->numeredEntFiniteElementPtr;
if (m_field.get_comm_rank() == partition) {
if (num_fe->getPStatus() & PSTATUS_SHARED)
MOFEM_LOG("SELF", Sev::inform) << "Num FE: " << *num_fe;
}
}
};
op_loop_skeleton_side->getOpPtrVector().push_back(op_print);
};
pip.push_back(op_loop_skeleton_side);
};
auto assemble_domain_rhs = [&](auto &pip) {
auto source = [&](const double x, const double y,
const double z) constexpr {
return -1; // sin(100 * (x / 10.) * M_PI_2);
};
pip.push_back(new OpDomainSource("U", source));
};
auto *pip_mng = m_field.getInterface<PipelineManager>();
CHKERR assemble_domain_lhs(pip_mng->getOpDomainLhsPipeline());
CHKERR assemble_domain_rhs(pip_mng->getOpDomainRhsPipeline());
CHKERR pip_mng->setDomainLhsIntegrationRule(integration_rule);
CHKERR pip_mng->setDomainRhsIntegrationRule(integration_rule);
CHKERR pip_mng->setSkeletonLhsIntegrationRule(integration_rule);
CHKERR pip_mng->setSkeletonRhsIntegrationRule(integration_rule);
TetPolynomialBase::switchCacheBaseOn<HDIV>(
{pip_mng->getDomainLhsFE().get(), pip_mng->getDomainRhsFE().get()});
TetPolynomialBase::switchCacheBaseOn<L2>(
{pip_mng->getDomainLhsFE().get(), pip_mng->getDomainRhsFE().get()});
auto x = createDMVector(simple->getDM());
auto f = vectorDuplicate(x);
if (AT == PETSC) {
auto ksp = pip_mng->createKSP();
CHKERR KSPSetFromOptions(ksp);
BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
MOFEM_LOG("TIMER", Sev::inform) << "KSPSetUp";
CHKERR KSPSetUp(ksp);
MOFEM_LOG("TIMER", Sev::inform) << "KSPSetUp <= Done";
MOFEM_LOG("TIMER", Sev::inform) << "KSPSolve";
CHKERR KSPSolve(ksp, f, x);
MOFEM_LOG("TIMER", Sev::inform) << "KSPSolve <= Done";
CHKERR VecGhostUpdateBegin(x, INSERT_VALUES, SCATTER_FORWARD);
CHKERR VecGhostUpdateEnd(x, INSERT_VALUES, SCATTER_FORWARD);
CHKERR DMoFEMMeshToLocalVector(simple->getDM(), x, INSERT_VALUES,
SCATTER_REVERSE);
} else {
auto ksp = pip_mng->createKSP();
auto schur_ptr = SetUpSchur::createSetUpSchur(m_field);
BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
MOFEM_LOG("TIMER", Sev::inform) << "KSPSetUp";
CHKERR schur_ptr->setUp(ksp);
MOFEM_LOG("TIMER", Sev::inform) << "KSPSetUp <= Done";
MOFEM_LOG("TIMER", Sev::inform) << "KSPSolve";
CHKERR KSPSolve(ksp, f, x);
MOFEM_LOG("TIMER", Sev::inform) << "KSPSolve <= Done";
CHKERR VecGhostUpdateBegin(x, INSERT_VALUES, SCATTER_FORWARD);
CHKERR VecGhostUpdateEnd(x, INSERT_VALUES, SCATTER_FORWARD);
CHKERR DMoFEMMeshToLocalVector(simple->getDM(), x, INSERT_VALUES,
SCATTER_REVERSE);
}
auto check_residual = [&](auto x, auto f) {
auto *simple = m_field.getInterface<Simple>();
auto *pip_mng = m_field.getInterface<PipelineManager>();
// auto &skeleton_rhs = pip_mng->getOpSkeletonRhsPipeline();
auto &domain_rhs = pip_mng->getOpDomainRhsPipeline();
// skeleton_rhs.clear();
domain_rhs.clear();
auto div_flux_ptr = boost::make_shared<VectorDouble>();
"BROKEN", div_flux_ptr));
auto beta = [](double, double, double) constexpr { return 1; };
domain_rhs.push_back(new OpUDivFlux("U", div_flux_ptr, beta));
auto source = [&](const double x, const double y,
const double z) constexpr { return 1; };
domain_rhs.push_back(new OpDomainSource("U", source));
IT>::OpMixDivTimesU<3, 1, SPACE_DIM>;
auto flux_ptr = boost::make_shared<MatrixDouble>();
domain_rhs.push_back(
new OpCalculateHVecVectorField<3>("BROKEN", flux_ptr));
boost::shared_ptr<VectorDouble> u_ptr =
boost::make_shared<VectorDouble>();
domain_rhs.push_back(new OpCalculateScalarFieldValues("U", u_ptr));
domain_rhs.push_back(new OpHDivH("BROKEN", u_ptr, beta));
domain_rhs.push_back(new OpHdivFlux("BROKEN", flux_ptr, beta));
// First: Iterate over skeleton FEs adjacent to Domain FEs
// Note: BoundaryEle, i.e. uses skeleton interation rule
auto op_loop_skeleton_side = new OpLoopSide<BoundaryEle>(
m_field, simple->getSkeletonFEName(), SPACE_DIM - 1, Sev::noisy);
op_loop_skeleton_side->getSideFEPtr()->getRuleHook = integration_rule;
op_loop_skeleton_side->getOpPtrVector(), {});
// Second: Iterate over domain FEs adjacent to skelton, particularly one
// domain element.
auto broken_data_ptr =
boost::make_shared<std::vector<BrokenBaseSideData>>();
// Note: EleOnSide, i.e. uses on domain projected skeleton rule
auto op_loop_domain_side = new OpBrokenLoopSide<EleOnSide>(
m_field, simple->getDomainFEName(), SPACE_DIM, Sev::noisy);
op_loop_domain_side->getOpPtrVector(), {HDIV});
op_loop_domain_side->getOpPtrVector().push_back(
new OpGetBrokenBaseSideData<SideEleOp>("BROKEN", broken_data_ptr));
auto flux_mat_ptr = boost::make_shared<MatrixDouble>();
op_loop_domain_side->getOpPtrVector().push_back(
new OpCalculateHVecTensorField<1, 3>("BROKEN", flux_mat_ptr));
op_loop_domain_side->getOpPtrVector().push_back(
new OpSetFlux<SideEleOp>(broken_data_ptr, flux_mat_ptr));
// Assemble on skeleton
op_loop_skeleton_side->getOpPtrVector().push_back(op_loop_domain_side);
IT>::OpBrokenSpaceConstrainDHybrid<1>;
IT>::OpBrokenSpaceConstrainDFlux<1>;
op_loop_skeleton_side->getOpPtrVector().push_back(
new OpC_dHybrid("HYBRID", broken_data_ptr, 1.));
auto hybrid_ptr = boost::make_shared<MatrixDouble>();
op_loop_skeleton_side->getOpPtrVector().push_back(
new OpCalculateVectorFieldValues<1>("HYBRID", hybrid_ptr));
op_loop_skeleton_side->getOpPtrVector().push_back(
new OpC_dBroken(broken_data_ptr, hybrid_ptr, 1.));
// Add skeleton to domain pipeline
domain_rhs.push_back(op_loop_skeleton_side);
CHKERR VecZeroEntries(f);
CHKERR VecGhostUpdateBegin(f, INSERT_VALUES, SCATTER_FORWARD);
CHKERR VecGhostUpdateEnd(f, INSERT_VALUES, SCATTER_FORWARD);
pip_mng->getDomainRhsFE()->f = f;
pip_mng->getSkeletonRhsFE()->f = f;
pip_mng->getDomainRhsFE()->x = x;
pip_mng->getSkeletonRhsFE()->x = x;
simple->getDomainFEName(),
pip_mng->getDomainRhsFE());
CHKERR VecGhostUpdateBegin(f, ADD_VALUES, SCATTER_REVERSE);
CHKERR VecGhostUpdateEnd(f, ADD_VALUES, SCATTER_REVERSE);
CHKERR VecAssemblyBegin(f);
CHKERR VecAssemblyEnd(f);
double fnrm;
CHKERR VecNorm(f, NORM_2, &fnrm);
MOFEM_LOG_C("AT", Sev::inform, "Residual %3.4e", fnrm);
constexpr double eps = 1e-8;
if (fnrm > eps)
SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
"Residual norm larger than accepted");
};
auto calculate_error = [&]() {
// auto &skeleton_rhs = pip_mng->getOpSkeletonRhsPipeline();
auto &domain_rhs = pip_mng->getOpDomainRhsPipeline();
// skeleton_rhs.clear();
domain_rhs.clear();
auto u_grad_ptr = boost::make_shared<MatrixDouble>();
auto flux_val_ptr = boost::make_shared<MatrixDouble>();
auto div_val_ptr = boost::make_shared<VectorDouble>();
auto source_ptr = boost::make_shared<VectorDouble>();
domain_rhs.push_back(
domain_rhs.push_back(
new OpCalculateHVecVectorField<3, SPACE_DIM>("BROKEN", flux_val_ptr));
"BROKEN", div_val_ptr));
auto source = [&](const double x, const double y,
const double z) constexpr { return -1; };
domain_rhs.push_back(new OpGetTensor0fromFunc(source_ptr, source));
enum { DIV, GRAD, LAST };
auto mpi_vec = createVectorMPI(
m_field.get_comm(), (!m_field.get_comm_rank()) ? LAST : 0, LAST);
domain_rhs.push_back(
new OpCalcNormL2Tensor0(div_val_ptr, mpi_vec, DIV, source_ptr));
domain_rhs.push_back(new OpCalcNormL2Tensor1<SPACE_DIM>(
u_grad_ptr, mpi_vec, GRAD, flux_val_ptr));
simple->getDomainFEName(),
pip_mng->getDomainRhsFE());
CHKERR VecAssemblyBegin(mpi_vec);
CHKERR VecAssemblyEnd(mpi_vec);
if (!m_field.get_comm_rank()) {
const double *error_ind;
CHKERR VecGetArrayRead(mpi_vec, &error_ind);
MOFEM_LOG("AT", Sev::inform)
<< "Approximation error ||div flux - source||: "
<< std::sqrt(error_ind[DIV]);
MOFEM_LOG("AT", Sev::inform) << "Approximation error ||grad-flux||: "
<< std::sqrt(error_ind[GRAD]);
CHKERR VecRestoreArrayRead(mpi_vec, &error_ind);
}
};
auto get_post_proc_fe = [&]() {
auto post_proc_fe = boost::make_shared<PostProcEle>(m_field);
auto op_loop_side = new OpLoopSide<EleOnSide>(
m_field, simple->getDomainFEName(), SPACE_DIM, Sev::noisy,
boost::make_shared<
ForcesAndSourcesCore::UserDataOperator::AdjCache>());
post_proc_fe->getOpPtrVector().push_back(op_loop_side);
op_loop_side->getOpPtrVector(), {HDIV});
auto u_vec_ptr = boost::make_shared<VectorDouble>();
auto flux_mat_ptr = boost::make_shared<MatrixDouble>();
op_loop_side->getOpPtrVector().push_back(
new OpCalculateScalarFieldValues("U", u_vec_ptr));
op_loop_side->getOpPtrVector().push_back(
new OpCalculateHVecVectorField<3>("BROKEN", flux_mat_ptr));
op_loop_side->getOpPtrVector().push_back(
new OpPPMap(
post_proc_fe->getPostProcMesh(),
post_proc_fe->getMapGaussPts(),
{{"U", u_vec_ptr}},
{{"BROKEN", flux_mat_ptr}},
{}, {})
);
return post_proc_fe;
};
auto post_proc_fe = get_post_proc_fe();
simple->getBoundaryFEName(), post_proc_fe);
CHKERR post_proc_fe->writeFile("out_result.h5m");
CHKERR calculate_error();
CHKERR check_residual(x, f);
}
}
struct SetUpSchurImpl : public SetUpSchur {
SetUpSchurImpl(MoFEM::Interface &m_field) : SetUpSchur(), mField(m_field) {}
virtual ~SetUpSchurImpl() = default;
private:
};
auto pip_mng = mField.getInterface<PipelineManager>();
CHKERR KSPSetFromOptions(ksp);
PC pc;
CHKERR KSPGetPC(ksp, &pc);
PetscBool is_pcfs = PETSC_FALSE;
PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &is_pcfs);
if (is_pcfs) {
MOFEM_LOG("AT", Sev::inform) << "Setup Schur pc";
auto create_sub_dm = [&]() {
auto create_dm = [&](
std::string problem_name,
std::vector<std::string> fe_names,
std::vector<std::string> fields,
auto dm_type
) {
auto dm = createDM(mField.get_comm(), dm_type);
auto create_dm_imp = [&]() {
CHKERR DMMoFEMCreateSubDM(dm, simple->getDM(), problem_name.c_str());
for (auto fe : fe_names) {
}
CHKERR DMMoFEMAddElement(dm, simple->getSkeletonFEName());
for (auto field : fields) {
}
CHKERR DMSetUp(dm);
};
create_dm_imp(),
"Error in creating schurDM. It is possible that schurDM is "
"already created");
return dm;
};
auto schur_dm = create_dm(
"SCHUR",
{simple->getDomainFEName(), simple->getSkeletonFEName()},
{"HYBRID"},
"DMMOFEM_MG");
auto block_dm = create_dm(
"BLOCK",
{simple->getDomainFEName(), simple->getSkeletonFEName()},
{"BROKEN", "U"},
"DMMOFEM");
return std::make_tuple(schur_dm, block_dm);
};
auto get_nested_mat_data = [&](auto schur_dm, auto block_dm) {
auto block_mat_data = createBlockMatStructure(
simple->getDM(),
{
{
simple->getDomainFEName(),
{
{"BROKEN", "BROKEN"},
{"U", "U"},
{"BROKEN", "U"},
{"U", "BROKEN"}
}
},
{
simple->getSkeletonFEName(),
{
{"BROKEN", "HYBRID"}, {"HYBRID", "BROKEN"}
}
}
}
);
{schur_dm, block_dm}, block_mat_data,
{"BROKEN", "U"}, {nullptr, nullptr}, true
);
};
auto set_ops = [&](auto schur_dm) {
auto dm_is = getDMSubData(schur_dm)->getSmartRowIs();
auto ao_up = createAOMappingIS(dm_is, PETSC_NULL);
boost::shared_ptr<BlockStructure> block_data;
CHKERR DMMoFEMGetBlocMatData(simple->getDM(), block_data);
pip_mng->getOpDomainLhsPipeline().push_front(
pip_mng->getOpDomainLhsPipeline().push_back(
createOpSchurAssembleEnd({"BROKEN", "U"}, {nullptr, nullptr}, ao_up,
S, true, true)
);
auto pre_proc_schur_lhs_ptr = boost::make_shared<FEMethod>();
auto post_proc_schur_lhs_ptr = boost::make_shared<FEMethod>();
pre_proc_schur_lhs_ptr->preProcessHook = [this]() {
CHKERR MatZeroEntries(S);
MOFEM_LOG("AT", Sev::verbose) << "Lhs Assemble Begin";
};
post_proc_schur_lhs_ptr->postProcessHook = [this, ao_up,
post_proc_schur_lhs_ptr]() {
MOFEM_LOG("AT", Sev::verbose) << "Lhs Assemble End";
CHKERR MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY);
CHKERR MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY);
MOFEM_LOG("AT", Sev::verbose) << "Lhs Assemble Finish";
};
auto ksp_ctx_ptr = getDMKspCtx(simple->getDM());
ksp_ctx_ptr->getPreProcSetOperators().push_front(pre_proc_schur_lhs_ptr);
ksp_ctx_ptr->getPostProcSetOperators().push_back(post_proc_schur_lhs_ptr);
};
auto set_pc = [&](auto pc, auto block_dm) {
auto block_is = getDMSubData(block_dm)->getSmartRowIs();
CHKERR PCFieldSplitSetIS(pc, NULL, block_is);
CHKERR PCFieldSplitSetSchurPre(pc, PC_FIELDSPLIT_SCHUR_PRE_USER, S);
};
auto set_diagonal_pc = [&](auto pc, auto schur_dm) {
if (AT == BLOCK_SCHUR) {
auto A = createDMBlockMat(simple->getDM());
auto P = createDMNestSchurMat(simple->getDM());
CHKERR PCSetOperators(pc, A, P);
}
KSP *subksp;
CHKERR PCFieldSplitSchurGetSubKSP(pc, PETSC_NULL, &subksp);
auto get_pc = [](auto ksp) {
PC pc_raw;
CHKERR KSPGetPC(ksp, &pc_raw);
return pc_raw;
};
CHKERR setSchurA00MatSolvePC(SmartPetscObj<PC>(get_pc(subksp[0]), true));
auto set_pc_p_mg = [&](auto dm, auto pc) {
CHKERR PCSetDM(pc, dm);
PetscBool same = PETSC_FALSE;
PetscObjectTypeCompare((PetscObject)pc, PCMG, &same);
if (same) {
// By default do not use shell mg mat. Implementation of SOR is slow.
CHKERR PCSetFromOptions(pc);
}
};
CHKERR set_pc_p_mg(schur_dm, get_pc(subksp[1]));
CHKERR PetscFree(subksp);
};
auto [schur_dm, block_dm] = create_sub_dm();
if (AT == BLOCK_SCHUR) {
auto nested_mat_data = get_nested_mat_data(schur_dm, block_dm);
CHKERR DMMoFEMSetNestSchurData(simple->getDM(), nested_mat_data);
}
CHKERR MatSetDM(S, PETSC_NULL);
int bs = (SPACE_DIM == 2) ? NBEDGE_L2(approx_order - 1)
CHKERR MatSetBlockSize(S, bs);
CHKERR set_ops(schur_dm);
CHKERR set_pc(pc, block_dm);
DM solver_dm;
CHKERR KSPGetDM(ksp, &solver_dm);
if (AT == BLOCK_SCHUR)
CHKERR DMSetMatType(solver_dm, MATSHELL);
CHKERR KSPSetUp(ksp);
if (AT == BLOCK_SCHUR)
CHKERR set_diagonal_pc(pc, schur_dm);
} else {
SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
"PC is not set to PCFIELDSPLIT");
}
}
boost::shared_ptr<SetUpSchur>
return boost::shared_ptr<SetUpSchur>(new SetUpSchurImpl(m_field));
}
Integrator for broken space constraints.
#define MOFEM_LOG_C(channel, severity, format,...)
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
static char help[]
int main()
static const double eps
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpSource< 1, FIELD_DIM > OpDomainSource
constexpr int SPACE_DIM
ElementsAndOps< SPACE_DIM >::BoundaryEle BoundaryEle
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
[Define dimension]
#define SCHUR_ASSEMBLE
Definition contact.cpp:18
#define CATCH_ERRORS
Catch errors.
FieldApproximationBase
approximation base
Definition definitions.h:58
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base nme:nme847.
Definition definitions.h:60
@ AINSWORTH_LOBATTO_BASE
Definition definitions.h:62
@ DEMKOWICZ_JACOBI_BASE
Definition definitions.h:66
@ AINSWORTH_BERNSTEIN_BEZIER_BASE
Definition definitions.h:64
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
FieldSpace
approximation spaces
Definition definitions.h:82
@ L2
field with C-1 continuity
Definition definitions.h:88
@ NOSPACE
Definition definitions.h:83
@ HCURL
field with continuous tangents
Definition definitions.h:86
@ HDIV
field with continuous normal traction
Definition definitions.h:87
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_IMPOSSIBLE_CASE
Definition definitions.h:35
@ 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.
static const bool debug
auto integration_rule
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:215
PetscErrorCode DMMoFEMAddElement(DM dm, std::string fe_name)
add element to dm
Definition DMMoFEM.cpp:497
PetscErrorCode DMMoFEMSetSquareProblem(DM dm, PetscBool square_problem)
set squared problem
Definition DMMoFEM.cpp:456
PetscErrorCode DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode)
set local (or ghosted) vector values on mesh for partition only
Definition DMMoFEM.cpp:523
PetscErrorCode DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
Definition DMMoFEM.cpp:238
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:586
auto createDMVector(DM dm)
Get smart vector from DM.
Definition DMMoFEM.hpp:1099
PetscErrorCode DMMoFEMAddSubFieldCol(DM dm, const char field_name[])
Definition DMMoFEM.cpp:280
IntegrationType
Form integrator integration types.
AssemblyType
[Storage and set boundary conditions]
#define MOFEM_LOG(channel, severity)
Log.
#define MOFEM_LOG_TAG(channel, tag)
Tag channel.
#define NBFACETRI_L2(P)
Number of base functions on triangle for L2 space.
#define NBEDGE_L2(P)
Number of base functions on edge from L2 space.
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMixDivTimesScalar< 2 > OpHdivU
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
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:2186
PetscErrorCode PetscOptionsGetInt(PetscOptions *, const char pre[], const char name[], PetscInt *ivalue, PetscBool *set)
MoFEMErrorCode DMMoFEMGetBlocMatData(DM dm, boost::shared_ptr< BlockStructure > &)
Get data for block mat.
Definition DMMoFEM.cpp:1542
MoFEMErrorCode setSchurA00MatSolvePC(SmartPetscObj< PC > pc)
Set PC for A00 block.
Definition Schur.cpp:2223
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
boost::shared_ptr< PCMGSetUpViaApproxOrdersCtx > createPCMGSetUpViaApproxOrdersCtx(DM dm, Mat A, bool use_shell_mat)
createPCMGSetUpViaApproxOrdersCtx
auto createVectorMPI(MPI_Comm comm, PetscInt n, PetscInt N)
Create MPI Vector.
auto getDMKspCtx(DM dm)
Get KSP context data structure used by DM.
Definition DMMoFEM.hpp:1113
auto createDMHybridisedL2Matrix(DM dm)
Get smart hybridised L2 matrix from DM.
Definition DMMoFEM.hpp:1069
auto getDMSubData(DM dm)
Get sub problem data structure.
Definition DMMoFEM.hpp:1157
MoFEMErrorCode PCMGSetUpViaApproxOrders(PC pc, boost::shared_ptr< PCMGSetUpViaApproxOrdersCtx > ctx, int verb)
Function build MG structure.
boost::shared_ptr< BlockStructure > createBlockMatStructure(DM dm, SchurFEOpsFEandFields schur_fe_op_vec)
Create a Mat Diag Blocks object.
Definition Schur.cpp:1009
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)
Get the Schur Nest Mat Array object.
Definition Schur.cpp:1944
auto createAOMappingIS(IS isapp, IS ispetsc)
Creates an application mapping using two index sets.
PetscErrorCode PetscOptionsGetEList(PetscOptions *, const char pre[], const char name[], const char *const *list, PetscInt next, PetscInt *value, PetscBool *set)
MoFEMErrorCode DMMoFEMSetNestSchurData(DM dm, boost::shared_ptr< NestSchurData >)
Definition DMMoFEM.cpp:1562
auto createDMNestSchurMat(DM dm)
Definition DMMoFEM.hpp:1083
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
OpSchurAssembleBase * createOpSchurAssembleBegin()
Definition Schur.cpp:2181
auto createDMBlockMat(DM dm)
Definition DMMoFEM.hpp:1076
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
#define EXECUTABLE_DIMENSION
Definition plastic.cpp:13
static constexpr int approx_order
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::FaceSideEle EleOnSide
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpMixDivTimesU< 3, 1, 2 > OpHDivH
Integrate Rhs div flux base times temperature (T)
Definition seepage.cpp:115
Simple interface for fast problem set-up.
Definition BcManager.hpp:25
MoFEMErrorCode removeSideDOFs(const std::string problem_name, const std::string block_name, const std::string field_name, int bridge_dim, int lo, int hi, bool is_distributed_mesh=true)
Remove side DOFs.
virtual moab::Interface & get_moab()=0
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
Core (interface) class.
Definition Core.hpp:82
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
Definition Core.cpp:72
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Definition Core.cpp:112
base operator to do operations at Gauss Pt. level
Deprecated interface functions.
Data on single entity (This is passed as argument to DataOperator::doWork)
Get norm of input VectorDouble for Tensor0.
Get norm of input MatrixDouble for Tensor1.
Calculate tenor field using vectorial base, i.e. Hdiv/Hcurl.
Get vector field for H-div approximation.
Calculate divergence of vector field.
Get field gradients at integration pts for scalar filed rank 0, i.e. vector field.
Get value at integration points for scalar field.
Get values at integration pts for tensor filed rank 1, i.e. vector field.
Get values from scalar function at integration points and save them to VectorDouble for Tensor0.
Element used to execute operators on side of the element.
Post post-proc data at points from hash maps.
PipelineManager interface.
Simple interface for fast problem set-up.
Definition Simple.hpp:27
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
[Push operators to pipeline]
SetUpSchur()=default
virtual MoFEMErrorCode setUp(SmartPetscObj< KSP >)=0
virtual ~SetUpSchur()=default
static boost::shared_ptr< SetUpSchur > createSetUpSchur(MoFEM::Interface &m_field)
virtual ~SetUpSchurImpl()=default
SmartPetscObj< Mat > S
SetUpSchurImpl(MoFEM::Interface &m_field)
MoFEMErrorCode setUp(SmartPetscObj< KSP >)
MoFEM::Interface & mField
constexpr AssemblyType AT
constexpr IntegrationType IT
BoundaryEle::UserDataOperator BdyEleOp
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpBaseTimesVector< 3, SPACE_DIM, 1 > OpHdivFlux
Integrating Rhs flux base (1/k) flux (FLUX)
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMass< 3, SPACE_DIM > OpHdivHdiv
[Linear elastic problem]