v0.16.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.
 
MoFEMErrorCode checkResults ()
 Check results for correctness.
 

Friends

struct TSPrePostProc
 

Detailed Description

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

Definition at line 802 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 809 of file free_surface.cpp.

809: 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/free_surface.cpp.

Definition at line 2035 of file free_surface.cpp.

2035 {
2037 auto simple = mField.getInterface<Simple>();
2038
2039 using UDO = ForcesAndSourcesCore::UserDataOperator;
2040
2041 auto add_parent_field_domain = [&](auto fe, auto op, auto field) {
2042 return setParentDofs(
2043 fe, field, op, bit(get_skin_parent_bit()),
2044
2045 [&]() {
2046 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2047 new DomainParentEle(mField));
2048 return fe_parent;
2049 },
2050
2051 QUIET, Sev::noisy);
2052 };
2053
2054 auto add_parent_field_bdy = [&](auto fe, auto op, auto field) {
2055 return setParentDofs(
2056 fe, field, op, bit(get_skin_parent_bit()),
2057
2058 [&]() {
2059 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2061 return fe_parent;
2062 },
2063
2064 QUIET, Sev::noisy);
2065 };
2066
2067 auto test_bit_child = [](FEMethod *fe_ptr) {
2068 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
2069 get_start_bit() + nb_levels - 1);
2070 };
2071
2072 auto dot_u_ptr = boost::make_shared<MatrixDouble>(); // time derivative of velocity u ie du/dt
2073 auto u_ptr = boost::make_shared<MatrixDouble>(); // velocity u
2074 auto grad_u_ptr = boost::make_shared<MatrixDouble>(); // velocity gradient tensor ie grad(u)
2075 auto dot_h_ptr = boost::make_shared<VectorDouble>(); // time derivative of phase field ie dh/dt
2076 auto h_ptr = boost::make_shared<VectorDouble>(); // phase field variable h
2077 auto grad_h_ptr = boost::make_shared<MatrixDouble>(); // phase field gradient ie grad(h)
2078 auto g_ptr = boost::make_shared<VectorDouble>(); // chemical potential g
2079 auto grad_g_ptr = boost::make_shared<MatrixDouble>(); // chemical potential gradient ie grad(g)
2080 auto lambda_ptr = boost::make_shared<VectorDouble>(); // Lagrange multiplier lambda
2081 auto p_ptr = boost::make_shared<VectorDouble>(); // pressure p
2082 auto div_u_ptr = boost::make_shared<VectorDouble>(); // divergence of velocity ie div(u)
2083
2084 // Push element from reference configuration to current configuration in 3d
2085 // space
2086 auto set_domain_general = [&](auto fe) {
2088 auto &pip = fe->getOpPtrVector();
2089
2091
2093 fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
2094
2095 [&]() {
2096 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2097 new DomainParentEle(mField));
2099 fe_parent->getOpPtrVector(), {H1});
2100 return fe_parent;
2101 },
2102
2103 QUIET, Sev::noisy);
2104
2105 CHKERR add_parent_field_domain(fe, UDO::OPROW, "U");
2106 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "U");
2107 pip.push_back(
2109 pip.push_back(new OpCalculateVectorFieldValues<U_FIELD_DIM>("U", u_ptr));
2111 "U", grad_u_ptr));
2112
2113 switch (coord_type) {
2114 case CARTESIAN:
2115 pip.push_back(
2117 "U", div_u_ptr));
2118 break;
2119 case CYLINDRICAL:
2120 pip.push_back(
2122 "U", div_u_ptr));
2123 break;
2124 default:
2125 SETERRQ(PETSC_COMM_WORLD, MOFEM_NOT_IMPLEMENTED,
2126 "Coordinate system not implemented");
2127 }
2128
2129 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "H");
2130 pip.push_back(new OpCalculateScalarFieldValuesDot("H", dot_h_ptr));
2131 pip.push_back(new OpCalculateScalarFieldValues("H", h_ptr));
2132 pip.push_back(
2133 new OpCalculateScalarFieldGradient<SPACE_DIM>("H", grad_h_ptr));
2134
2135 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "G");
2136 pip.push_back(new OpCalculateScalarFieldValues("G", g_ptr));
2137 pip.push_back(
2138 new OpCalculateScalarFieldGradient<SPACE_DIM>("G", grad_g_ptr));
2139
2140 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "P");
2141 pip.push_back(new OpCalculateScalarFieldValues("P", p_ptr));
2143 };
2144
2145 auto set_domain_rhs = [&](auto fe) {
2147 auto &pip = fe->getOpPtrVector();
2148
2149 CHKERR set_domain_general(fe);
2150
2151 CHKERR add_parent_field_domain(fe, UDO::OPROW, "U");
2152 pip.push_back(new OpRhsU("U", dot_u_ptr, u_ptr, grad_u_ptr, h_ptr,
2153 grad_h_ptr, g_ptr, p_ptr));
2154
2155 CHKERR add_parent_field_domain(fe, UDO::OPROW, "H");
2156 pip.push_back(new OpRhsH<false>("H", u_ptr, dot_h_ptr, h_ptr, grad_h_ptr,
2157 grad_g_ptr));
2158
2159 CHKERR add_parent_field_domain(fe, UDO::OPROW, "G");
2160 pip.push_back(new OpRhsG<false>("G", h_ptr, grad_h_ptr, g_ptr));
2161
2162 CHKERR add_parent_field_domain(fe, UDO::OPROW, "P");
2163 pip.push_back(new OpDomainAssembleScalar(
2164 "P", div_u_ptr, [](const double r, const double, const double) {
2165 return cylindrical(r);
2166 }));
2167 pip.push_back(new OpDomainAssembleScalar(
2168 "P", p_ptr, [](const double r, const double, const double) {
2169 return eps * cylindrical(r);
2170 }));
2172 };
2173
2174 auto set_domain_lhs = [&](auto fe) {
2176 auto &pip = fe->getOpPtrVector();
2177
2178 CHKERR set_domain_general(fe);
2179
2180 CHKERR add_parent_field_domain(fe, UDO::OPROW, "U");
2181 {
2182 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "U");
2183 pip.push_back(new OpLhsU_dU("U", u_ptr, grad_u_ptr, h_ptr));
2184 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "H");
2185 pip.push_back(
2186 new OpLhsU_dH("U", "H", dot_u_ptr, u_ptr, grad_u_ptr, h_ptr, g_ptr));
2187
2188 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "G");
2189 pip.push_back(new OpLhsU_dG("U", "G", grad_h_ptr));
2190 }
2191
2192 CHKERR add_parent_field_domain(fe, UDO::OPROW, "H");
2193 {
2194 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "U");
2195 pip.push_back(new OpLhsH_dU("H", "U", grad_h_ptr));
2196 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "H");
2197 pip.push_back(new OpLhsH_dH<false>("H", u_ptr, h_ptr, grad_g_ptr));
2198 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "G");
2199 pip.push_back(new OpLhsH_dG<false>("H", "G", h_ptr));
2200 }
2201
2202 CHKERR add_parent_field_domain(fe, UDO::OPROW, "G");
2203 {
2204 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "H");
2205 pip.push_back(new OpLhsG_dH<false>("G", "H", h_ptr));
2206 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "G");
2207 pip.push_back(new OpLhsG_dG("G"));
2208 }
2209
2210 CHKERR add_parent_field_domain(fe, UDO::OPROW, "P");
2211 {
2212 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "U");
2213
2214 switch (coord_type) {
2215 case CARTESIAN:
2216 pip.push_back(new OpMixScalarTimesDiv<CARTESIAN>(
2217 "P", "U",
2218 [](const double r, const double, const double) {
2219 return cylindrical(r);
2220 },
2221 true, false));
2222 break;
2223 case CYLINDRICAL:
2224 pip.push_back(new OpMixScalarTimesDiv<CYLINDRICAL>(
2225 "P", "U",
2226 [](const double r, const double, const double) {
2227 return cylindrical(r);
2228 },
2229 true, false));
2230 break;
2231 default:
2232 SETERRQ(PETSC_COMM_WORLD, MOFEM_NOT_IMPLEMENTED,
2233 "Coordinate system not implemented");
2234 }
2235
2236 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "P");
2237 pip.push_back(new OpDomainMassP("P", "P", [](double r, double, double) {
2238 return eps * cylindrical(r);
2239 }));
2240 }
2241
2243 };
2244
2245 auto get_block_name = [](auto name) {
2246 return boost::format("%s(.*)") % "WETTING_ANGLE";
2247 };
2248
2249 auto get_blocks = [&](auto &&name) {
2250 return mField.getInterface<MeshsetsManager>()->getCubitMeshsetPtr(
2251 std::regex(name.str()));
2252 };
2253
2254 auto set_boundary_rhs = [&](auto fe) {
2256 auto &pip = fe->getOpPtrVector();
2257
2259 fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
2260
2261 [&]() {
2262 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2264 return fe_parent;
2265 },
2266
2267 QUIET, Sev::noisy);
2268
2269 CHKERR add_parent_field_bdy(fe, UDO::OPCOL, "U");
2270 pip.push_back(new OpCalculateVectorFieldValues<U_FIELD_DIM>("U", u_ptr));
2271
2272 CHKERR add_parent_field_bdy(fe, UDO::OPCOL, "L");
2273 pip.push_back(new OpCalculateScalarFieldValues("L", lambda_ptr));
2274 pip.push_back(new OpNormalConstrainRhs("L", u_ptr));
2275
2277 pip, mField, "L", {}, "INFLUX",
2278 [](double r, double, double) { return cylindrical(r); }, Sev::inform);
2279
2280 CHKERR add_parent_field_bdy(fe, UDO::OPROW, "U");
2281 pip.push_back(new OpNormalForceRhs("U", lambda_ptr));
2282
2283 auto wetting_block = get_blocks(get_block_name("WETTING_ANGLE"));
2284 if (wetting_block.size()) {
2285 // push operators to the side element which is called from op_bdy_side
2286 auto op_bdy_side =
2287 new OpLoopSide<SideEle>(mField, simple->getDomainFEName(), SPACE_DIM);
2288 op_bdy_side->getSideFEPtr()->exeTestHook = test_bit_child;
2289
2291 op_bdy_side->getOpPtrVector(), {H1});
2292
2294 op_bdy_side->getSideFEPtr(), "", UDO::OPSPACE,
2296
2297 [&]() {
2298 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2299 new DomainParentEle(mField));
2301 fe_parent->getOpPtrVector(), {H1});
2302 return fe_parent;
2303 },
2304
2305 QUIET, Sev::noisy);
2306
2307 CHKERR add_parent_field_domain(op_bdy_side->getSideFEPtr(), UDO::OPCOL,
2308 "H");
2309 op_bdy_side->getOpPtrVector().push_back(
2310 new OpCalculateScalarFieldGradient<SPACE_DIM>("H", grad_h_ptr));
2311 // push bdy side op
2312 pip.push_back(op_bdy_side);
2313
2314 // push operators for rhs wetting angle
2315 for (auto &b : wetting_block) {
2316 Range force_edges;
2317 std::vector<double> attr_vec;
2318 CHKERR b->getMeshsetIdEntitiesByDimension(
2319 mField.get_moab(), SPACE_DIM - 1, force_edges, true);
2320 b->getAttributes(attr_vec);
2321 if (attr_vec.size() != 1)
2322 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
2323 "Should be one attribute");
2324 MOFEM_LOG("FS", Sev::inform) << "Wetting angle: " << attr_vec.front();
2325 // need to find the attributes and pass to operator
2326 CHKERR add_parent_field_bdy(fe, UDO::OPROW, "G");
2327 CHKERR add_parent_field_bdy(fe, UDO::OPCOL, "G");
2328 pip.push_back(new OpWettingAngleRhs(
2329 "G", grad_h_ptr, boost::make_shared<Range>(force_edges),
2330 attr_vec.front()));
2331 }
2332 }
2333
2335 };
2336
2337 auto set_boundary_lhs = [&](auto fe) {
2339 auto &pip = fe->getOpPtrVector();
2340
2342 fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
2343
2344 [&]() {
2345 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2347 return fe_parent;
2348 },
2349
2350 QUIET, Sev::noisy);
2351
2352 CHKERR add_parent_field_bdy(fe, UDO::OPROW, "L");
2353 CHKERR add_parent_field_bdy(fe, UDO::OPCOL, "U");
2354 pip.push_back(new OpNormalConstrainLhs("L", "U"));
2355
2356 auto wetting_block = get_blocks(get_block_name("WETTING_ANGLE"));
2357 if (wetting_block.size()) {
2358 auto col_ind_ptr = boost::make_shared<std::vector<VectorInt>>();
2359 auto col_diff_base_ptr = boost::make_shared<std::vector<MatrixDouble>>();
2360
2361 // push operators to the side element which is called from op_bdy_side
2362 auto op_bdy_side =
2363 new OpLoopSide<SideEle>(mField, simple->getDomainFEName(), SPACE_DIM);
2364 op_bdy_side->getSideFEPtr()->exeTestHook = test_bit_child;
2365
2367 op_bdy_side->getOpPtrVector(), {H1});
2368
2370 op_bdy_side->getSideFEPtr(), "", UDO::OPSPACE,
2372
2373 [&]() {
2374 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
2375 new DomainParentEle(mField));
2377 fe_parent->getOpPtrVector(), {H1});
2378 return fe_parent;
2379 },
2380
2381 QUIET, Sev::noisy);
2382
2383 CHKERR add_parent_field_domain(op_bdy_side->getSideFEPtr(), UDO::OPROW,
2384 "H");
2385 CHKERR add_parent_field_domain(op_bdy_side->getSideFEPtr(), UDO::OPCOL,
2386 "H");
2387 op_bdy_side->getOpPtrVector().push_back(
2388 new OpCalculateScalarFieldGradient<SPACE_DIM>("H", grad_h_ptr));
2389 op_bdy_side->getOpPtrVector().push_back(
2390 new OpLoopSideGetDataForSideEle("H", col_ind_ptr, col_diff_base_ptr));
2391
2392 // push bdy side op
2393 pip.push_back(op_bdy_side);
2394
2395 // push operators for lhs wetting angle
2396 for (auto &b : wetting_block) {
2397 Range force_edges;
2398 std::vector<double> attr_vec;
2399 CHKERR b->getMeshsetIdEntitiesByDimension(
2400 mField.get_moab(), SPACE_DIM - 1, force_edges, true);
2401 b->getAttributes(attr_vec);
2402 if (attr_vec.size() != 1)
2403 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
2404 "Should be one attribute");
2405 MOFEM_LOG("FS", Sev::inform)
2406 << "wetting angle edges size " << force_edges.size();
2407
2408 CHKERR add_parent_field_bdy(fe, UDO::OPROW, "G");
2409 CHKERR add_parent_field_bdy(fe, UDO::OPCOL, "G");
2410 pip.push_back(new OpWettingAngleLhs(
2411 "G", grad_h_ptr, col_ind_ptr, col_diff_base_ptr,
2412 boost::make_shared<Range>(force_edges), attr_vec.front()));
2413 }
2414 }
2415
2417 };
2418
2419 auto *pip_mng = mField.getInterface<PipelineManager>();
2420
2421 CHKERR set_domain_rhs(pip_mng->getCastDomainRhsFE());
2422 CHKERR set_domain_lhs(pip_mng->getCastDomainLhsFE());
2423 CHKERR set_boundary_rhs(pip_mng->getCastBoundaryRhsFE());
2424 CHKERR set_boundary_lhs(pip_mng->getCastBoundaryLhsFE());
2425
2426 CHKERR pip_mng->setDomainRhsIntegrationRule(integration_rule);
2427 CHKERR pip_mng->setDomainLhsIntegrationRule(integration_rule);
2428 CHKERR pip_mng->setBoundaryRhsIntegrationRule(integration_rule);
2429 CHKERR pip_mng->setBoundaryLhsIntegrationRule(integration_rule);
2430
2431 pip_mng->getDomainLhsFE()->exeTestHook = test_bit_child;
2432 pip_mng->getDomainRhsFE()->exeTestHook = test_bit_child;
2433 pip_mng->getBoundaryLhsFE()->exeTestHook = test_bit_child;
2434 pip_mng->getBoundaryRhsFE()->exeTestHook = test_bit_child;
2435
2437}
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
[cylindrical]
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:205
Lhs for H dH (Jacobian block ∂R_H/∂H)
Lhs for U dG (Jacobian block ∂R_U/∂G)
Lhs for U dH (Jacobian block ∂R_U/∂H)
Rhs for G (chemical potential residual)
Rhs for H (phase-field residual)
[OpWettingAngleLhs]
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 MatrixDouble 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/free_surface.cpp.

