v0.15.5
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 797 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 804 of file free_surface.cpp.

804: 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 2030 of file free_surface.cpp.

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

Definition at line 1109 of file free_surface.cpp.

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

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

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

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

988 {
990 MOFEM_LOG("FS", Sev::inform) << "Read mesh for problem";
992
994 simple->getBitRefLevel() = BitRefLevel();
995
996 CHKERR simple->getOptions();
997 CHKERR simple->loadFile();
998
1000}
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 3046 of file free_surface.cpp.

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

975 {
984}
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 3277 of file free_surface.cpp.

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

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

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

Member Data Documentation

◆ mField

MoFEM::Interface& FreeSurface::mField

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