v0.15.0
Loading...
Searching...
No Matches
Public Member Functions | Public Attributes | Private Member Functions | Friends | List of all members
FreeSurface Struct Reference
Collaboration diagram for FreeSurface:
[legend]

Public Member Functions

 FreeSurface (MoFEM::Interface &m_field)
 Constructor.
 
MoFEMErrorCode runProblem ()
 Main function to run the complete free surface simulation.
 
MoFEMErrorCode makeRefProblem ()
 Create refined problem for mesh adaptation.
 

Public Attributes

MoFEM::InterfacemField
 

Private Member Functions

MoFEMErrorCode readMesh ()
 Read mesh from input file.
 
MoFEMErrorCode setupProblem ()
 Setup problem fields and parameters.
 
MoFEMErrorCode boundaryCondition ()
 Apply boundary conditions and initialize fields.
 
MoFEMErrorCode projectData ()
 Project solution data between mesh levels.
 
MoFEMErrorCode assembleSystem ()
 Assemble system operators and matrices.
 
MoFEMErrorCode solveSystem ()
 Solve the time-dependent free surface problem.
 
std::vector< RangefindEntitiesCrossedByPhaseInterface (size_t overlap)
 Find entities on refinement levels.
 
Range findParentsToRefine (Range ents, BitRefLevel level, BitRefLevel mask)
 Find parent entities that need refinement.
 
MoFEMErrorCode refineMesh (size_t overlap)
 Perform adaptive mesh refinement.
 
MoFEMErrorCode setParentDofs (boost::shared_ptr< FEMethod > fe_top, std::string field_name, ForcesAndSourcesCore::UserDataOperator::OpType op, BitRefLevel child_ent_bit, boost::function< boost::shared_ptr< ForcesAndSourcesCore >()> get_elem, int verbosity, LogManager::SeverityLevel sev)
 Create hierarchy of elements run on parent levels.
 

Friends

struct TSPrePostProc
 

Detailed Description

Examples
mofem/tutorials/vec-5/free_surface.cpp.

Definition at line 796 of file free_surface.cpp.

Constructor & Destructor Documentation

◆ FreeSurface()

FreeSurface::FreeSurface ( MoFEM::Interface m_field)
inline

Constructor.

Parameters
m_fieldReference to MoFEM interface for finite element operations

Definition at line 803 of file free_surface.cpp.

803: mField(m_field) {}
MoFEM::Interface & mField

Member Function Documentation

◆ assembleSystem()

MoFEMErrorCode FreeSurface::assembleSystem ( )
private

Assemble system operators and matrices.

[Data projection]

Returns
MoFEMErrorCode Success/failure code

Sets up finite element operators for:

  • Domain integration (momentum, phase field, mass conservation)
  • Boundary integration (surface tension, wetting angle, Lagrange multipliers)
  • Parent-child mesh hierarchies for adaptive refinement

[Push operators to pip]

Examples
mofem/tutorials/vec-5/free_surface.cpp.

Definition at line 2019 of file free_surface.cpp.

2019 {
2021 auto simple = mField.getInterface<Simple>();
2022
2023 using UDO = ForcesAndSourcesCore::UserDataOperator;
2024
2025 auto add_parent_field_domain = [&](auto fe, auto op, auto field) {
2026 return setParentDofs(
2027 fe, field, op, bit(get_skin_parent_bit()),
2028
2029 [&]() {
2030 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2031 new DomainParentEle(mField));
2032 return fe_parent;
2033 },
2034
2035 QUIET, Sev::noisy);
2036 };
2037
2038 auto add_parent_field_bdy = [&](auto fe, auto op, auto field) {
2039 return setParentDofs(
2040 fe, field, op, bit(get_skin_parent_bit()),
2041
2042 [&]() {
2043 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2045 return fe_parent;
2046 },
2047
2048 QUIET, Sev::noisy);
2049 };
2050
2051 auto test_bit_child = [](FEMethod *fe_ptr) {
2052 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
2053 get_start_bit() + nb_levels - 1);
2054 };
2055
2056 auto dot_u_ptr = boost::make_shared<MatrixDouble>();
2057 auto u_ptr = boost::make_shared<MatrixDouble>();
2058 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
2059 auto dot_h_ptr = boost::make_shared<VectorDouble>();
2060 auto h_ptr = boost::make_shared<VectorDouble>();
2061 auto grad_h_ptr = boost::make_shared<MatrixDouble>();
2062 auto g_ptr = boost::make_shared<VectorDouble>();
2063 auto grad_g_ptr = boost::make_shared<MatrixDouble>();
2064 auto lambda_ptr = boost::make_shared<VectorDouble>();
2065 auto p_ptr = boost::make_shared<VectorDouble>();
2066 auto div_u_ptr = boost::make_shared<VectorDouble>();
2067
2068 // Push element from reference configuration to current configuration in 3d
2069 // space
2070 auto set_domain_general = [&](auto fe) {
2072 auto &pip = fe->getOpPtrVector();
2073
2075
2077 fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
2078
2079 [&]() {
2080 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2081 new DomainParentEle(mField));
2083 fe_parent->getOpPtrVector(), {H1});
2084 return fe_parent;
2085 },
2086
2087 QUIET, Sev::noisy);
2088
2089 CHKERR add_parent_field_domain(fe, UDO::OPROW, "U");
2090 pip.push_back(
2092 pip.push_back(new OpCalculateVectorFieldValues<U_FIELD_DIM>("U", u_ptr));
2094 "U", grad_u_ptr));
2095
2096 switch (coord_type) {
2097 case CARTESIAN:
2098 pip.push_back(
2100 "U", div_u_ptr));
2101 break;
2102 case CYLINDRICAL:
2103 pip.push_back(
2105 "U", div_u_ptr));
2106 break;
2107 default:
2108 SETERRQ(PETSC_COMM_WORLD, MOFEM_NOT_IMPLEMENTED,
2109 "Coordinate system not implemented");
2110 }
2111
2112 CHKERR add_parent_field_domain(fe, UDO::OPROW, "H");
2113 pip.push_back(new OpCalculateScalarFieldValuesDot("H", dot_h_ptr));
2114 pip.push_back(new OpCalculateScalarFieldValues("H", h_ptr));
2115 pip.push_back(
2116 new OpCalculateScalarFieldGradient<SPACE_DIM>("H", grad_h_ptr));
2117
2118 CHKERR add_parent_field_domain(fe, UDO::OPROW, "G");
2119 pip.push_back(new OpCalculateScalarFieldValues("G", g_ptr));
2120 pip.push_back(
2121 new OpCalculateScalarFieldGradient<SPACE_DIM>("G", grad_g_ptr));
2122
2123 CHKERR add_parent_field_domain(fe, UDO::OPROW, "P");
2124 pip.push_back(new OpCalculateScalarFieldValues("P", p_ptr));
2126 };
2127
2128 auto set_domain_rhs = [&](auto fe) {
2130 auto &pip = fe->getOpPtrVector();
2131
2132 CHKERR set_domain_general(fe);
2133
2134 CHKERR add_parent_field_domain(fe, UDO::OPROW, "U");
2135 pip.push_back(new OpRhsU("U", dot_u_ptr, u_ptr, grad_u_ptr, h_ptr,
2136 grad_h_ptr, g_ptr, p_ptr));
2137
2138 CHKERR add_parent_field_domain(fe, UDO::OPROW, "H");
2139 pip.push_back(new OpRhsH<false>("H", u_ptr, dot_h_ptr, h_ptr, grad_h_ptr,
2140 grad_g_ptr));
2141
2142 CHKERR add_parent_field_domain(fe, UDO::OPROW, "G");
2143 pip.push_back(new OpRhsG<false>("G", h_ptr, grad_h_ptr, g_ptr));
2144
2145 CHKERR add_parent_field_domain(fe, UDO::OPROW, "P");
2146 pip.push_back(new OpDomainAssembleScalar(
2147 "P", div_u_ptr, [](const double r, const double, const double) {
2148 return cylindrical(r);
2149 }));
2150 pip.push_back(new OpDomainAssembleScalar(
2151 "P", p_ptr, [](const double r, const double, const double) {
2152 return eps * cylindrical(r);
2153 }));
2155 };
2156
2157 auto set_domain_lhs = [&](auto fe) {
2159 auto &pip = fe->getOpPtrVector();
2160
2161 CHKERR set_domain_general(fe);
2162
2163 CHKERR add_parent_field_domain(fe, UDO::OPROW, "U");
2164 {
2165 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "U");
2166 pip.push_back(new OpLhsU_dU("U", u_ptr, grad_u_ptr, h_ptr));
2167 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "H");
2168 pip.push_back(
2169 new OpLhsU_dH("U", "H", dot_u_ptr, u_ptr, grad_u_ptr, h_ptr, g_ptr));
2170
2171 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "G");
2172 pip.push_back(new OpLhsU_dG("U", "G", grad_h_ptr));
2173 }
2174
2175 CHKERR add_parent_field_domain(fe, UDO::OPROW, "H");
2176 {
2177 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "U");
2178 pip.push_back(new OpLhsH_dU("H", "U", grad_h_ptr));
2179 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "H");
2180 pip.push_back(new OpLhsH_dH<false>("H", u_ptr, h_ptr, grad_g_ptr));
2181 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "G");
2182 pip.push_back(new OpLhsH_dG<false>("H", "G", h_ptr));
2183 }
2184
2185 CHKERR add_parent_field_domain(fe, UDO::OPROW, "G");
2186 {
2187 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "H");
2188 pip.push_back(new OpLhsG_dH<false>("G", "H", h_ptr));
2189 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "G");
2190 pip.push_back(new OpLhsG_dG("G"));
2191 }
2192
2193 CHKERR add_parent_field_domain(fe, UDO::OPROW, "P");
2194 {
2195 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "U");
2196
2197 switch (coord_type) {
2198 case CARTESIAN:
2199 pip.push_back(new OpMixScalarTimesDiv<CARTESIAN>(
2200 "P", "U",
2201 [](const double r, const double, const double) {
2202 return cylindrical(r);
2203 },
2204 true, false));
2205 break;
2206 case CYLINDRICAL:
2207 pip.push_back(new OpMixScalarTimesDiv<CYLINDRICAL>(
2208 "P", "U",
2209 [](const double r, const double, const double) {
2210 return cylindrical(r);
2211 },
2212 true, false));
2213 break;
2214 default:
2215 SETERRQ(PETSC_COMM_WORLD, MOFEM_NOT_IMPLEMENTED,
2216 "Coordinate system not implemented");
2217 }
2218
2219 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "P");
2220 pip.push_back(new OpDomainMassP("P", "P", [](double r, double, double) {
2221 return eps * cylindrical(r);
2222 }));
2223 }
2224
2226 };
2227
2228 auto get_block_name = [](auto name) {
2229 return boost::format("%s(.*)") % "WETTING_ANGLE";
2230 };
2231
2232 auto get_blocks = [&](auto &&name) {
2233 return mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(
2234 std::regex(name.str()));
2235 };
2236
2237 auto set_boundary_rhs = [&](auto fe) {
2239 auto &pip = fe->getOpPtrVector();
2240
2242 fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
2243
2244 [&]() {
2245 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2247 return fe_parent;
2248 },
2249
2250 QUIET, Sev::noisy);
2251
2252 CHKERR add_parent_field_bdy(fe, UDO::OPROW, "U");
2253 pip.push_back(new OpCalculateVectorFieldValues<U_FIELD_DIM>("U", u_ptr));
2254
2255 CHKERR add_parent_field_bdy(fe, UDO::OPROW, "L");
2256 pip.push_back(new OpCalculateScalarFieldValues("L", lambda_ptr));
2257 pip.push_back(new OpNormalConstrainRhs("L", u_ptr));
2258
2260 pip, mField, "L", {}, "INFLUX",
2261 [](double r, double, double) { return cylindrical(r); }, Sev::inform);
2262
2263 CHKERR add_parent_field_bdy(fe, UDO::OPROW, "U");
2264 pip.push_back(new OpNormalForceRhs("U", lambda_ptr));
2265
2266 auto wetting_block = get_blocks(get_block_name("WETTING_ANGLE"));
2267 if (wetting_block.size()) {
2268 // push operators to the side element which is called from op_bdy_side
2269 auto op_bdy_side =
2270 new OpLoopSide<SideEle>(mField, simple->getDomainFEName(), SPACE_DIM);
2271 op_bdy_side->getSideFEPtr()->exeTestHook = test_bit_child;
2272
2274 op_bdy_side->getOpPtrVector(), {H1});
2275
2277 op_bdy_side->getSideFEPtr(), "", UDO::OPSPACE,
2279
2280 [&]() {
2281 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2282 new DomainParentEle(mField));
2284 fe_parent->getOpPtrVector(), {H1});
2285 return fe_parent;
2286 },
2287
2288 QUIET, Sev::noisy);
2289
2290 CHKERR add_parent_field_domain(op_bdy_side->getSideFEPtr(), UDO::OPROW,
2291 "H");
2292 op_bdy_side->getOpPtrVector().push_back(
2293 new OpCalculateScalarFieldGradient<SPACE_DIM>("H", grad_h_ptr));
2294 // push bdy side op
2295 pip.push_back(op_bdy_side);
2296
2297 // push operators for rhs wetting angle
2298 for (auto &b : wetting_block) {
2299 Range force_edges;
2300 std::vector<double> attr_vec;
2301 CHKERR b->getMeshsetIdEntitiesByDimension(
2302 mField.get_moab(), SPACE_DIM - 1, force_edges, true);
2303 b->getAttributes(attr_vec);
2304 if (attr_vec.size() != 1)
2305 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
2306 "Should be one attribute");
2307 MOFEM_LOG("FS", Sev::inform) << "Wetting angle: " << attr_vec.front();
2308 // need to find the attributes and pass to operator
2309 CHKERR add_parent_field_bdy(fe, UDO::OPROW, "G");
2310 pip.push_back(new OpWettingAngleRhs(
2311 "G", grad_h_ptr, boost::make_shared<Range>(force_edges),
2312 attr_vec.front()));
2313 }
2314 }
2315
2317 };
2318
2319 auto set_boundary_lhs = [&](auto fe) {
2321 auto &pip = fe->getOpPtrVector();
2322
2324 fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
2325
2326 [&]() {
2327 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2329 return fe_parent;
2330 },
2331
2332 QUIET, Sev::noisy);
2333
2334 CHKERR add_parent_field_bdy(fe, UDO::OPROW, "L");
2335 CHKERR add_parent_field_bdy(fe, UDO::OPCOL, "U");
2336 pip.push_back(new OpNormalConstrainLhs("L", "U"));
2337
2338 auto wetting_block = get_blocks(get_block_name("WETTING_ANGLE"));
2339 if (wetting_block.size()) {
2340 auto col_ind_ptr = boost::make_shared<std::vector<VectorInt>>();
2341 auto col_diff_base_ptr = boost::make_shared<std::vector<MatrixDouble>>();
2342
2343 // push operators to the side element which is called from op_bdy_side
2344 auto op_bdy_side =
2345 new OpLoopSide<SideEle>(mField, simple->getDomainFEName(), SPACE_DIM);
2346 op_bdy_side->getSideFEPtr()->exeTestHook = test_bit_child;
2347
2349 op_bdy_side->getOpPtrVector(), {H1});
2350
2352 op_bdy_side->getSideFEPtr(), "", UDO::OPSPACE,
2354
2355 [&]() {
2356 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2357 new DomainParentEle(mField));
2359 fe_parent->getOpPtrVector(), {H1});
2360 return fe_parent;
2361 },
2362
2363 QUIET, Sev::noisy);
2364
2365 CHKERR add_parent_field_domain(op_bdy_side->getSideFEPtr(), UDO::OPROW,
2366 "H");
2367 op_bdy_side->getOpPtrVector().push_back(
2368 new OpCalculateScalarFieldGradient<SPACE_DIM>("H", grad_h_ptr));
2369 CHKERR add_parent_field_domain(op_bdy_side->getSideFEPtr(), UDO::OPCOL,
2370 "H");
2371 op_bdy_side->getOpPtrVector().push_back(
2372 new OpLoopSideGetDataForSideEle("H", col_ind_ptr, col_diff_base_ptr));
2373
2374 // push bdy side op
2375 pip.push_back(op_bdy_side);
2376
2377 // push operators for lhs wetting angle
2378 for (auto &b : wetting_block) {
2379 Range force_edges;
2380 std::vector<double> attr_vec;
2381 CHKERR b->getMeshsetIdEntitiesByDimension(
2382 mField.get_moab(), SPACE_DIM - 1, force_edges, true);
2383 b->getAttributes(attr_vec);
2384 if (attr_vec.size() != 1)
2385 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
2386 "Should be one attribute");
2387 MOFEM_LOG("FS", Sev::inform)
2388 << "wetting angle edges size " << force_edges.size();
2389
2390 CHKERR add_parent_field_bdy(fe, UDO::OPROW, "G");
2391 pip.push_back(new OpWettingAngleLhs(
2392 "G", grad_h_ptr, col_ind_ptr, col_diff_base_ptr,
2393 boost::make_shared<Range>(force_edges), attr_vec.front()));
2394 }
2395 }
2396
2398 };
2399
2400 auto *pip_mng = mField.getInterface<PipelineManager>();
2401
2402 CHKERR set_domain_rhs(pip_mng->getCastDomainRhsFE());
2403 CHKERR set_domain_lhs(pip_mng->getCastDomainLhsFE());
2404 CHKERR set_boundary_rhs(pip_mng->getCastBoundaryRhsFE());
2405 CHKERR set_boundary_lhs(pip_mng->getCastBoundaryLhsFE());
2406
2407 CHKERR pip_mng->setDomainRhsIntegrationRule(integration_rule);
2408 CHKERR pip_mng->setDomainLhsIntegrationRule(integration_rule);
2409 CHKERR pip_mng->setBoundaryRhsIntegrationRule(integration_rule);
2410 CHKERR pip_mng->setBoundaryLhsIntegrationRule(integration_rule);
2411
2412 pip_mng->getDomainLhsFE()->exeTestHook = test_bit_child;
2413 pip_mng->getDomainRhsFE()->exeTestHook = test_bit_child;
2414 pip_mng->getBoundaryLhsFE()->exeTestHook = test_bit_child;
2415 pip_mng->getBoundaryRhsFE()->exeTestHook = test_bit_child;
2416
2418}
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
@ QUIET
@ 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 ...
@ MOFEM_INVALID_DATA
Definition definitions.h:36
@ MOFEM_NOT_IMPLEMENTED
Definition definitions.h:32
@ CYLINDRICAL
@ CARTESIAN
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
auto cylindrical
Coordinate system scaling factor.
ElementsAndOps< SPACE_DIM >::DomainParentEle DomainParentEle
ElementsAndOps< SPACE_DIM >::BoundaryParentEle BoundaryParentEle
auto integration_rule
constexpr int SPACE_DIM
int coord_type
auto get_skin_parent_bit
auto get_start_bit
OpDomainMassH OpDomainMassP
int nb_levels
FormsIntegrators< DomainEleOp >::Assembly< A >::LinearForm< I >::OpBaseTimesScalar< BASE_DIM > OpDomainAssembleScalar
double eps
FormsIntegrators< DomainEleOp >::Assembly< A >::BiLinearForm< I >::OpMixScalarTimesDiv< SPACE_DIM, COORD_TYPE > OpMixScalarTimesDiv
auto bit
Create bit reference level.
#define MOFEM_LOG(channel, severity)
Log.
auto test_bit_child
lambda function used to select elements on which finite element pipelines are executed.
OpCalculateScalarFieldValuesFromPetscVecImpl< PetscData::CTX_SET_X_T > OpCalculateScalarFieldValuesDot
int r
Definition sdf.py:8
MoFEMErrorCode setParentDofs(boost::shared_ptr< FEMethod > fe_top, std::string field_name, ForcesAndSourcesCore::UserDataOperator::OpType op, BitRefLevel child_ent_bit, boost::function< boost::shared_ptr< ForcesAndSourcesCore >()> get_elem, int verbosity, LogManager::SeverityLevel sev)
Create hierarchy of elements run on parent levels.
Add operators pushing bases from local to physical configuration.
virtual moab::Interface & get_moab()=0
Structure for user loop methods on finite elements.
Interface for managing meshsets containing materials and boundary conditions.
Calculate divergence of vector field at integration points.
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Specialization for double precision scalar field values calculation.
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Approximate field values for given petsc vector.
Specialization for double precision vector field values calculation.
Element used to execute operators on side of the element.
PipelineManager interface.
Simple interface for fast problem set-up.
Definition Simple.hpp:27
BitRefLevel & getBitRefLevel()
Get the BitRefLevel.
Definition Simple.hpp:415
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.

