v0.15.5
Loading...
Searching...
No Matches
FreeSurfaceOps.hpp
Go to the documentation of this file.
1/**
2 * @file FreeSurfaceOps.hpp
3 * @brief Implements operators for assembling residuals and Jacobians for the Navier–Stokes–Cahn–Hilliard free-surface problem.
4 *
5 * This file contains boundary and domain operators used in MoFEM pipelines:
6 * - Boundary operators: normal constraints, wetting angle, lift force.
7 * - Domain operators: momentum, phase evolution, chemical potential.
8 *
9 * Documentation: see `free_surface.dox` in the `doc` folder of this tutorial.
10 * Note that documentation has been produced with the help of copilot. (Though all has had human review and editing!)
11 *
12 * @see free_surface.dox
13 * @see Lovrić et al., "Low Order Finite Element Methods for the Navier–Stokes–Cahn–Hilliard Equations", arXiv:1911.06718
14 */
15
16namespace FreeSurfaceOps {
17
18
19/**
20 * @brief Calculate lift force on free surface boundary
21 * @param field_name Name of the field associated with the operator
22 * @param p_ptr Pointer to the pressure vector on the free surface
23 * @param lift_ptr Pointer to the lift force vector to be computed
24 * @param ents_ptr Pointer to the range of entities (edges) to consider
25 * @return MoFEMErrorCode
26 *
27 * Computes the integral ∫_Γ ​-p n dΓ, where:
28 * - p : pressure on the free surface
29 * - n : outward normal vector on the boundary
30 */
32 OpCalculateLift(const std::string field_name,
33 boost::shared_ptr<VectorDouble> p_ptr,
34 boost::shared_ptr<VectorDouble> lift_ptr,
35 boost::shared_ptr<Range> ents_ptr)
37 pPtr(p_ptr), liftPtr(lift_ptr), entsPtr(ents_ptr) {
38 std::fill(&doEntities[MBVERTEX], &doEntities[MBMAXTYPE], false);
39 doEntities[MBEDGE] = true;
40 }
41
42 MoFEMErrorCode doWork(int row_side, EntityType row_type,
43 EntitiesFieldData::EntData &data) {
45
46 const auto fe_ent = getFEEntityHandle();
47 if (entsPtr->find(fe_ent) != entsPtr->end()) {
48
49 auto t_w = getFTensor0IntegrationWeight();
50 auto t_p = getFTensor0FromVec(*pPtr);
51 auto t_normal = getFTensor1Normal();
52 auto t_coords = getFTensor1CoordsAtGaussPts();
53 auto t_lift = getFTensor1FromArray<SPACE_DIM, SPACE_DIM>(*liftPtr);
54
55 const auto nb_int_points = getGaussPts().size2();
56
57 for (int gg = 0; gg != nb_int_points; gg++) {
58
59 const double r = t_coords(0);
60 const double alpha = cylindrical(r) * t_w;
61 t_lift(i) -= t_normal(i) * (t_p * alpha); // −p n
62
63 ++t_w;
64 ++t_p;
65 ++t_coords;
66 }
67 }
68
70 }
71
72private:
73 boost::shared_ptr<VectorDouble> pPtr;
74 boost::shared_ptr<VectorDouble> liftPtr;
75 boost::shared_ptr<Range> entsPtr;
76};
77
78//! [OpNormalConstrainRhs]
79/**
80 * @brief Boundary normal constraint RHS
81 * @param field_name Name of the field associated with the operator
82 * @param u_ptr Pointer to the velocity matrix on the free surface
83 * @return MoFEMErrorCode
84 *
85 * Computes the integral ∫_Γ ​w_L​·(n·u) dΓ, where:
86 * - w_L : test function for Lagrange multiplier (λ)
87 * - n : outward normal vector on the boundary
88 */
91 boost::shared_ptr<MatrixDouble> u_ptr)
94 uPtr(u_ptr) {}
95
96 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data) {
98
99 auto t_w = getFTensor0IntegrationWeight();
100 auto t_normal = getFTensor1Normal();
101 auto t_u = getFTensor1FromMat<SPACE_DIM>(*uPtr);
102 auto t_row_base = row_data.getFTensor0N();
103 auto t_coords = getFTensor1CoordsAtGaussPts();
104
105 for (int gg = 0; gg != nbIntegrationPts; gg++) {
106
107 const double r = t_coords(0);
108 const double alpha = t_w * cylindrical(r);
109
110 int bb = 0;
111 for (; bb != nbRows; ++bb) {
112 locF[bb] += alpha * t_row_base * (t_normal(i) * t_u(i)); // λ * (n · u)
113 ++t_row_base;
114 }
115
116 for (; bb < nbRowBaseFunctions; ++bb)
117 ++t_row_base;
118
119 ++t_w;
120 ++t_u;
121 ++t_coords;
122 }
123
125 }
126
127private:
128 boost::shared_ptr<MatrixDouble> uPtr;
129};
130//! [OpNormalConstrainRhs]
131
132/**
133 * @brief Boundary normal force RHS
134 * @param field_name Name of the field associated with the operator
135 * @param lambda_ptr Pointer to the Lagrange multiplier vector on the free surface
136 * @return MoFEMErrorCode
137 *
138 * Assembles the contribution of the Lagrange multiplier (λ) normal force
139 * ie ∫_Γ N_u · (λ n) dΓ into the momentum residual.
140 */
142 OpNormalForceRhs(const std::string field_name,
143 boost::shared_ptr<VectorDouble> lambda_ptr)
145 AssemblyDomainEleOp::OPROW),
146 lambdaPtr(lambda_ptr) {}
147
148 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data) {
150
151 auto t_w = getFTensor0IntegrationWeight();
152 auto t_normal = getFTensor1Normal();
153 auto t_lambda = getFTensor0FromVec(*lambdaPtr);
154 auto t_row_base = row_data.getFTensor0N();
155 auto t_coords = getFTensor1CoordsAtGaussPts();
156
157 for (int gg = 0; gg != nbIntegrationPts; gg++) {
158
159 auto t_nf = getFTensor1FromArray<U_FIELD_DIM, U_FIELD_DIM>(locF);
160
161 const double r = t_coords(0);
162 const double alpha = t_w * cylindrical(r);
163
164 int bb = 0;
165 for (; bb != nbRows / U_FIELD_DIM; ++bb) {
166
167 t_nf(i) += alpha * t_row_base * t_normal(i) * t_lambda; // N_u · (λ n)
168 ++t_row_base;
169 ++t_nf;
170 }
171
172 for (; bb < nbRowBaseFunctions; ++bb)
173 ++t_row_base;
174
175 ++t_w;
176 ++t_lambda;
177 ++t_coords;
178 }
179
181 }
182
183private:
184 boost::shared_ptr<VectorDouble> lambdaPtr;
185};
186
187//! [OpWettingAngleRhs]
188/**
189 * @brief Boundary wetting-angle RHS
190 * @param field_name Name of the field associated with the operator
191 * @param grad_h_ptr Pointer to the gradient of the free surface height matrix
192 * @param ents_ptr Pointer to the range of entities (edges) to consider
193 * @param wetting_angle Contact wetting angle in degrees
194 * @return MoFEMErrorCode
195 *
196 * Implements the boundary term from eq. 3.2d:
197 * - ∫_Γ sh ε² ||∇ϕ|| cos(α) dΓ
198 * The operator computes rhs_wetting = s * η² * ||∇h|| * cos(angle) and
199 * assembles it into the G residual on selected meshset edges.
200 */
202 OpWettingAngleRhs(const std::string field_name,
203 boost::shared_ptr<MatrixDouble> grad_h_ptr,
204 boost::shared_ptr<Range> ents_ptr = nullptr,
205 double wetting_angle = 0)
207 AssemblyBoundaryEleOp::OPROW),
208 gradHPtr(grad_h_ptr), entsPtr(ents_ptr), wettingAngle(wetting_angle) {}
209
210 MoFEMErrorCode iNtegrate(DataForcesAndSourcesCore::EntData &row_data) {
212 if (entsPtr) {
213 if (entsPtr->find(AssemblyBoundaryEleOp::getFEEntityHandle()) ==
214 entsPtr->end())
216 }
217 const double area = getMeasure();
218 auto t_w = getFTensor0IntegrationWeight();
219 auto t_row_base = row_data.getFTensor0N();
220 auto t_grad_h = getFTensor1FromMat<SPACE_DIM>(*gradHPtr);
221 auto t_coords = getFTensor1CoordsAtGaussPts();
222
223 auto s = wetting_angle_sub_stepping(getFEMethod()->ts_step);
224
225 for (int gg = 0; gg != nbIntegrationPts; gg++) {
226
227 const double r = t_coords(0);
228 const double alpha = t_w * cylindrical(r) * area;
229 const double h_grad_norm = sqrt(t_grad_h(i) * t_grad_h(i) + eps); // ||∇h||
230 const double cos_angle = std::cos(M_PI * wettingAngle / 180);
231 const double rhs_wetting = s * eta2 * h_grad_norm * cos_angle; // s * η² * ||∇h|| * cos(angle)
232
233 // cerr << "pass "
234 // << h_grad_norm <<"\n";
235 int bb = 0;
236 for (; bb != nbRows; ++bb) {
237 locF[bb] += alpha * t_row_base * rhs_wetting;
238 ++t_row_base;
239 }
240
241 for (; bb < nbRowBaseFunctions; ++bb)
242 ++t_row_base;
243
244 ++t_w;
245 ++t_grad_h;
246 ++t_coords;
247 }
248
250 }
251
252private:
253 boost::shared_ptr<MatrixDouble> gradHPtr;
254 boost::shared_ptr<Range> entsPtr;
256};
257//! [OpWettingAngleRhs]
258
259//! [OpNormalConstrainLhs]
260/**
261 * @brief Boundary normal constraint LHS (Jacobian block)
262 * @param field_name_row Name of the field associated with the row operator
263 * @param field_name_col Name of the field associated with the column operator
264 * @return MoFEMErrorCode
265 *
266 * Computes the matrix entries for ∫_Γ ​w_L​⋅(n⋅u) dΓ, and its transpose
267 * ∫_Γ ​w_u​⋅(λn) dΓ, where:
268 * - w_L : test function for Lagrange multiplier (λ)
269 * - w_u : test function for velocity (u)
270 * - n : outward normal vector on the boundary.
271 */
273
274 OpNormalConstrainLhs(const std::string field_name_row,
275 const std::string field_name_col)
276 : AssemblyBoundaryEleOp(field_name_row, field_name_col,
277 AssemblyBoundaryEleOp::OPROWCOL) {
278 assembleTranspose = true;
279 sYmm = false;
280 }
281
282 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
283 EntitiesFieldData::EntData &col_data) {
285
286 auto t_w = getFTensor0IntegrationWeight();
287 auto t_normal = getFTensor1Normal();
288 auto t_row_base = row_data.getFTensor0N();
289 auto t_coords = getFTensor1CoordsAtGaussPts();
290
291 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
292
293 auto t_mat = getFTensor1FromPtr<U_FIELD_DIM>(&locMat(0, 0));
294
295 const double r = t_coords(0);
296 const double alpha = t_w * cylindrical(r);
297
298 int rr = 0;
299 for (; rr != nbRows; ++rr) {
300
301 auto t_col_base = col_data.getFTensor0N(gg, 0);
302 const double a = alpha * t_row_base;
303
304 for (int cc = 0; cc != nbCols / U_FIELD_DIM; ++cc) {
305 t_mat(i) += (a * t_col_base) * t_normal(i); // α * N_row * N_col * n
306 ++t_col_base;
307 ++t_mat;
308 }
309 ++t_row_base;
310 }
311
312 for (; rr < nbRowBaseFunctions; ++rr)
313 ++t_row_base;
314
315 ++t_w;
316 ++t_coords;
317 }
318
320 };
321};
322//! [OpNormalConstrainLhs]
323
324//! [OpWettingAngleLhs]
325/**
326* @brief Boundary wetting-angle LHS (linearization)
327* @param field_name Name of the field associated with the operator
328* @param grad_h_ptr Pointer to the gradient of the free surface height matrix
329* @param col_ind_ptr Pointer to the column indices vector
330* @param col_diff_base_ptr Pointer to the column difference base functions vector
331* @param ents_ptr Pointer to the range of entities (edges) to consider
332* @param wetting_angle Contact wetting angle in degrees
333* @return MoFEMErrorCode
334*
335* Linearization of the wetting-angle boundary term (3.1d - Gamma part) used to assemble the
336* corresponding Jacobian contributions for G (and coupling into H).
337*
338* δ R_g / δ h = ∫_Γ s ε² (∇h / ||∇h||) · ∇(δ h) cos(α) dΓ
339*/
341
343 const std::string row_field_name,
344 boost::shared_ptr<MatrixDouble> grad_h_ptr,
345 boost::shared_ptr<std::vector<VectorInt>> col_ind_ptr,
346 boost::shared_ptr<std::vector<MatrixDouble>> col_diff_base_ptr,
347 boost::shared_ptr<Range> ents_ptr = nullptr, double wetting_angle = 0)
348 : BoundaryEleOp(row_field_name, BoundaryEleOp::OPROW),
349 gradHPtr(grad_h_ptr), colIndicesPtr(col_ind_ptr),
350 colDiffBaseFunctionsPtr(col_diff_base_ptr), entsPtr(ents_ptr),
352
353 MoFEMErrorCode doWork(int side, EntityType type,
354 DataForcesAndSourcesCore::EntData &data) {
356 if (entsPtr) {
357 if (entsPtr->find(BoundaryEleOp::getFEEntityHandle()) == entsPtr->end())
359 }
360 const double area = getMeasure();
361
362 const auto row_size = data.getIndices().size();
363 if (row_size == 0)
365
366 auto integrate = [&](auto col_indicies, auto &col_diff_base_functions) {
368
369 const auto col_size = col_indicies.size();
370
371 locMat.resize(row_size, col_size, false);
372 locMat.clear();
373 int nb_gp = getGaussPts().size2();
374 int nb_rows = data.getIndices().size();
375
376 auto t_w = getFTensor0IntegrationWeight();
377 auto t_coords = getFTensor1CoordsAtGaussPts();
378 auto t_grad_h = getFTensor1FromMat<SPACE_DIM>(*gradHPtr);
379 auto t_row_base = data.getFTensor0N();
380 int nb_row_base_functions = data.getN().size2();
381
382 auto s = wetting_angle_sub_stepping(getFEMethod()->ts_step);
383
384 for (int gg = 0; gg != nb_gp; ++gg) {
385
386 const double r = t_coords(0);
387 const double alpha = t_w * area * cylindrical(r);
388 const double h_grad_norm = sqrt(t_grad_h(i) * t_grad_h(i) + eps);
389 const double one_over_h_grad_norm = 1. / h_grad_norm;
390 const double beta = s * alpha * eta2 * one_over_h_grad_norm *
391 std::cos(M_PI * wettingAngle / 180); // s * α * η² * (1/||∇h||) * cos(angle)
392
393 int rr = 0;
394 for (; rr != nb_rows; ++rr) {
395 const double delta = beta * t_row_base; // β * N_row
396
397 auto ptr = &col_diff_base_functions(gg, 0);
398 auto t_col_diff_base = getFTensor1FromPtr<SPACE_DIM>(ptr);
399
400 for (int cc = 0; cc != col_size; ++cc) {
401 locMat(rr, cc) += t_col_diff_base(i) * (delta * t_grad_h(i));
402 ++t_col_diff_base;
403 }
404 ++t_row_base;
405 }
406
407 for (; rr < nb_row_base_functions; ++rr) {
408 ++t_row_base;
409 }
410
411 ++t_grad_h;
412 ++t_w;
413 ++t_coords;
414 }
415
417 };
418
419 for (auto c = 0; c != colIndicesPtr->size(); ++c) {
420
421 auto &col_ind = (*colIndicesPtr)[c];
422 if (col_ind.size()) {
423 auto &diff_base = (*colDiffBaseFunctionsPtr)[c];
424
425 CHKERR integrate(col_ind, diff_base);
426
427 CHKERR MatSetValues(getKSPB(), data.getIndices().size(),
428 &*data.getIndices().begin(), col_ind.size(),
429 &*col_ind.begin(), &locMat(0, 0), ADD_VALUES);
430 }
431 }
432
434 }
435
436private:
437 MatrixDouble locMat;
438
439 boost::shared_ptr<MatrixDouble> gradHPtr;
440 boost::shared_ptr<Range> entsPtr;
442 boost::shared_ptr<std::vector<VectorInt>> colIndicesPtr;
443 boost::shared_ptr<std::vector<MatrixDouble>> colDiffBaseFunctionsPtr;
444};
445//! [OpWettingAngleLhs]
446
447//! [OpRhsU]
448/**
449 * @brief Rhs for U (momentum residual)
450 * @param field_name Name of the field associated with the operator
451 * @param dot_u_ptr Pointer to the velocity time derivative matrix (∂U/∂t)
452 * @param u_ptr Pointer to the velocity matrix (U)
453 * @param grad_u_ptr Pointer to the velocity gradient matrix (∇U)
454 * @param h_ptr Pointer to the free surface height vector (h)
455 * @param grad_h_ptr Pointer to the free surface height gradient matrix (∇h)
456 * @param g_ptr Pointer to the chemical potential vector (g)
457 * @param p_ptr Pointer to the pressure vector (p)
458 * @return MoFEMErrorCode
459 *
460 * This operator implements the volume terms of the momentum equation (not Jacobian)
461 * (Lovric 3.1a)
462 *
463 * R_u = ∫_Ω w·(ρ(h)(∂u/∂t + u·∇u + a_0) - κg∇h) - (∇·w)p + (∇w):(2μ(h)D(u))dΩ
464 *
465 * Code ↔ PDE term mapping (paper notation : code variable)
466 * - ρ(ϕ) ∂u/∂t : t_inertia_force(i) = (rho * alpha) * t_dot_u(i)
467 * - ρ(ϕ) (u·∇)u : t_convection(i) = (rho * alpha) * (t_u(j) * t_grad_u(i,j))
468 * - ∇·(2 μ(ϕ) D(u)) : t_stress built from get_D(2*mu) and t_grad_u,
469 * then assembled with t_diff_base into locF
470 * - −∇p (pressure grad) : incorporated via t_kd(i,j)*t_p term inside t_stress
471 * - −κ η ∇ϕ (surface) : t_phase_force(i) = -alpha * kappa * t_g * t_grad_h(i)
472 * - body force ρ a0 : t_gravity(SPACE_DIM-1) = alpha * rho * a0
473 * - buoyancy force : (currently commented out) t_buoyancy(SPACE_DIM-1) = -(alpha * rho * a0) * t_h;
474 */
476
477 OpRhsU(const std::string field_name,
478 boost::shared_ptr<MatrixDouble> dot_u_ptr, // ∂U/∂t
479 boost::shared_ptr<MatrixDouble> u_ptr,
480 boost::shared_ptr<MatrixDouble> grad_u_ptr, // ∇U
481 boost::shared_ptr<VectorDouble> h_ptr,
482 boost::shared_ptr<MatrixDouble> grad_h_ptr, // ∇h
483 boost::shared_ptr<VectorDouble> g_ptr, // chemical potential
484 boost::shared_ptr<VectorDouble> p_ptr) // pressure
486 dotUPtr(dot_u_ptr), uPtr(u_ptr), gradUPtr(grad_u_ptr), hPtr(h_ptr),
487 gradHPtr(grad_h_ptr), gPtr(g_ptr), pPtr(p_ptr) {}
488
489 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &data) {
491
492 const double vol = getMeasure();
493 auto t_dot_u = getFTensor1FromMat<U_FIELD_DIM>(*dotUPtr);
494 auto t_u = getFTensor1FromMat<U_FIELD_DIM>(*uPtr);
495 auto t_p = getFTensor0FromVec(*pPtr);
496 auto t_grad_u = getFTensor2FromMat<U_FIELD_DIM, SPACE_DIM>(*gradUPtr);
497 auto t_h = getFTensor0FromVec(*hPtr);
498 auto t_grad_h = getFTensor1FromMat<SPACE_DIM>(*gradHPtr);
499 auto t_g = getFTensor0FromVec(*gPtr);
500 auto t_coords = getFTensor1CoordsAtGaussPts();
501
502 auto t_base = data.getFTensor0N();
503 auto t_diff_base = data.getFTensor1DiffN<SPACE_DIM>();
504
505 auto t_w = getFTensor0IntegrationWeight();
506
515
516 t_buoyancy(i) = 0;
517 t_gravity(i) = 0;
518
519 for (int gg = 0; gg != nbIntegrationPts; gg++) {
520
521 const double r = t_coords(0);
522 const double alpha = t_w * vol * cylindrical(r);
523
524 const double rho = phase_function(t_h, rho_diff, rho_ave);
525 const double mu = phase_function(t_h, mu_diff, mu_ave);
526
527 auto t_D = get_D(2 * mu);
528
529 t_inertia_force(i) = (rho * alpha) * (t_dot_u(i)); // ρ(h)∂U/∂t
530 // t_buoyancy(SPACE_DIM - 1) = -(alpha * rho * a0) * t_h;
531 t_gravity(SPACE_DIM - 1) = (alpha * rho * a0); // ρ(h)a_0 (a_0 is gravity)
532 t_phase_force(i) = -alpha * kappa * t_g * t_grad_h(i); // -κg∇h
533 t_convection(i) = (rho * alpha) * (t_u(j) * t_grad_u(i, j)); // ρ(h)(U·∇)U
534
535 t_stress(i, j) =
536 alpha * (t_D(i, j, k, l) * t_grad_u(k, l) + t_kd(i, j) * t_p); // ∇·(2μ(h)D(U))
537
538 auto t_nf = getFTensor1FromArray<U_FIELD_DIM, U_FIELD_DIM>(locF);
539
540 t_forces(i) = t_inertia_force(i) + t_buoyancy(i) + t_gravity(i) +
541 t_convection(i) + t_phase_force(i);
542
543 int bb = 0;
544 for (; bb != nbRows / U_FIELD_DIM; ++bb) {
545
546 // Assemble total force contributions into local residual
547 t_nf(i) += t_base * t_forces(i);
548 t_nf(i) += t_diff_base(j) * t_stress(i, j); // ∇w : ∇·(2μ(h)D(U)) - ∇p
549
550 if (coord_type == CYLINDRICAL) {
551 t_nf(0) += (t_base * (alpha / t_coords(0))) * (2 * mu * t_u(0) + t_p);
552 }
553
554 ++t_base;
555 ++t_diff_base;
556 ++t_nf;
557 }
558
559 for (; bb < nbRowBaseFunctions; ++bb) {
560 ++t_diff_base;
561 ++t_base;
562 }
563
564 ++t_dot_u;
565 ++t_u;
566 ++t_grad_u;
567 ++t_h;
568 ++t_grad_h;
569 ++t_g;
570 ++t_p;
571
572 ++t_w;
573 ++t_coords;
574 }
575
577 }
578
579private:
580 boost::shared_ptr<MatrixDouble> dotUPtr;
581 boost::shared_ptr<MatrixDouble> uPtr;
582 boost::shared_ptr<MatrixDouble> gradUPtr;
583 boost::shared_ptr<VectorDouble> hPtr;
584 boost::shared_ptr<MatrixDouble> gradHPtr;
585 boost::shared_ptr<VectorDouble> gPtr;
586 boost::shared_ptr<VectorDouble> pPtr;
587};
588//! [OpRhsU]
589
590//! [OpLhsU_dU]
591/**
592 * @brief Lhs for U dU (Jacobian block ∂R_U/∂U)
593 * @param field_name Name of the field associated with the operator
594 * @param u_ptr Pointer to the velocity matrix (U)
595 * @param grad_u_ptr Pointer to the velocity gradient matrix (∇U)
596 * @param h_ptr Pointer to the free surface height vector (h)
597 * @return MoFEMErrorCode
598 *
599 * Implements linearization of momentum residual w.r.t. velocity U:
600 *
601 * Matches the Jacobian terms required to solve the implicit momentum equation
602 * used when solving the coupled NS–CH system (Lovric 3.1a linearization).
603 */
605
606 OpLhsU_dU(const std::string field_name, boost::shared_ptr<MatrixDouble> u_ptr,
607 boost::shared_ptr<MatrixDouble> grad_u_ptr,
608 boost::shared_ptr<VectorDouble> h_ptr)
610 AssemblyDomainEleOp::OPROWCOL),
611 uPtr(u_ptr), gradUPtr(grad_u_ptr), hPtr(h_ptr) {
612 sYmm = false;
613 assembleTranspose = false;
614 }
615
616 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
617 EntitiesFieldData::EntData &col_data) {
619
620 const double vol = getMeasure();
621 auto t_u = getFTensor1FromMat<U_FIELD_DIM>(*uPtr);
622 auto t_grad_u = getFTensor2FromMat<U_FIELD_DIM, SPACE_DIM>(*gradUPtr);
623 auto t_h = getFTensor0FromVec(*hPtr);
624 auto t_coords = getFTensor1CoordsAtGaussPts();
625
626 auto t_row_base = row_data.getFTensor0N();
627 auto t_row_diff_base = row_data.getFTensor1DiffN<SPACE_DIM>();
628
629 auto t_w = getFTensor0IntegrationWeight();
630
631 auto get_mat = [&](const int rr) {
632 return getFTensor2FromArray<SPACE_DIM, SPACE_DIM, SPACE_DIM>(locMat, rr);
633 };
634
635 auto ts_a = getTSa();
636 constexpr auto t_kd = FTensor::Kronecker_Delta_symmetric<double>(); // t_kd(i,j)=1 iff i=j
637
638 for (int gg = 0; gg != nbIntegrationPts; gg++) {
639
640 const double r = t_coords(0);
641 const double alpha = t_w * vol * cylindrical(r);
642 const double rho = phase_function(t_h, rho_diff, rho_ave);
643 const double mu = phase_function(t_h, mu_diff, mu_ave);
644
645 const double beta0 = alpha * rho;
646 const double beta1 = beta0 * ts_a;
647 auto t_D = get_D(2 * mu); // Fourth-order viscosity tensor
648
649 int rr = 0;
650 for (; rr != nbRows / U_FIELD_DIM; ++rr) {
651
652 auto t_mat = get_mat(rr * U_FIELD_DIM);
653 auto t_col_base = col_data.getFTensor0N(gg, 0);
654 auto t_col_diff_base = col_data.getFTensor1DiffN<SPACE_DIM>(gg, 0);
655
656 // Symmetric on last two indices
657 // ie Christof(i,j,k) == Christof(i,k,j)
659 t_d_stress(l, j, k) = t_D(i, j, k, l) * (alpha * t_row_diff_base(i));
660
661 for (int cc = 0; cc != nbCols / U_FIELD_DIM; ++cc) {// Assemble contributions for each col basis function
662
663 const double bb = t_row_base * t_col_base;
664
665 t_mat(i, j) += (beta1 * bb) * t_kd(i, j); // Derivative of inertia term ρ ∂U/∂t
666 t_mat(i, j) += (beta0 * bb) * t_grad_u(i, j); // Derivative of convection term ρ (U·∇)U
667 t_mat(i, j) +=
668 (beta0 * t_row_base) * t_kd(i, j) * (t_col_diff_base(k) * t_u(k));
669 t_mat(i, j) += t_d_stress(i, j, k) * t_col_diff_base(k); // Derivative of viscous term ∇·(2μD(U))
670
671 if (coord_type == CYLINDRICAL) {
672 t_mat(0, 0) += (bb * (alpha / t_coords(0))) * (2 * mu);
673 }
674
675 ++t_mat;
676 ++t_col_base;
677 ++t_col_diff_base;
678 }
679
680 ++t_row_base;
681 ++t_row_diff_base;
682 }
683
684 for (; rr < nbRowBaseFunctions; ++rr) {
685 ++t_row_diff_base;
686 ++t_row_base;
687 }
688
689 ++t_u;
690 ++t_grad_u;
691 ++t_h;
692
693 ++t_coords;
694 ++t_w;
695 }
696
698 }
699
700private:
701 boost::shared_ptr<MatrixDouble> uPtr;
702 boost::shared_ptr<MatrixDouble> gradUPtr;
703 boost::shared_ptr<VectorDouble> hPtr;
704};
705//! [OpLhsU_dU]
706
707struct OpLoopSideGetDataForSideEle : ForcesAndSourcesCore::UserDataOperator {
708
709 using UDO = ForcesAndSourcesCore::UserDataOperator;
710
712 const std::string field_name,
713 boost::shared_ptr<std::vector<VectorInt>> col_indices_ptr,
714 boost::shared_ptr<std::vector<MatrixDouble>> col_diff_basefunctions_ptr)
715 : UDO(field_name, UDO::OPCOL), colIndicesPtr(col_indices_ptr),
716 colDiffBaseFunctionsPtr(col_diff_basefunctions_ptr) {}
717
718 MoFEMErrorCode doWork(int side, EntityType type,
719 DataForcesAndSourcesCore::EntData &data) {
721
722 if (type == MBVERTEX) {
723 colIndicesPtr->clear();
725 }
726
727 colIndicesPtr->push_back(data.getIndices());
728 colDiffBaseFunctionsPtr->push_back(data.getDiffN());
729
731 }
732
733protected:
734 boost::shared_ptr<std::vector<VectorInt>> colIndicesPtr;
735 boost::shared_ptr<std::vector<MatrixDouble>> colDiffBaseFunctionsPtr;
736};
737
738/**
739 * @brief Lhs for U dH (Jacobian block ∂R_U/∂H)
740 * @param field_name_u Name of the field associated with the row operator (U)
741 * @param field_name_h Name of the field associated with the column operator (H)
742 * @param dot_u_ptr Pointer to the velocity time derivative matrix (∂U/∂t)
743 * @param u_ptr Pointer to the velocity matrix (U)
744 * @param grad_u_ptr Pointer to the velocity gradient matrix (∇U)
745 * @param h_ptr Pointer to the free surface height vector (h)
746 * @param g_ptr Pointer to the chemical potential vector (g)
747 * @return MoFEMErrorCode
748 *
749 * This operator builds the sensitivity of the momentum residual to changes
750 * in the phase field h (paper 3.2a cross-coupling). It implements:
751 *
752 * In code: rho_dh = d_phase_function_h(t_h, rho_diff), mu_dh = d_phase_function_h(t_h, mu_diff)
753 */
755
756 OpLhsU_dH(const std::string field_name_u, const std::string field_name_h,
757 boost::shared_ptr<MatrixDouble> dot_u_ptr,
758 boost::shared_ptr<MatrixDouble> u_ptr,
759 boost::shared_ptr<MatrixDouble> grad_u_ptr,
760 boost::shared_ptr<VectorDouble> h_ptr,
761 boost::shared_ptr<VectorDouble> g_ptr)
762 : AssemblyDomainEleOp(field_name_u, field_name_h,
763 AssemblyDomainEleOp::OPROWCOL),
764 dotUPtr(dot_u_ptr), uPtr(u_ptr), gradUPtr(grad_u_ptr), hPtr(h_ptr),
765 gPtr(g_ptr) {
766 sYmm = false;
767 assembleTranspose = false;
768 }
769
770 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
771 EntitiesFieldData::EntData &col_data) {
773
774 const double vol = getMeasure();
775 auto t_dot_u = getFTensor1FromMat<U_FIELD_DIM>(*dotUPtr);
776 auto t_u = getFTensor1FromMat<U_FIELD_DIM>(*uPtr);
777 auto t_grad_u = getFTensor2FromMat<U_FIELD_DIM, SPACE_DIM>(*gradUPtr);
778 auto t_h = getFTensor0FromVec(*hPtr);
779 auto t_g = getFTensor0FromVec(*gPtr);
780 auto t_coords = getFTensor1CoordsAtGaussPts();
781
782 auto t_row_base = row_data.getFTensor0N();
783 auto t_row_diff_base = row_data.getFTensor1DiffN<SPACE_DIM>();
784
785 auto t_w = getFTensor0IntegrationWeight();
786
789 FTensor::Tensor1<double, U_FIELD_DIM> t_inertia_force_dh;
794
795 t_buoyancy_dh(i) = 0;
796 t_gravity_dh(i) = 0;
797
798 for (int gg = 0; gg != nbIntegrationPts; gg++) {
799
800 const double r = t_coords(0);
801 const double alpha = t_w * vol * cylindrical(r);
802
803 const double rho_dh = d_phase_function_h(t_h, rho_diff); // dρ/dh
804 const double mu_dh = d_phase_function_h(t_h, mu_diff); // dμ/dh
805
806 auto t_D_dh = get_D(2 * mu_dh);
807
808 t_inertia_force_dh(i) = (alpha * rho_dh) * t_dot_u(i); // dρ/dh * ∂U/∂t
809 // t_buoyancy_dh(SPACE_DIM - 1) = -(alpha * a0) * (rho + rho_dh * t_h);
810 t_gravity_dh(SPACE_DIM - 1) = (alpha * rho_dh * a0); // dρ/dh * a_0
811 t_convection_dh(i) = (rho_dh * alpha) * (t_u(j) * t_grad_u(i, j)); // dρ/dh * (U·∇)U
812 const double t_phase_force_g_dh = -alpha * kappa * t_g; // -κ g
813 t_forces_dh(i) = t_inertia_force_dh(i) + t_buoyancy_dh(i) +
814 t_gravity_dh(i) + t_convection_dh(i); // Total dR_U/dh force
815
816 t_stress_dh(i, j) = alpha * (t_D_dh(i, j, k, l) * t_grad_u(k, l)); // d(∇·(2μD(U)))/dh
817
818 int rr = 0;
819 for (; rr != nbRows / U_FIELD_DIM; ++rr) {
820
821 auto t_mat =
822 getFTensor1FromMat<U_FIELD_DIM, 1>(locMat, rr * U_FIELD_DIM);
823 auto t_col_base = col_data.getFTensor0N(gg, 0);
824 auto t_col_diff_base = col_data.getFTensor1DiffN<SPACE_DIM>(gg, 0);
825
826 for (int cc = 0; cc != nbCols; ++cc) {
827
828 const double bb = t_row_base * t_col_base;
829 t_mat(i) += t_forces_dh(i) * bb; // Assemble total dR_U/dh force contribution
830 t_mat(i) += (t_phase_force_g_dh * t_row_base) * t_col_diff_base(i); // -κ g ∇h term
831 t_mat(i) += (t_row_diff_base(j) * t_col_base) * t_stress_dh(i, j); // Viscous term contribution via dμ/dh
832
833 if (coord_type == CYLINDRICAL) {
834 t_mat(0) += (bb * (alpha / t_coords(0))) * (2 * mu_dh * t_u(0));
835 }
836
837 ++t_mat;
838 ++t_col_base;
839 ++t_col_diff_base;
840 }
841
842 ++t_row_base;
843 ++t_row_diff_base;
844 }
845
846 for (; rr < nbRowBaseFunctions; ++rr) {
847 ++t_row_diff_base;
848 ++t_row_base;
849 }
850
851 ++t_dot_u;
852 ++t_u;
853 ++t_grad_u;
854 ++t_h;
855 ++t_g;
856 ++t_coords;
857 ++t_w;
858 }
859
861 }
862
863private:
864 boost::shared_ptr<MatrixDouble> dotUPtr;
865 boost::shared_ptr<MatrixDouble> uPtr;
866 boost::shared_ptr<MatrixDouble> gradUPtr;
867 boost::shared_ptr<VectorDouble> hPtr;
868 boost::shared_ptr<VectorDouble> gPtr;
869};
870
871/**
872 * @brief Lhs for U dG (Jacobian block ∂R_U/∂G)
873 * @param field_name_u Name of the field associated with the row operator (U)
874 * @param field_name_h Name of the field associated with the column operator (H)
875 * @param grad_h_ptr Pointer to the free surface height gradient matrix (∇h)
876 * @return MoFEMErrorCode
877 *
878 * This operator assembles the contribution of the chemical potential G into
879 * the momentum Jacobian. It corresponds to linearization of the surface
880 * tension term −κ g ∇h wrt g.
881 */
883
884 OpLhsU_dG(const std::string field_name_u, const std::string field_name_h,
885 boost::shared_ptr<MatrixDouble> grad_h_ptr)
886 : AssemblyDomainEleOp(field_name_u, field_name_h,
887 AssemblyDomainEleOp::OPROWCOL),
888 gradHPtr(grad_h_ptr) {
889 sYmm = false;
890 assembleTranspose = false;
891 }
892
893 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
894 EntitiesFieldData::EntData &col_data) {
896
897 const double vol = getMeasure();
898 auto t_grad_h = getFTensor1FromMat<SPACE_DIM>(*gradHPtr);
899 auto t_coords = getFTensor1CoordsAtGaussPts();
900
901 auto t_row_base = row_data.getFTensor0N();
902 auto t_w = getFTensor0IntegrationWeight();
903
904 for (int gg = 0; gg != nbIntegrationPts; gg++) {
905
906 const double r = t_coords(0);
907 const double alpha = t_w * vol * cylindrical(r);
908
910 t_phase_force_dg(i) = -alpha * kappa * t_grad_h(i); // -κ ∇h
911
912 int rr = 0;
913 for (; rr != nbRows / U_FIELD_DIM; ++rr) {
914 auto t_mat =
915 getFTensor1FromMat<U_FIELD_DIM, 1>(locMat, rr * U_FIELD_DIM);
916 auto t_col_base = col_data.getFTensor0N(gg, 0);
917
918 for (int cc = 0; cc != nbCols; ++cc) {
919 const double bb = t_row_base * t_col_base;
920 t_mat(i) += t_phase_force_dg(i) * bb;
921
922 ++t_mat;
923 ++t_col_base;
924 }
925
926 ++t_row_base;
927 }
928
929 for (; rr < nbRowBaseFunctions; ++rr) {
930 ++t_row_base;
931 }
932
933 ++t_grad_h;
934 ++t_coords;
935 ++t_w;
936 }
937
939 }
940
941private:
942 boost::shared_ptr<MatrixDouble> gradHPtr;
943};
944
945/**
946 * @brief Rhs for H (phase-field residual)
947 * @param field_name Name of the field associated with the operator
948 * @param u_ptr Pointer to the velocity matrix (U)
949 * @param dot_h_ptr Pointer to the free surface height time derivative vector (∂H/∂t)
950 * @param h_ptr Pointer to the free surface height vector (H)
951 * @param grad_h_ptr Pointer to the free surface height gradient matrix (∇H)
952 * @param grad_g_ptr Pointer to the chemical potential gradient matrix (∇G)
953 * @return MoFEMErrorCode
954 *
955 * Maps the conserved phase evolution (Lovric 3.1c):
956 * R_h = ∫_Ω v(∂h/∂t + u·∇h) + ∇v·(M(h) ∇g)) dΩ
957 *
958 * The template boolean I selects initialization (I=true) vs evolution (I=false).
959 */
960template <bool I> struct OpRhsH : public AssemblyDomainEleOp {
961
962 OpRhsH(const std::string field_name, boost::shared_ptr<MatrixDouble> u_ptr,
963 boost::shared_ptr<VectorDouble> dot_h_ptr,
964 boost::shared_ptr<VectorDouble> h_ptr,
965 boost::shared_ptr<MatrixDouble> grad_h_ptr,
966 boost::shared_ptr<MatrixDouble> grad_g_ptr)
968 uPtr(u_ptr), dotHPtr(dot_h_ptr), hPtr(h_ptr), gradHPtr(grad_h_ptr),
969 gradGPtr(grad_g_ptr) {}
970
971 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &data) {
973
974 const double vol = getMeasure();
975 auto t_w = getFTensor0IntegrationWeight();
976 auto t_coords = getFTensor1CoordsAtGaussPts();
977 auto t_base = data.getFTensor0N();
978 auto t_diff_base = data.getFTensor1DiffN<SPACE_DIM>();
979
980#ifndef NDEBUG
981 if (data.getDiffN().size1() != data.getN().size1())
982 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "wrong size 1");
983 if (data.getDiffN().size2() != data.getN().size2() * SPACE_DIM) {
984 MOFEM_LOG("SELF", Sev::error)
985 << "Side " << rowSide << " " << CN::EntityTypeName(rowType);
986 MOFEM_LOG("SELF", Sev::error) << data.getN();
987 MOFEM_LOG("SELF", Sev::error) << data.getDiffN();
988 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "wrong size 2");
989 }
990#endif
991
992 if constexpr (I) {
993 // Find h ∈ H¹(Ω) to minimise ∫(h - h_init)² dΩ + ∫∇v·(M ∇g) dΩ
994
995 auto t_h = getFTensor0FromVec(*hPtr);
996 auto t_grad_g = getFTensor1FromMat<SPACE_DIM>(*gradGPtr);
997
998 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
999
1000 const double r = t_coords(0);
1001 const double alpha = t_w * vol * cylindrical(r);
1002
1003 const double set_h = init_h(t_coords(0), t_coords(1), t_coords(2));
1004 const double m = get_M(set_h) * alpha;
1005
1006 int bb = 0;
1007 for (; bb != nbRows; ++bb) {
1008 locF[bb] += (t_base * alpha) * (t_h - set_h); // minimize ∫(h - h_init)² dΩ
1009 locF[bb] += (t_diff_base(i) * m) * t_grad_g(i);
1010 ++t_base;
1011 ++t_diff_base;
1012 }
1013
1014 for (; bb < nbRowBaseFunctions; ++bb) {
1015 ++t_base;
1016 ++t_diff_base;
1017 }
1018
1019 ++t_h;
1020 ++t_grad_g;
1021
1022 ++t_coords;
1023 ++t_w;
1024 }
1025
1026 } else {
1027
1028 auto t_dot_h = getFTensor0FromVec(*dotHPtr);
1029 auto t_h = getFTensor0FromVec(*hPtr);
1030 auto t_u = getFTensor1FromMat<U_FIELD_DIM>(*uPtr);
1031 auto t_grad_h = getFTensor1FromMat<SPACE_DIM>(*gradHPtr);
1032 auto t_grad_g = getFTensor1FromMat<SPACE_DIM>(*gradGPtr);
1033
1034 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
1035
1036 const double r = t_coords(0);
1037 const double alpha = t_w * vol * cylindrical(r);
1038
1039 const double m = get_M(t_h) * alpha;
1040
1041 int bb = 0;
1042 for (; bb != nbRows; ++bb) {
1043 locF[bb] += (t_base * alpha) * (t_dot_h); // time derivative ∂h/∂t
1044 locF[bb] += (t_base * alpha) * (t_grad_h(i) * t_u(i)); // convection u·∇h
1045 locF[bb] += (t_diff_base(i) * t_grad_g(i)) * m; // mobility/divergence (M ∇g)
1046 ++t_base;
1047 ++t_diff_base;
1048 }
1049
1050 for (; bb < nbRowBaseFunctions; ++bb) {
1051 ++t_base;
1052 ++t_diff_base;
1053 }
1054
1055 ++t_dot_h;
1056 ++t_h;
1057 ++t_grad_g;
1058 ++t_u;
1059 ++t_grad_h;
1060
1061 ++t_coords;
1062 ++t_w;
1063 }
1064 }
1065
1067 }
1068
1069private:
1070 boost::shared_ptr<MatrixDouble> uPtr;
1071 boost::shared_ptr<VectorDouble> dotHPtr;
1072 boost::shared_ptr<VectorDouble> hPtr;
1073 boost::shared_ptr<MatrixDouble> gradHPtr;
1074 boost::shared_ptr<MatrixDouble> gradGPtr;
1075};
1076
1077/**
1078 * @brief Lhs for H dU
1079 * @param h_field_name Name of the field associated with the row operator (H)
1080 * @param u_field_name Name of the field associated with the column operator (U)
1081 * @param grad_h_ptr Pointer to the free surface height gradient matrix (∇H)
1082 * @return MoFEMErrorCode
1083 *
1084 * (Jacobian block ∂R_H/∂U)
1085 * Linearization of the conserved phase equation (Lovric 3.1c) w.r.t. U
1086 */
1088 OpLhsH_dU(const std::string h_field_name, const std::string u_field_name,
1089 boost::shared_ptr<MatrixDouble> grad_h_ptr)
1090 : AssemblyDomainEleOp(h_field_name, u_field_name,
1091 AssemblyDomainEleOp::OPROWCOL),
1092 gradHPtr(grad_h_ptr) {
1093 sYmm = false;
1094 assembleTranspose = false;
1095 }
1096 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
1097 EntitiesFieldData::EntData &col_data) {
1099
1100 const double vol = getMeasure();
1101 auto t_grad_h = getFTensor1FromMat<SPACE_DIM>(*gradHPtr);
1102 auto t_coords = getFTensor1CoordsAtGaussPts();
1103
1104 auto t_row_base = row_data.getFTensor0N();
1105 auto t_w = getFTensor0IntegrationWeight();
1106
1107 for (int gg = 0; gg != nbIntegrationPts; gg++) {
1108
1109 const auto r = t_coords(0);
1110 const auto alpha = t_w * vol * cylindrical(r);
1111 auto t_mat = getFTensor1FromPtr<U_FIELD_DIM>(&locMat(0, 0));
1113
1114 int rr = 0;
1115 for (; rr != nbRows; ++rr) {
1116 t_row(i) = (alpha * t_row_base) * t_grad_h(i);
1117 auto t_col_base = col_data.getFTensor0N(gg, 0);
1118 for (int cc = 0; cc != nbCols / U_FIELD_DIM; ++cc) {
1119 t_mat(i) += t_row(i) * t_col_base;
1120 ++t_mat;
1121 ++t_col_base;
1122 }
1123 ++t_row_base;
1124 }
1125
1126 for (; rr < nbRowBaseFunctions; ++rr)
1127 ++t_row_base;
1128
1129 ++t_grad_h;
1130 ++t_w;
1131 ++t_coords;
1132 }
1133
1135 }
1136
1137private:
1138 boost::shared_ptr<MatrixDouble> gradHPtr;
1139};
1140
1141/**
1142 * @brief Lhs for H dH (Jacobian block ∂R_H/∂H)
1143 * @param field_name Name of the field associated with the operator
1144 * @param u_ptr Pointer to the velocity matrix (U)
1145 * @param h_ptr Pointer to the free surface height vector (H)
1146 * @param grad_g_ptr Pointer to the chemical potential gradient matrix (∇G)
1147 * @return MoFEMErrorCode
1148 *
1149 * Linearization of the conserved phase equation (3.1c) w.r.t. H
1150 * - time-stepping mass scaling (ts_a) terms
1151 * - contributions from mobility derivative M'(h)
1152 * - coupling terms with chemical potential gradient where M depends on h
1153 *
1154 * When I==true the operator builds initialization-mode blocks (uses init_h)
1155 */
1156template <bool I> struct OpLhsH_dH : public AssemblyDomainEleOp {
1157
1158 OpLhsH_dH(const std::string field_name, boost::shared_ptr<MatrixDouble> u_ptr,
1159 boost::shared_ptr<VectorDouble> h_ptr,
1160 boost::shared_ptr<MatrixDouble> grad_g_ptr)
1162 AssemblyDomainEleOp::OPROWCOL),
1163 uPtr(u_ptr), hPtr(h_ptr), gradGPtr(grad_g_ptr) {
1164 sYmm = false;
1165 }
1166
1167 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
1168 EntitiesFieldData::EntData &col_data) {
1170
1171 const double vol = getMeasure();
1172 auto t_w = getFTensor0IntegrationWeight();
1173 auto t_coords = getFTensor1CoordsAtGaussPts();
1174 auto t_row_base = row_data.getFTensor0N();
1175 auto t_row_diff_base = row_data.getFTensor1DiffN<SPACE_DIM>();
1176
1177#ifndef NDEBUG
1178 if (row_data.getDiffN().size1() != row_data.getN().size1())
1179 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "wrong size 1");
1180 if (row_data.getDiffN().size2() != row_data.getN().size2() * SPACE_DIM) {
1181 MOFEM_LOG("SELF", Sev::error)
1182 << "Side " << rowSide << " " << CN::EntityTypeName(rowType);
1183 MOFEM_LOG("SELF", Sev::error) << row_data.getN();
1184 MOFEM_LOG("SELF", Sev::error) << row_data.getDiffN();
1185 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "wrong size 2");
1186 }
1187
1188 if (col_data.getDiffN().size1() != col_data.getN().size1())
1189 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "wrong size 1");
1190 if (col_data.getDiffN().size2() != col_data.getN().size2() * SPACE_DIM) {
1191 MOFEM_LOG("SELF", Sev::error)
1192 << "Side " << rowSide << " " << CN::EntityTypeName(rowType);
1193 MOFEM_LOG("SELF", Sev::error) << col_data.getN();
1194 MOFEM_LOG("SELF", Sev::error) << col_data.getDiffN();
1195 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "wrong size 2");
1196 }
1197#endif
1198
1199 if constexpr (I) {
1200
1201 auto t_h = getFTensor0FromVec(*hPtr);
1202 auto t_grad_g = getFTensor1FromMat<SPACE_DIM>(*gradGPtr);
1203
1204 for (int gg = 0; gg != nbIntegrationPts; gg++) {
1205
1206 const double r = t_coords(0);
1207 const double alpha = t_w * vol * cylindrical(r);
1208
1209 int rr = 0;
1210 for (; rr != nbRows; ++rr) {
1211
1212 auto t_col_base = col_data.getFTensor0N(gg, 0);
1213 auto t_col_diff_base = col_data.getFTensor1DiffN<SPACE_DIM>(gg, 0);
1214
1215 for (int cc = 0; cc != nbCols; ++cc) {
1216
1217 locMat(rr, cc) += (t_row_base * t_col_base * alpha);
1218
1219 ++t_col_base;
1220 ++t_col_diff_base;
1221 }
1222
1223 ++t_row_base;
1224 ++t_row_diff_base;
1225 }
1226
1227 for (; rr < nbRowBaseFunctions; ++rr) {
1228 ++t_row_base;
1229 ++t_row_diff_base;
1230 }
1231
1232 ++t_h;
1233 ++t_grad_g;
1234 ++t_w;
1235 ++t_coords;
1236 }
1237
1238 } else {
1239
1240 auto t_h = getFTensor0FromVec(*hPtr);
1241 auto t_grad_g = getFTensor1FromMat<SPACE_DIM>(*gradGPtr);
1242 auto t_u = getFTensor1FromMat<U_FIELD_DIM>(*uPtr);
1243
1244 auto ts_a = getTSa();
1245
1246 for (int gg = 0; gg != nbIntegrationPts; gg++) {
1247
1248 const double r = t_coords(0);
1249 const double alpha = t_w * vol * cylindrical(r);
1250
1251 auto m_dh = get_M_dh(t_h) * alpha;
1252 int rr = 0;
1253 for (; rr != nbRows; ++rr) {
1254
1255 auto t_col_base = col_data.getFTensor0N(gg, 0);
1256 auto t_col_diff_base = col_data.getFTensor1DiffN<SPACE_DIM>(gg, 0);
1257
1258 for (int cc = 0; cc != nbCols; ++cc) {
1259
1260 locMat(rr, cc) += (t_row_base * t_col_base * alpha) * ts_a; // time-stepping mass term
1261 locMat(rr, cc) +=
1262 (t_row_base * alpha) * (t_col_diff_base(i) * t_u(i)); // convection term u·∇h
1263 locMat(rr, cc) +=
1264 (t_row_diff_base(i) * t_grad_g(i)) * (t_col_base * m_dh); // mobility derivative term M'(h) ∇g
1265
1266 ++t_col_base;
1267 ++t_col_diff_base;
1268 }
1269
1270 ++t_row_base;
1271 ++t_row_diff_base;
1272 }
1273
1274 for (; rr < nbRowBaseFunctions; ++rr) {
1275 ++t_row_base;
1276 ++t_row_diff_base;
1277 }
1278
1279 ++t_u;
1280 ++t_h;
1281 ++t_grad_g;
1282 ++t_w;
1283 ++t_coords;
1284 }
1285 }
1286
1288 }
1289
1290private:
1291 boost::shared_ptr<MatrixDouble> uPtr;
1292 boost::shared_ptr<VectorDouble> hPtr;
1293 boost::shared_ptr<MatrixDouble> gradGPtr;
1294};
1295
1296/**
1297 * @brief Lhs for H dG
1298 * @param field_name_h Name of the field associated with the row operator (H)
1299 * @param field_name_g Name of the field associated with the column operator (G)
1300 * @param h_ptr Pointer to the free surface height vector (H)
1301 * @return MoFEMErrorCode
1302 *
1303 * (Jacobian block ∂R_H/∂G)
1304 * Linearization of the conserved phase equation (Lovric 3.1c) w.r.t. G
1305 */
1306template <bool I> struct OpLhsH_dG : public AssemblyDomainEleOp {
1307
1308 OpLhsH_dG(const std::string field_name_h, const std::string field_name_g,
1309 boost::shared_ptr<VectorDouble> h_ptr)
1310 : AssemblyDomainEleOp(field_name_h, field_name_g,
1311 AssemblyDomainEleOp::OPROWCOL),
1312 hPtr(h_ptr) {
1313 sYmm = false;
1314 assembleTranspose = false;
1315 }
1316
1317 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
1318 EntitiesFieldData::EntData &col_data) {
1320
1321 const double vol = getMeasure();
1322 auto t_h = getFTensor0FromVec(*hPtr);
1323
1324 auto t_row_diff_base = row_data.getFTensor1DiffN<SPACE_DIM>();
1325 auto t_w = getFTensor0IntegrationWeight();
1326 auto t_coords = getFTensor1CoordsAtGaussPts();
1327
1328 for (int gg = 0; gg != nbIntegrationPts; gg++) {
1329
1330 const double r = t_coords(0);
1331 const double alpha = t_w * vol * cylindrical(r);
1332
1333 double set_h;
1334 if constexpr (I)
1335 set_h = init_h(t_coords(0), t_coords(1), t_coords(2));
1336 else
1337 set_h = t_h;
1338
1339 auto m = get_M(set_h) * alpha;
1340
1341 int rr = 0;
1342 for (; rr != nbRows; ++rr) {
1343 auto t_col_diff_base = col_data.getFTensor1DiffN<SPACE_DIM>(gg, 0);
1344
1345 for (int cc = 0; cc != nbCols; ++cc) {
1346 locMat(rr, cc) += (t_row_diff_base(i) * t_col_diff_base(i)) * m; // mobility/divergence (M ∇g)
1347
1348 ++t_col_diff_base;
1349 }
1350
1351 ++t_row_diff_base;
1352 }
1353
1354 for (; rr < nbRowBaseFunctions; ++rr) {
1355 ++t_row_diff_base;
1356 }
1357
1358 ++t_h;
1359 ++t_w;
1360 ++t_coords;
1361 }
1362
1364 }
1365
1366private:
1367 boost::shared_ptr<VectorDouble> hPtr;
1368};
1369
1370/**
1371 * @brief Rhs for G (chemical potential residual)
1372 * @param field_name Name of the field associated with the operator
1373 * @param h_ptr Pointer to the free surface height vector (H)
1374 * @param grad_h_ptr Pointer to the free surface height gradient matrix (∇H)
1375 * @param g_ptr Pointer to the chemical potential vector (G)
1376 * @return MoFEMErrorCode
1377 *
1378 * Implements Lovric 3.1d (excpet for wetting boundary term - see OpWettingAngleRhs/Lhs):
1379 * R_g = ∫_Ω s(g - f(h)) - ∇s·(ε²∇h) dΩ
1380 *
1381 * The template boolean I selects initialization (I=true) vs evolution (I=false).
1382 */
1383template <bool I> struct OpRhsG : public AssemblyDomainEleOp {
1384
1385 OpRhsG(const std::string field_name, boost::shared_ptr<VectorDouble> h_ptr,
1386 boost::shared_ptr<MatrixDouble> grad_h_ptr,
1387 boost::shared_ptr<VectorDouble> g_ptr)
1389 hPtr(h_ptr), gradHPtr(grad_h_ptr), gPtr(g_ptr) {}
1390
1391 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &data) {
1393
1394 const double vol = getMeasure();
1395 auto t_h = getFTensor0FromVec(*hPtr);
1396 auto t_grad_h = getFTensor1FromMat<SPACE_DIM>(*gradHPtr);
1397 auto t_g = getFTensor0FromVec(*gPtr);
1398 auto t_coords = getFTensor1CoordsAtGaussPts();
1399
1400 auto t_base = data.getFTensor0N();
1401 auto t_diff_base = data.getFTensor1DiffN<SPACE_DIM>();
1402 auto t_w = getFTensor0IntegrationWeight();
1403
1404 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
1405
1406 const double r = t_coords(0);
1407 const double alpha = t_w * vol * cylindrical(r);
1408
1409 double set_h;
1410 if constexpr (I)
1411 set_h = init_h(t_coords(0), t_coords(1), t_coords(2));
1412 else
1413 set_h = t_h;
1414
1415 const double f = get_f(set_h);
1416
1417 int bb = 0;
1418 for (; bb != nbRows; ++bb) {
1419 locF[bb] += (t_base * alpha) * (t_g - f); // Bulk term: (g - f(h))
1420 locF[bb] -= (t_diff_base(i) * (eta2 * alpha)) * t_grad_h(i); // Diffusion term: -ε²∇h
1421 ++t_base;
1422 ++t_diff_base;
1423 }
1424
1425 for (; bb < nbRowBaseFunctions; ++bb) {
1426 ++t_base;
1427 ++t_diff_base;
1428 }
1429
1430 ++t_h;
1431 ++t_grad_h;
1432 ++t_g;
1433
1434 ++t_coords;
1435 ++t_w;
1436 }
1437
1439 }
1440
1441private:
1442 boost::shared_ptr<VectorDouble> hPtr;
1443 boost::shared_ptr<MatrixDouble> gradHPtr;
1444 boost::shared_ptr<VectorDouble> gPtr;
1445};
1446
1447/**
1448 * @brief Lhs for G dH
1449 * @param field_name_g Name of the field associated with the row operator (G)
1450 * @param field_name_h Name of the field associated with the column operator (H)
1451 * @param h_ptr Pointer to the free surface height vector (H)
1452 * @return MoFEMErrorCode
1453 *
1454 * (Jacobian block ∂R_G/∂H)
1455 * Linearization of the chemical potential equation (Lovric 3.1d) w.r.t. H
1456 */
1457template <bool I> struct OpLhsG_dH : public AssemblyDomainEleOp {
1458
1459 OpLhsG_dH(const std::string field_name_g, const std::string field_name_h,
1460 boost::shared_ptr<VectorDouble> h_ptr)
1461 : AssemblyDomainEleOp(field_name_g, field_name_h,
1462 AssemblyDomainEleOp::OPROWCOL),
1463 hPtr(h_ptr) {
1464 sYmm = false;
1465 assembleTranspose = false;
1466 }
1467
1468 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
1469 EntitiesFieldData::EntData &col_data) {
1471
1472 const double vol = getMeasure();
1473 auto t_h = getFTensor0FromVec(*hPtr);
1474
1475 auto t_row_base = row_data.getFTensor0N();
1476 auto t_row_diff_base = row_data.getFTensor1DiffN<SPACE_DIM>();
1477 auto t_w = getFTensor0IntegrationWeight();
1478 auto t_coords = getFTensor1CoordsAtGaussPts();
1479
1480 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
1481
1482 const double r = t_coords(0);
1483 const double alpha = t_w * vol * cylindrical(r);
1484
1485 const double f_dh = get_f_dh(t_h) * alpha; // derivative of f(h)
1486 const double beta = eta2 * alpha; // coefficient for diffusion term -ε²
1487
1488 int rr = 0;
1489 for (; rr != nbRows; ++rr) {
1490
1491 auto t_col_base = col_data.getFTensor0N(gg, 0);
1492 auto t_col_diff_base = col_data.getFTensor1DiffN<SPACE_DIM>(gg, 0);
1493
1494 for (int cc = 0; cc != nbCols; ++cc) {
1495
1496 if constexpr (I == false)
1497 locMat(rr, cc) -= (t_row_base * t_col_base) * f_dh; // bulk term derivative (g - f(h))
1498 locMat(rr, cc) -= (t_row_diff_base(i) * beta) * t_col_diff_base(i); // diffusion term derivative -ε²∇h
1499
1500 ++t_col_base;
1501 ++t_col_diff_base;
1502 }
1503
1504 ++t_row_base;
1505 ++t_row_diff_base;
1506 }
1507
1508 for (; rr < nbRowBaseFunctions; ++rr) {
1509 ++t_row_base;
1510 ++t_row_diff_base;
1511 }
1512
1513 ++t_h;
1514 ++t_w;
1515 ++t_coords;
1516 }
1517
1519 }
1520
1521private:
1522 boost::shared_ptr<VectorDouble> hPtr;
1523};
1524
1525/**
1526 * @brief Lhs for G dG
1527 * @param field_name Name of the field associated with the operator
1528 * @return MoFEMErrorCode
1529 *
1530 * (Jacobian block ∂R_G/∂G)
1531 * Linearization of the chemical potential equation (Lovric 3.1d) w.r.t. G
1532 */
1534
1535 OpLhsG_dG(const std::string field_name)
1537 AssemblyDomainEleOp::OPROWCOL) {
1538 sYmm = true;
1539 }
1540
1541 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
1542 EntitiesFieldData::EntData &col_data) {
1544
1545 const double vol = getMeasure();
1546
1547 auto t_row_base = row_data.getFTensor0N();
1548 auto t_w = getFTensor0IntegrationWeight();
1549 auto t_coords = getFTensor1CoordsAtGaussPts();
1550
1551 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
1552
1553 const double r = t_coords(0);
1554 const double alpha = t_w * vol * cylindrical(r);
1555
1556 int rr = 0;
1557 for (; rr != nbRows; ++rr) {
1558 auto t_col_base = col_data.getFTensor0N(gg, 0);
1559 const double beta = alpha * t_row_base;
1560 for (int cc = 0; cc != nbCols; ++cc) {
1561 locMat(rr, cc) += (t_col_base * beta);
1562 ++t_col_base;
1563 }
1564
1565 ++t_row_base;
1566 }
1567
1568 for (; rr < nbRowBaseFunctions; ++rr) {
1569 ++t_row_base;
1570 }
1571
1572 ++t_w;
1573 ++t_coords;
1574 }
1575
1577 }
1578
1579private:
1580};
1581
1582} // namespace FreeSurfaceOps
constexpr double a
static const double eps
constexpr int SPACE_DIM
Kronecker Delta class symmetric.
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
@ CYLINDRICAL
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
auto cylindrical
[cylindrical]
double kappa
double mu_diff
constexpr int U_FIELD_DIM
auto get_M_dh
double rho_diff
auto init_h
Initialisation function.
constexpr auto t_kd
auto d_phase_function_h
Derivative of phase function with respect to h.
double rho_ave
double eta2
auto get_f_dh
Derivative of double-well potential.
auto wetting_angle
Wetting angle function (placeholder)
auto get_M
double mu_ave
auto phase_function
Phase-dependent material property interpolation.
auto get_D
Create deviatoric stress tensor.
auto wetting_angle_sub_stepping
[cylindrical]
auto get_f
Double-well potential function.
#define MOFEM_LOG(channel, severity)
Log.
constexpr double a0
FTensor::Index< 'i', SPACE_DIM > i
constexpr CoordinateTypes coord_type
const double c
speed of light (cm/ns)
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
constexpr IntegrationType I
constexpr auto field_name
static constexpr double delta
FTensor::Index< 'm', 3 > m
Calculate lift force on free surface boundary.
MoFEMErrorCode doWork(int row_side, EntityType row_type, EntitiesFieldData::EntData &data)
boost::shared_ptr< VectorDouble > liftPtr
OpCalculateLift(const std::string field_name, boost::shared_ptr< VectorDouble > p_ptr, boost::shared_ptr< VectorDouble > lift_ptr, boost::shared_ptr< Range > ents_ptr)
boost::shared_ptr< VectorDouble > pPtr
boost::shared_ptr< Range > entsPtr
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data)
OpLhsG_dG(const std::string field_name)
boost::shared_ptr< VectorDouble > hPtr
OpLhsG_dH(const std::string field_name_g, const std::string field_name_h, boost::shared_ptr< VectorDouble > h_ptr)
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data)
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data)
OpLhsH_dG(const std::string field_name_h, const std::string field_name_g, boost::shared_ptr< VectorDouble > h_ptr)
boost::shared_ptr< VectorDouble > hPtr
Lhs for H dH (Jacobian block ∂R_H/∂H)
boost::shared_ptr< MatrixDouble > uPtr
OpLhsH_dH(const std::string field_name, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< VectorDouble > h_ptr, boost::shared_ptr< MatrixDouble > grad_g_ptr)
boost::shared_ptr< MatrixDouble > gradGPtr
boost::shared_ptr< VectorDouble > hPtr
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data)
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data)
boost::shared_ptr< MatrixDouble > gradHPtr
OpLhsH_dU(const std::string h_field_name, const std::string u_field_name, boost::shared_ptr< MatrixDouble > grad_h_ptr)
Lhs for U dG (Jacobian block ∂R_U/∂G)
OpLhsU_dG(const std::string field_name_u, const std::string field_name_h, boost::shared_ptr< MatrixDouble > grad_h_ptr)
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data)
boost::shared_ptr< MatrixDouble > gradHPtr
Lhs for U dH (Jacobian block ∂R_U/∂H)
boost::shared_ptr< VectorDouble > gPtr
OpLhsU_dH(const std::string field_name_u, const std::string field_name_h, boost::shared_ptr< MatrixDouble > dot_u_ptr, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< MatrixDouble > grad_u_ptr, boost::shared_ptr< VectorDouble > h_ptr, boost::shared_ptr< VectorDouble > g_ptr)
boost::shared_ptr< VectorDouble > hPtr
boost::shared_ptr< MatrixDouble > uPtr
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data)
boost::shared_ptr< MatrixDouble > gradUPtr
boost::shared_ptr< MatrixDouble > dotUPtr
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data)
boost::shared_ptr< MatrixDouble > gradUPtr
OpLhsU_dU(const std::string field_name, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< MatrixDouble > grad_u_ptr, boost::shared_ptr< VectorDouble > h_ptr)
boost::shared_ptr< MatrixDouble > uPtr
boost::shared_ptr< VectorDouble > hPtr
boost::shared_ptr< std::vector< VectorInt > > colIndicesPtr
MoFEMErrorCode doWork(int side, EntityType type, DataForcesAndSourcesCore::EntData &data)
OpLoopSideGetDataForSideEle(const std::string field_name, boost::shared_ptr< std::vector< VectorInt > > col_indices_ptr, boost::shared_ptr< std::vector< MatrixDouble > > col_diff_basefunctions_ptr)
ForcesAndSourcesCore::UserDataOperator UDO
boost::shared_ptr< std::vector< MatrixDouble > > colDiffBaseFunctionsPtr
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data, EntitiesFieldData::EntData &col_data)
OpNormalConstrainLhs(const std::string field_name_row, const std::string field_name_col)
OpNormalConstrainRhs(const std::string field_name, boost::shared_ptr< MatrixDouble > u_ptr)
boost::shared_ptr< MatrixDouble > uPtr
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data)
boost::shared_ptr< VectorDouble > lambdaPtr
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data)
OpNormalForceRhs(const std::string field_name, boost::shared_ptr< VectorDouble > lambda_ptr)
Rhs for G (chemical potential residual)
OpRhsG(const std::string field_name, boost::shared_ptr< VectorDouble > h_ptr, boost::shared_ptr< MatrixDouble > grad_h_ptr, boost::shared_ptr< VectorDouble > g_ptr)
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &data)
boost::shared_ptr< MatrixDouble > gradHPtr
boost::shared_ptr< VectorDouble > hPtr
boost::shared_ptr< VectorDouble > gPtr
Rhs for H (phase-field residual)
boost::shared_ptr< VectorDouble > hPtr
boost::shared_ptr< MatrixDouble > gradGPtr
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &data)
boost::shared_ptr< MatrixDouble > uPtr
boost::shared_ptr< VectorDouble > dotHPtr
boost::shared_ptr< MatrixDouble > gradHPtr
OpRhsH(const std::string field_name, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< VectorDouble > dot_h_ptr, boost::shared_ptr< VectorDouble > h_ptr, boost::shared_ptr< MatrixDouble > grad_h_ptr, boost::shared_ptr< MatrixDouble > grad_g_ptr)
[OpWettingAngleLhs]
boost::shared_ptr< MatrixDouble > gradUPtr
boost::shared_ptr< VectorDouble > pPtr
OpRhsU(const std::string field_name, boost::shared_ptr< MatrixDouble > dot_u_ptr, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< MatrixDouble > grad_u_ptr, boost::shared_ptr< VectorDouble > h_ptr, boost::shared_ptr< MatrixDouble > grad_h_ptr, boost::shared_ptr< VectorDouble > g_ptr, boost::shared_ptr< VectorDouble > p_ptr)
boost::shared_ptr< VectorDouble > gPtr
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &data)
boost::shared_ptr< VectorDouble > hPtr
boost::shared_ptr< MatrixDouble > dotUPtr
boost::shared_ptr< MatrixDouble > uPtr
boost::shared_ptr< MatrixDouble > gradHPtr
boost::shared_ptr< MatrixDouble > gradHPtr
boost::shared_ptr< std::vector< VectorInt > > colIndicesPtr
boost::shared_ptr< std::vector< MatrixDouble > > colDiffBaseFunctionsPtr
boost::shared_ptr< Range > entsPtr
OpWettingAngleLhs(const std::string row_field_name, boost::shared_ptr< MatrixDouble > grad_h_ptr, boost::shared_ptr< std::vector< VectorInt > > col_ind_ptr, boost::shared_ptr< std::vector< MatrixDouble > > col_diff_base_ptr, boost::shared_ptr< Range > ents_ptr=nullptr, double wetting_angle=0)
MoFEMErrorCode doWork(int side, EntityType type, DataForcesAndSourcesCore::EntData &data)
boost::shared_ptr< MatrixDouble > gradHPtr
OpWettingAngleRhs(const std::string field_name, boost::shared_ptr< MatrixDouble > grad_h_ptr, boost::shared_ptr< Range > ents_ptr=nullptr, double wetting_angle=0)
MoFEMErrorCode iNtegrate(DataForcesAndSourcesCore::EntData &row_data)
boost::shared_ptr< Range > entsPtr
double rho
Definition plastic.cpp:144