Definition at line 1114 of file free_surface.cpp.

1114 {
1116
1117#ifdef PYTHON_INIT_SURFACE
1118 auto get_py_surface_init = []() {
1119 auto py_surf_init = boost::make_shared<SurfacePython>();
1120 CHKERR py_surf_init->surfaceInit("surface.py");
1121 surfacePythonWeakPtr = py_surf_init;
1122 return py_surf_init;
1123 };
1124 auto py_surf_init = get_py_surface_init();
1125#endif
1126
1127 auto simple = mField.getInterface<Simple>();
1128 auto pip_mng = mField.getInterface<PipelineManager>();
1129 auto bc_mng = mField.getInterface<BcManager>();
1130 auto bit_mng = mField.getInterface<BitRefManager>();
1131 auto dm = simple->getDM();
1132
1133 using UDO = ForcesAndSourcesCore::UserDataOperator;
1134
1135 auto reset_bits = [&]() {
1137 BitRefLevel start_mask;
1138 for (auto s = 0; s != get_start_bit(); ++s)
1139 start_mask[s] = true;
1140 // reset bit ref levels
1141 CHKERR bit_mng->lambdaBitRefLevel(
1142 [&](EntityHandle ent, BitRefLevel &bit) { bit &= start_mask; });
1143 Range level0;
1144 CHKERR bit_mng->getEntitiesByRefLevel(bit(0), BitRefLevel().set(), level0);
1145 CHKERR bit_mng->setNthBitRefLevel(level0, get_current_bit(), true);
1146 CHKERR bit_mng->setNthBitRefLevel(level0, get_projection_bit(), true);
1148 };
1149
1150 auto add_parent_field = [&](auto fe, auto op, auto field) {
1151 return setParentDofs(
1152 fe, field, op, bit(get_skin_parent_bit()),
1153
1154 [&]() {
1155 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1156 new DomainParentEle(mField));
1157 return fe_parent;
1158 },
1159
1160 QUIET, Sev::noisy);
1161 };
1162
1163 auto h_ptr = boost::make_shared<VectorDouble>();
1164 auto grad_h_ptr = boost::make_shared<MatrixDouble>();
1165 auto g_ptr = boost::make_shared<VectorDouble>();
1166 auto grad_g_ptr = boost::make_shared<MatrixDouble>();
1167
1168 auto set_generic = [&](auto fe) {
1170 auto &pip = fe->getOpPtrVector();
1171
1173
1175 fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
1176
1177 [&]() {
1178 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1179 new DomainParentEle(mField));
1181 fe_parent->getOpPtrVector(), {H1});
1182 return fe_parent;
1183 },
1184
1185 QUIET, Sev::noisy);
1186
1187 CHKERR add_parent_field(fe, UDO::OPCOL, "H");
1188 pip.push_back(new OpCalculateScalarFieldValues("H", h_ptr));
1189 pip.push_back(
1190 new OpCalculateScalarFieldGradient<SPACE_DIM>("H", grad_h_ptr));
1191
1192 CHKERR add_parent_field(fe, UDO::OPCOL, "G");
1193 pip.push_back(new OpCalculateScalarFieldValues("G", g_ptr));
1194 pip.push_back(
1195 new OpCalculateScalarFieldGradient<SPACE_DIM>("G", grad_g_ptr));
1196
1198 };
1199
1200 auto post_proc = [&](auto exe_test) {
1202 auto post_proc_fe = boost::make_shared<PostProcEleDomain>(mField);
1203 post_proc_fe->exeTestHook = exe_test;
1204
1205 CHKERR set_generic(post_proc_fe);
1206
1208
1209 post_proc_fe->getOpPtrVector().push_back(
1210
1211 new OpPPMap(post_proc_fe->getPostProcMesh(),
1212 post_proc_fe->getMapGaussPts(),
1213
1214 {{"H", h_ptr}, {"G", g_ptr}},
1215
1216 {{"GRAD_H", grad_h_ptr}, {"GRAD_G", grad_g_ptr}},
1217
1218 {},
1219
1220 {}
1221
1222 )
1223
1224 );
1225
1226 CHKERR DMoFEMLoopFiniteElements(dm, "dFE", post_proc_fe);
1227 CHKERR post_proc_fe->writeFile("out_init.h5m");
1228
1230 };
1231
1232 auto solve_init = [&](auto exe_test) {
1234
1235 pip_mng->getOpDomainRhsPipeline().clear();
1236 pip_mng->getOpDomainLhsPipeline().clear();
1237
1238 auto set_domain_rhs = [&](auto fe) {
1240 CHKERR set_generic(fe);
1241 auto &pip = fe->getOpPtrVector();
1242
1243 CHKERR add_parent_field(fe, UDO::OPROW, "H");
1244 pip.push_back(new OpRhsH<true>("H", nullptr, nullptr, h_ptr, grad_h_ptr,
1245 grad_g_ptr));
1246 CHKERR add_parent_field(fe, UDO::OPROW, "G");
1247 pip.push_back(new OpRhsG<true>("G", h_ptr, grad_h_ptr, g_ptr));
1249 };
1250
1251 auto set_domain_lhs = [&](auto fe) {
1253
1254 CHKERR set_generic(fe);
1255 auto &pip = fe->getOpPtrVector();
1256
1257 CHKERR add_parent_field(fe, UDO::OPROW, "H");
1258 CHKERR add_parent_field(fe, UDO::OPCOL, "H");
1259 pip.push_back(new OpLhsH_dH<true>("H", nullptr, h_ptr, grad_g_ptr));
1260
1261 CHKERR add_parent_field(fe, UDO::OPCOL, "G");
1262 pip.push_back(new OpLhsH_dG<true>("H", "G", h_ptr));
1263
1264 CHKERR add_parent_field(fe, UDO::OPROW, "G");
1265 pip.push_back(new OpLhsG_dG("G"));
1266
1267 CHKERR add_parent_field(fe, UDO::OPCOL, "H");
1268 pip.push_back(new OpLhsG_dH<true>("G", "H", h_ptr));
1270 };
1271
1272 auto create_subdm = [&]() {
1273 auto level_ents_ptr = boost::make_shared<Range>();
1274 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByRefLevel(
1275 bit(get_current_bit()), BitRefLevel().set(), *level_ents_ptr);
1276
1277 DM subdm;
1278 CHKERR DMCreate(mField.get_comm(), &subdm);
1279 CHKERR DMSetType(subdm, "DMMOFEM");
1280 CHKERR DMMoFEMCreateSubDM(subdm, dm, "SUB_INIT");
1281 CHKERR DMMoFEMAddElement(subdm, simple->getDomainFEName());
1282 CHKERR DMMoFEMSetSquareProblem(subdm, PETSC_TRUE);
1283 CHKERR DMMoFEMSetDestroyProblem(subdm, PETSC_TRUE);
1284
1285 for (auto f : {"H", "G"}) {
1286 CHKERR DMMoFEMAddSubFieldRow(subdm, f, level_ents_ptr);
1287 CHKERR DMMoFEMAddSubFieldCol(subdm, f, level_ents_ptr);
1288 }
1289 CHKERR DMSetUp(subdm);
1290
1291 if constexpr (debug) {
1292 if (mField.get_comm_size() == 1) {
1293 auto dm_ents = get_dofs_ents_all(SmartPetscObj<DM>(subdm, true));
1294 CHKERR save_range(mField.get_moab(), "sub_dm_init_ents_verts.h5m",
1295 dm_ents.subset_by_type(MBVERTEX));
1296 dm_ents = subtract(dm_ents, dm_ents.subset_by_type(MBVERTEX));
1297 CHKERR save_range(mField.get_moab(), "sub_dm_init_ents.h5m", dm_ents);
1298 }
1299 }
1300
1301 return SmartPetscObj<DM>(subdm);
1302 };
1303
1304 auto subdm = create_subdm();
1305
1306 pip_mng->getDomainRhsFE().reset();
1307 pip_mng->getDomainLhsFE().reset();
1308 CHKERR pip_mng->setDomainRhsIntegrationRule(integration_rule);
1309 CHKERR pip_mng->setDomainLhsIntegrationRule(integration_rule);
1310 pip_mng->getDomainLhsFE()->exeTestHook = exe_test;
1311 pip_mng->getDomainRhsFE()->exeTestHook = exe_test;
1312
1313 CHKERR set_domain_rhs(pip_mng->getCastDomainRhsFE());
1314 CHKERR set_domain_lhs(pip_mng->getCastDomainLhsFE());
1315
1316 auto D = createDMVector(subdm);
1317 auto snes = pip_mng->createSNES(subdm);
1318 auto snes_ctx_ptr = getDMSnesCtx(subdm);
1319
1320 auto set_section_monitor = [&](auto solver) {
1322 CHKERR SNESMonitorSet(solver,
1323 (MoFEMErrorCode(*)(SNES, PetscInt, PetscReal,
1324 void *))MoFEMSNESMonitorFields,
1325 (void *)(snes_ctx_ptr.get()), nullptr);
1326
1328 };
1329
1330 auto print_section_field = [&]() {
1332
1333 auto section =
1334 mField.getInterface<ISManager>()->sectionCreate("SUB_INIT");
1335 PetscInt num_fields;
1336 CHKERR PetscSectionGetNumFields(section, &num_fields);
1337 for (int f = 0; f < num_fields; ++f) {
1338 const char *field_name;
1339 CHKERR PetscSectionGetFieldName(section, f, &field_name);
1340 MOFEM_LOG("FS", Sev::inform)
1341 << "Field " << f << " " << std::string(field_name);
1342 }
1343
1345 };
1346
1347 CHKERR set_section_monitor(snes);
1348 CHKERR print_section_field();
1349
1350 for (auto f : {"U", "P", "H", "G", "L"}) {
1351 CHKERR mField.getInterface<FieldBlas>()->setField(0, f);
1352 }
1353
1354 CHKERR SNESSetFromOptions(snes);
1355 auto B = createDMMatrix(subdm);
1356 CHKERR SNESSetJacobian(snes, B, B,
1357 PETSC_NULLPTR, PETSC_NULLPTR);
1358 CHKERR SNESSolve(snes, PETSC_NULLPTR, D);
1359
1360 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
1361 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
1362 CHKERR DMoFEMMeshToLocalVector(subdm, D, INSERT_VALUES, SCATTER_REVERSE);
1363
1365 };
1366
1367 CHKERR reset_bits();
1368 CHKERR solve_init(
1369 [](FEMethod *fe_ptr) { return get_fe_bit(fe_ptr).test(0); });
1371
1372 for (auto f : {"U", "P", "H", "G", "L"}) {
1373 CHKERR mField.getInterface<FieldBlas>()->setField(0, f);
1374 }
1375 CHKERR solve_init([](FEMethod *fe_ptr) {
1376 return get_fe_bit(fe_ptr).test(get_start_bit() + nb_levels - 1);
1377 });
1378
1379 CHKERR post_proc([](FEMethod *fe_ptr) {
1380 return get_fe_bit(fe_ptr).test(get_start_bit() + nb_levels - 1);
1381 });
1382
1383 pip_mng->getOpDomainRhsPipeline().clear();
1384 pip_mng->getOpDomainLhsPipeline().clear();
1385
1386 // Remove DOFs where boundary conditions are set
1387 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "SYM_X",
1388 "U", 0, 0);
1389 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "SYM_X",
1390 "L", 0, 0);
1391 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "SYM_Y",
1392 "U", 1, 1);
1393 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "SYM_Y",
1394 "L", 1, 1);
1395 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "FIX", "U",
1396 0, SPACE_DIM);
1397 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "FIX", "L",
1398 0, 0);
1399 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "ZERO",
1400 "L", 0, 0);
1401
1403}
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 DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
Definition DMMoFEM.cpp:238
PetscErrorCode DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode, RowColData rc=RowColData::COL)
set local (or ghosted) vector values on mesh for partition only
Definition DMMoFEM.cpp:514
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, RowColData rc=RowColData::COL)
Get smart vector from DM.
Definition DMMoFEM.hpp:1237
PetscErrorCode DMMoFEMAddSubFieldCol(DM dm, const char field_name[])
Definition DMMoFEM.cpp:280
auto createDMMatrix(DM dm)
Get smart matrix from DM.
Definition DMMoFEM.hpp:1194
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:600
auto getDMSnesCtx(DM dm)
Get SNES context data structure used by DM.
Definition DMMoFEM.hpp:1265
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