◆ boundaryCondition()

MoFEMErrorCode FreeSurface::boundaryCondition ( )
private

Apply boundary conditions and initialize fields.

[Set up problem]

Returns
MoFEMErrorCode Success/failure code
  • Initializes phase field using analytical or Python functions
  • Solves initialization problem for consistent initial conditions
  • Performs mesh refinement based on interface location
  • Removes DOFs for boundary conditions (symmetry, fixed, etc.)

[Boundary condition]

Examples
mofem/tutorials/vec-5/free_surface.cpp.

Definition at line 1098 of file free_surface.cpp.

1098 {
1100
1101#ifdef PYTHON_INIT_SURFACE
1102 auto get_py_surface_init = []() {
1103 auto py_surf_init = boost::make_shared<SurfacePython>();
1104 CHKERR py_surf_init->surfaceInit("surface.py");
1105 surfacePythonWeakPtr = py_surf_init;
1106 return py_surf_init;
1107 };
1108 auto py_surf_init = get_py_surface_init();
1109#endif
1110
1111 auto simple = mField.getInterface<Simple>();
1112 auto pip_mng = mField.getInterface<PipelineManager>();
1113 auto bc_mng = mField.getInterface<BcManager>();
1114 auto bit_mng = mField.getInterface<BitRefManager>();
1115 auto dm = simple->getDM();
1116
1117 using UDO = ForcesAndSourcesCore::UserDataOperator;
1118
1119 auto reset_bits = [&]() {
1121 BitRefLevel start_mask;
1122 for (auto s = 0; s != get_start_bit(); ++s)
1123 start_mask[s] = true;
1124 // reset bit ref levels
1125 CHKERR bit_mng->lambdaBitRefLevel(
1126 [&](EntityHandle ent, BitRefLevel &bit) { bit &= start_mask; });
1127 Range level0;
1128 CHKERR bit_mng->getEntitiesByRefLevel(bit(0), BitRefLevel().set(), level0);
1129 CHKERR bit_mng->setNthBitRefLevel(level0, get_current_bit(), true);
1130 CHKERR bit_mng->setNthBitRefLevel(level0, get_projection_bit(), true);
1132 };
1133
1134 auto add_parent_field = [&](auto fe, auto op, auto field) {
1135 return setParentDofs(
1136 fe, field, op, bit(get_skin_parent_bit()),
1137
1138 [&]() {
1139 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1140 new DomainParentEle(mField));
1141 return fe_parent;
1142 },
1143
1144 QUIET, Sev::noisy);
1145 };
1146
1147 auto h_ptr = boost::make_shared<VectorDouble>();
1148 auto grad_h_ptr = boost::make_shared<MatrixDouble>();
1149 auto g_ptr = boost::make_shared<VectorDouble>();
1150 auto grad_g_ptr = boost::make_shared<MatrixDouble>();
1151
1152 auto set_generic = [&](auto fe) {
1154 auto &pip = fe->getOpPtrVector();
1155
1157
1159 fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
1160
1161 [&]() {
1162 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1163 new DomainParentEle(mField));
1165 fe_parent->getOpPtrVector(), {H1});
1166 return fe_parent;
1167 },
1168
1169 QUIET, Sev::noisy);
1170
1171 CHKERR add_parent_field(fe, UDO::OPROW, "H");
1172 pip.push_back(new OpCalculateScalarFieldValues("H", h_ptr));
1173 pip.push_back(
1174 new OpCalculateScalarFieldGradient<SPACE_DIM>("H", grad_h_ptr));
1175
1176 CHKERR add_parent_field(fe, UDO::OPROW, "G");
1177 pip.push_back(new OpCalculateScalarFieldValues("G", g_ptr));
1178 pip.push_back(
1179 new OpCalculateScalarFieldGradient<SPACE_DIM>("G", grad_g_ptr));
1180
1182 };
1183
1184 auto post_proc = [&](auto exe_test) {
1186 auto post_proc_fe = boost::make_shared<PostProcEleDomain>(mField);
1187 post_proc_fe->exeTestHook = exe_test;
1188
1189 CHKERR set_generic(post_proc_fe);
1190
1192
1193 post_proc_fe->getOpPtrVector().push_back(
1194
1195 new OpPPMap(post_proc_fe->getPostProcMesh(),
1196 post_proc_fe->getMapGaussPts(),
1197
1198 {{"H", h_ptr}, {"G", g_ptr}},
1199
1200 {{"GRAD_H", grad_h_ptr}, {"GRAD_G", grad_g_ptr}},
1201
1202 {},
1203
1204 {}
1205
1206 )
1207
1208 );
1209
1210 CHKERR DMoFEMLoopFiniteElements(dm, "dFE", post_proc_fe);
1211 CHKERR post_proc_fe->writeFile("out_init.h5m");
1212
1214 };
1215
1216 auto solve_init = [&](auto exe_test) {
1218
1219 pip_mng->getOpDomainRhsPipeline().clear();
1220 pip_mng->getOpDomainLhsPipeline().clear();
1221
1222 auto set_domain_rhs = [&](auto fe) {
1224 CHKERR set_generic(fe);
1225 auto &pip = fe->getOpPtrVector();
1226
1227 CHKERR add_parent_field(fe, UDO::OPROW, "H");
1228 pip.push_back(new OpRhsH<true>("H", nullptr, nullptr, h_ptr, grad_h_ptr,
1229 grad_g_ptr));
1230 CHKERR add_parent_field(fe, UDO::OPROW, "G");
1231 pip.push_back(new OpRhsG<true>("G", h_ptr, grad_h_ptr, g_ptr));
1233 };
1234
1235 auto set_domain_lhs = [&](auto fe) {
1237
1238 CHKERR set_generic(fe);
1239 auto &pip = fe->getOpPtrVector();
1240
1241 CHKERR add_parent_field(fe, UDO::OPROW, "H");
1242 CHKERR add_parent_field(fe, UDO::OPCOL, "H");
1243 pip.push_back(new OpLhsH_dH<true>("H", nullptr, h_ptr, grad_g_ptr));
1244
1245 CHKERR add_parent_field(fe, UDO::OPCOL, "G");
1246 pip.push_back(new OpLhsH_dG<true>("H", "G", h_ptr));
1247
1248 CHKERR add_parent_field(fe, UDO::OPROW, "G");
1249 pip.push_back(new OpLhsG_dG("G"));
1250
1251 CHKERR add_parent_field(fe, UDO::OPCOL, "H");
1252 pip.push_back(new OpLhsG_dH<true>("G", "H", h_ptr));
1254 };
1255
1256 auto create_subdm = [&]() {
1257 auto level_ents_ptr = boost::make_shared<Range>();
1258 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByRefLevel(
1259 bit(get_current_bit()), BitRefLevel().set(), *level_ents_ptr);
1260
1261 DM subdm;
1262 CHKERR DMCreate(mField.get_comm(), &subdm);
1263 CHKERR DMSetType(subdm, "DMMOFEM");
1264 CHKERR DMMoFEMCreateSubDM(subdm, dm, "SUB_INIT");
1265 CHKERR DMMoFEMAddElement(subdm, simple->getDomainFEName());
1266 CHKERR DMMoFEMSetSquareProblem(subdm, PETSC_TRUE);
1267 CHKERR DMMoFEMSetDestroyProblem(subdm, PETSC_TRUE);
1268
1269 for (auto f : {"H", "G"}) {
1270 CHKERR DMMoFEMAddSubFieldRow(subdm, f, level_ents_ptr);
1271 CHKERR DMMoFEMAddSubFieldCol(subdm, f, level_ents_ptr);
1272 }
1273 CHKERR DMSetUp(subdm);
1274
1275 if constexpr (debug) {
1276 if (mField.get_comm_size() == 1) {
1277 auto dm_ents = get_dofs_ents_all(SmartPetscObj<DM>(subdm, true));
1278 CHKERR save_range(mField.get_moab(), "sub_dm_init_ents_verts.h5m",
1279 dm_ents.subset_by_type(MBVERTEX));
1280 dm_ents = subtract(dm_ents, dm_ents.subset_by_type(MBVERTEX));
1281 CHKERR save_range(mField.get_moab(), "sub_dm_init_ents.h5m", dm_ents);
1282 }
1283 }
1284
1285 return SmartPetscObj<DM>(subdm);
1286 };
1287
1288 auto subdm = create_subdm();
1289
1290 pip_mng->getDomainRhsFE().reset();
1291 pip_mng->getDomainLhsFE().reset();
1292 CHKERR pip_mng->setDomainRhsIntegrationRule(integration_rule);
1293 CHKERR pip_mng->setDomainLhsIntegrationRule(integration_rule);
1294 pip_mng->getDomainLhsFE()->exeTestHook = exe_test;
1295 pip_mng->getDomainRhsFE()->exeTestHook = exe_test;
1296
1297 CHKERR set_domain_rhs(pip_mng->getCastDomainRhsFE());
1298 CHKERR set_domain_lhs(pip_mng->getCastDomainLhsFE());
1299
1300 auto D = createDMVector(subdm);
1301 auto snes = pip_mng->createSNES(subdm);
1302 auto snes_ctx_ptr = getDMSnesCtx(subdm);
1303
1304 auto set_section_monitor = [&](auto solver) {
1306 CHKERR SNESMonitorSet(solver,
1307 (MoFEMErrorCode(*)(SNES, PetscInt, PetscReal,
1308 void *))MoFEMSNESMonitorFields,
1309 (void *)(snes_ctx_ptr.get()), nullptr);
1310
1312 };
1313
1314 auto print_section_field = [&]() {
1316
1317 auto section =
1318 mField.getInterface<ISManager>()->sectionCreate("SUB_INIT");
1319 PetscInt num_fields;
1320 CHKERR PetscSectionGetNumFields(section, &num_fields);
1321 for (int f = 0; f < num_fields; ++f) {
1322 const char *field_name;
1323 CHKERR PetscSectionGetFieldName(section, f, &field_name);
1324 MOFEM_LOG("FS", Sev::inform)
1325 << "Field " << f << " " << std::string(field_name);
1326 }
1327
1329 };
1330
1331 CHKERR set_section_monitor(snes);
1332 CHKERR print_section_field();
1333
1334 for (auto f : {"U", "P", "H", "G", "L"}) {
1335 CHKERR mField.getInterface<FieldBlas>()->setField(0, f);
1336 }
1337
1338 CHKERR SNESSetFromOptions(snes);
1339 auto B = createDMMatrix(subdm);
1340 CHKERR SNESSetJacobian(snes, B, B,
1341 PETSC_NULLPTR, PETSC_NULLPTR);
1342 CHKERR SNESSolve(snes, PETSC_NULLPTR, D);
1343
1344 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
1345 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
1346 CHKERR DMoFEMMeshToLocalVector(subdm, D, INSERT_VALUES, SCATTER_REVERSE);
1347
1349 };
1350
1351 CHKERR reset_bits();
1352 CHKERR solve_init(
1353 [](FEMethod *fe_ptr) { return get_fe_bit(fe_ptr).test(0); });
1355
1356 for (auto f : {"U", "P", "H", "G", "L"}) {
1357 CHKERR mField.getInterface<FieldBlas>()->setField(0, f);
1358 }
1359 CHKERR solve_init([](FEMethod *fe_ptr) {
1360 return get_fe_bit(fe_ptr).test(get_start_bit() + nb_levels - 1);
1361 });
1362
1363 CHKERR post_proc([](FEMethod *fe_ptr) {
1364 return get_fe_bit(fe_ptr).test(get_start_bit() + nb_levels - 1);
1365 });
1366
1367 pip_mng->getOpDomainRhsPipeline().clear();
1368 pip_mng->getOpDomainLhsPipeline().clear();
1369
1370 // Remove DOFs where boundary conditions are set
1371 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "SYM_X",
1372 "U", 0, 0);
1373 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "SYM_X",
1374 "L", 0, 0);
1375 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "SYM_Y",
1376 "U", 1, 1);
1377 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "SYM_Y",
1378 "L", 1, 1);
1379 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "FIX", "U",
1380 0, SPACE_DIM);
1381 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "FIX", "L",
1382 0, 0);
1383 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "ZERO",
1384 "L", 0, 0);
1385
1387}
auto save_range
Save range of entities to file.
auto get_fe_bit
Get bit reference level from finite element.
auto get_dofs_ents_all
Get all entities with DOFs in the problem - used for debugging.
int refine_overlap
auto get_current_bit
dofs bit used to do calculations
auto get_projection_bit
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:488
PetscErrorCode DMMoFEMSetSquareProblem(DM dm, PetscBool square_problem)
set squared problem
Definition DMMoFEM.cpp:450
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:514
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:576
auto createDMVector(DM dm)
Get smart vector from DM.
Definition DMMoFEM.hpp:1234
PetscErrorCode DMMoFEMAddSubFieldCol(DM dm, const char field_name[])
Definition DMMoFEM.cpp:280
auto createDMMatrix(DM dm)
Get smart matrix from DM.
Definition DMMoFEM.hpp:1191
double D
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
std::bitset< BITREFLEVEL_SIZE > BitRefLevel
Bit structure attached to each entity identifying to what mesh entity is attached.
Definition Types.hpp:40
PetscErrorCode DMMoFEMSetDestroyProblem(DM dm, PetscBool destroy_problem)
Definition DMMoFEM.cpp:434
static const bool debug
MoFEMErrorCode MoFEMSNESMonitorFields(SNES snes, PetscInt its, PetscReal fgnorm, SnesCtx *ctx)
Sens monitor printing residual field by field.
Definition SnesCtx.cpp:596
auto getDMSnesCtx(DM dm)
Get SNES context data structure used by DM.
Definition DMMoFEM.hpp:1262
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
constexpr auto field_name
MoFEMErrorCode refineMesh(size_t overlap)
Perform adaptive mesh refinement.
Boundary condition manager for finite element problem setup.
Managing BitRefLevels.
virtual int get_comm_size() const =0
virtual MPI_Comm & get_comm() const =0
Basic algebra on fields.
Definition FieldBlas.hpp:21
Section manager is used to create indexes and sections.
Definition ISManager.hpp:23
Post post-proc data at points from hash maps.
intrusive_ptr for managing petsc objects

