v0.16.0
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,
823 DataLayoutTraits<DataLayout::CoeffsByGauss>>(
824 locMat, rr * U_FIELD_DIM);
825 auto t_col_base = col_data.getFTensor0N(gg, 0);
826 auto t_col_diff_base = col_data.getFTensor1DiffN<SPACE_DIM>(gg, 0);
827
828 for (int cc = 0; cc != nbCols; ++cc) {
829
830 const double bb = t_row_base * t_col_base;
831 t_mat(i) += t_forces_dh(i) * bb; // Assemble total dR_U/dh force contribution
832 t_mat(i) += (t_phase_force_g_dh * t_row_base) * t_col_diff_base(i); // -κ g ∇h term
833 t_mat(i) += (t_row_diff_base(j) * t_col_base) * t_stress_dh(i, j); // Viscous term contribution via dμ/dh
834
835 if (coord_type == CYLINDRICAL) {
836 t_mat(0) += (bb * (alpha / t_coords(0))) * (2 * mu_dh * t_u(0));
837 }
838
839 ++t_mat;
840 ++t_col_base;
841 ++t_col_diff_base;
842 }
843
844 ++t_row_base;
845 ++t_row_diff_base;
846 }
847
848 for (; rr < nbRowBaseFunctions; ++rr) {
849 ++t_row_diff_base;
850 ++t_row_base;
851 }
852
853 ++t_dot_u;
854 ++t_u;
855 ++t_grad_u;
856 ++t_h;
857 ++t_g;
858 ++t_coords;
859 ++t_w;
860 }
861
863 }
864
865private:
866 boost::shared_ptr<MatrixDouble> dotUPtr;
867 boost::shared_ptr<MatrixDouble> uPtr;
868 boost::shared_ptr<MatrixDouble> gradUPtr;
869 boost::shared_ptr<VectorDouble> hPtr;
870 boost::shared_ptr<VectorDouble> gPtr;
871};
872
873/**
874 * @brief Lhs for U dG (Jacobian block ∂R_U/∂G)
875 * @param field_name_u Name of the field associated with the row operator (U)
876 * @param field_name_h Name of the field associated with the column operator (H)
877 * @param grad_h_ptr Pointer to the free surface height gradient matrix (∇h)
878 * @return MoFEMErrorCode
879 *
880 * This operator assembles the contribution of the chemical potential G into
881 * the momentum Jacobian. It corresponds to linearization of the surface
882 * tension term −κ g ∇h wrt g.
883 */
885
886 OpLhsU_dG(const std::string field_name_u, const std::string field_name_h,
887 boost::shared_ptr<MatrixDouble> grad_h_ptr)
888 : AssemblyDomainEleOp(field_name_u, field_name_h,
889 AssemblyDomainEleOp::OPROWCOL),
890 gradHPtr(grad_h_ptr) {
891 sYmm = false;
892 assembleTranspose = false;
893 }
894
895 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
896 EntitiesFieldData::EntData &col_data) {
898
899 const double vol = getMeasure();
900 auto t_grad_h = getFTensor1FromMat<SPACE_DIM>(*gradHPtr);
901 auto t_coords = getFTensor1CoordsAtGaussPts();
902
903 auto t_row_base = row_data.getFTensor0N();
904 auto t_w = getFTensor0IntegrationWeight();
905
906 for (int gg = 0; gg != nbIntegrationPts; gg++) {
907
908 const double r = t_coords(0);
909 const double alpha = t_w * vol * cylindrical(r);
910
912 t_phase_force_dg(i) = -alpha * kappa * t_grad_h(i); // -κ ∇h
913
914 int rr = 0;
915 for (; rr != nbRows / U_FIELD_DIM; ++rr) {
916 auto t_mat =
917 getFTensor1FromMat<U_FIELD_DIM, 1,
918 DataLayoutTraits<DataLayout::CoeffsByGauss>>(
919 locMat, rr * U_FIELD_DIM);
920 auto t_col_base = col_data.getFTensor0N(gg, 0);
921
922 for (int cc = 0; cc != nbCols; ++cc) {
923 const double bb = t_row_base * t_col_base;
924 t_mat(i) += t_phase_force_dg(i) * bb;
925
926 ++t_mat;
927 ++t_col_base;
928 }
929
930 ++t_row_base;
931 }
932
933 for (; rr < nbRowBaseFunctions; ++rr) {
934 ++t_row_base;
935 }
936
937 ++t_grad_h;
938 ++t_coords;
939 ++t_w;
940 }
941
943 }
944
945private:
946 boost::shared_ptr<MatrixDouble> gradHPtr;
947};
948
949/**
950 * @brief Rhs for H (phase-field residual)
951 * @param field_name Name of the field associated with the operator
952 * @param u_ptr Pointer to the velocity matrix (U)
953 * @param dot_h_ptr Pointer to the free surface height time derivative vector (∂H/∂t)
954 * @param h_ptr Pointer to the free surface height vector (H)
955 * @param grad_h_ptr Pointer to the free surface height gradient matrix (∇H)
956 * @param grad_g_ptr Pointer to the chemical potential gradient matrix (∇G)
957 * @return MoFEMErrorCode
958 *
959 * Maps the conserved phase evolution (Lovric 3.1c):
960 * R_h = ∫_Ω v(∂h/∂t + u·∇h) + ∇v·(M(h) ∇g)) dΩ
961 *
962 * The template boolean I selects initialization (I=true) vs evolution (I=false).
963 */
964template <bool I> struct OpRhsH : public AssemblyDomainEleOp {
965
966 OpRhsH(const std::string field_name, boost::shared_ptr<MatrixDouble> u_ptr,
967 boost::shared_ptr<VectorDouble> dot_h_ptr,
968 boost::shared_ptr<VectorDouble> h_ptr,
969 boost::shared_ptr<MatrixDouble> grad_h_ptr,
970 boost::shared_ptr<MatrixDouble> grad_g_ptr)
972 uPtr(u_ptr), dotHPtr(dot_h_ptr), hPtr(h_ptr), gradHPtr(grad_h_ptr),
973 gradGPtr(grad_g_ptr) {}
974
975 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &data) {
977
978 const double vol = getMeasure();
979 auto t_w = getFTensor0IntegrationWeight();
980 auto t_coords = getFTensor1CoordsAtGaussPts();
981 auto t_base = data.getFTensor0N();
982 auto t_diff_base = data.getFTensor1DiffN<SPACE_DIM>();
983
984#ifndef NDEBUG
985 if (data.getDiffN().size1() != data.getN().size1())
986 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "wrong size 1");
987 if (data.getDiffN().size2() != data.getN().size2() * SPACE_DIM) {
988 MOFEM_LOG("SELF", Sev::error)
989 << "Side " << rowSide << " " << CN::EntityTypeName(rowType);
990 MOFEM_LOG("SELF", Sev::error) << data.getN();
991 MOFEM_LOG("SELF", Sev::error) << data.getDiffN();
992 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "wrong size 2");
993 }
994#endif
995
996 if constexpr (I) {
997 // Find h ∈ H¹(Ω) to minimise ∫(h - h_init)² dΩ + ∫∇v·(M ∇g) dΩ
998
999 auto t_h = getFTensor0FromVec(*hPtr);
1000 auto t_grad_g = getFTensor1FromMat<SPACE_DIM>(*gradGPtr);
1001
1002 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
1003
1004 const double r = t_coords(0);
1005 const double alpha = t_w * vol * cylindrical(r);
1006
1007 const double set_h = init_h(t_coords(0), t_coords(1), t_coords(2));
1008 const double m = get_M(set_h) * alpha;
1009
1010 int bb = 0;
1011 for (; bb != nbRows; ++bb) {
1012 locF[bb] += (t_base * alpha) * (t_h - set_h); // minimize ∫(h - h_init)² dΩ
1013 locF[bb] += (t_diff_base(i) * m) * t_grad_g(i);
1014 ++t_base;
1015 ++t_diff_base;
1016 }
1017
1018 for (; bb < nbRowBaseFunctions; ++bb) {
1019 ++t_base;
1020 ++t_diff_base;
1021 }
1022
1023 ++t_h;
1024 ++t_grad_g;
1025
1026 ++t_coords;
1027 ++t_w;
1028 }
1029
1030 } else {
1031
1032 auto t_dot_h = getFTensor0FromVec(*dotHPtr);
1033 auto t_h = getFTensor0FromVec(*hPtr);
1034 auto t_u = getFTensor1FromMat<U_FIELD_DIM>(*uPtr);
1035 auto t_grad_h = getFTensor1FromMat<SPACE_DIM>(*gradHPtr);
1036 auto t_grad_g = getFTensor1FromMat<SPACE_DIM>(*gradGPtr);
1037
1038 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
1039
1040 const double r = t_coords(0);
1041 const double alpha = t_w * vol * cylindrical(r);
1042
1043 const double m = get_M(t_h) * alpha;
1044
1045 int bb = 0;
1046 for (; bb != nbRows; ++bb) {
1047 locF[bb] += (t_base * alpha) * (t_dot_h); // time derivative ∂h/∂t
1048 locF[bb] += (t_base * alpha) * (t_grad_h(i) * t_u(i)); // convection u·∇h
1049 locF[bb] += (t_diff_base(i) * t_grad_g(i)) * m; // mobility/divergence (M ∇g)
1050 ++t_base;
1051 ++t_diff_base;
1052 }
1053
1054 for (; bb < nbRowBaseFunctions; ++bb) {
1055 ++t_base;
1056 ++t_diff_base;
1057 }
1058
1059 ++t_dot_h;
1060 ++t_h;
1061 ++t_grad_g;
1062 ++t_u;
1063 ++t_grad_h;
1064
1065 ++t_coords;
1066 ++t_w;
1067 }
1068 }
1069
1071 }
1072
1073private:
1074 boost::shared_ptr<MatrixDouble> uPtr;
1075 boost::shared_ptr<VectorDouble> dotHPtr;
1076 boost::shared_ptr<VectorDouble> hPtr;
1077 boost::shared_ptr<MatrixDouble> gradHPtr;
1078 boost::shared_ptr<MatrixDouble> gradGPtr;
1079};
1080
1081/**
1082 * @brief Lhs for H dU
1083 * @param h_field_name Name of the field associated with the row operator (H)
1084 * @param u_field_name Name of the field associated with the column operator (U)
1085 * @param grad_h_ptr Pointer to the free surface height gradient matrix (∇H)
1086 * @return MoFEMErrorCode
1087 *
1088 * (Jacobian block ∂R_H/∂U)
1089 * Linearization of the conserved phase equation (Lovric 3.1c) w.r.t. U
1090 */
1092 OpLhsH_dU(const std::string h_field_name, const std::string u_field_name,
1093 boost::shared_ptr<MatrixDouble> grad_h_ptr)
1094 : AssemblyDomainEleOp(h_field_name, u_field_name,
1095 AssemblyDomainEleOp::OPROWCOL),
1096 gradHPtr(grad_h_ptr) {
1097 sYmm = false;
1098 assembleTranspose = false;
1099 }
1100 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
1101 EntitiesFieldData::EntData &col_data) {
1103
1104 const double vol = getMeasure();
1105 auto t_grad_h = getFTensor1FromMat<SPACE_DIM>(*gradHPtr);
1106 auto t_coords = getFTensor1CoordsAtGaussPts();
1107
1108 auto t_row_base = row_data.getFTensor0N();
1109 auto t_w = getFTensor0IntegrationWeight();
1110
1111 for (int gg = 0; gg != nbIntegrationPts; gg++) {
1112
1113 const auto r = t_coords(0);
1114 const auto alpha = t_w * vol * cylindrical(r);
1115 auto t_mat = getFTensor1FromPtr<U_FIELD_DIM>(&locMat(0, 0));
1117
1118 int rr = 0;
1119 for (; rr != nbRows; ++rr) {
1120 t_row(i) = (alpha * t_row_base) * t_grad_h(i);
1121 auto t_col_base = col_data.getFTensor0N(gg, 0);
1122 for (int cc = 0; cc != nbCols / U_FIELD_DIM; ++cc) {
1123 t_mat(i) += t_row(i) * t_col_base;
1124 ++t_mat;
1125 ++t_col_base;
1126 }
1127 ++t_row_base;
1128 }
1129
1130 for (; rr < nbRowBaseFunctions; ++rr)
1131 ++t_row_base;
1132
1133 ++t_grad_h;
1134 ++t_w;
1135 ++t_coords;
1136 }
1137
1139 }
1140
1141private:
1142 boost::shared_ptr<MatrixDouble> gradHPtr;
1143};
1144
1145/**
1146 * @brief Lhs for H dH (Jacobian block ∂R_H/∂H)
1147 * @param field_name Name of the field associated with the operator
1148 * @param u_ptr Pointer to the velocity matrix (U)
1149 * @param h_ptr Pointer to the free surface height vector (H)
1150 * @param grad_g_ptr Pointer to the chemical potential gradient matrix (∇G)
1151 * @return MoFEMErrorCode
1152 *
1153 * Linearization of the conserved phase equation (3.1c) w.r.t. H
1154 * - time-stepping mass scaling (ts_a) terms
1155 * - contributions from mobility derivative M'(h)
1156 * - coupling terms with chemical potential gradient where M depends on h
1157 *
1158 * When I==true the operator builds initialization-mode blocks (uses init_h)
1159 */
1160template <bool I> struct OpLhsH_dH : public AssemblyDomainEleOp {
1161
1162 OpLhsH_dH(const std::string field_name, boost::shared_ptr<MatrixDouble> u_ptr,
1163 boost::shared_ptr<VectorDouble> h_ptr,
1164 boost::shared_ptr<MatrixDouble> grad_g_ptr)
1166 AssemblyDomainEleOp::OPROWCOL),
1167 uPtr(u_ptr), hPtr(h_ptr), gradGPtr(grad_g_ptr) {
1168 sYmm = false;
1169 }
1170
1171 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
1172 EntitiesFieldData::EntData &col_data) {
1174
1175 const double vol = getMeasure();
1176 auto t_w = getFTensor0IntegrationWeight();
1177 auto t_coords = getFTensor1CoordsAtGaussPts();
1178 auto t_row_base = row_data.getFTensor0N();
1179 auto t_row_diff_base = row_data.getFTensor1DiffN<SPACE_DIM>();
1180
1181#ifndef NDEBUG
1182 if (row_data.getDiffN().size1() != row_data.getN().size1())
1183 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "wrong size 1");
1184 if (row_data.getDiffN().size2() != row_data.getN().size2() * SPACE_DIM) {
1185 MOFEM_LOG("SELF", Sev::error)
1186 << "Side " << rowSide << " " << CN::EntityTypeName(rowType);
1187 MOFEM_LOG("SELF", Sev::error) << row_data.getN();
1188 MOFEM_LOG("SELF", Sev::error) << row_data.getDiffN();
1189 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "wrong size 2");
1190 }
1191
1192 if (col_data.getDiffN().size1() != col_data.getN().size1())
1193 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "wrong size 1");
1194 if (col_data.getDiffN().size2() != col_data.getN().size2() * SPACE_DIM) {
1195 MOFEM_LOG("SELF", Sev::error)
1196 << "Side " << rowSide << " " << CN::EntityTypeName(rowType);
1197 MOFEM_LOG("SELF", Sev::error) << col_data.getN();
1198 MOFEM_LOG("SELF", Sev::error) << col_data.getDiffN();
1199 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "wrong size 2");
1200 }
1201#endif
1202
1203 if constexpr (I) {
1204
1205 auto t_h = getFTensor0FromVec(*hPtr);
1206 auto t_grad_g = getFTensor1FromMat<SPACE_DIM>(*gradGPtr);
1207
1208 for (int gg = 0; gg != nbIntegrationPts; gg++) {
1209
1210 const double r = t_coords(0);
1211 const double alpha = t_w * vol * cylindrical(r);
1212
1213 int rr = 0;
1214 for (; rr != nbRows; ++rr) {
1215
1216 auto t_col_base = col_data.getFTensor0N(gg, 0);
1217 auto t_col_diff_base = col_data.getFTensor1DiffN<SPACE_DIM>(gg, 0);
1218
1219 for (int cc = 0; cc != nbCols; ++cc) {
1220
1221 locMat(rr, cc) += (t_row_base * t_col_base * alpha);
1222
1223 ++t_col_base;
1224 ++t_col_diff_base;
1225 }
1226
1227 ++t_row_base;
1228 ++t_row_diff_base;
1229 }
1230
1231 for (; rr < nbRowBaseFunctions; ++rr) {
1232 ++t_row_base;
1233 ++t_row_diff_base;
1234 }
1235
1236 ++t_h;
1237 ++t_grad_g;
1238 ++t_w;
1239 ++t_coords;
1240 }
1241
1242 } else {
1243
1244 auto t_h = getFTensor0FromVec(*hPtr);
1245 auto t_grad_g = getFTensor1FromMat<SPACE_DIM>(*gradGPtr);
1246 auto t_u = getFTensor1FromMat<U_FIELD_DIM>(*uPtr);
1247
1248 auto ts_a = getTSa();
1249
1250 for (int gg = 0; gg != nbIntegrationPts; gg++) {
1251
1252 const double r = t_coords(0);
1253 const double alpha = t_w * vol * cylindrical(r);
1254
1255 auto m_dh = get_M_dh(t_h) * alpha;
1256 int rr = 0;
1257 for (; rr != nbRows; ++rr) {
1258
1259 auto t_col_base = col_data.getFTensor0N(gg, 0);
1260 auto t_col_diff_base = col_data.getFTensor1DiffN<SPACE_DIM>(gg, 0);
1261
1262 for (int cc = 0; cc != nbCols; ++cc) {
1263
1264 locMat(rr, cc) += (t_row_base * t_col_base * alpha) * ts_a; // time-stepping mass term
1265 locMat(rr, cc) +=
1266 (t_row_base * alpha) * (t_col_diff_base(i) * t_u(i)); // convection term u·∇h
1267 locMat(rr, cc) +=
1268 (t_row_diff_base(i) * t_grad_g(i)) * (t_col_base * m_dh); // mobility derivative term M'(h) ∇g
1269
1270 ++t_col_base;
1271 ++t_col_diff_base;
1272 }
1273
1274 ++t_row_base;
1275 ++t_row_diff_base;
1276 }
1277
1278 for (; rr < nbRowBaseFunctions; ++rr) {
1279 ++t_row_base;
1280 ++t_row_diff_base;
1281 }
1282
1283 ++t_u;
1284 ++t_h;
1285 ++t_grad_g;
1286 ++t_w;
1287 ++t_coords;
1288 }
1289 }
1290
1292 }
1293
1294private:
1295 boost::shared_ptr<MatrixDouble> uPtr;
1296 boost::shared_ptr<VectorDouble> hPtr;
1297 boost::shared_ptr<MatrixDouble> gradGPtr;
1298};
1299
1300/**
1301 * @brief Lhs for H dG
1302 * @param field_name_h Name of the field associated with the row operator (H)
1303 * @param field_name_g Name of the field associated with the column operator (G)
1304 * @param h_ptr Pointer to the free surface height vector (H)
1305 * @return MoFEMErrorCode
1306 *
1307 * (Jacobian block ∂R_H/∂G)
1308 * Linearization of the conserved phase equation (Lovric 3.1c) w.r.t. G
1309 */
1310template <bool I> struct OpLhsH_dG : public AssemblyDomainEleOp {
1311
1312 OpLhsH_dG(const std::string field_name_h, const std::string field_name_g,
1313 boost::shared_ptr<VectorDouble> h_ptr)
1314 : AssemblyDomainEleOp(field_name_h, field_name_g,
1315 AssemblyDomainEleOp::OPROWCOL),
1316 hPtr(h_ptr) {
1317 sYmm = false;
1318 assembleTranspose = false;
1319 }
1320
1321 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
1322 EntitiesFieldData::EntData &col_data) {
1324
1325 const double vol = getMeasure();
1326 auto t_h = getFTensor0FromVec(*hPtr);
1327
1328 auto t_row_diff_base = row_data.getFTensor1DiffN<SPACE_DIM>();
1329 auto t_w = getFTensor0IntegrationWeight();
1330 auto t_coords = getFTensor1CoordsAtGaussPts();
1331
1332 for (int gg = 0; gg != nbIntegrationPts; gg++) {
1333
1334 const double r = t_coords(0);
1335 const double alpha = t_w * vol * cylindrical(r);
1336
1337 double set_h;
1338 if constexpr (I)
1339 set_h = init_h(t_coords(0), t_coords(1), t_coords(2));
1340 else
1341 set_h = t_h;
1342
1343 auto m = get_M(set_h) * alpha;
1344
1345 int rr = 0;
1346 for (; rr != nbRows; ++rr) {
1347 auto t_col_diff_base = col_data.getFTensor1DiffN<SPACE_DIM>(gg, 0);
1348
1349 for (int cc = 0; cc != nbCols; ++cc) {
1350 locMat(rr, cc) += (t_row_diff_base(i) * t_col_diff_base(i)) * m; // mobility/divergence (M ∇g)
1351
1352 ++t_col_diff_base;
1353 }
1354
1355 ++t_row_diff_base;
1356 }
1357
1358 for (; rr < nbRowBaseFunctions; ++rr) {
1359 ++t_row_diff_base;
1360 }
1361
1362 ++t_h;
1363 ++t_w;
1364 ++t_coords;
1365 }
1366
1368 }
1369
1370private:
1371 boost::shared_ptr<VectorDouble> hPtr;
1372};
1373
1374/**
1375 * @brief Rhs for G (chemical potential residual)
1376 * @param field_name Name of the field associated with the operator
1377 * @param h_ptr Pointer to the free surface height vector (H)
1378 * @param grad_h_ptr Pointer to the free surface height gradient matrix (∇H)
1379 * @param g_ptr Pointer to the chemical potential vector (G)
1380 * @return MoFEMErrorCode
1381 *
1382 * Implements Lovric 3.1d (excpet for wetting boundary term - see OpWettingAngleRhs/Lhs):
1383 * R_g = ∫_Ω s(g - f(h)) - ∇s·(ε²∇h) dΩ
1384 *
1385 * The template boolean I selects initialization (I=true) vs evolution (I=false).
1386 */
1387template <bool I> struct OpRhsG : public AssemblyDomainEleOp {
1388
1389 OpRhsG(const std::string field_name, boost::shared_ptr<VectorDouble> h_ptr,
1390 boost::shared_ptr<MatrixDouble> grad_h_ptr,
1391 boost::shared_ptr<VectorDouble> g_ptr)
1393 hPtr(h_ptr), gradHPtr(grad_h_ptr), gPtr(g_ptr) {}
1394
1395 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &data) {
1397
1398 const double vol = getMeasure();
1399 auto t_h = getFTensor0FromVec(*hPtr);
1400 auto t_grad_h = getFTensor1FromMat<SPACE_DIM>(*gradHPtr);
1401 auto t_g = getFTensor0FromVec(*gPtr);
1402 auto t_coords = getFTensor1CoordsAtGaussPts();
1403
1404 auto t_base = data.getFTensor0N();
1405 auto t_diff_base = data.getFTensor1DiffN<SPACE_DIM>();
1406 auto t_w = getFTensor0IntegrationWeight();
1407
1408 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
1409
1410 const double r = t_coords(0);
1411 const double alpha = t_w * vol * cylindrical(r);
1412
1413 double set_h;
1414 if constexpr (I)
1415 set_h = init_h(t_coords(0), t_coords(1), t_coords(2));
1416 else
1417 set_h = t_h;
1418
1419 const double f = get_f(set_h);
1420
1421 int bb = 0;
1422 for (; bb != nbRows; ++bb) {
1423 locF[bb] += (t_base * alpha) * (t_g - f); // Bulk term: (g - f(h))
1424 locF[bb] -= (t_diff_base(i) * (eta2 * alpha)) * t_grad_h(i); // Diffusion term: -ε²∇h
1425 ++t_base;
1426 ++t_diff_base;
1427 }
1428
1429 for (; bb < nbRowBaseFunctions; ++bb) {
1430 ++t_base;
1431 ++t_diff_base;
1432 }
1433
1434 ++t_h;
1435 ++t_grad_h;
1436 ++t_g;
1437
1438 ++t_coords;
1439 ++t_w;
1440 }
1441
1443 }
1444
1445private:
1446 boost::shared_ptr<VectorDouble> hPtr;
1447 boost::shared_ptr<MatrixDouble> gradHPtr;
1448 boost::shared_ptr<VectorDouble> gPtr;
1449};
1450
1451/**
1452 * @brief Lhs for G dH
1453 * @param field_name_g Name of the field associated with the row operator (G)
1454 * @param field_name_h Name of the field associated with the column operator (H)
1455 * @param h_ptr Pointer to the free surface height vector (H)
1456 * @return MoFEMErrorCode
1457 *
1458 * (Jacobian block ∂R_G/∂H)
1459 * Linearization of the chemical potential equation (Lovric 3.1d) w.r.t. H
1460 */
1461template <bool I> struct OpLhsG_dH : public AssemblyDomainEleOp {
1462
1463 OpLhsG_dH(const std::string field_name_g, const std::string field_name_h,
1464 boost::shared_ptr<VectorDouble> h_ptr)
1465 : AssemblyDomainEleOp(field_name_g, field_name_h,
1466 AssemblyDomainEleOp::OPROWCOL),
1467 hPtr(h_ptr) {
1468 sYmm = false;
1469 assembleTranspose = false;
1470 }
1471
1472 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
1473 EntitiesFieldData::EntData &col_data) {
1475
1476 const double vol = getMeasure();
1477 auto t_h = getFTensor0FromVec(*hPtr);
1478
1479 auto t_row_base = row_data.getFTensor0N();
1480 auto t_row_diff_base = row_data.getFTensor1DiffN<SPACE_DIM>();
1481 auto t_w = getFTensor0IntegrationWeight();
1482 auto t_coords = getFTensor1CoordsAtGaussPts();
1483
1484 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
1485
1486 const double r = t_coords(0);
1487 const double alpha = t_w * vol * cylindrical(r);
1488
1489 const double f_dh = get_f_dh(t_h) * alpha; // derivative of f(h)
1490 const double beta = eta2 * alpha; // coefficient for diffusion term -ε²
1491
1492 int rr = 0;
1493 for (; rr != nbRows; ++rr) {
1494
1495 auto t_col_base = col_data.getFTensor0N(gg, 0);
1496 auto t_col_diff_base = col_data.getFTensor1DiffN<SPACE_DIM>(gg, 0);
1497
1498 for (int cc = 0; cc != nbCols; ++cc) {
1499
1500 if constexpr (I == false)
1501 locMat(rr, cc) -= (t_row_base * t_col_base) * f_dh; // bulk term derivative (g - f(h))
1502 locMat(rr, cc) -= (t_row_diff_base(i) * beta) * t_col_diff_base(i); // diffusion term derivative -ε²∇h
1503
1504 ++t_col_base;
1505 ++t_col_diff_base;
1506 }
1507
1508 ++t_row_base;
1509 ++t_row_diff_base;
1510 }
1511
1512 for (; rr < nbRowBaseFunctions; ++rr) {
1513 ++t_row_base;
1514 ++t_row_diff_base;
1515 }
1516
1517 ++t_h;
1518 ++t_w;
1519 ++t_coords;
1520 }
1521
1523 }
1524
1525private:
1526 boost::shared_ptr<VectorDouble> hPtr;
1527};
1528
1529/**
1530 * @brief Lhs for G dG
1531 * @param field_name Name of the field associated with the operator
1532 * @return MoFEMErrorCode
1533 *
1534 * (Jacobian block ∂R_G/∂G)
1535 * Linearization of the chemical potential equation (Lovric 3.1d) w.r.t. G
1536 */
1538
1539 OpLhsG_dG(const std::string field_name)
1541 AssemblyDomainEleOp::OPROWCOL) {
1542 sYmm = true;
1543 }
1544
1545 MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &row_data,
1546 EntitiesFieldData::EntData &col_data) {
1548
1549 const double vol = getMeasure();
1550
1551 auto t_row_base = row_data.getFTensor0N();
1552 auto t_w = getFTensor0IntegrationWeight();
1553 auto t_coords = getFTensor1CoordsAtGaussPts();
1554
1555 for (int gg = 0; gg != nbIntegrationPts; ++gg) {
1556
1557 const double r = t_coords(0);
1558 const double alpha = t_w * vol * cylindrical(r);
1559
1560 int rr = 0;
1561 for (; rr != nbRows; ++rr) {
1562 auto t_col_base = col_data.getFTensor0N(gg, 0);
1563 const double beta = alpha * t_row_base;
1564 for (int cc = 0; cc != nbCols; ++cc) {
1565 locMat(rr, cc) += (t_col_base * beta);
1566 ++t_col_base;
1567 }
1568
1569 ++t_row_base;
1570 }
1571
1572 for (; rr < nbRowBaseFunctions; ++rr) {
1573 ++t_row_base;
1574 }
1575
1576 ++t_w;
1577 ++t_coords;
1578 }
1579
1581 }
1582
1583private:
1584};
1585
1586} // namespace FreeSurfaceOps
std::string type
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:145