◆ checkResults()

MoFEMErrorCode FreeSurface::checkResults ( )
private

Check results for correctness.

[Check]

Returns
MoFEMErrorCode Success/failure code
Examples
mofem/tutorials/vec-5_free_surface/free_surface.cpp.

Definition at line 3655 of file free_surface.cpp.

3655 {
3657 PetscInt test_nb = 0;
3658 PetscBool test_flg = PETSC_FALSE;
3659 double regression_value = 0.0;
3660 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-test", &test_nb, &test_flg);
3661 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-regression_value", &regression_value, PETSC_NULLPTR);
3662
3663 if (test_flg) {
3664 auto simple = mField.getInterface<Simple>();
3665 auto T = createDMVector(simple->getDM());
3666 CHKERR DMoFEMMeshToLocalVector(simple->getDM(), T, INSERT_VALUES,
3667 SCATTER_FORWARD);
3668 double nrm2;
3669 CHKERR VecNorm(T, NORM_2, &nrm2);
3670 MOFEM_LOG("FS", Sev::verbose) << "Regression norm " << nrm2;
3671 switch (test_nb) {
3672 case 1:
3673 break;
3674 default:
3675 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID, "Wrong test number.");
3676 break;
3677 }
3678 if (fabs(nrm2 - regression_value) > 1e-2)
3679 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
3680 "Regression test field; wrong norm value. %6.4e != %6.4e", nrm2,
3681 regression_value);
3682 }
3684}
@ MOFEM_ATOM_TEST_INVALID
Definition definitions.h:40
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)