◆ findEntitiesCrossedByPhaseInterface()

std::vector< Range > FreeSurface::findEntitiesCrossedByPhaseInterface ( size_t  overlap)
private

Find entities on refinement levels.

Parameters
overlapLevel of overlap around phase interface
Returns
Vector of entity ranges for each refinement level

Identifies mesh entities that cross the phase interface by analyzing phase field values at vertices. Returns entities that need refinement at each hierarchical level with specified overlap.

Examples
mofem/tutorials/vec-5/free_surface.cpp.

Definition at line 2908 of file free_surface.cpp.

2908 {
2909
2910 auto &moab = mField.get_moab();
2911 auto bit_mng = mField.getInterface<BitRefManager>();
2912 auto comm_mng = mField.getInterface<CommInterface>();
2913
2914 Range vertices;
2915 CHK_THROW_MESSAGE(bit_mng->getEntitiesByTypeAndRefLevel(
2916 bit(0), BitRefLevel().set(), MBVERTEX, vertices),
2917 "can not get vertices on bit 0");
2918
2919 auto &dofs_mi = mField.get_dofs()->get<Unique_mi_tag>();
2920 auto field_bit_number = mField.get_field_bit_number("H");
2921
2922 Range plus_range, minus_range;
2923 std::vector<EntityHandle> plus, minus;
2924
2925 // get vertices on level 0 on plus and minus side
2926 for (auto p = vertices.pair_begin(); p != vertices.pair_end(); ++p) {
2927
2928 const auto f = p->first;
2929 const auto s = p->second;
2930
2931 // Lowest Dof UId for given field (field bit number) on entity f
2932 const auto lo_uid = DofEntity::getLoFieldEntityUId(field_bit_number, f);
2933 const auto hi_uid = DofEntity::getHiFieldEntityUId(field_bit_number, s);
2934 auto it = dofs_mi.lower_bound(lo_uid);
2935 const auto hi_it = dofs_mi.upper_bound(hi_uid);
2936
2937 plus.clear();
2938 minus.clear();
2939 plus.reserve(std::distance(it, hi_it));
2940 minus.reserve(std::distance(it, hi_it));
2941
2942 for (; it != hi_it; ++it) {
2943 const auto v = (*it)->getFieldData();
2944 if (v > 0)
2945 plus.push_back((*it)->getEnt());
2946 else
2947 minus.push_back((*it)->getEnt());
2948 }
2949
2950 plus_range.insert_list(plus.begin(), plus.end());
2951 minus_range.insert_list(minus.begin(), minus.end());
2952 }
2953
2954 MOFEM_LOG_CHANNEL("SYNC");
2955 MOFEM_TAG_AND_LOG("SYNC", Sev::noisy, "FS")
2956 << "Plus range " << plus_range << endl;
2957 MOFEM_TAG_AND_LOG("SYNC", Sev::noisy, "FS")
2958 << "Minus range " << minus_range << endl;
2960
2961 auto get_elems = [&](auto &ents, auto bit, auto mask) {
2962 Range adj;
2963 CHK_MOAB_THROW(moab.get_adjacencies(ents, SPACE_DIM, false, adj,
2964 moab::Interface::UNION),
2965 "can not get adjacencies");
2966 CHK_THROW_MESSAGE(bit_mng->filterEntitiesByRefLevel(bit, mask, adj),
2967 "can not filter elements with bit 0");
2968 return adj;
2969 };
2970
2971 CHKERR comm_mng->synchroniseEntities(plus_range);
2972 CHKERR comm_mng->synchroniseEntities(minus_range);
2973
2974 std::vector<Range> ele_plus(nb_levels), ele_minus(nb_levels);
2975 ele_plus[0] = get_elems(plus_range, bit(0), BitRefLevel().set());
2976 ele_minus[0] = get_elems(minus_range, bit(0), BitRefLevel().set());
2977 auto common = intersect(ele_plus[0], ele_minus[0]);
2978 ele_plus[0] = subtract(ele_plus[0], common);
2979 ele_minus[0] = subtract(ele_minus[0], common);
2980
2981 auto get_children = [&](auto &p, auto &c) {
2983 CHKERR bit_mng->updateRangeByChildren(p, c);
2984 c = c.subset_by_dimension(SPACE_DIM);
2986 };
2987
2988 for (auto l = 1; l != nb_levels; ++l) {
2989 CHK_THROW_MESSAGE(get_children(ele_plus[l - 1], ele_plus[l]),
2990 "get children");
2991 CHK_THROW_MESSAGE(get_children(ele_minus[l - 1], ele_minus[l]),
2992 "get children");
2993 }
2994
2995 auto get_level = [&](auto &p, auto &m, auto z, auto bit, auto mask) {
2996 Range l;
2998 bit_mng->getEntitiesByDimAndRefLevel(bit, mask, SPACE_DIM, l),
2999 "can not get vertices on bit");
3000 l = subtract(l, p);
3001 l = subtract(l, m);
3002 for (auto f = 0; f != z; ++f) {
3003 Range conn;
3004 CHK_MOAB_THROW(moab.get_connectivity(l, conn, true), "");
3005 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(conn);
3006 l = get_elems(conn, bit, mask);
3007 }
3008 return l;
3009 };
3010
3011 std::vector<Range> vec_levels(nb_levels);
3012 for (auto l = nb_levels - 1; l >= 0; --l) {
3013 vec_levels[l] = get_level(ele_plus[l], ele_minus[l], 2 * overlap, bit(l),
3014 BitRefLevel().set());
3015 }
3016
3017 if constexpr (debug) {
3018 if (mField.get_comm_size() == 1) {
3019 for (auto l = 0; l != nb_levels; ++l) {
3020 std::string name = (boost::format("out_r%d.h5m") % l).str();
3021 CHK_THROW_MESSAGE(save_range(mField.get_moab(), name, vec_levels[l]),
3022 "save mesh");
3023 }
3024 }
3025 }
3026
3027 return vec_levels;
3028}
#define MOFEM_LOG_SEVERITY_SYNC(comm, severity)
Synchronise "SYNC" on curtain severity level.
#define MOFEM_TAG_AND_LOG(channel, severity, tag)
Tag and log in channel.
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
#define CHK_MOAB_THROW(err, msg)
Check error code of MoAB function and throw MoFEM exception.
FTensor::Index< 'l', SPACE_DIM > l
virtual const DofEntity_multiIndex * get_dofs() const =0
Get the dofs object.
#define MOFEM_LOG_CHANNEL(channel)
Set and reset channel.
const double c
speed of light (cm/ns)
const double v
phase velocity of light in medium (cm/ns)
FTensor::Index< 'm', 3 > m
Managing BitRefLevels.
virtual FieldBitNumber get_field_bit_number(const std::string name) const =0
get field bit number
static UId getLoFieldEntityUId(const FieldBitNumber bit, const EntityHandle ent)
static UId getHiFieldEntityUId(const FieldBitNumber bit, const EntityHandle ent)

◆ findParentsToRefine()

Range FreeSurface::findParentsToRefine ( Range  ents,
BitRefLevel  level,
BitRefLevel  mask 
)
private

Find parent entities that need refinement.

Parameters
entsChild entities requiring refinement
levelBit level for entity marking
maskBit mask for filtering
Returns
Range of parent entities to refine

Traverses mesh hierarchy to find parent entities that should be refined to accommodate interface tracking requirements.

Examples
mofem/tutorials/vec-5/free_surface.cpp.

◆ makeRefProblem()

MoFEMErrorCode FreeSurface::makeRefProblem ( )

Create refined problem for mesh adaptation.

Returns
MoFEMErrorCode Success/failure code

Creates mesh refinement data structures needed for adaptive meshing

Examples
mofem/tutorials/vec-5/free_surface.cpp.

◆ projectData()

MoFEMErrorCode FreeSurface::projectData ( )
private

Project solution data between mesh levels.

[Boundary condition]

Returns
MoFEMErrorCode Success/failure code

Projects field data from coarse to fine mesh levels during refinement. Handles both time stepping vectors (for theta method) and regular fields. Uses L2 projection with mass matrix assembly.

[Data projection]

Zero DOFs, used by FieldBlas

get TSTheta data operators

Examples
mofem/tutorials/vec-5/free_surface.cpp.

Definition at line 1391 of file free_surface.cpp.