◆ 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/free_surface.cpp.

Definition at line 2929 of file free_surface.cpp.

2929 {
2930
2931 auto &moab = mField.get_moab();
2932 auto bit_mng = mField.getInterface<BitRefManager>();
2933 auto comm_mng = mField.getInterface<CommInterface>();
2934
2935 Range vertices;
2936 CHK_THROW_MESSAGE(bit_mng->getEntitiesByTypeAndRefLevel(
2937 bit(0), BitRefLevel().set(), MBVERTEX, vertices),
2938 "can not get vertices on bit 0");
2939
2940 auto &dofs_mi = mField.get_dofs()->get<Unique_mi_tag>();
2941 auto field_bit_number = mField.get_field_bit_number("H");
2942
2943 Range plus_range, minus_range;
2944 std::vector<EntityHandle> plus, minus;
2945
2946 // get vertices on level 0 on plus and minus side
2947 for (auto p = vertices.pair_begin(); p != vertices.pair_end(); ++p) {
2948
2949 const auto f = p->first;
2950 const auto s = p->second;
2951
2952 // Lowest Dof UId for given field (field bit number) on entity f
2953 const auto lo_uid = DofEntity::getLoFieldEntityUId(field_bit_number, f);
2954 const auto hi_uid = DofEntity::getHiFieldEntityUId(field_bit_number, s);
2955 auto it = dofs_mi.lower_bound(lo_uid);
2956 const auto hi_it = dofs_mi.upper_bound(hi_uid);
2957
2958 plus.clear();
2959 minus.clear();
2960 plus.reserve(std::distance(it, hi_it));
2961 minus.reserve(std::distance(it, hi_it));
2962
2963 for (; it != hi_it; ++it) {
2964 const auto v = (*it)->getFieldData();
2965 if (v > 0)
2966 plus.push_back((*it)->getEnt());
2967 else
2968 minus.push_back((*it)->getEnt());
2969 }
2970
2971 plus_range.insert_list(plus.begin(), plus.end());
2972 minus_range.insert_list(minus.begin(), minus.end());
2973 }
2974
2975 MOFEM_LOG_CHANNEL("SYNC");
2976 MOFEM_TAG_AND_LOG("SYNC", Sev::noisy, "FS")
2977 << "Plus range " << plus_range << endl;
2978 MOFEM_TAG_AND_LOG("SYNC", Sev::noisy, "FS")
2979 << "Minus range " << minus_range << endl;
2981
2982 auto get_elems = [&](auto &ents, auto bit, auto mask) {
2983 Range adj;
2984 CHK_MOAB_THROW(moab.get_adjacencies(ents, SPACE_DIM, false, adj,
2985 moab::Interface::UNION),
2986 "can not get adjacencies");
2987 CHK_THROW_MESSAGE(bit_mng->filterEntitiesByRefLevel(bit, mask, adj),
2988 "can not filter elements with bit 0");
2989 return adj;
2990 };
2991
2992 CHKERR comm_mng->synchroniseEntities(plus_range);
2993 CHKERR comm_mng->synchroniseEntities(minus_range);
2994
2995 std::vector<Range> ele_plus(nb_levels), ele_minus(nb_levels);
2996 ele_plus[0] = get_elems(plus_range, bit(0), BitRefLevel().set());
2997 ele_minus[0] = get_elems(minus_range, bit(0), BitRefLevel().set());
2998 auto common = intersect(ele_plus[0], ele_minus[0]);
2999 ele_plus[0] = subtract(ele_plus[0], common);
3000 ele_minus[0] = subtract(ele_minus[0], common);
3001
3002 auto get_children = [&](auto &p, auto &c) {
3004 CHKERR bit_mng->updateRangeByChildren(p, c);
3005 c = c.subset_by_dimension(SPACE_DIM);
3007 };
3008
3009 for (auto l = 1; l != nb_levels; ++l) {
3010 CHK_THROW_MESSAGE(get_children(ele_plus[l - 1], ele_plus[l]),
3011 "get children");
3012 CHK_THROW_MESSAGE(get_children(ele_minus[l - 1], ele_minus[l]),
3013 "get children");
3014 }
3015
3016 auto get_level = [&](auto &p, auto &m, auto z, auto bit, auto mask) {
3017 Range l;
3019 bit_mng->getEntitiesByDimAndRefLevel(bit, mask, SPACE_DIM, l),
3020 "can not get vertices on bit");
3021 l = subtract(l, p);
3022 l = subtract(l, m);
3023 for (auto f = 0; f != z; ++f) {
3024 Range conn;
3025 CHK_MOAB_THROW(moab.get_connectivity(l, conn, true), "");
3026 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(conn);
3027 l = get_elems(conn, bit, mask);
3028 }
3029 return l;
3030 };
3031
3032 std::vector<Range> vec_levels(nb_levels);
3033 for (auto l = nb_levels - 1; l >= 0; --l) {
3034 vec_levels[l] = get_level(ele_plus[l], ele_minus[l], 2 * overlap, bit(l),
3035 BitRefLevel().set());
3036 }
3037
3038 if constexpr (debug) {
3039 if (mField.get_comm_size() == 1) {
3040 for (auto l = 0; l != nb_levels; ++l) {
3041 std::string name = (boost::format("out_r%d.h5m") % l).str();
3042 CHK_THROW_MESSAGE(save_range(mField.get_moab(), name, vec_levels[l]),
3043 "save mesh");
3044 }
3045 }
3046 }
3047
3048 return vec_levels;
3049}
#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/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/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/free_surface.cpp.

Definition at line 1407 of file free_surface.cpp.

1407 {
1409
1410 // FIXME: Functionality in this method should be improved (projection should
1411 // be done field by field), generalized, and move to become core
1412 // functionality.
1413
1414 auto simple = mField.getInterface<Simple>();
1415 auto pip_mng = mField.getInterface<PipelineManager>();
1416 auto bit_mng = mField.getInterface<BitRefManager>();
1417 auto field_blas = mField.getInterface<FieldBlas>();
1418
1419 // Store all existing elements pipelines, replace them by data projection
1420 // pipelines, to put them back when projection is done.
1421 auto fe_domain_lhs = pip_mng->getDomainLhsFE();
1422 auto fe_domain_rhs = pip_mng->getDomainRhsFE();
1423 auto fe_bdy_lhs = pip_mng->getBoundaryLhsFE();
1424 auto fe_bdy_rhs = pip_mng->getBoundaryRhsFE();
1425
1426 pip_mng->getDomainLhsFE().reset();
1427 pip_mng->getDomainRhsFE().reset();
1428 pip_mng->getBoundaryLhsFE().reset();
1429 pip_mng->getBoundaryRhsFE().reset();
1430
1431 using UDO = ForcesAndSourcesCore::UserDataOperator;
1432
1433 // extract field data for domain parent element
1434 auto add_parent_field_domain = [&](auto fe, auto op, auto field, auto bit) {
1435 return setParentDofs(
1436 fe, field, op, bit,
1437
1438 [&]() {
1439 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1440 new DomainParentEle(mField));
1441 return fe_parent;
1442 },
1443
1444 QUIET, Sev::noisy);
1445 };
1446
1447 // extract field data for boundary parent element
1448 auto add_parent_field_bdy = [&](auto fe, auto op, auto field, auto bit) {
1449 return setParentDofs(
1450 fe, field, op, bit,
1451
1452 [&]() {
1453 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1455 return fe_parent;
1456 },
1457
1458 QUIET, Sev::noisy);
1459 };
1460
1461 // run this element on element with given bit, otherwise run other nested
1462 // element
1463 auto create_run_parent_op = [&](auto parent_fe_ptr, auto this_fe_ptr,
1464 auto fe_bit) {
1465 auto parent_mask = fe_bit;
1466 parent_mask.flip();
1467 return new OpRunParent(parent_fe_ptr, BitRefLevel().set(), parent_mask,
1468 this_fe_ptr, fe_bit, BitRefLevel().set(), QUIET,
1469 Sev::inform);
1470 };
1471
1472 // create hierarchy of nested elements
1473 auto get_parents_vel_fe_ptr = [&](auto this_fe_ptr, auto fe_bit) {
1474 std::vector<boost::shared_ptr<DomainParentEle>> parents_elems_ptr_vec;
1475 for (int l = 0; l < nb_levels; ++l)
1476 parents_elems_ptr_vec.emplace_back(
1477 boost::make_shared<DomainParentEle>(mField));
1478 for (auto l = 1; l < nb_levels; ++l) {
1479 parents_elems_ptr_vec[l - 1]->getOpPtrVector().push_back(
1480 create_run_parent_op(parents_elems_ptr_vec[l], this_fe_ptr, fe_bit));
1481 }
1482 return parents_elems_ptr_vec[0];
1483 };
1484
1485 // solve projection problem
1486 auto solve_projection = [&](auto exe_test) {
1488
1489 auto set_domain_rhs = [&](auto fe) {
1491 auto &pip = fe->getOpPtrVector();
1492
1493 auto u_ptr = boost::make_shared<MatrixDouble>();
1494 auto p_ptr = boost::make_shared<VectorDouble>();
1495 auto h_ptr = boost::make_shared<VectorDouble>();
1496 auto g_ptr = boost::make_shared<VectorDouble>();
1497
1498 auto eval_fe_ptr = boost::make_shared<DomainParentEle>(mField);
1499 {
1500 auto &pip = eval_fe_ptr->getOpPtrVector();
1503 eval_fe_ptr, "", UDO::OPSPACE, bit(get_skin_projection_bit()),
1504
1505 [&]() {
1506 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1507 new DomainParentEle(mField));
1508 return fe_parent;
1509 },
1510
1511 QUIET, Sev::noisy);
1512 // That can be done much smarter, by block, field by field. For
1513 // simplicity is like that.
1514 CHKERR add_parent_field_domain(eval_fe_ptr, UDO::OPCOL, "U",
1516 pip.push_back(new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
1517 CHKERR add_parent_field_domain(eval_fe_ptr, UDO::OPCOL, "P",
1519 pip.push_back(new OpCalculateScalarFieldValues("P", p_ptr));
1520 CHKERR add_parent_field_domain(eval_fe_ptr, UDO::OPCOL, "H",
1522 pip.push_back(new OpCalculateScalarFieldValues("H", h_ptr));
1523 CHKERR add_parent_field_domain(eval_fe_ptr, UDO::OPCOL, "G",
1525 pip.push_back(new OpCalculateScalarFieldValues("G", g_ptr));
1526 }
1527 auto parent_eval_fe_ptr =
1528 get_parents_vel_fe_ptr(eval_fe_ptr, bit(get_projection_bit()));
1529 pip.push_back(create_run_parent_op(parent_eval_fe_ptr, eval_fe_ptr,
1531
1532 auto assemble_fe_ptr = boost::make_shared<DomainParentEle>(mField);
1533 {
1534 auto &pip = assemble_fe_ptr->getOpPtrVector();
1537 assemble_fe_ptr, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
1538
1539 [&]() {
1540 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1541 new DomainParentEle(mField));
1542 return fe_parent;
1543 },
1544
1545 QUIET, Sev::noisy);
1546 CHKERR add_parent_field_domain(assemble_fe_ptr, UDO::OPROW, "U",
1548 pip.push_back(new OpDomainAssembleVector("U", u_ptr));
1549 CHKERR add_parent_field_domain(assemble_fe_ptr, UDO::OPROW, "P",
1551 pip.push_back(new OpDomainAssembleScalar("P", p_ptr));
1552 CHKERR add_parent_field_domain(assemble_fe_ptr, UDO::OPROW, "H",
1554 pip.push_back(new OpDomainAssembleScalar("H", h_ptr));
1555 CHKERR add_parent_field_domain(assemble_fe_ptr, UDO::OPROW, "G",
1557 pip.push_back(new OpDomainAssembleScalar("G", g_ptr));
1558 }
1559 auto parent_assemble_fe_ptr =
1560 get_parents_vel_fe_ptr(assemble_fe_ptr, bit(get_current_bit()));
1561 pip.push_back(create_run_parent_op(
1562 parent_assemble_fe_ptr, assemble_fe_ptr, bit(get_current_bit())));
1563
1565 };
1566
1567 auto set_domain_lhs = [&](auto fe) {
1569
1570 auto &pip = fe->getOpPtrVector();
1571
1573
1575 fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
1576
1577 [&]() {
1578 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1579 new DomainParentEle(mField));
1580 return fe_parent;
1581 },
1582
1583 QUIET, Sev::noisy);
1584
1585 // That can be done much smarter, by block, field by field. For simplicity
1586 // is like that.
1587 CHKERR add_parent_field_domain(fe, UDO::OPROW, "U",
1589 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "U",
1591 pip.push_back(new OpDomainMassU("U", "U"));
1592 CHKERR add_parent_field_domain(fe, UDO::OPROW, "P",
1594 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "P",
1596 pip.push_back(new OpDomainMassP("P", "P"));
1597 CHKERR add_parent_field_domain(fe, UDO::OPROW, "H",
1599 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "H",
1601 pip.push_back(new OpDomainMassH("H", "H"));
1602 CHKERR add_parent_field_domain(fe, UDO::OPROW, "G",
1604 CHKERR add_parent_field_domain(fe, UDO::OPCOL, "G",
1606 pip.push_back(new OpDomainMassG("G", "G"));
1607
1609 };
1610
1611 auto set_bdy_rhs = [&](auto fe) {
1613 auto &pip = fe->getOpPtrVector();
1614
1615 auto l_ptr = boost::make_shared<VectorDouble>();
1616
1617 auto eval_fe_ptr = boost::make_shared<BoundaryParentEle>(mField);
1618 {
1619 auto &pip = eval_fe_ptr->getOpPtrVector();
1621 eval_fe_ptr, "", UDO::OPSPACE, bit(get_skin_projection_bit()),
1622
1623 [&]() {
1624 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1626 return fe_parent;
1627 },
1628
1629 QUIET, Sev::noisy);
1630 // That can be done much smarter, by block, field by field. For
1631 // simplicity is like that.
1632 CHKERR add_parent_field_bdy(eval_fe_ptr, UDO::OPCOL, "L",
1634 pip.push_back(new OpCalculateScalarFieldValues("L", l_ptr));
1635 }
1636 auto parent_eval_fe_ptr =
1637 get_parents_vel_fe_ptr(eval_fe_ptr, bit(get_projection_bit()));
1638 pip.push_back(create_run_parent_op(parent_eval_fe_ptr, eval_fe_ptr,
1640
1641 auto assemble_fe_ptr = boost::make_shared<BoundaryParentEle>(mField);
1642 {
1643 auto &pip = assemble_fe_ptr->getOpPtrVector();
1645 assemble_fe_ptr, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
1646
1647 [&]() {
1648 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1650 return fe_parent;
1651 },
1652
1653 QUIET, Sev::noisy);
1654
1655 struct OpLSize : public BoundaryEleOp {
1656 OpLSize(boost::shared_ptr<VectorDouble> l_ptr)
1657 : BoundaryEleOp(NOSPACE, DomainEleOp::OPSPACE), lPtr(l_ptr) {}
1658 MoFEMErrorCode doWork(int, EntityType, EntData &) {
1660 if (lPtr->size() != getGaussPts().size2()) {
1661 lPtr->resize(getGaussPts().size2());
1662 lPtr->clear();
1663 }
1665 }
1666
1667 private:
1668 boost::shared_ptr<VectorDouble> lPtr;
1669 };
1670
1671 pip.push_back(new OpLSize(l_ptr));
1672
1673 CHKERR add_parent_field_bdy(assemble_fe_ptr, UDO::OPROW, "L",
1675 pip.push_back(new OpBoundaryAssembleScalar("L", l_ptr));
1676 }
1677 auto parent_assemble_fe_ptr =
1678 get_parents_vel_fe_ptr(assemble_fe_ptr, bit(get_current_bit()));
1679 pip.push_back(create_run_parent_op(
1680 parent_assemble_fe_ptr, assemble_fe_ptr, bit(get_current_bit())));
1681
1683 };
1684
1685 auto set_bdy_lhs = [&](auto fe) {
1687
1688 auto &pip = fe->getOpPtrVector();
1689
1691 fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
1692
1693 [&]() {
1694 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1696 return fe_parent;
1697 },
1698
1699 QUIET, Sev::noisy);
1700
1701 // That can be done much smarter, by block, field by field. For simplicity
1702 // is like that.
1703 CHKERR add_parent_field_bdy(fe, UDO::OPROW, "L",
1705 CHKERR add_parent_field_bdy(fe, UDO::OPCOL, "L",
1707 pip.push_back(new OpBoundaryMassL("L", "L"));
1708
1710 };
1711
1712 auto create_subdm = [&]() -> SmartPetscObj<DM> {
1713 auto level_ents_ptr = boost::make_shared<Range>();
1714 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByRefLevel(
1715 bit(get_current_bit()), BitRefLevel().set(), *level_ents_ptr);
1716
1717 auto get_prj_ents = [&]() {
1718 Range prj_mesh;
1719 CHKERR bit_mng->getEntitiesByDimAndRefLevel(bit(get_projection_bit()),
1720 BitRefLevel().set(),
1721 SPACE_DIM, prj_mesh);
1722 auto common_ents = intersect(prj_mesh, *level_ents_ptr);
1723 prj_mesh = subtract(unite(*level_ents_ptr, prj_mesh), common_ents)
1724 .subset_by_dimension(SPACE_DIM);
1725
1726 return prj_mesh;
1727 };
1728
1729 auto prj_ents = get_prj_ents();
1730
1731 if (get_global_size(prj_ents.size())) {
1732
1733 auto rebuild = [&]() {
1734 auto prb_mng = mField.getInterface<ProblemsManager>();
1736
1737 std::vector<std::string> fields{"U", "P", "H", "G", "L"};
1738 std::map<std::string, boost::shared_ptr<Range>> range_maps{
1739
1740 {"U", level_ents_ptr},
1741 {"P", level_ents_ptr},
1742 {"H", level_ents_ptr},
1743 {"G", level_ents_ptr},
1744 {"L", level_ents_ptr}
1745
1746 };
1747
1748 CHKERR prb_mng->buildSubProblem("SUB_SOLVER", fields, fields,
1749 simple->getProblemName(), PETSC_TRUE,
1750 &range_maps, &range_maps);
1751
1752 // partition problem
1753 CHKERR prb_mng->partitionFiniteElements("SUB_SOLVER", true, 0,
1755 // set ghost nodes
1756 CHKERR prb_mng->partitionGhostDofsOnDistributedMesh("SUB_SOLVER");
1757
1759 };
1760
1761 MOFEM_LOG("FS", Sev::verbose) << "Create projection problem";
1762
1763 CHKERR rebuild();
1764
1765 auto dm = simple->getDM();
1766 DM subdm;
1767 CHKERR DMCreate(mField.get_comm(), &subdm);
1768 CHKERR DMSetType(subdm, "DMMOFEM");
1769 CHKERR DMMoFEMCreateSubDM(subdm, dm, "SUB_SOLVER");
1770 return SmartPetscObj<DM>(subdm);
1771 }
1772
1773 MOFEM_LOG("FS", Sev::inform) << "Nothing to project";
1774
1775 return SmartPetscObj<DM>();
1776 };
1777
1778 auto create_dummy_dm = [&]() {
1779 auto dummy_dm = createDM(mField.get_comm(), "DMMOFEM");
1781 simple->getProblemName().c_str(),
1783 "create dummy dm");
1784 return dummy_dm;
1785 };
1786
1787 auto subdm = create_subdm();
1788 if (subdm) {
1789
1790 pip_mng->getDomainRhsFE().reset();
1791 pip_mng->getDomainLhsFE().reset();
1792 pip_mng->getBoundaryRhsFE().reset();
1793 pip_mng->getBoundaryLhsFE().reset();
1794 CHKERR pip_mng->setDomainRhsIntegrationRule(integration_rule);
1795 CHKERR pip_mng->setDomainLhsIntegrationRule(integration_rule);
1796 CHKERR pip_mng->setBoundaryRhsIntegrationRule(integration_rule);
1797 CHKERR pip_mng->setBoundaryLhsIntegrationRule(integration_rule);
1798 pip_mng->getDomainLhsFE()->exeTestHook = exe_test;
1799 pip_mng->getDomainRhsFE()->exeTestHook = [](FEMethod *fe_ptr) {
1800 return get_fe_bit(fe_ptr).test(nb_levels - 1);
1801 };
1802 pip_mng->getBoundaryLhsFE()->exeTestHook = exe_test;
1803 pip_mng->getBoundaryRhsFE()->exeTestHook = [](FEMethod *fe_ptr) {
1804 return get_fe_bit(fe_ptr).test(nb_levels - 1);
1805 };
1806
1807 CHKERR set_domain_rhs(pip_mng->getCastDomainRhsFE());
1808 CHKERR set_domain_lhs(pip_mng->getCastDomainLhsFE());
1809 CHKERR set_bdy_rhs(pip_mng->getCastBoundaryRhsFE());
1810 CHKERR set_bdy_lhs(pip_mng->getCastBoundaryLhsFE());
1811
1812 auto D = createDMVector(subdm);
1813 auto F = vectorDuplicate(D);
1814
1815 auto ksp = pip_mng->createKSP(subdm);
1816 CHKERR KSPSetFromOptions(ksp);
1817 CHKERR KSPSetUp(ksp);
1818
1819 // get vector norm
1820 auto get_norm = [&](auto x) {
1821 double nrm;
1822 CHKERR VecNorm(x, NORM_2, &nrm);
1823 return nrm;
1824 };
1825
1826 /**
1827 * @brief Zero DOFs, used by FieldBlas
1828 */
1829 auto zero_dofs = [](boost::shared_ptr<FieldEntity> ent_ptr) {
1831 for (auto &v : ent_ptr->getEntFieldData()) {
1832 v = 0;
1833 }
1835 };
1836
1837 auto solve = [&](auto S) {
1839 CHKERR VecZeroEntries(S);
1840 CHKERR VecZeroEntries(F);
1841 CHKERR VecGhostUpdateBegin(F, INSERT_VALUES, SCATTER_FORWARD);
1842 CHKERR VecGhostUpdateEnd(F, INSERT_VALUES, SCATTER_FORWARD);
1843 CHKERR KSPSolve(ksp, F, S);
1844 CHKERR VecGhostUpdateBegin(S, INSERT_VALUES, SCATTER_FORWARD);
1845 CHKERR VecGhostUpdateEnd(S, INSERT_VALUES, SCATTER_FORWARD);
1846
1847
1848
1850 };
1851
1852 MOFEM_LOG("FS", Sev::inform) << "Solve projection";
1853 CHKERR solve(D);
1854
1855 auto glob_x = createDMVector(simple->getDM());
1856 auto sub_x = createDMVector(subdm);
1857 auto dummy_dm = create_dummy_dm();
1858
1859 /**
1860 * @brief get TSTheta data operators
1861 */
1862 auto apply_restrict = [&]() {
1863 auto get_is = [](auto v) {
1864 IS iy;
1865 auto create = [&]() {
1867 int n, ystart;
1868 CHKERR VecGetLocalSize(v, &n);
1869 CHKERR VecGetOwnershipRange(v, &ystart, NULL);
1870 CHKERR ISCreateStride(PETSC_COMM_SELF, n, ystart, 1, &iy);
1872 };
1873 CHK_THROW_MESSAGE(create(), "create is");
1874 return SmartPetscObj<IS>(iy);
1875 };
1876
1877 auto iy = get_is(glob_x);
1878 auto s = createVecScatter(glob_x, PETSC_NULLPTR, glob_x, iy);
1879
1881 DMSubDomainRestrict(simple->getDM(), s, PETSC_NULLPTR, dummy_dm),
1882 "restrict");
1883 Vec X0, Xdot;
1884 CHK_THROW_MESSAGE(DMGetNamedGlobalVector(dummy_dm, "TSTheta_X0", &X0),
1885 "get X0");
1887 DMGetNamedGlobalVector(dummy_dm, "TSTheta_Xdot", &Xdot),
1888 "get Xdot");
1889
1890 auto forward_ghost = [](auto g) {
1892 CHKERR VecGhostUpdateBegin(g, INSERT_VALUES, SCATTER_FORWARD);
1893 CHKERR VecGhostUpdateEnd(g, INSERT_VALUES, SCATTER_FORWARD);
1895 };
1896
1897 CHK_THROW_MESSAGE(forward_ghost(X0), "");
1898 CHK_THROW_MESSAGE(forward_ghost(Xdot), "");
1899
1900 if constexpr (debug) {
1901 MOFEM_LOG("FS", Sev::inform)
1902 << "Reverse restrict: X0 " << get_norm(X0) << " Xdot "
1903 << get_norm(Xdot);
1904 }
1905
1906 return std::vector<Vec>{X0, Xdot};
1907 };
1908
1909 auto ts_solver_vecs = apply_restrict();
1910
1911 if (ts_solver_vecs.size()) {
1912
1913 for (auto v : ts_solver_vecs) {
1914 MOFEM_LOG("FS", Sev::inform) << "Solve projection vector";
1915
1916 CHKERR DMoFEMMeshToLocalVector(simple->getDM(), v, INSERT_VALUES,
1917 SCATTER_REVERSE);
1918 CHKERR solve(sub_x);
1919
1920 for (auto f : {"U", "P", "H", "G", "L"}) {
1921 MOFEM_LOG("WORLD", Sev::verbose) << "Zero field " << f;
1922 CHKERR field_blas->fieldLambdaOnEntities(zero_dofs, f);
1923 }
1924
1925 CHKERR DMoFEMMeshToLocalVector(subdm, sub_x, INSERT_VALUES,
1926 SCATTER_REVERSE);
1927 CHKERR DMoFEMMeshToLocalVector(simple->getDM(), v, INSERT_VALUES,
1928 SCATTER_FORWARD);
1929
1930 MOFEM_LOG("FS", Sev::inform) << "Norm V " << get_norm(v);
1931 }
1932
1933 CHKERR DMRestoreNamedGlobalVector(dummy_dm, "TSTheta_X0",
1934 &ts_solver_vecs[0]);
1935 CHKERR DMRestoreNamedGlobalVector(dummy_dm, "TSTheta_Xdot",
1936 &ts_solver_vecs[1]);
1937 }
1938
1939 for (auto f : {"U", "P", "H", "G", "L"}) {
1940 MOFEM_LOG("WORLD", Sev::verbose) << "Zero field " << f;
1941 CHKERR field_blas->fieldLambdaOnEntities(zero_dofs, f);
1942 }
1943 CHKERR DMoFEMMeshToLocalVector(subdm, D, INSERT_VALUES, SCATTER_REVERSE);
1944 }
1945
1947 };
1948
1949 // postprocessing (only for debugging purposes)
1950 auto post_proc = [&](auto exe_test) {
1952 auto post_proc_fe = boost::make_shared<PostProcEleDomain>(mField);
1953 auto &pip = post_proc_fe->getOpPtrVector();
1954 post_proc_fe->exeTestHook = exe_test;
1955
1957
1959 post_proc_fe, "", UDO::OPSPACE, bit(get_skin_parent_bit()),
1960
1961 [&]() {
1962 boost::shared_ptr<ForcesAndSourcesCore> fe_parent(
1963 new DomainParentEle(mField));
1965 fe_parent->getOpPtrVector(), {H1});
1966 return fe_parent;
1967 },
1968
1969 QUIET, Sev::noisy);
1970
1972
1973 auto u_ptr = boost::make_shared<MatrixDouble>();
1974 auto p_ptr = boost::make_shared<VectorDouble>();
1975 auto h_ptr = boost::make_shared<VectorDouble>();
1976 auto g_ptr = boost::make_shared<VectorDouble>();
1977
1978 CHKERR add_parent_field_domain(post_proc_fe, UDO::OPCOL, "U",
1980 pip.push_back(new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
1981 CHKERR add_parent_field_domain(post_proc_fe, UDO::OPCOL, "P",
1983 pip.push_back(new OpCalculateScalarFieldValues("P", p_ptr));
1984 CHKERR add_parent_field_domain(post_proc_fe, UDO::OPCOL, "H",
1986 pip.push_back(new OpCalculateScalarFieldValues("H", h_ptr));
1987 CHKERR add_parent_field_domain(post_proc_fe, UDO::OPCOL, "G",
1989 pip.push_back(new OpCalculateScalarFieldValues("G", g_ptr));
1990
1991 post_proc_fe->getOpPtrVector().push_back(
1992
1993 new OpPPMap(post_proc_fe->getPostProcMesh(),
1994 post_proc_fe->getMapGaussPts(),
1995
1996 {{"P", p_ptr}, {"H", h_ptr}, {"G", g_ptr}},
1997
1998 {{"U", u_ptr}},
1999
2000 {},
2001
2002 {}
2003
2004 )
2005
2006 );
2007
2008 auto dm = simple->getDM();
2009 CHKERR DMoFEMLoopFiniteElements(dm, "dFE", post_proc_fe);
2010 CHKERR post_proc_fe->writeFile("out_projection.h5m");
2011
2013 };
2014
2015 CHKERR solve_projection([](FEMethod *fe_ptr) {
2016 return get_fe_bit(fe_ptr).test(get_current_bit());
2017 });
2018
2019 if constexpr (debug) {
2020 CHKERR post_proc([](FEMethod *fe_ptr) {
2021 return get_fe_bit(fe_ptr).test(get_current_bit());
2022 });
2023 }
2024
2025 fe_domain_lhs.swap(pip_mng->getDomainLhsFE());
2026 fe_domain_rhs.swap(pip_mng->getDomainRhsFE());
2027 fe_bdy_lhs.swap(pip_mng->getBoundaryLhsFE());
2028 fe_bdy_rhs.swap(pip_mng->getBoundaryRhsFE());
2029
2031}
@ NOSPACE
Definition definitions.h:83
@ F
OpDomainMassH OpDomainMassG
FormsIntegrators< DomainEleOp >::Assembly< A >::LinearForm< I >::OpBaseTimesVector< BASE_DIM, SPACE_DIM, SPACE_DIM > 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:1322
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/free_surface.cpp.

Definition at line 993 of file free_surface.cpp.

993 {
995 MOFEM_LOG("FS", Sev::inform) << "Read mesh for problem";
997
999 simple->getBitRefLevel() = BitRefLevel();
1000
1001 CHKERR simple->getOptions();
1002 CHKERR simple->loadFile();
1003
1005}
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/free_surface.cpp.

Definition at line 3051 of file free_surface.cpp.

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

Definition at line 980 of file free_surface.cpp.

980 {
989}
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 checkResults()
Check results for correctness.
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/free_surface.cpp.

Definition at line 3282 of file free_surface.cpp.

3287 {
3289
3290 /**
3291 * @brief Collect data from parent elements to child
3292 */
3293 boost::function<void(boost::shared_ptr<ForcesAndSourcesCore>, int)>
3294 add_parent_level =
3295 [&](boost::shared_ptr<ForcesAndSourcesCore> parent_fe_pt, int level) {
3296 // Evaluate if not last parent element
3297 if (level > 0) {
3298
3299 // Create domain parent FE
3300 auto fe_ptr_current = get_elem();
3301
3302 // Call next level
3303 add_parent_level(
3304 boost::dynamic_pointer_cast<ForcesAndSourcesCore>(
3305 fe_ptr_current),
3306 level - 1);
3307
3308 // Add data to curent fe level
3310
3311 // Only base
3312 parent_fe_pt->getOpPtrVector().push_back(
3313
3315
3316 H1, op, fe_ptr_current,
3317
3318 BitRefLevel().set(), BitRefLevel().set(),
3319
3320 child_ent_bit, BitRefLevel().set(),
3321
3322 verbosity, sev));
3323
3324 } else {
3325
3326 // Filed data
3327 parent_fe_pt->getOpPtrVector().push_back(
3328
3330
3331 field_name, op, fe_ptr_current,
3332
3333 BitRefLevel().set(), BitRefLevel().set(),
3334
3335 child_ent_bit, BitRefLevel().set(),
3336
3337 verbosity, sev));
3338 }
3339 }
3340 };
3341
3342 add_parent_level(boost::dynamic_pointer_cast<ForcesAndSourcesCore>(fe_top),
3343 nb_levels);
3344
3346}
@ 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/free_surface.cpp.

Definition at line 1009 of file free_surface.cpp.

1009 {
1011
1012 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &order, PETSC_NULLPTR);
1013 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-nb_levels", &nb_levels,
1014 PETSC_NULLPTR);
1015 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-refine_overlap", &refine_overlap,
1016 PETSC_NULLPTR);
1017
1018 const char *coord_type_names[] = {"cartesian", "polar", "cylindrical",
1019 "spherical"};
1020 CHKERR PetscOptionsGetEList(PETSC_NULLPTR, NULL, "-coords", coord_type_names,
1021 LAST_COORDINATE_SYSTEM, &coord_type, PETSC_NULLPTR);
1022
1023 MOFEM_LOG("FS", Sev::inform) << "Approximation order = " << order;
1024 MOFEM_LOG("FS", Sev::inform)
1025 << "Number of refinement levels nb_levels = " << nb_levels;
1026 nb_levels += 1;
1027
1028 auto simple = mField.getInterface<Simple>();
1029
1030 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-a0", &a0, PETSC_NULLPTR); // Acceleration
1031 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-rho_m", &rho_m, PETSC_NULLPTR); // Density minus phase
1032 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-mu_m", &mu_m, PETSC_NULLPTR); // Viscosity minus phase
1033 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-rho_p", &rho_p, PETSC_NULLPTR); // Density plus phase
1034 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-mu_p", &mu_p, PETSC_NULLPTR); // Viscosity plus phase
1035 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-lambda", &lambda, PETSC_NULLPTR); // Surface tension
1036 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-W", &W, PETSC_NULLPTR); // Height of the well in energy functional
1037
1038 rho_ave = (rho_p + rho_m) / 2;
1039 rho_diff = (rho_p - rho_m) / 2;
1040 mu_ave = (mu_p + mu_m) / 2;
1041 mu_diff = (mu_p - mu_m) / 2;
1042
1043 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-h", &h, PETSC_NULLPTR);
1044 eta = h;
1045 eta2 = eta * eta;
1046 kappa = (3. / (4. * std::sqrt(2. * W))) * (lambda / eta);
1047
1048 CHKERR PetscOptionsGetScalar(PETSC_NULLPTR, "", "-md", &md, PETSC_NULLPTR);
1049
1050 MOFEM_LOG("FS", Sev::inform) << "Acceleration a0 = " << a0;
1051 MOFEM_LOG("FS", Sev::inform) << "\"Minus\" phase density rho_m = " << rho_m;
1052 MOFEM_LOG("FS", Sev::inform) << "\"Minus\" phase viscosity mu_m = " << mu_m;
1053 MOFEM_LOG("FS", Sev::inform) << "\"Plus\" phase density rho_p = " << rho_p;
1054 MOFEM_LOG("FS", Sev::inform) << "\"Plus\" phase viscosity mu_p = " << mu_p;
1055 MOFEM_LOG("FS", Sev::inform) << "Surface tension lambda = " << lambda;
1056 MOFEM_LOG("FS", Sev::inform)
1057 << "Height of the well in energy functional W = " << W;
1058 MOFEM_LOG("FS", Sev::inform) << "Characteristic mesh size h = " << h;
1059 MOFEM_LOG("FS", Sev::inform) << "Mobility md = " << md;
1060
1061 MOFEM_LOG("FS", Sev::inform) << "Average density rho_ave = " << rho_ave;
1062 MOFEM_LOG("FS", Sev::inform) << "Difference density rho_diff = " << rho_diff;
1063 MOFEM_LOG("FS", Sev::inform) << "Average viscosity mu_ave = " << mu_ave;
1064 MOFEM_LOG("FS", Sev::inform) << "Difference viscosity mu_diff = " << mu_diff;
1065 MOFEM_LOG("FS", Sev::inform) << "kappa = " << kappa;
1066
1067
1068 // Fields on domain
1069
1070 // Velocity field
1071 CHKERR simple->addDomainField("U", H1, AINSWORTH_LEGENDRE_BASE, U_FIELD_DIM);
1072 // Pressure field
1073 CHKERR simple->addDomainField("P", H1, AINSWORTH_LEGENDRE_BASE, 1);
1074 // Order/phase fild
1075 CHKERR simple->addDomainField("H", H1, AINSWORTH_LEGENDRE_BASE, 1);
1076 // Chemical potential
1077 CHKERR simple->addDomainField("G", H1, AINSWORTH_LEGENDRE_BASE, 1);
1078
1079 // Field on boundary
1080 CHKERR simple->addBoundaryField("U", H1, AINSWORTH_LEGENDRE_BASE,
1081 U_FIELD_DIM);
1082 CHKERR simple->addBoundaryField("H", H1, AINSWORTH_LEGENDRE_BASE, 1);
1083 CHKERR simple->addBoundaryField("G", H1, AINSWORTH_LEGENDRE_BASE, 1);
1084 // Lagrange multiplier which constrains slip conditions
1085 CHKERR simple->addBoundaryField("L", H1, AINSWORTH_LEGENDRE_BASE, 1);
1086
1087 CHKERR simple->setFieldOrder("U", order);
1088 CHKERR simple->setFieldOrder("P", order - 1);
1089 CHKERR simple->setFieldOrder("H", order);
1090 CHKERR simple->setFieldOrder("G", order);
1091 CHKERR simple->setFieldOrder("L", order);
1092
1093 // Initialise bit ref levels
1094 auto set_problem_bit = [&]() {
1096 // Set bits to build adjacencies between parents and children. That is
1097 // used by simple interface.
1098 simple->getBitAdjEnt() = BitRefLevel().set();
1099 simple->getBitAdjParent() = BitRefLevel().set();
1100 simple->getBitRefLevel() = BitRefLevel().set();
1101 simple->getBitRefLevelMask() = BitRefLevel().set();
1103 };
1104
1105 CHKERR set_problem_bit();
1106
1107 CHKERR simple->setUp();
1108
1110}
@ 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 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/free_surface.cpp.

Definition at line 2503 of file free_surface.cpp.

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

Friends And Related Symbol Documentation

◆ TSPrePostProc

friend struct TSPrePostProc
friend

Definition at line 969 of file free_surface.cpp.

Member Data Documentation

◆ mField

MoFEM::Interface& FreeSurface::mField

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