1391 {
1393
1394 // FIXME: Functionality in this method should be improved (projection should
1395 // be done field by field), generalized, and move to become core
1396 // functionality.
1397
1398 auto simple = mField.getInterface<Simple>();
1399 auto pip_mng = mField.getInterface<PipelineManager>();
1400 auto bit_mng = mField.getInterface<BitRefManager>();
1401 auto field_blas = mField.getInterface<FieldBlas>();
1402
1403 // Store all existing elements pipelines, replace them by data projection
1404 // pipelines, to put them back when projection is done.
1405 auto fe_domain_lhs = pip_mng->getDomainLhsFE();
1406 auto fe_domain_rhs = pip_mng->getDomainRhsFE();
1407 auto fe_bdy_lhs = pip_mng->getBoundaryLhsFE();
1408 auto fe_bdy_rhs = pip_mng->getBoundaryRhsFE();
1409
1410 pip_mng->getDomainLhsFE().reset();
1411 pip_mng->getDomainRhsFE().reset();
1412 pip_mng->getBoundaryLhsFE().reset();
1413 pip_mng->getBoundaryRhsFE().reset();
1414
1415 using UDO = ForcesAndSourcesCore::UserDataOperator;
1416
1417 // extract field data for domain parent element
1418 auto add_parent_field_domain = [&](auto fe, auto op, auto field, auto bit) {
1419 return setParentDofs(
1420 fe, field, op, bit,
1421
1422 [&]() {
1423 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1424 new DomainParentEle(mField));
1425 return fe_parent;
1426 },
1427
1428 QUIET, Sev::noisy);
1429 };
1430
1431 // extract field data for boundary parent element
1432 auto add_parent_field_bdy = [&](auto fe, auto op, auto field, auto bit) {
1433 return setParentDofs(
1434 fe, field, op, bit,
1435
1436 [&]() {
1437 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1439 return fe_parent;
1440 },
1441
1442 QUIET, Sev::noisy);
1443 };
1444
1445 // run this element on element with given bit, otherwise run other nested
1446 // element
1447 auto create_run_parent_op = [&](auto parent_fe_ptr, auto this_fe_ptr,
1448 auto fe_bit) {
1449 auto parent_mask = fe_bit;
1450 parent_mask.flip();
1451 return new OpRunParent(parent_fe_ptr, BitRefLevel().set(), parent_mask,
1452 this_fe_ptr, fe_bit, BitRefLevel().set(), QUIET,
1453 Sev::inform);
1454 };
1455
1456 // create hierarchy of nested elements
1457 auto get_parents_vel_fe_ptr = [&](auto this_fe_ptr, auto fe_bit) {
1458 std::vector<boost::shared_ptr<DomainParentEle>> parents_elems_ptr_vec;
1459 for (int l = 0; l < nb_levels; ++l)
1460 parents_elems_ptr_vec.emplace_back(
1461 boost::make_shared<DomainParentEle>(mField));
1462 for (auto l = 1; l < nb_levels; ++l) {
1463 parents_elems_ptr_vec[l - 1]->getOpPtrVector().push_back(
1464 create_run_parent_op(parents_elems_ptr_vec[l], this_fe_ptr, fe_bit));
1465 }
1466 return parents_elems_ptr_vec[0];
1467 };
1468
1469 // solve projection problem
1470 auto solve_projection = [&](auto exe_test) {
1472
1473 auto set_domain_rhs = [&](auto fe) {
1475 auto &pip = fe->getOpPtrVector();
1476
1477 auto u_ptr = boost::make_shared<MatrixDouble>();
1478 auto p_ptr = boost::make_shared<VectorDouble>();
1479 auto h_ptr = boost::make_shared<VectorDouble>();
1480 auto g_ptr = boost::make_shared<VectorDouble>();
1481
1482 auto eval_fe_ptr = boost::make_shared<DomainParentEle>(mField);
1483 {
1484 auto &pip = eval_fe_ptr->getOpPtrVector();
1487 eval_fe_ptr, "", UDO::OPSPACE, bit(get_skin_projection_bit()),
1488
1489 [&]() {
1490 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1491 new DomainParentEle(mField));
1492 return fe_parent;
1493 },
1494
1495 QUIET, Sev::noisy);
1496 // That can be done much smarter, by block, field by field. For
1497 // simplicity is like that.
1498 CHKERR add_parent_field_domain(eval_fe_ptr, UDO::OPROW, "U",
1500 pip.push_back(new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
1501 CHKERR add_parent_field_domain(eval_fe_ptr, UDO::OPROW, "P",
1503 pip.push_back(new OpCalculateScalarFieldValues("P", p_ptr));
1504 CHKERR add_parent_field_domain(eval_fe_ptr, UDO::OPROW, "H",
1506 pip.push_back(new OpCalculateScalarFieldValues("H", h_ptr));
1507 CHKERR add_parent_field_domain(eval_fe_ptr, UDO::OPROW, "G",
1509 pip.push_back(new OpCalculateScalarFieldValues("G", g_ptr));
1510 }
1511 auto parent_eval_fe_ptr =
1512 get_parents_vel_fe_ptr(eval_fe_ptr, bit(get_projection_bit()));
1513 pip.push_back(create_run_parent_op(parent_eval_fe_ptr, eval_fe_ptr,
1515
1516 auto assemble_fe_ptr = boost::make_shared<DomainParentEle>(mField);
1517 {
1518 auto &pip = assemble_fe_ptr->getOpPtrVector();
1521 assemble_fe_ptr, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
1522
1523 [&]() {
1524 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1525 new DomainParentEle(mField));
1526 return fe_parent;
1527 },
1528
1529 QUIET, Sev::noisy);
1530 CHKERR add_parent_field_domain(assemble_fe_ptr, UDO::OPROW, "U",
1532 pip.push_back(new OpDomainAssembleVector("U", u_ptr));
1533 CHKERR add_parent_field_domain(assemble_fe_ptr, UDO::OPROW, "P",
1535 pip.push_back(new OpDomainAssembleScalar("P", p_ptr));
1536 CHKERR add_parent_field_domain(assemble_fe_ptr, UDO::OPROW, "H",
1538 pip.push_back(new OpDomainAssembleScalar("H", h_ptr));
1539 CHKERR add_parent_field_domain(assemble_fe_ptr, UDO::OPROW, "G",
1541 pip.push_back(new OpDomainAssembleScalar("G", g_ptr));
1542 }
1543 auto parent_assemble_fe_ptr =
1544 get_parents_vel_fe_ptr(assemble_fe_ptr, bit(get_current_bit()));
1545 pip.push_back(create_run_parent_op(
1546 parent_assemble_fe_ptr, assemble_fe_ptr, bit(get_current_bit())));
1547
1549 };
1550
1551 auto set_domain_lhs = [&](auto fe) {
1553
1554 auto &pip = fe->getOpPtrVector();
1555
1557
1559 fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
1560
1561 [&]() {
1562 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1563 new DomainParentEle(mField));
1564 return fe_parent;
1565 },
1566
1567 QUIET, Sev::noisy);
1568
1569 // That can be done much smarter, by block, field by field. For simplicity
1570 // is like that.
1571 CHKERR add_parent_field_domain(fe, UDO::OPROW, "U",
1573 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "U",
1575 pip.push_back(new OpDomainMassU("U", "U"));
1576 CHKERR add_parent_field_domain(fe, UDO::OPROW, "P",
1578 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "P",
1580 pip.push_back(new OpDomainMassP("P", "P"));
1581 CHKERR add_parent_field_domain(fe, UDO::OPROW, "H",
1583 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "H",
1585 pip.push_back(new OpDomainMassH("H", "H"));
1586 CHKERR add_parent_field_domain(fe, UDO::OPROW, "G",
1588 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "G",
1590 pip.push_back(new OpDomainMassG("G", "G"));
1591
1593 };
1594
1595 auto set_bdy_rhs = [&](auto fe) {
1597 auto &pip = fe->getOpPtrVector();
1598
1599 auto l_ptr = boost::make_shared<VectorDouble>();
1600
1601 auto eval_fe_ptr = boost::make_shared<BoundaryParentEle>(mField);
1602 {
1603 auto &pip = eval_fe_ptr->getOpPtrVector();
1605 eval_fe_ptr, "", UDO::OPSPACE, bit(get_skin_projection_bit()),
1606
1607 [&]() {
1608 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1610 return fe_parent;
1611 },
1612
1613 QUIET, Sev::noisy);
1614 // That can be done much smarter, by block, field by field. For
1615 // simplicity is like that.
1616 CHKERR add_parent_field_bdy(eval_fe_ptr, UDO::OPROW, "L",
1618 pip.push_back(new OpCalculateScalarFieldValues("L", l_ptr));
1619 }
1620 auto parent_eval_fe_ptr =
1621 get_parents_vel_fe_ptr(eval_fe_ptr, bit(get_projection_bit()));
1622 pip.push_back(create_run_parent_op(parent_eval_fe_ptr, eval_fe_ptr,
1624
1625 auto assemble_fe_ptr = boost::make_shared<BoundaryParentEle>(mField);
1626 {
1627 auto &pip = assemble_fe_ptr->getOpPtrVector();
1629 assemble_fe_ptr, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
1630
1631 [&]() {
1632 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1634 return fe_parent;
1635 },
1636
1637 QUIET, Sev::noisy);
1638
1639 struct OpLSize : public BoundaryEleOp {
1640 OpLSize(boost::shared_ptr<VectorDouble> l_ptr)
1641 : BoundaryEleOp(NOSPACE, DomainEleOp::OPSPACE), lPtr(l_ptr) {}
1642 MoFEMErrorCode doWork(int, EntityType, EntData &) {
1644 if (lPtr->size() != getGaussPts().size2()) {
1645 lPtr->resize(getGaussPts().size2());
1646 lPtr->clear();
1647 }
1649 }
1650
1651 private:
1652 boost::shared_ptr<VectorDouble> lPtr;
1653 };
1654
1655 pip.push_back(new OpLSize(l_ptr));
1656
1657 CHKERR add_parent_field_bdy(assemble_fe_ptr, UDO::OPROW, "L",
1659 pip.push_back(new OpBoundaryAssembleScalar("L", l_ptr));
1660 }
1661 auto parent_assemble_fe_ptr =
1662 get_parents_vel_fe_ptr(assemble_fe_ptr, bit(get_current_bit()));
1663 pip.push_back(create_run_parent_op(
1664 parent_assemble_fe_ptr, assemble_fe_ptr, bit(get_current_bit())));
1665
1667 };
1668
1669 auto set_bdy_lhs = [&](auto fe) {
1671
1672 auto &pip = fe->getOpPtrVector();
1673
1675 fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
1676
1677 [&]() {
1678 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1680 return fe_parent;
1681 },
1682
1683 QUIET, Sev::noisy);
1684
1685 // That can be done much smarter, by block, field by field. For simplicity
1686 // is like that.
1687 CHKERR add_parent_field_bdy(fe, UDO::OPROW, "L",
1689 CHKERR add_parent_field_bdy(fe, UDO::OPCOL, "L",
1691 pip.push_back(new OpBoundaryMassL("L", "L"));
1692
1694 };
1695
1696 auto create_subdm = [&]() -> SmartPetscObj<DM> {
1697 auto level_ents_ptr = boost::make_shared<Range>();
1698 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByRefLevel(
1699 bit(get_current_bit()), BitRefLevel().set(), *level_ents_ptr);
1700
1701 auto get_prj_ents = [&]() {
1702 Range prj_mesh;
1703 CHKERR bit_mng->getEntitiesByDimAndRefLevel(bit(get_projection_bit()),
1704 BitRefLevel().set(),
1705 SPACE_DIM, prj_mesh);
1706 auto common_ents = intersect(prj_mesh, *level_ents_ptr);
1707 prj_mesh = subtract(unite(*level_ents_ptr, prj_mesh), common_ents)
1708 .subset_by_dimension(SPACE_DIM);
1709
1710 return prj_mesh;
1711 };
1712
1713 auto prj_ents = get_prj_ents();
1714
1715 if (get_global_size(prj_ents.size())) {
1716
1717 auto rebuild = [&]() {
1718 auto prb_mng = mField.getInterface<ProblemsManager>();
1720
1721 std::vector<std::string> fields{"U", "P", "H", "G", "L"};
1722 std::map<std::string, boost::shared_ptr<Range>> range_maps{
1723
1724 {"U", level_ents_ptr},
1725 {"P", level_ents_ptr},
1726 {"H", level_ents_ptr},
1727 {"G", level_ents_ptr},
1728 {"L", level_ents_ptr}
1729
1730 };
1731
1732 CHKERR prb_mng->buildSubProblem("SUB_SOLVER", fields, fields,
1733 simple->getProblemName(), PETSC_TRUE,
1734 &range_maps, &range_maps);
1735
1736 // partition problem
1737 CHKERR prb_mng->partitionFiniteElements("SUB_SOLVER", true, 0,
1739 // set ghost nodes
1740 CHKERR prb_mng->partitionGhostDofsOnDistributedMesh("SUB_SOLVER");
1741
1743 };
1744
1745 MOFEM_LOG("FS", Sev::verbose) << "Create projection problem";
1746
1747 CHKERR rebuild();
1748
1749 auto dm = simple->getDM();
1750 DM subdm;
1751 CHKERR DMCreate(mField.get_comm(), &subdm);
1752 CHKERR DMSetType(subdm, "DMMOFEM");
1753 CHKERR DMMoFEMCreateSubDM(subdm, dm, "SUB_SOLVER");
1754 return SmartPetscObj<DM>(subdm);
1755 }
1756
1757 MOFEM_LOG("FS", Sev::inform) << "Nothing to project";
1758
1759 return SmartPetscObj<DM>();
1760 };
1761
1762 auto create_dummy_dm = [&]() {
1763 auto dummy_dm = createDM(mField.get_comm(), "DMMOFEM");
1765 simple->getProblemName().c_str(),
1767 "create dummy dm");
1768 return dummy_dm;
1769 };
1770
1771 auto subdm = create_subdm();
1772 if (subdm) {
1773
1774 pip_mng->getDomainRhsFE().reset();
1775 pip_mng->getDomainLhsFE().reset();
1776 pip_mng->getBoundaryRhsFE().reset();
1777 pip_mng->getBoundaryLhsFE().reset();
1778 CHKERR pip_mng->setDomainRhsIntegrationRule(integration_rule);
1779 CHKERR pip_mng->setDomainLhsIntegrationRule(integration_rule);
1780 CHKERR pip_mng->setBoundaryRhsIntegrationRule(integration_rule);
1781 CHKERR pip_mng->setBoundaryLhsIntegrationRule(integration_rule);
1782 pip_mng->getDomainLhsFE()->exeTestHook = exe_test;
1783 pip_mng->getDomainRhsFE()->exeTestHook = [](FEMethod *fe_ptr) {
1784 return get_fe_bit(fe_ptr).test(nb_levels - 1);
1785 };
1786 pip_mng->getBoundaryLhsFE()->exeTestHook = exe_test;
1787 pip_mng->getBoundaryRhsFE()->exeTestHook = [](FEMethod *fe_ptr) {
1788 return get_fe_bit(fe_ptr).test(nb_levels - 1);
1789 };
1790
1791 CHKERR set_domain_rhs(pip_mng->getCastDomainRhsFE());
1792 CHKERR set_domain_lhs(pip_mng->getCastDomainLhsFE());
1793 CHKERR set_bdy_rhs(pip_mng->getCastBoundaryRhsFE());
1794 CHKERR set_bdy_lhs(pip_mng->getCastBoundaryLhsFE());
1795
1796 auto D = createDMVector(subdm);
1797 auto F = vectorDuplicate(D);
1798
1799 auto ksp = pip_mng->createKSP(subdm);
1800 CHKERR KSPSetFromOptions(ksp);
1801 CHKERR KSPSetUp(ksp);
1802
1803 // get vector norm
1804 auto get_norm = [&](auto x) {
1805 double nrm;
1806 CHKERR VecNorm(x, NORM_2, &nrm);
1807 return nrm;
1808 };
1809
1810 /**
1811 * @brief Zero DOFs, used by FieldBlas
1812 */
1813 auto zero_dofs = [](boost::shared_ptr<FieldEntity> ent_ptr) {
1815 for (auto &v : ent_ptr->getEntFieldData()) {
1816 v = 0;
1817 }
1819 };
1820
1821 auto solve = [&](auto S) {
1823 CHKERR VecZeroEntries(S);
1824 CHKERR VecZeroEntries(F);
1825 CHKERR VecGhostUpdateBegin(F, INSERT_VALUES, SCATTER_FORWARD);
1826 CHKERR VecGhostUpdateEnd(F, INSERT_VALUES, SCATTER_FORWARD);
1827 CHKERR KSPSolve(ksp, F, S);
1828 CHKERR VecGhostUpdateBegin(S, INSERT_VALUES, SCATTER_FORWARD);
1829 CHKERR VecGhostUpdateEnd(S, INSERT_VALUES, SCATTER_FORWARD);
1830
1831
1832
1834 };
1835
1836 MOFEM_LOG("FS", Sev::inform) << "Solve projection";
1837 CHKERR solve(D);
1838
1839 auto glob_x = createDMVector(simple->getDM());
1840 auto sub_x = createDMVector(subdm);
1841 auto dummy_dm = create_dummy_dm();
1842
1843 /**
1844 * @brief get TSTheta data operators
1845 */
1846 auto apply_restrict = [&]() {
1847 auto get_is = [](auto v) {
1848 IS iy;
1849 auto create = [&]() {
1851 int n, ystart;
1852 CHKERR VecGetLocalSize(v, &n);
1853 CHKERR VecGetOwnershipRange(v, &ystart, NULL);
1854 CHKERR ISCreateStride(PETSC_COMM_SELF, n, ystart, 1, &iy);
1856 };
1857 CHK_THROW_MESSAGE(create(), "create is");
1858 return SmartPetscObj<IS>(iy);
1859 };
1860
1861 auto iy = get_is(glob_x);
1862 auto s = createVecScatter(glob_x, PETSC_NULLPTR, glob_x, iy);
1863
1865 DMSubDomainRestrict(simple->getDM(), s, PETSC_NULLPTR, dummy_dm),
1866 "restrict");
1867 Vec X0, Xdot;
1868 CHK_THROW_MESSAGE(DMGetNamedGlobalVector(dummy_dm, "TSTheta_X0", &X0),
1869 "get X0");
1871 DMGetNamedGlobalVector(dummy_dm, "TSTheta_Xdot", &Xdot),
1872 "get Xdot");
1873
1874 auto forward_ghost = [](auto g) {
1876 CHKERR VecGhostUpdateBegin(g, INSERT_VALUES, SCATTER_FORWARD);
1877 CHKERR VecGhostUpdateEnd(g, INSERT_VALUES, SCATTER_FORWARD);
1879 };
1880
1881 CHK_THROW_MESSAGE(forward_ghost(X0), "");
1882 CHK_THROW_MESSAGE(forward_ghost(Xdot), "");
1883
1884 if constexpr (debug) {
1885 MOFEM_LOG("FS", Sev::inform)
1886 << "Reverse restrict: X0 " << get_norm(X0) << " Xdot "
1887 << get_norm(Xdot);
1888 }
1889
1890 return std::vector<Vec>{X0, Xdot};
1891 };
1892
1893 auto ts_solver_vecs = apply_restrict();
1894
1895 if (ts_solver_vecs.size()) {
1896
1897 for (auto v : ts_solver_vecs) {
1898 MOFEM_LOG("FS", Sev::inform) << "Solve projection vector";
1899
1900 CHKERR DMoFEMMeshToLocalVector(simple->getDM(), v, INSERT_VALUES,
1901 SCATTER_REVERSE);
1902 CHKERR solve(sub_x);
1903
1904 for (auto f : {"U", "P", "H", "G", "L"}) {
1905 MOFEM_LOG("WORLD", Sev::verbose) << "Zero field " << f;
1906 CHKERR field_blas->fieldLambdaOnEntities(zero_dofs, f);
1907 }
1908
1909 CHKERR DMoFEMMeshToLocalVector(subdm, sub_x, INSERT_VALUES,
1910 SCATTER_REVERSE);
1911 CHKERR DMoFEMMeshToLocalVector(simple->getDM(), v, INSERT_VALUES,
1912 SCATTER_FORWARD);
1913
1914 MOFEM_LOG("FS", Sev::inform) << "Norm V " << get_norm(v);
1915 }
1916
1917 CHKERR DMRestoreNamedGlobalVector(dummy_dm, "TSTheta_X0",
1918 &ts_solver_vecs[0]);
1919 CHKERR DMRestoreNamedGlobalVector(dummy_dm, "TSTheta_Xdot",
1920 &ts_solver_vecs[1]);
1921 }
1922
1923 for (auto f : {"U", "P", "H", "G", "L"}) {
1924 MOFEM_LOG("WORLD", Sev::verbose) << "Zero field " << f;
1925 CHKERR field_blas->fieldLambdaOnEntities(zero_dofs, f);
1926 }
1927 CHKERR DMoFEMMeshToLocalVector(subdm, D, INSERT_VALUES, SCATTER_REVERSE);
1928 }
1929
1931 };
1932
1933 // postprocessing (only for debugging purposes)
1934 auto post_proc = [&](auto exe_test) {
1936 auto post_proc_fe = boost::make_shared<PostProcEleDomain>(mField);
1937 auto &pip = post_proc_fe->getOpPtrVector();
1938 post_proc_fe->exeTestHook = exe_test;
1939
1941
1943 post_proc_fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
1944
1945 [&]() {
1946 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1947 new DomainParentEle(mField));
1949 fe_parent->getOpPtrVector(), {H1});
1950 return fe_parent;
1951 },
1952
1953 QUIET, Sev::noisy);
1954
1956
1957 auto u_ptr = boost::make_shared<MatrixDouble>();
1958 auto p_ptr = boost::make_shared<VectorDouble>();
1959 auto h_ptr = boost::make_shared<VectorDouble>();
1960 auto g_ptr = boost::make_shared<VectorDouble>();
1961
1962 CHKERR add_parent_field_domain(post_proc_fe, UDO::OPROW, "U",
1964 pip.push_back(new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
1965 CHKERR add_parent_field_domain(post_proc_fe, UDO::OPROW, "P",
1967 pip.push_back(new OpCalculateScalarFieldValues("P", p_ptr));
1968 CHKERR add_parent_field_domain(post_proc_fe, UDO::OPROW, "H",
1970 pip.push_back(new OpCalculateScalarFieldValues("H", h_ptr));
1971 CHKERR add_parent_field_domain(post_proc_fe, UDO::OPROW, "G",
1973 pip.push_back(new OpCalculateScalarFieldValues("G", g_ptr));
1974
1975 post_proc_fe->getOpPtrVector().push_back(
1976
1977 new OpPPMap(post_proc_fe->getPostProcMesh(),
1978 post_proc_fe->getMapGaussPts(),
1979
1980 {{"P", p_ptr}, {"H", h_ptr}, {"G", g_ptr}},
1981
1982 {{"U", u_ptr}},
1983
1984 {},
1985
1986 {}
1987
1988 )
1989
1990 );
1991
1992 auto dm = simple->getDM();
1993 CHKERR DMoFEMLoopFiniteElements(dm, "dFE", post_proc_fe);
1994 CHKERR post_proc_fe->writeFile("out_projection.h5m");
1995
1997 };
1998
1999 CHKERR solve_projection([](FEMethod *fe_ptr) {
2000 return get_fe_bit(fe_ptr).test(get_current_bit());
2001 });
2002
2003 if constexpr (debug) {
2004 CHKERR post_proc([](FEMethod *fe_ptr) {
2005 return get_fe_bit(fe_ptr).test(get_current_bit());
2006 });
2007 }
2008
2009 fe_domain_lhs.swap(pip_mng->getDomainLhsFE());
2010 fe_domain_rhs.swap(pip_mng->getDomainRhsFE());
2011 fe_bdy_lhs.swap(pip_mng->getBoundaryLhsFE());
2012 fe_bdy_rhs.swap(pip_mng->getBoundaryRhsFE());
2013
2015}
@ NOSPACE
Definition definitions.h:83
@ F
OpDomainMassH OpDomainMassG
FormsIntegrators< DomainEleOp >::Assembly< A >::LinearForm< I >::OpBaseTimesVector< BASE_DIM, SPACE_DIM, 1 > OpDomainAssembleVector
FormsIntegrators< DomainEleOp >::Assembly< A >::BiLinearForm< I >::OpMass< BASE_DIM, 1 > OpDomainMassH
auto get_skin_projection_bit
auto get_global_size
Get global size across all processors.
FormsIntegrators< BoundaryEleOp >::Assembly< A >::BiLinearForm< I >::OpMass< BASE_DIM, 1 > OpBoundaryMassL
FormsIntegrators< BoundaryEleOp >::Assembly< A >::LinearForm< I >::OpBaseTimesScalar< BASE_DIM > OpBoundaryAssembleScalar
FormsIntegrators< DomainEleOp >::Assembly< A >::BiLinearForm< I >::OpMass< BASE_DIM, U_FIELD_DIM > OpDomainMassU
PetscErrorCode DMMoFEMCreateMoFEM(DM dm, MoFEM::Interface *m_field_ptr, const char problem_name[], const MoFEM::BitRefLevel bit_level, const MoFEM::BitRefLevel bit_mask=MoFEM::BitRefLevel().set())
Must be called by user to set MoFEM data structures.
Definition DMMoFEM.cpp:114
MoFEMErrorCode buildSubProblem(const std::string out_name, const std::vector< std::string > &fields_row, const std::vector< std::string > &fields_col, const std::string main_problem, const bool square_matrix=true, const map< std::string, boost::shared_ptr< Range > > *entityMapRow=nullptr, const map< std::string, boost::shared_ptr< Range > > *entityMapCol=nullptr, int verb=VERBOSE)
build sub problem
const double n
refractive index of diffusive medium
const FTensor::Tensor2< T, Dim, Dim > Vec
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
auto createVecScatter(Vec x, IS ix, Vec y, IS iy)
Create a Vec Scatter object.
static PetscErrorCode solve(Mat mat, Vec x, Vec y)
Definition Schur.cpp:1296
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
constexpr double g
Data on single entity (This is passed as argument to DataOperator::doWork)
Operator to execute finite element instance on parent element. This operator is typically used to pro...
Problem manager is used to build and partition problems.

◆ readMesh()

MoFEMErrorCode FreeSurface::readMesh ( )
private

Read mesh from input file.

[Run programme]

Returns
MoFEMErrorCode Success/failure code

Loads mesh using Simple interface and sets up parent adjacencies for hierarchical mesh refinement

[Read mesh]

Examples
mofem/tutorials/vec-5/free_surface.cpp.

Definition at line 971 of file free_surface.cpp.

971 {
973 MOFEM_LOG("FS", Sev::inform) << "Read mesh for problem";
975
977 simple->getBitRefLevel() = BitRefLevel();
978
979 CHKERR simple->getOptions();
980 CHKERR simple->loadFile();
981
983}
bool & getParentAdjacencies()
Get the addParentAdjacencies flag.
Definition Simple.hpp:555

◆ refineMesh()

MoFEMErrorCode FreeSurface::refineMesh ( size_t  overlap)
private

Perform adaptive mesh refinement.

Parameters
overlapNumber of element layers around interface to refine
Returns
MoFEMErrorCode Success/failure code

Performs hierarchical mesh refinement around the phase interface:

  • Identifies entities crossing interface
  • Creates refinement hierarchy
  • Sets up skin elements between levels
  • Updates bit level markings for computation
Examples
mofem/tutorials/vec-5/free_surface.cpp.

Definition at line 3030 of file free_surface.cpp.

3030 {
3032
3033 auto bit_mng = mField.getInterface<BitRefManager>();
3034
3035 BitRefLevel start_mask;
3036 for (auto s = 0; s != get_start_bit(); ++s)
3037 start_mask[s] = true;
3038
3039 // store prev_level
3040 Range prev_level;
3041 CHKERR bit_mng->getEntitiesByRefLevel(bit(get_current_bit()),
3042 BitRefLevel().set(), prev_level);
3043 Range prev_level_skin;
3044 CHKERR bit_mng->getEntitiesByRefLevel(bit(get_skin_parent_bit()),
3045 BitRefLevel().set(), prev_level_skin);
3046 // reset bit ref levels
3047 CHKERR bit_mng->lambdaBitRefLevel(
3048 [&](EntityHandle ent, BitRefLevel &bit) { bit &= start_mask; });
3049 CHKERR bit_mng->setNthBitRefLevel(prev_level, get_projection_bit(), true);
3050 CHKERR bit_mng->setNthBitRefLevel(prev_level_skin, get_skin_projection_bit(),
3051 true);
3052
3053 // set refinement levels
3054 auto set_levels = [&](auto &&
3055 vec_levels /*entities are refined on each level*/) {
3057
3058 // start with zero level, which is the coarsest mesh
3059 Range level0;
3060 CHKERR bit_mng->getEntitiesByRefLevel(bit(0), BitRefLevel().set(), level0);
3061 CHKERR bit_mng->setNthBitRefLevel(level0, get_start_bit(), true);
3062
3063 // get lower dimension entities
3064 auto get_adj = [&](auto ents) {
3065 Range conn;
3066 CHK_MOAB_THROW(mField.get_moab().get_connectivity(ents, conn, true),
3067 "get conn");
3068 for (auto d = 1; d != SPACE_DIM; ++d) {
3069 CHK_MOAB_THROW(mField.get_moab().get_adjacencies(
3070 ents.subset_by_dimension(SPACE_DIM), d, false, conn,
3071 moab::Interface::UNION),
3072 "get adj");
3073 }
3074 ents.merge(conn);
3075 return ents;
3076 };
3077
3078 // set bit levels
3079 for (auto l = 1; l != nb_levels; ++l) {
3080 Range level_prev;
3081 CHKERR bit_mng->getEntitiesByDimAndRefLevel(bit(get_start_bit() + l - 1),
3082 BitRefLevel().set(),
3083 SPACE_DIM, level_prev);
3084 Range parents;
3085 CHKERR bit_mng->updateRangeByParent(vec_levels[l], parents);
3086 // subtract entities from previous level, which are refined, so should be
3087 // not there
3088 level_prev = subtract(level_prev, parents);
3089 // and instead add their children
3090 level_prev.merge(vec_levels[l]);
3091 // set bit to each level
3092 CHKERR bit_mng->setNthBitRefLevel(level_prev, get_start_bit() + l, true);
3093 }
3094
3095 // set bit levels to lower dimension entities
3096 for (auto l = 1; l != nb_levels; ++l) {
3097 Range level;
3098 CHKERR bit_mng->getEntitiesByDimAndRefLevel(
3099 bit(get_start_bit() + l), BitRefLevel().set(), SPACE_DIM, level);
3100 level = get_adj(level);
3101 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(level);
3102 CHKERR bit_mng->setNthBitRefLevel(level, get_start_bit() + l, true);
3103 }
3104
3106 };
3107
3108 // resolve skin between refined levels
3109 auto set_skins = [&]() {
3111
3112 moab::Skinner skinner(&mField.get_moab());
3113 ParallelComm *pcomm =
3114 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
3115
3116 // get skin of bit level
3117 auto get_bit_skin = [&](BitRefLevel bit, BitRefLevel mask) {
3118 Range bit_ents;
3121 bit, mask, SPACE_DIM, bit_ents),
3122 "can't get bit level");
3123 Range bit_skin;
3124 CHK_MOAB_THROW(skinner.find_skin(0, bit_ents, false, bit_skin),
3125 "can't get skin");
3126 return bit_skin;
3127 };
3128
3129 auto get_level_skin = [&]() {
3130 Range skin;
3131 BitRefLevel bit_prev;
3132 for (auto l = 1; l != nb_levels; ++l) {
3133 auto skin_level_mesh = get_bit_skin(bit(l), BitRefLevel().set());
3134 // filter (remove) all entities which are on partition borders
3135 CHKERR pcomm->filter_pstatus(skin_level_mesh,
3136 PSTATUS_SHARED | PSTATUS_MULTISHARED,
3137 PSTATUS_NOT, -1, nullptr);
3138 auto skin_level =
3139 get_bit_skin(bit(get_start_bit() + l), BitRefLevel().set());
3140 skin_level = subtract(skin_level,
3141 skin_level_mesh); // get only internal skins, not
3142 // on the body boundary
3143 // get lower dimension adjacencies (FIXME: add edges if 3D)
3144 Range skin_level_verts;
3145 CHKERR mField.get_moab().get_connectivity(skin_level, skin_level_verts,
3146 true);
3147 skin_level.merge(skin_level_verts);
3148
3149 // remove previous level
3150 bit_prev.set(l - 1);
3151 Range level_prev;
3152 CHKERR bit_mng->getEntitiesByRefLevel(bit_prev, BitRefLevel().set(),
3153 level_prev);
3154 skin.merge(subtract(skin_level, level_prev));
3155 }
3156
3157 return skin;
3158 };
3159
3160 auto resolve_shared = [&](auto &&skin) {
3161 Range tmp_skin = skin;
3162
3163 map<int, Range> map_procs;
3164 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
3165 tmp_skin, &map_procs);
3166
3167 Range from_other_procs; // entities which also exist on other processors
3168 for (auto &m : map_procs) {
3169 if (m.first != mField.get_comm_rank()) {
3170 from_other_procs.merge(m.second);
3171 }
3172 }
3173
3174 auto common = intersect(
3175 skin, from_other_procs); // entities which are on internal skin
3176 skin.merge(from_other_procs);
3177
3178 // entities which are on processor borders, and several processors are not
3179 // true skin.
3180 if (!common.empty()) {
3181 // skin is internal exist on other procs
3182 skin = subtract(skin, common);
3183 }
3184
3185 return skin;
3186 };
3187
3188 // get parents of entities
3189 auto get_parent_level_skin = [&](auto skin) {
3190 Range skin_parents;
3191 CHKERR bit_mng->updateRangeByParent(
3192 skin.subset_by_dimension(SPACE_DIM - 1), skin_parents);
3193 Range skin_parent_verts;
3194 CHKERR mField.get_moab().get_connectivity(skin_parents, skin_parent_verts,
3195 true);
3196 skin_parents.merge(skin_parent_verts);
3197 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
3198 skin_parents);
3199 return skin_parents;
3200 };
3201
3202 auto child_skin = resolve_shared(get_level_skin());
3203 auto parent_skin = get_parent_level_skin(child_skin);
3204
3205 child_skin = subtract(child_skin, parent_skin);
3206 CHKERR bit_mng->setNthBitRefLevel(child_skin, get_skin_child_bit(), true);
3207 CHKERR bit_mng->setNthBitRefLevel(parent_skin, get_skin_parent_bit(), true);
3208
3210 };
3211
3212 // take last level, remove childs on boarder, and set bit
3213 auto set_current = [&]() {
3215 Range last_level;
3216 CHKERR bit_mng->getEntitiesByRefLevel(bit(get_start_bit() + nb_levels - 1),
3217 BitRefLevel().set(), last_level);
3218 Range skin_child;
3219 CHKERR bit_mng->getEntitiesByRefLevel(bit(get_skin_child_bit()),
3220 BitRefLevel().set(), skin_child);
3221
3222 last_level = subtract(last_level, skin_child);
3223 CHKERR bit_mng->setNthBitRefLevel(last_level, get_current_bit(), true);
3225 };
3226
3227 // set bits to levels
3228 CHKERR set_levels(findEntitiesCrossedByPhaseInterface(overlap));
3229 // set bits to skin
3230 CHKERR set_skins();
3231 // set current level bit
3232 CHKERR set_current();
3233
3234 if constexpr (debug) {
3235 if (mField.get_comm_size() == 1) {
3236 for (auto l = 0; l != nb_levels; ++l) {
3237 std::string name = (boost::format("out_level%d.h5m") % l).str();
3238 CHKERR bit_mng->writeBitLevel(BitRefLevel().set(get_start_bit() + l),
3239 BitRefLevel().set(), name.c_str(), "MOAB",
3240 "PARALLEL=WRITE_PART");
3241 }
3242 CHKERR bit_mng->writeBitLevel(BitRefLevel().set(get_current_bit()),
3243 BitRefLevel().set(), "current_bit.h5m",
3244 "MOAB", "PARALLEL=WRITE_PART");
3245 CHKERR bit_mng->writeBitLevel(BitRefLevel().set(get_projection_bit()),
3246 BitRefLevel().set(), "projection_bit.h5m",
3247 "MOAB", "PARALLEL=WRITE_PART");
3248
3249 CHKERR bit_mng->writeBitLevel(BitRefLevel().set(get_skin_child_bit()),
3250 BitRefLevel().set(), "skin_child_bit.h5m",
3251 "MOAB", "PARALLEL=WRITE_PART");
3252 CHKERR bit_mng->writeBitLevel(BitRefLevel().set(get_skin_parent_bit()),
3253 BitRefLevel().set(), "skin_parent_bit.h5m",
3254 "MOAB", "PARALLEL=WRITE_PART");
3255 }
3256 }
3257
3259};
#define MYPCOMM_INDEX
default communicator number PCOMM
auto get_skin_child_bit
MoFEMErrorCode getEntitiesByDimAndRefLevel(const BitRefLevel bit, const BitRefLevel mask, const int dim, const EntityHandle meshset, int verb=0) const
add all ents from ref level given by bit to meshset
std::vector< Range > findEntitiesCrossedByPhaseInterface(size_t overlap)
Find entities on refinement levels.
virtual int get_comm_rank() const =0

◆ runProblem()

MoFEMErrorCode FreeSurface::runProblem ( )

Main function to run the complete free surface simulation.

[Run programme]

Returns
MoFEMErrorCode Success/failure code

Executes the complete simulation workflow:

  1. Read mesh from file
  2. Setup problem (fields, approximation orders, parameters)
  3. Apply boundary conditions and initialize fields
  4. Assemble system matrices and operators
  5. Solve time-dependent problem
Examples
mofem/tutorials/vec-5/free_surface.cpp.

Definition at line 959 of file free_surface.cpp.

959 {
967}
MoFEMErrorCode setupProblem()
Setup problem fields and parameters.
MoFEMErrorCode boundaryCondition()
Apply boundary conditions and initialize fields.
MoFEMErrorCode readMesh()
Read mesh from input file.
MoFEMErrorCode assembleSystem()
Assemble system operators and matrices.
MoFEMErrorCode solveSystem()
Solve the time-dependent free surface problem.

◆ setParentDofs()

MoFEMErrorCode FreeSurface::setParentDofs ( boost::shared_ptr< FEMethod fe_top,
std::string  field_name,
ForcesAndSourcesCore::UserDataOperator::OpType  op,
BitRefLevel  child_ent_bit,
boost::function< boost::shared_ptr< ForcesAndSourcesCore >()>  get_elem,
int  verbosity,
LogManager::SeverityLevel  sev 
)
private

Create hierarchy of elements run on parent levels.

Parameters
fe_topPipeline element to which hierarchy is attached
field_nameName of field for DOF extraction ("" for all fields)
opType of operator OPSPACE, OPROW, OPCOL or OPROWCOL
child_ent_bitBit level marking child entities
get_elemLambda function to create element on hierarchy
verbosityVerbosity level for debugging output
sevSeverity level for logging
Returns
MoFEMErrorCode Success/failure code

Sets up parent-child relationships for hierarchical mesh refinement. Allows access to field data from parent mesh levels during computation on refined child meshes. Essential for projection and interpolation.

Collect data from parent elements to child

Examples
mofem/tutorials/vec-5/free_surface.cpp.

Definition at line 3261 of file free_surface.cpp.

3266 {
3268
3269 /**
3270 * @brief Collect data from parent elements to child
3271 */
3272 boost::function<void(boost::shared_ptr<ForcesAndSourcesCore>, int)>
3273 add_parent_level =
3274 [&](boost::shared_ptr<ForcesAndSourcesCore> parent_fe_pt, int level) {
3275 // Evaluate if not last parent element
3276 if (level > 0) {
3277
3278 // Create domain parent FE
3279 auto fe_ptr_current = get_elem();
3280
3281 // Call next level
3282 add_parent_level(
3283 boost::dynamic_pointer_cast<ForcesAndSourcesCore>(
3284 fe_ptr_current),
3285 level - 1);
3286
3287 // Add data to curent fe level
3289
3290 // Only base
3291 parent_fe_pt->getOpPtrVector().push_back(
3292
3294
3295 H1, op, fe_ptr_current,
3296
3297 BitRefLevel().set(), BitRefLevel().set(),
3298
3299 child_ent_bit, BitRefLevel().set(),
3300
3301 verbosity, sev));
3302
3303 } else {
3304
3305 // Filed data
3306 parent_fe_pt->getOpPtrVector().push_back(
3307
3309
3310 field_name, op, fe_ptr_current,
3311
3312 BitRefLevel().set(), BitRefLevel().set(),
3313
3314 child_ent_bit, BitRefLevel().set(),
3315
3316 verbosity, sev));
3317 }
3318 }
3319 };
3320
3321 add_parent_level(boost::dynamic_pointer_cast<ForcesAndSourcesCore>(fe_top),
3322 nb_levels);
3323
3325}
@ OPSPACE
operator do Work is execute on space data
Operator to project base functions from parent entity to child.

◆ setupProblem()

MoFEMErrorCode FreeSurface::setupProblem ( )
private

Setup problem fields and parameters.

[Read mesh]

Returns
MoFEMErrorCode Success/failure code

Creates finite element fields:

  • U: Velocity field (H1, vector)
  • P: Pressure field (H1, scalar)
  • H: Phase/order field (H1, scalar)
  • G: Chemical potential (H1, scalar)
  • L: Lagrange multiplier for boundary conditions (H1, scalar)

Sets approximation orders and reads physical parameters from command line

[Set up problem]

Examples
mofem/tutorials/vec-5/free_surface.cpp.

Definition at line 987 of file free_surface.cpp.

987 {
989
990 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &order, PETSC_NULLPTR);
991 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-nb_levels", &nb_levels,
992 PETSC_NULLPTR);
993 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-refine_overlap", &refine_overlap,
994 PETSC_NULLPTR);
995
996 const char *coord_type_names[] = {"cartesian", "polar", "cylindrical",
997 "spherical"};
998 CHKERR PetscOptionsGetEList(PETSC_NULLPTR, NULL, "-coords", coord_type_names,
999 LAST_COORDINATE_SYSTEM, &coord_type, PETSC_NULLPTR);
1000
1001 MOFEM_LOG("FS", Sev::inform) << "Approximation order = " << order;
1002 MOFEM_LOG("FS", Sev::inform)
1003 << "Number of refinement levels nb_levels = " << nb_levels;
1004 nb_levels += 1;
1005
1006 auto simple = mField.getInterface<Simple>();
1007
1008 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "Acceleration", "-a0", &a0, PETSC_NULLPTR);
1009 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "\"Minus\" phase density rho_m",
1010 "-rho_m", &rho_m, PETSC_NULLPTR);
1011 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "\"Minus\" phase viscosity", "-mu_m",
1012 &mu_m, PETSC_NULLPTR);
1013 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "\"Plus\" phase density", "-rho_p",
1014 &rho_p, PETSC_NULLPTR);
1015 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "\"Plus\" phase viscosity", "-mu_p",
1016 &mu_p, PETSC_NULLPTR);
1017 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "Surface tension", "-lambda",
1018 &lambda, PETSC_NULLPTR);
1019 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR,
1020 "Height of the well in energy functional", "-W",
1021 &W, PETSC_NULLPTR);
1022 rho_ave = (rho_p + rho_m) / 2;
1023 rho_diff = (rho_p - rho_m) / 2;
1024 mu_ave = (mu_p + mu_m) / 2;
1025 mu_diff = (mu_p - mu_m) / 2;
1026
1027 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-h", &h, PETSC_NULLPTR);
1028 eta = h;
1029 eta2 = eta * eta;
1030 kappa = (3. / (4. * std::sqrt(2. * W))) * (lambda / eta);
1031
1032 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-md", &eta, PETSC_NULLPTR);
1033
1034 MOFEM_LOG("FS", Sev::inform) << "Acceleration a0 = " << a0;
1035 MOFEM_LOG("FS", Sev::inform) << "\"Minus\" phase density rho_m = " << rho_m;
1036 MOFEM_LOG("FS", Sev::inform) << "\"Minus\" phase viscosity mu_m = " << mu_m;
1037 MOFEM_LOG("FS", Sev::inform) << "\"Plus\" phase density rho_p = " << rho_p;
1038 MOFEM_LOG("FS", Sev::inform) << "\"Plus\" phase viscosity mu_p = " << mu_p;
1039 MOFEM_LOG("FS", Sev::inform) << "Surface tension lambda = " << lambda;
1040 MOFEM_LOG("FS", Sev::inform)
1041 << "Height of the well in energy functional W = " << W;
1042 MOFEM_LOG("FS", Sev::inform) << "Characteristic mesh size h = " << h;
1043 MOFEM_LOG("FS", Sev::inform) << "Mobility md = " << md;
1044
1045 MOFEM_LOG("FS", Sev::inform) << "Average density rho_ave = " << rho_ave;
1046 MOFEM_LOG("FS", Sev::inform) << "Difference density rho_diff = " << rho_diff;
1047 MOFEM_LOG("FS", Sev::inform) << "Average viscosity mu_ave = " << mu_ave;
1048 MOFEM_LOG("FS", Sev::inform) << "Difference viscosity mu_diff = " << mu_diff;
1049 MOFEM_LOG("FS", Sev::inform) << "kappa = " << kappa;
1050
1051
1052 // Fields on domain
1053
1054 // Velocity field
1055 CHKERR simple->addDomainField("U", H1, AINSWORTH_LEGENDRE_BASE, U_FIELD_DIM);
1056 // Pressure field
1057 CHKERR simple->addDomainField("P", H1, AINSWORTH_LEGENDRE_BASE, 1);
1058 // Order/phase fild
1059 CHKERR simple->addDomainField("H", H1, AINSWORTH_LEGENDRE_BASE, 1);
1060 // Chemical potential
1061 CHKERR simple->addDomainField("G", H1, AINSWORTH_LEGENDRE_BASE, 1);
1062
1063 // Field on boundary
1064 CHKERR simple->addBoundaryField("U", H1, AINSWORTH_LEGENDRE_BASE,
1065 U_FIELD_DIM);
1066 CHKERR simple->addBoundaryField("H", H1, AINSWORTH_LEGENDRE_BASE, 1);
1067 CHKERR simple->addBoundaryField("G", H1, AINSWORTH_LEGENDRE_BASE, 1);
1068 // Lagrange multiplier which constrains slip conditions
1069 CHKERR simple->addBoundaryField("L", H1, AINSWORTH_LEGENDRE_BASE, 1);
1070
1071 CHKERR simple->setFieldOrder("U", order);
1072 CHKERR simple->setFieldOrder("P", order - 1);
1073 CHKERR simple->setFieldOrder("H", order);
1074 CHKERR simple->setFieldOrder("G", order);
1075 CHKERR simple->setFieldOrder("L", order);
1076
1077 // Initialise bit ref levels
1078 auto set_problem_bit = [&]() {
1080 // Set bits to build adjacencies between parents and children. That is
1081 // used by simple interface.
1082 simple->getBitAdjEnt() = BitRefLevel().set();
1083 simple->getBitAdjParent() = BitRefLevel().set();
1084 simple->getBitRefLevel() = BitRefLevel().set();
1085 simple->getBitRefLevelMask() = BitRefLevel().set();
1087 };
1088
1089 CHKERR set_problem_bit();
1090
1091 CHKERR simple->setUp();
1092
1094}
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
@ LAST_COORDINATE_SYSTEM
double kappa
double mu_diff
constexpr int U_FIELD_DIM
double mu_m
double lambda
surface tension
double rho_diff
double rho_ave
double W
double eta2
double rho_p
double mu_p
double h
double mu_ave
int order
approximation order
double a0
double rho_m
double eta
double md
PetscErrorCode PetscOptionsGetInt(PetscOptions *, const char pre[], const char name[], PetscInt *ivalue, PetscBool *set)
PetscErrorCode PetscOptionsGetScalar(PetscOptions *, const char pre[], const char name[], PetscScalar *dval, PetscBool *set)
PetscErrorCode PetscOptionsGetEList(PetscOptions *, const char pre[], const char name[], const char *const *list, PetscInt next, PetscInt *value, PetscBool *set)

◆ solveSystem()

MoFEMErrorCode FreeSurface::solveSystem ( )
private

Solve the time-dependent free surface problem.

[Solve]

Returns
MoFEMErrorCode Success/failure code

Creates and configures time stepping solver with:

  • Sub-problem DM for refined mesh
  • Post-processing for output visualization
  • Custom preconditioner and monitors
  • TSTheta implicit time integration
Examples
mofem/tutorials/vec-5/free_surface.cpp.

Definition at line 2482 of file free_surface.cpp.

2482 {
2484
2485 using UDO = ForcesAndSourcesCore::UserDataOperator;
2486
2487 auto simple = mField.getInterface<Simple>();
2488 auto pip_mng = mField.getInterface<PipelineManager>();
2489
2490 auto create_solver_dm = [&](auto dm) -> SmartPetscObj<DM> {
2491 DM subdm;
2492
2493 auto setup_subdm = [&](auto dm) {
2495 auto simple = mField.getInterface<Simple>();
2496 auto bit_mng = mField.getInterface<BitRefManager>();
2497 auto dm = simple->getDM();
2498 auto level_ents_ptr = boost::make_shared<Range>();
2499 CHKERR bit_mng->getEntitiesByRefLevel(
2500 bit(get_current_bit()), BitRefLevel().set(), *level_ents_ptr);
2501 CHKERR DMCreate(mField.get_comm(), &subdm);
2502 CHKERR DMSetType(subdm, "DMMOFEM");
2503 CHKERR DMMoFEMCreateSubDM(subdm, dm, "SUB_SOLVER");
2504 CHKERR DMMoFEMAddElement(subdm, simple->getDomainFEName());
2505 CHKERR DMMoFEMAddElement(subdm, simple->getBoundaryFEName());
2506 CHKERR DMMoFEMSetSquareProblem(subdm, PETSC_TRUE);
2507 CHKERR DMMoFEMSetDestroyProblem(subdm, PETSC_FALSE);
2508 for (auto f : {"U", "P", "H", "G", "L"}) {
2509 CHKERR DMMoFEMAddSubFieldRow(subdm, f, level_ents_ptr);
2510 CHKERR DMMoFEMAddSubFieldCol(subdm, f, level_ents_ptr);
2511 }
2512 CHKERR DMSetUp(subdm);
2514 };
2515
2516 CHK_THROW_MESSAGE(setup_subdm(dm), "create subdm");
2517
2518 return SmartPetscObj<DM>(subdm);
2519 };
2520
2521 auto get_fe_post_proc = [&](auto post_proc_mesh) {
2522 auto add_parent_field_domain = [&](auto fe, auto op, auto field) {
2523 return setParentDofs(
2524 fe, field, op, bit(get_skin_parent_bit()),
2525
2526 [&]() {
2527 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2528 new DomainParentEle(mField));
2529 return fe_parent;
2530 },
2531
2532 QUIET, Sev::noisy);
2533 };
2534
2535 auto post_proc_fe =
2536 boost::make_shared<PostProcEleDomainCont>(mField, post_proc_mesh);
2537 post_proc_fe->exeTestHook = [](FEMethod *fe_ptr) {
2538 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
2539 get_start_bit() + nb_levels - 1);
2540 };
2541
2542 auto u_ptr = boost::make_shared<MatrixDouble>();
2543 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
2544 auto h_ptr = boost::make_shared<VectorDouble>();
2545 auto grad_h_ptr = boost::make_shared<MatrixDouble>();
2546 auto p_ptr = boost::make_shared<VectorDouble>();
2547 auto g_ptr = boost::make_shared<VectorDouble>();
2548 auto grad_g_ptr = boost::make_shared<MatrixDouble>();
2549
2551 post_proc_fe->getOpPtrVector(), {H1});
2552
2554 post_proc_fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
2555
2556 [&]() {
2557 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2558 new DomainParentEle(mField));
2560 fe_parent->getOpPtrVector(), {H1});
2561 return fe_parent;
2562 },
2563
2564 QUIET, Sev::noisy);
2565
2566 CHKERR add_parent_field_domain(post_proc_fe, UDO::OPROW, "U");
2567 post_proc_fe->getOpPtrVector().push_back(
2569 post_proc_fe->getOpPtrVector().push_back(
2571 grad_u_ptr));
2572
2573 CHKERR add_parent_field_domain(post_proc_fe, UDO::OPROW, "H");
2574 post_proc_fe->getOpPtrVector().push_back(
2575 new OpCalculateScalarFieldValues("H", h_ptr));
2576 post_proc_fe->getOpPtrVector().push_back(
2577 new OpCalculateScalarFieldGradient<SPACE_DIM>("H", grad_h_ptr));
2578
2579 CHKERR add_parent_field_domain(post_proc_fe, UDO::OPROW, "P");
2580 post_proc_fe->getOpPtrVector().push_back(
2581 new OpCalculateScalarFieldValues("P", p_ptr));
2582
2583 CHKERR add_parent_field_domain(post_proc_fe, UDO::OPROW, "G");
2584 post_proc_fe->getOpPtrVector().push_back(
2585 new OpCalculateScalarFieldValues("G", g_ptr));
2586 post_proc_fe->getOpPtrVector().push_back(
2587 new OpCalculateScalarFieldGradient<SPACE_DIM>("G", grad_g_ptr));
2588
2590
2591 post_proc_fe->getOpPtrVector().push_back(
2592
2593 new OpPPMap(
2594 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
2595
2596 {{"H", h_ptr}, {"P", p_ptr}, {"G", g_ptr}},
2597
2598 {{"U", u_ptr}, {"H_GRAD", grad_h_ptr}, {"G_GRAD", grad_g_ptr}},
2599
2600 {{"GRAD_U", grad_u_ptr}},
2601
2602 {}
2603
2604 )
2605
2606 );
2607
2608 return post_proc_fe;
2609 };
2610
2611 auto get_bdy_post_proc_fe = [&](auto post_proc_mesh) {
2612 auto add_parent_field_bdy = [&](auto fe, auto op, auto field) {
2613 return setParentDofs(
2614 fe, field, op, bit(get_skin_parent_bit()),
2615
2616 [&]() {
2617 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2619 return fe_parent;
2620 },
2621
2622 QUIET, Sev::noisy);
2623 };
2624
2625 auto post_proc_fe =
2626 boost::make_shared<PostProcEleBdyCont>(mField, post_proc_mesh);
2627 post_proc_fe->exeTestHook = [](FEMethod *fe_ptr) {
2628 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
2629 get_start_bit() + nb_levels - 1);
2630 };
2631
2633 post_proc_fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
2634
2635 [&]() {
2636 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2638 return fe_parent;
2639 },
2640
2641 QUIET, Sev::noisy);
2642
2643 struct OpGetNormal : public BoundaryEleOp {
2644
2645 OpGetNormal(boost::shared_ptr<VectorDouble> l_ptr,
2646 boost::shared_ptr<MatrixDouble> n_ptr)
2647 : BoundaryEleOp(NOSPACE, BoundaryEleOp::OPSPACE), ptrL(l_ptr),
2648 ptrNormal(n_ptr) {}
2649
2650 MoFEMErrorCode doWork(int side, EntityType type,
2653 auto t_l = getFTensor0FromVec(*ptrL);
2654 auto t_n_fe = getFTensor1NormalsAtGaussPts();
2655 ptrNormal->resize(SPACE_DIM, getGaussPts().size2(), false);
2656 auto t_n = getFTensor1FromMat<SPACE_DIM>(*ptrNormal);
2657 for (auto gg = 0; gg != getGaussPts().size2(); ++gg) {
2658 t_n(i) = t_n_fe(i) * t_l / std::sqrt(t_n_fe(i) * t_n_fe(i));
2659 ++t_n_fe;
2660 ++t_l;
2661 ++t_n;
2662 }
2664 };
2665
2666 protected:
2667 boost::shared_ptr<VectorDouble> ptrL;
2668 boost::shared_ptr<MatrixDouble> ptrNormal;
2669 };
2670
2671 auto u_ptr = boost::make_shared<MatrixDouble>();
2672 auto p_ptr = boost::make_shared<VectorDouble>();
2673 auto lambda_ptr = boost::make_shared<VectorDouble>();
2674 auto normal_l_ptr = boost::make_shared<MatrixDouble>();
2675
2676 CHKERR add_parent_field_bdy(post_proc_fe, UDO::OPROW, "U");
2677 post_proc_fe->getOpPtrVector().push_back(
2679
2680 CHKERR add_parent_field_bdy(post_proc_fe, UDO::OPROW, "L");
2681 post_proc_fe->getOpPtrVector().push_back(
2682 new OpCalculateScalarFieldValues("L", lambda_ptr));
2683 post_proc_fe->getOpPtrVector().push_back(
2684 new OpGetNormal(lambda_ptr, normal_l_ptr));
2685
2686 CHKERR add_parent_field_bdy(post_proc_fe, UDO::OPROW, "P");
2687 post_proc_fe->getOpPtrVector().push_back(
2688 new OpCalculateScalarFieldValues("P", p_ptr));
2689
2690 auto op_ptr = new BoundaryEleOp(NOSPACE, BoundaryEleOp::OPSPACE);
2691 op_ptr->doWorkRhsHook = [&](DataOperator *base_op_ptr, int side,
2692 EntityType type,
2696 };
2697
2699
2700 post_proc_fe->getOpPtrVector().push_back(
2701
2702 new OpPPMap(post_proc_fe->getPostProcMesh(),
2703 post_proc_fe->getMapGaussPts(),
2704
2705 OpPPMap::DataMapVec{{"P", p_ptr}},
2706
2707 OpPPMap::DataMapMat{{"U", u_ptr}, {"L", normal_l_ptr}},
2708
2710
2712
2713 )
2714
2715 );
2716
2717 return post_proc_fe;
2718 };
2719
2720 auto get_lift_fe = [&]() {
2721 auto add_parent_field_bdy = [&](auto fe, auto op, auto field) {
2722 return setParentDofs(
2723 fe, field, op, bit(get_skin_parent_bit()),
2724
2725 [&]() {
2726 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2728 return fe_parent;
2729 },
2730
2731 QUIET, Sev::noisy);
2732 };
2733
2734 auto fe = boost::make_shared<BoundaryEle>(mField);
2735 fe->exeTestHook = [](FEMethod *fe_ptr) {
2736 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
2737 get_start_bit() + nb_levels - 1);
2738 };
2739
2740 auto lift_ptr = boost::make_shared<VectorDouble>();
2741 auto p_ptr = boost::make_shared<VectorDouble>();
2742 auto ents_ptr = boost::make_shared<Range>();
2743
2745 fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
2746
2747 [&]() {
2748 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2750 return fe_parent;
2751 },
2752
2753 QUIET, Sev::noisy);
2754
2755 std::vector<const CubitMeshSets *> vec_ptr;
2756 CHKERR mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(
2757 std::regex("LIFT"), vec_ptr);
2758 for (auto m_ptr : vec_ptr) {
2759 auto meshset = m_ptr->getMeshset();
2760 Range ents;
2761 CHKERR mField.get_moab().get_entities_by_dimension(meshset, SPACE_DIM - 1,
2762 ents, true);
2763 ents_ptr->merge(ents);
2764 }
2765
2766 MOFEM_LOG("FS", Sev::noisy) << "Lift ents " << (*ents_ptr);
2767
2768 CHKERR add_parent_field_bdy(fe, UDO::OPROW, "P");
2769 fe->getOpPtrVector().push_back(
2770 new OpCalculateScalarFieldValues("L", p_ptr));
2771 fe->getOpPtrVector().push_back(
2772 new OpCalculateLift("L", p_ptr, lift_ptr, ents_ptr));
2773
2774 return std::make_pair(fe, lift_ptr);
2775 };
2776
2777 auto set_post_proc_monitor = [&](auto ts) {
2779 DM dm;
2780 CHKERR TSGetDM(ts, &dm);
2781 boost::shared_ptr<FEMethod> null_fe;
2782 auto post_proc_mesh = boost::make_shared<moab::Core>();
2783 auto monitor_ptr = boost::make_shared<Monitor>(
2784 SmartPetscObj<DM>(dm, true), post_proc_mesh,
2785 get_fe_post_proc(post_proc_mesh), get_bdy_post_proc_fe(post_proc_mesh),
2786 get_lift_fe());
2787 CHKERR DMMoFEMTSSetMonitor(dm, ts, simple->getDomainFEName(), null_fe,
2788 null_fe, monitor_ptr);
2790 };
2791
2792 auto dm = simple->getDM();
2793 auto ts = createTS(mField.get_comm());
2794 CHKERR TSSetDM(ts, dm);
2795
2796 auto ts_pre_post_proc = boost::make_shared<TSPrePostProc>();
2797 tsPrePostProc = ts_pre_post_proc;
2798
2799 if (auto ptr = tsPrePostProc.lock()) {
2800
2801 ptr->fsRawPtr = this;
2802 ptr->solverSubDM = create_solver_dm(simple->getDM());
2803 ptr->globSol = createDMVector(dm);
2804 CHKERR DMoFEMMeshToLocalVector(dm, ptr->globSol, INSERT_VALUES,
2805 SCATTER_FORWARD);
2806 CHKERR VecAssemblyBegin(ptr->globSol);
2807 CHKERR VecAssemblyEnd(ptr->globSol);
2808
2809 auto sub_ts = pip_mng->createTSIM(ptr->solverSubDM);
2810
2811 CHKERR set_post_proc_monitor(sub_ts);
2812
2813 // Add monitor to time solver
2814 CHKERR TSSetFromOptions(ts);
2815 CHKERR ptr->tsSetUp(ts);
2816 CHKERR TSSetUp(ts);
2817
2818 auto print_fields_in_section = [&]() {
2820 auto section = mField.getInterface<ISManager>()->sectionCreate(
2821 simple->getProblemName());
2822 PetscInt num_fields;
2823 CHKERR PetscSectionGetNumFields(section, &num_fields);
2824 for (int f = 0; f < num_fields; ++f) {
2825 const char *field_name;
2826 CHKERR PetscSectionGetFieldName(section, f, &field_name);
2827 MOFEM_LOG("FS", Sev::inform)
2828 << "Field " << f << " " << std::string(field_name);
2829 }
2831 };
2832
2833 CHKERR print_fields_in_section();
2834
2835 CHKERR TSSolve(ts, ptr->globSol);
2836 }
2837
2839}
constexpr int SPACE_DIM
[Define dimension]
static boost::weak_ptr< TSPrePostProc > tsPrePostProc
BoundaryEle::UserDataOperator BoundaryEleOp
MoFEMErrorCode getMeshset(const int ms_id, const unsigned int cubit_bc_type, EntityHandle &meshset) const
get meshset from CUBIT Id and CUBIT type
FTensor::Index< 'i', SPACE_DIM > i
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.
Definition DMMoFEM.cpp:1046
auto createTS(MPI_Comm comm)
static auto getFTensor0FromVec(ublas::vector< T, A > &data)
Get tensor rank 0 (scalar) form data vector.
base operator to do operations at Gauss Pt. level
std::map< std::string, boost::shared_ptr< MatrixDouble > > DataMapMat
std::map< std::string, boost::shared_ptr< VectorDouble > > DataMapVec

Friends And Related Symbol Documentation

◆ TSPrePostProc

friend struct TSPrePostProc
friend

Definition at line 955 of file free_surface.cpp.

Member Data Documentation

◆ mField

MoFEM::Interface& FreeSurface::mField
Examples
mofem/tutorials/vec-5/free_surface.cpp.

Definition at line 828 of file free_surface.cpp.


The documentation for this struct was generated from the following file: