v0.16.0
Loading...
Searching...
No Matches
cell_forces.cpp
Go to the documentation of this file.
1/**
2 \file cell_forces.cpp
3 \brief Identify cell tractions from measured displacements
4
5 \tableofcontents
6
7 \section cell_potential Force-potential implementation
8
9This example identifies surface tractions that produce measured displacements
10on an interface within an elastic body. In the experiment, a transparent gel
11layer covers the body, and the motion of marker beads at the interface is
12measured. Cells on the upper surface deform the gel. The objective is to infer
13the tractions exerted by the cells from the measured displacements.
14
15The current implementation assumes that the measurement and traction surfaces
16are planar and parallel to the \f$x\f$-\f$y\f$ plane. An extension to curved
17surfaces would require intrinsic surface differential operators and a
18well-defined model for any normal traction.
19
20\ref mofem_citation
21
22\htmlonly
23<a href="https://doi.org/10.5281/zenodo.439392"><img
24src="https://zenodo.org/badge/DOI/10.5281/zenodo.439392.svg" alt="DOI"></a> <a
25href="https://doi.org/10.5281/zenodo.439395"><img
26src="https://zenodo.org/badge/DOI/10.5281/zenodo.439395.svg" alt="DOI"></a>
27\endhtmlonly
28
29\subsection cell_formulation Inverse traction formulation
30
31Let \f$V\f$ be the elastic body, \f$S_u\f$ the measurement surface, and
32\f$S_\rho\f$ the surface on which the unknown traction acts. The state
33displacement is denoted by \f$\mathbf{u}\f$, the measured displacement by
34\f$\mathbf{u}_d\f$, the Lagrange multiplier (adjoint field) by
35\f$\Upsilon\f$, and the traction by \f$\mathbf{t}\f$. The small-strain
36constitutive equation is
37\f[
38\sigma(\mathbf{u}) =
39\mathcal{A}:\varepsilon(\mathbf{u}), \qquad
40\varepsilon(\mathbf{u}) =
41\frac{1}{2}\left(\nabla\mathbf{u}+\nabla\mathbf{u}^{\mathrm T}\right).
42\f]
43For a symmetric elasticity tensor \f$\mathcal{A}\f$, define
44\f[
45a(\mathbf{u},\mathbf{v}) =
46\left(\varepsilon(\mathbf{v}),
47\mathcal{A}:\varepsilon(\mathbf{u})\right)_V.
48\f]
49
50The inverse problem is
51\f[
52\begin{aligned}
53\underset{\mathbf{u},\mathbf{t}}{\operatorname{minimise}}\quad
54J(\mathbf{u},\mathbf{t}) &=
55\frac{1}{2}
56\left(\mathbf{u}-\mathbf{u}_d,
57S(\mathbf{u}-\mathbf{u}_d)\right)_{S_u}
58+R(\mathbf{t}),\\
59-\operatorname{div}\sigma(\mathbf{u})&=0
60\quad\text{in }V,\\
61\sigma(\mathbf{u})\mathbf{n}&=\mathbf{t}
62\quad\text{on }S_\rho .
63\end{aligned}
64\f]
65The remaining boundary conditions must make the elasticity problem unique. In
66particular, sufficient displacement constraints are required to eliminate
67rigid-body modes.
68
69After integration by parts, the weak equilibrium constraint is
70\f[
71a(\mathbf{u},\mathbf{v})-(\mathbf{t},\mathbf{v})_{S_\rho}=0.
72\f]
73It follows from
74\f$-(\Upsilon,\operatorname{div}\sigma)_V\f$; boundary
75terms on portions other than \f$S_\rho\f$ vanish because of the corresponding
76essential or natural boundary conditions. The Lagrangian is therefore
77\f[
78\mathcal{L}(\mathbf{u},\mathbf{t},\Upsilon)=
79\frac{1}{2}
80\left(\mathbf{u}-\mathbf{u}_d,
81S(\mathbf{u}-\mathbf{u}_d)\right)_{S_u}
82+R(\mathbf{t})
83+a(\mathbf{u},\Upsilon)
84-(\mathbf{t},\Upsilon)_{S_\rho}.
85\f]
86Thus, traction is coupled to equilibrium in the weak sense.
87
88For the quadratic regularisation
89\f[
90R(\mathbf{t})=
91\frac{\epsilon_\rho^\mathrm{abs}}{2}
92(\mathbf{t},\mathbf{t})_{S_\rho},
93\f]
94stationarity gives
95\f[
96\begin{aligned}
97\left(S(\mathbf{u}-\mathbf{u}_d),\delta\mathbf{u}\right)_{S_u}
98+a(\delta\mathbf{u},\Upsilon)&=0,\\
99a(\mathbf{u},\delta\Upsilon)
100-(\mathbf{t},\delta\Upsilon)_{S_\rho}&=0,\\
101\epsilon_\rho^\mathrm{abs}
102(\mathbf{t},\delta\mathbf{t})_{S_\rho}
103-(\Upsilon,\delta\mathbf{t})_{S_\rho}&=0.
104\end{aligned}
105\f]
106
107Finite element discretisation gives
108\f[
109\left[
110\begin{array}{ccc}
111S & K & 0 \\
112K & 0 & -B^\mathrm{T} \\
1130 & -B & D
114\end{array}
115\right]
116\left[
117\begin{array}{c}
118\mathbf{u} \\ \Upsilon \\ \mathbf{t}
119\end{array}
120\right]
121=
122\left[
123\begin{array}{c}
124S\mathbf{u}_d \\ 0 \\ 0
125\end{array}
126\right],
127\f]
128where the two elastic blocks are identical because the linear-elastic bilinear
129form is symmetric. Swapping the first two block rows produces the system used
130by the implementation:
131\f[
132\left[
133\begin{array}{ccc}
134K & 0 & -B^\mathrm{T} \\
135S & K & 0 \\
1360 & -B & D
137\end{array}
138\right]
139\left[
140\begin{array}{c}
141\mathbf{u} \\ \Upsilon \\ \mathbf{t}
142\end{array}
143\right]
144=
145\left[
146\begin{array}{c}
1470 \\ S\mathbf{u}_d \\ 0
148\end{array}
149\right].
150\f]
151
152Only the measured \f$x\f$- and \f$y\f$-components enter the displacement
153misfit. Consequently,
154\f[
155S=\epsilon_u^{-1}P_{xy},\qquad
156P_{xy}=\operatorname{diag}(1,1,0),\qquad
157\epsilon_\rho^\mathrm{abs}
158=\epsilon_\rho^\mathrm{ref}\epsilon_u^{-1}.
159\f]
160
161\subsection cell_local Exact curl-free force-potential formulation
162
163The local model assumes that the tangential traction is curl-free. This is a
164modelling assumption motivated by an idealised network of short, prestressed
165fibres; it is not a consequence of equilibrium alone. On a simply connected
166planar surface, the traction can then be represented by a scalar potential:
167\f[
168\mathbf{t}=\nabla_s\Phi ,
169\f]
170where \f$\nabla_s\f$ denotes the surface gradient. The regularisation and
171traction coupling become
172\f[
173R(\Phi)=\frac{\epsilon_\rho^\mathrm{abs}}{2}
174(\nabla_s\Phi,\nabla_s\Phi)_{S_\rho},\qquad
175-(\nabla_s\Phi,\Upsilon)_{S_\rho}.
176\f]
177Variation with respect to the potential gives
178\f[
179\epsilon_\rho^\mathrm{abs}
180(\nabla_s\Phi,\nabla_s\delta\Phi)_{S_\rho}
181-(\Upsilon,\nabla_s\delta\Phi)_{S_\rho}=0.
182\f]
183The third algebraic unknown in this formulation is \f$\Phi\f$, not
184\f$\mathbf{t}\f$. The matrix \f$D\f$ is the surface stiffness matrix for the
185potential, and one value of \f$\Phi\f$ must be fixed to remove its arbitrary
186additive constant.
187
188 \subsubsection cell_local_approx Approximation
189
190The state and adjoint fields satisfy
191\f$\mathbf{u},\Upsilon\in[H^1(V)]^3\f$, with the appropriate
192essential boundary conditions. The potential satisfies
193\f$\Phi\in H^1(S_\rho)\f$, and the recovered tangential traction
194\f$\nabla_s\Phi\f$ belongs to \f$[L^2(S_\rho)]^2\f$.
195
196 \subsection cell_nonlocal Weak curl-free formulation
197
198The nonlocal model represents the traction directly and penalises, rather than
199eliminates, its surface curl. It is intended to account for the finite size and
200complex prestressed structure of a cell. The regularisation is
201\f[
202R(\mathbf{t})=
203\frac{\epsilon_\rho^\mathrm{abs}}{2}
204(\mathbf{t},\mathbf{t})_{S_\rho}
205+\frac{1}{2\epsilon_l^\mathrm{abs}}
206(\operatorname{curl}_s\mathbf{t},
207\operatorname{curl}_s\mathbf{t})_{S_\rho}.
208\f]
209The traction optimality equation is
210\f[
211\epsilon_\rho^\mathrm{abs}
212(\mathbf{t},\delta\mathbf{t})_{S_\rho}
213+(\epsilon_l^\mathrm{abs})^{-1}
214(\operatorname{curl}_s\mathbf{t},
215\operatorname{curl}_s\delta\mathbf{t})_{S_\rho}
216-(\Upsilon,\delta\mathbf{t})_{S_\rho}=0.
217\f]
218The command-line parameters are scaled in the implementation as
219\f[
220\epsilon_\rho^\mathrm{abs}
221=\epsilon_\rho^\mathrm{ref}\epsilon_u^{-1},\qquad
222\epsilon_l^\mathrm{abs}
223=\epsilon_l^\mathrm{ref}\epsilon_u.
224\f]
225For positive \f$\epsilon_l^\mathrm{ref}\f$, decreasing it strengthens the
226curl-free penalty. The exact value \f$\epsilon_l^\mathrm{ref}=0\f$ disables the
227curl term in the current implementation to avoid division by zero; it does not
228select the limiting exact-potential problem. Use \c -my_curl \c 0 to select the
229exact force-potential formulation.
230
231 \subsubsection cell_nonlocal_approx Approximation
232
233The state and adjoint fields satisfy
234\f$\mathbf{u},\Upsilon\in[H^1(V)]^3\f$. The traction belongs to the
235surface space
236\f$\mathbf{t}\in H(\operatorname{curl}_s;S_\rho)\f$.
237
238\section cell_solution Field-split preconditioner
239
240The implementation uses the block structure of the matrix through
241\e PCFIELDSPLIT and stores the matrix in the nested \e MATNEST format.
242
243The nested matrix containing the two upper-left blocks is
244\f[
245X = \left[
246\begin{array}{cc}
247K & 0 \\
248S & K
249\end{array}
250\right]
251\f]
252The complete matrix is then written as
253\f[
254A= \left[
255\begin{array}{cc}
256X & V \\
257H & D
258\end{array}
259\right]
260\f]
261where
262\f[
263V= \left[
264\begin{array}{c}
265-B^\textrm{T} \\
2660
267\end{array}
268\right]
269\f]
270and
271\f[
272H= \left[
273\begin{array}{cc}
2740 & -B
275\end{array}
276\right]
277\f]
278
279The system associated with \f$X\f$ is solved using \e PCFIELDSPLIT and a
280multiplicative relaxation scheme. The submatrix \f$K\f$ is factorised only
281once. The system associated with \f$A\f$, composed of
282\f$X\f$, \f$D\f$, \f$V\f$, and \f$H\f$, is solved using a Schur complement.
283MoFEM subproblems are used to construct the required blocks.
284
285\section cell_running_code Running code
286
287Mapping measured displacements:
288\code
289./map_disp \
290-my_data_x ./examples/data_x.csv \
291-my_data_y ./examples/data_y.csv \
292-my_file ./examples/mesh_cell_force_map.cub \
293-ksp_type cg -pc_type lu -pc_factor_mat_solver_package mumps -ksp_monitor \
294-lambda 0.01 -my_order 3 -scale 0.05 -cube_size 1 -my_nparts 4
295\endcode
296
297If only one layer is specified, a second thin polymer layer can be created
298automatically using prism elements:
299\code
300./map_disp_prism \
301-my_thickness 0.01 \
302-my_data_x ./examples/data_x.csv \
303-my_data_y ./examples/data_y.csv \
304-my_file ./examples/mesh_for_prisms.cub \
305-ksp_type cg -pc_type lu -pc_factor_mat_solver_package mumps -ksp_monitor \
306-lambda 0.01 -my_order 3 -scale 0.05 -cube_size 1 -my_nparts 4
307\endcode
308
309Configuration file:
310\include users_modules/cell_engineering/examples/block_config.in
311
312Calculating tractions:
313\code
314mpirun -np 4 ./cell_forces \
315-my_file analysis_mesh.h5m \
316-my_order 1 -my_order_force 2 -my_max_post_proc_ref_level 0 \
317-my_block_config ./examples/block_config.in \
318-ksp_type fgmres -ksp_monitor \
319-fieldsplit_1_ksp_type fgmres \
320-fieldsplit_1_pc_type lu \
321-fieldsplit_1_pc_factor_mat_solver_package mumps \
322-fieldsplit_1_ksp_max_it 100 \
323-fieldsplit_1_ksp_monitor \
324-fieldsplit_0_ksp_type gmres \
325-fieldsplit_0_ksp_max_it 25 \
326-fieldsplit_0_fieldsplit_0_ksp_type preonly \
327-fieldsplit_0_fieldsplit_0_pc_type lu \
328-fieldsplit_0_fieldsplit_0_pc_factor_mat_solver_package mumps \
329-fieldsplit_0_fieldsplit_1_ksp_type preonly \
330-fieldsplit_0_fieldsplit_1_pc_type lu \
331-fieldsplit_0_fieldsplit_1_pc_factor_mat_solver_package mumps \
332-ksp_atol 1e-6 -ksp_rtol 0 -my_eps_u 1e-4 -my_curl 1
333\endcode
334
335The resulting traction field is shown below:
336\image html cell_engineering_forces_example.gif "Example: results" width=600px
337
338\section cell_install Installation with Docker
339
340- First, install Docker according to the instructions at:
341<https://docs.docker.com/installation/#installation>
342- Install the cell user module: \e docker \e pull \e likask/cell_engineering
343
344\todo Improve documentation
345
346\todo Generalise the implementation to curved surfaces using intrinsic surface
347differential operators and an appropriate model for normal traction.
348
349\todo Replace the elastic material with the GEL model developed in another
350module to account for drying and other rheological effects.
351
352\todo Use an SNES solver when introducing a nonlinear material model.
353
354\todo Add equations for cell mechanics either directly to the minimised
355functional or as additional constraints.
356
357*/
358
359/**
360 \example cell_forces.cpp
361 Complete example for identifying cell forces from measured displacements.
362
363 See \ref cell_potential for the mathematical formulation, implementation
364 details, and command-line usage.
365*/
366
367/* Copyright (c) 2025 Authors under the MIT License.
368 * See LICENSE.md for details.
369 * SPDX-License-Identifier: MIT
370 */
371
372#include <MoFEM.hpp>
373using namespace MoFEM;
374#include <CellForces.hpp>
375
376constexpr int SPACE_DIM = 3;
378
379#include <HookeOps.hpp>
380
381static char help[] = "-my_block_config set block data\n"
382 "\n";
383
385
387 int oRder;
388 double yOung;
389 double pOisson;
390 BlockOptionData() : oRder(-1), yOung(-1), pOisson(-2) {}
391};
392
394 using VolumeElementForcesAndSourcesCore::VolumeElementForcesAndSourcesCore;
395 int getRule(int order) override { return 2 * order + 1; }
396};
397
398using ElasticBlockMap = std::map<int, Range>;
399
402
403 OpElasticEnergy(boost::shared_ptr<MatrixDouble> strain_ptr,
404 boost::shared_ptr<MatrixDouble> stress_ptr, double &energy)
406 NOSPACE, UserDataOperator::OPSPACE),
407 strainPtr(strain_ptr), stressPtr(stress_ptr), energy(energy) {}
408
409 MoFEMErrorCode doWork(int, EntityType,
410 EntitiesFieldData::EntData &) override {
412
413 const size_t nb_gauss_pts = getGaussPts().size2();
415 auto get_strain =
417 DL>::get(*strainPtr, nb_gauss_pts);
418 auto get_stress =
420 DL>::get(*stressPtr, nb_gauss_pts);
421 auto t_strain = get_strain();
422 auto t_stress = get_stress();
425
426 for (size_t gg = 0; gg != nb_gauss_pts; ++gg) {
427 const double alpha = getMeasure() * getGaussPts()(SPACE_DIM, gg);
428 energy += 0.5 * alpha * t_strain(i, j) * t_stress(i, j);
429 ++t_strain;
430 ++t_stress;
431 }
432
434 }
435
436private:
437 boost::shared_ptr<MatrixDouble> strainPtr;
438 boost::shared_ptr<MatrixDouble> stressPtr;
439 double &energy;
440};
441
442} // namespace CellEngineering
443
444using namespace boost::numeric;
445using namespace CellEngineering;
446
447#include <boost/program_options.hpp>
448using namespace std;
449namespace po = boost::program_options;
450
451static int debug = 0;
452
453int main(int argc, char *argv[]) {
454
455 MoFEM::Core::Initialize(&argc, &argv, (char *)0, help);
456
457 try {
458
459 moab::Core mb_instance;
460 moab::Interface &moab = mb_instance;
461
462 PetscBool flg_block_config, flg_file;
463 char mesh_file_name[255];
464 char block_config_file[255];
465 PetscBool flg_order_force;
466 PetscInt order = 2;
467 PetscInt order_force = 2;
468 PetscBool flg_eps_u, flg_eps_rho, flg_eps_l;
469 double eps_u = 1e-6;
470 double eps_rho = 1e-3;
471 double eps_l = 0;
472 PetscBool is_curl = PETSC_TRUE;
473 PetscOptionsBegin(PETSC_COMM_WORLD, "", "Elastic Config", "none");
474 CHKERR PetscOptionsString("-my_file", "mesh file name", "", "mesh.h5m",
475 mesh_file_name, 255, &flg_file);
476 CHKERR PetscOptionsInt("-my_order", "default approximation order", "",
477 order, &order, PETSC_NULLPTR);
478 CHKERR PetscOptionsInt(
479 "-my_order_force",
480 "default approximation order for traction approximation", "",
481 order_force, &order_force, &flg_order_force);
482 CHKERR PetscOptionsString("-my_block_config",
483 "elastic configuration file name", "",
484 "block_conf.in", block_config_file, 255,
485 &flg_block_config);
486 CHKERR PetscOptionsReal("-my_eps_rho", "traction regularisation parameter",
487 "", eps_rho, &eps_rho, &flg_eps_rho);
488 CHKERR PetscOptionsReal(
489 "-my_eps_u", "displacement-misfit regularisation parameter", "", eps_u,
490 &eps_u, &flg_eps_u);
491 CHKERR PetscOptionsReal("-my_eps_l", "curl regularisation parameter", "",
492 eps_l, &eps_l, &flg_eps_l);
493 CHKERR PetscOptionsBool(
494 "-my_curl", "use H(curl) space to approximate tractions", "", is_curl,
495 &is_curl, PETSC_NULLPTR);
496 PetscOptionsEnd();
497
498 // Read command-line parameters
499 if (flg_file != PETSC_TRUE) {
500 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
501 "*** ERROR -my_file (MESH FILE NEEDED)");
502 }
503
504 ParallelComm *pcomm = ParallelComm::get_pcomm(&moab, MYPCOMM_INDEX);
505 if (pcomm == nullptr)
506 pcomm = new ParallelComm(&moab, PETSC_COMM_WORLD);
507
508 // Read mesh to MOAB
509 const char *option;
510 option = "PARALLEL=READ_PART;"
511 "PARALLEL_RESOLVE_SHARED_ENTS;"
512 "PARTITION=PARALLEL_PARTITION;";
513 // option = "";
514 CHKERR moab.load_file(mesh_file_name, 0, option);
515
516 // Create MoFEM (Joseph) database
517 MoFEM::Core core(moab);
518 MoFEM::Interface &m_field = core;
519
520 auto mmanager_ptr = m_field.getInterface<MeshsetsManager>();
521 auto comm_interface_ptr = m_field.getInterface<CommInterface>();
522 // print bcs
523 CHKERR mmanager_ptr->printDisplacementSet();
524 CHKERR mmanager_ptr->printForceSet();
525 // print block sets with materials
526 CHKERR mmanager_ptr->printMaterialsSet();
527
528 // stl::bitset see for more details
529 BitRefLevel bit_level0;
530 bit_level0.set(0);
531 {
532 Range ents3d;
533 CHKERR moab.get_entities_by_dimension(0, 3, ents3d);
534 CHKERR m_field.getInterface<BitRefManager>()->setBitRefLevel(
535 ents3d, bit_level0, false);
536 }
537
538 // Set the approximation order
539
540 std::vector<Range> setOrderToEnts(10);
541
542 // configure blocks by parsing config file
543 // it allow to set approximation order for each block independently
544 Range set_order_ents;
545 std::map<int, BlockOptionData> block_data;
546 if (flg_block_config) {
547 double read_eps_u, read_eps_rho, read_eps_l;
548 try {
549 ifstream ini_file(block_config_file);
550 if (!ini_file.is_open()) {
551 SETERRQ(PETSC_COMM_SELF, 1,
552 "*** -my_block_config does not exist ***");
553 }
554 // std::cerr << block_config_file << std::endl;
555 po::variables_map vm;
556 po::options_description config_file_options;
557 config_file_options.add_options()(
558 "eps_u", po::value<double>(&read_eps_u)->default_value(-1))(
559 "eps_rho", po::value<double>(&read_eps_rho)->default_value(-1))(
560 "eps_l", po::value<double>(&read_eps_l)->default_value(-1));
562 std::ostringstream str_order;
563 str_order << "block_" << it->getMeshsetId() << ".displacement_order";
564 config_file_options.add_options()(
565 str_order.str().c_str(),
566 po::value<int>(&block_data[it->getMeshsetId()].oRder)
567 ->default_value(order));
568 std::ostringstream str_cond;
569 str_cond << "block_" << it->getMeshsetId() << ".young_modulus";
570 config_file_options.add_options()(
571 str_cond.str().c_str(),
572 po::value<double>(&block_data[it->getMeshsetId()].yOung)
573 ->default_value(-1));
574 std::ostringstream str_capa;
575 str_capa << "block_" << it->getMeshsetId() << ".poisson_ratio";
576 config_file_options.add_options()(
577 str_capa.str().c_str(),
578 po::value<double>(&block_data[it->getMeshsetId()].pOisson)
579 ->default_value(-2));
580 }
581 po::parsed_options parsed =
582 parse_config_file(ini_file, config_file_options, true);
583 store(parsed, vm);
584 po::notify(vm);
586 if (block_data[it->getMeshsetId()].oRder == -1)
587 continue;
588 if (block_data[it->getMeshsetId()].oRder == order)
589 continue;
590 PetscPrintf(PETSC_COMM_WORLD, "Set block %d order to %d\n",
591 it->getMeshsetId(), block_data[it->getMeshsetId()].oRder);
592 Range block_ents;
593 CHKERR moab.get_entities_by_handle(it->getMeshset(), block_ents,
594 true);
595 // block_ents = block_ents.subset_by_type(MBTET);
596 Range nodes;
597 CHKERR moab.get_connectivity(block_ents, nodes, true);
598 Range ents_to_set_order, ents3d;
599 CHKERR moab.get_adjacencies(nodes, 3, false, ents3d,
600 moab::Interface::UNION);
601 CHKERR moab.get_adjacencies(ents3d, 2, false, ents_to_set_order,
602 moab::Interface::UNION);
603 CHKERR moab.get_adjacencies(ents3d, 1, false, ents_to_set_order,
604 moab::Interface::UNION);
605 ents_to_set_order = subtract(
606 ents_to_set_order, ents_to_set_order.subset_by_type(MBQUAD));
607 ents_to_set_order = subtract(
608 ents_to_set_order, ents_to_set_order.subset_by_type(MBPRISM));
609 set_order_ents.merge(ents3d);
610 set_order_ents.merge(ents_to_set_order);
611 setOrderToEnts[block_data[it->getMeshsetId()].oRder].merge(
612 set_order_ents);
613 }
614 CHKERR comm_interface_ptr->synchroniseEntities(set_order_ents, 0);
615 std::vector<std::string> additional_parameters;
616 additional_parameters =
617 collect_unrecognized(parsed.options, po::include_positional);
618 for (std::vector<std::string>::iterator vit =
619 additional_parameters.begin();
620 vit != additional_parameters.end(); vit++) {
621 CHKERR PetscPrintf(PETSC_COMM_WORLD,
622 "** WARNING Unrecognized option %s\n",
623 vit->c_str());
624 }
625 } catch (const std::exception &ex) {
626 std::ostringstream ss;
627 ss << ex.what() << std::endl;
628 SETERRQ(PETSC_COMM_SELF, MOFEM_STD_EXCEPTION_THROW, ss.str().c_str());
629 }
630 if (read_eps_u > 0) {
631 eps_u = read_eps_u;
632 };
633 if (read_eps_rho > 0) {
634 eps_rho = read_eps_rho;
635 }
636 if (read_eps_l > 0) {
637 eps_l = read_eps_l;
638 }
639 }
640
641 PetscPrintf(PETSC_COMM_WORLD, "epsU = %6.4e epsRho = %6.4e\n", eps_u,
642 eps_rho);
643
644 // Fields
645 CHKERR m_field.add_field("U", H1, AINSWORTH_LEGENDRE_BASE, 3, MB_TAG_SPARSE,
646 MF_ZERO);
647 CHKERR m_field.add_field("UPSILON", H1, AINSWORTH_LEGENDRE_BASE, 3,
648 MB_TAG_SPARSE, MF_ZERO);
649 if (is_curl) {
650 CHKERR m_field.add_field("RHO", HCURL, AINSWORTH_LEGENDRE_BASE, 1);
651 } else {
652 CHKERR m_field.add_field("RHO", H1, AINSWORTH_LEGENDRE_BASE, 1);
653 }
654
655 // Add entities (by tetrahedra) to the field
656 CHKERR m_field.add_ents_to_field_by_type(0, MBTET, "U");
657 CHKERR m_field.add_ents_to_field_by_type(0, MBTET, "UPSILON");
658 CHKERR m_field.add_ents_to_field_by_type(0, MBPRISM, "U");
659 CHKERR m_field.add_ents_to_field_by_type(0, MBPRISM, "UPSILON");
660
661 CHKERR comm_interface_ptr->synchroniseFieldEntities("U");
662 CHKERR comm_interface_ptr->synchroniseFieldEntities("UPSILON");
663 CHKERR comm_interface_ptr->synchroniseFieldEntities("RHO");
664
665 Range vertex_to_fix;
666 Range edges_to_fix;
667 Range ents_1st_layer;
668 // In a partitioned problem, the meshset might not exist on this rank
669 if (mmanager_ptr->checkMeshset(202, SIDESET)) {
670 CHKERR mmanager_ptr->getEntitiesByDimension(202, SIDESET, 2,
671 ents_1st_layer, true);
672 CHKERR mmanager_ptr->getEntitiesByDimension(202, SIDESET, 0,
673 vertex_to_fix, false);
674 CHKERR mmanager_ptr->getEntitiesByDimension(202, SIDESET, 1, edges_to_fix,
675 false);
676 if (vertex_to_fix.size() != 1 && !vertex_to_fix.empty()) {
677 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
678 "Should be one vertex only, but is %zu", vertex_to_fix.size());
679 }
680 }
681 CHKERR comm_interface_ptr->synchroniseEntities(ents_1st_layer, 0);
683 ents_1st_layer.subset_by_type(MBTRI), MBTRI, "RHO");
684 Range ents_2nd_layer;
685 // In a partitioned problem, the meshset might not exist on this rank
686 if (mmanager_ptr->checkMeshset(101, SIDESET)) {
687 CHKERR mmanager_ptr->getEntitiesByDimension(101, SIDESET, 2,
688 ents_2nd_layer, true);
689 }
690 CHKERR comm_interface_ptr->synchroniseEntities(ents_2nd_layer, 0);
691
692 for (int oo = 2; oo != setOrderToEnts.size(); oo++) {
693 if (setOrderToEnts[oo].size() > 0) {
694 CHKERR comm_interface_ptr->synchroniseEntities(setOrderToEnts[oo], 0);
695 CHKERR m_field.set_field_order(setOrderToEnts[oo], "U", oo);
696 CHKERR m_field.set_field_order(setOrderToEnts[oo], "UPSILON", oo);
697 }
698 }
699
700 const int through_thickness_order = 2;
701 {
702 Range ents3d;
703 CHKERR moab.get_entities_by_dimension(0, 3, ents3d);
704 Range ents;
705 CHKERR moab.get_adjacencies(ents3d, 2, false, ents,
706 moab::Interface::UNION);
707 CHKERR moab.get_adjacencies(ents3d, 1, false, ents,
708 moab::Interface::UNION);
709
710 Range prisms;
711 CHKERR moab.get_entities_by_type(0, MBPRISM, prisms);
712 {
713 Range quads;
714 CHKERR moab.get_adjacencies(prisms, 2, false, quads,
715 moab::Interface::UNION);
716 Range prism_tris;
717 prism_tris = quads.subset_by_type(MBTRI);
718 quads = subtract(quads, prism_tris);
719 Range quads_edges;
720 CHKERR moab.get_adjacencies(quads, 1, false, quads_edges,
721 moab::Interface::UNION);
722 Range prism_tris_edges;
723 CHKERR moab.get_adjacencies(prism_tris, 1, false, prism_tris_edges,
724 moab::Interface::UNION);
725 quads_edges = subtract(quads_edges, prism_tris_edges);
726 prisms.merge(quads);
727 prisms.merge(quads_edges);
728 }
729
730 ents.merge(ents3d);
731 ents = subtract(ents, set_order_ents);
732 ents = subtract(ents, prisms);
733
734 CHKERR comm_interface_ptr->synchroniseEntities(ents, 0);
735 CHKERR comm_interface_ptr->synchroniseEntities(prisms, 0);
736
737 CHKERR m_field.set_field_order(ents, "U", order);
738 CHKERR m_field.set_field_order(ents, "UPSILON", order);
739 // approx. order through thickness to 2
740 CHKERR m_field.set_field_order(prisms, "U", through_thickness_order);
741 CHKERR m_field.set_field_order(prisms, "UPSILON",
742 through_thickness_order);
743 }
744 CHKERR m_field.set_field_order(0, MBVERTEX, "U", 1);
745 CHKERR m_field.set_field_order(0, MBVERTEX, "UPSILON", 1);
746
747 if (is_curl) {
748 CHKERR m_field.set_field_order(0, MBTRI, "RHO", order_force);
749 CHKERR m_field.set_field_order(0, MBEDGE, "RHO", order_force);
750 } else {
751 CHKERR m_field.set_field_order(0, MBTRI, "RHO", order_force);
752 CHKERR m_field.set_field_order(0, MBEDGE, "RHO", order_force);
753 CHKERR m_field.set_field_order(0, MBVERTEX, "RHO", 1);
754 }
755
756 // The vec-0 Hooke operators read material data directly from
757 // MAT_ELASTIC* meshsets.
758 ElasticBlockMap elastic_blocks;
759 int default_block_id = -1;
760 Tag block_id_tag;
761 CHKERR moab.tag_get_handle("BLOCK_ID", 1, MB_TYPE_INTEGER, block_id_tag,
762 MB_TAG_CREAT | MB_TAG_SPARSE, &default_block_id);
764 m_field, BLOCKSET | MAT_ELASTICSET, it)) {
765 Mat_Elastic material;
766 CHKERR it->getAttributeDataStructure(material);
767 const int block_id = it->getMeshsetId();
768 CHKERR moab.get_entities_by_handle(it->getMeshset(),
769 elastic_blocks[block_id], true);
770 const auto block_elements =
771 elastic_blocks[block_id].subset_by_type(MBTET);
772 CHKERR moab.tag_clear_data(block_id_tag, block_elements, &block_id);
773
774 const auto options_it = block_data.find(block_id);
775 if (options_it != block_data.end() && options_it->second.yOung > 0) {
776 material.data.Young = options_it->second.yOung;
777 CHKERR PetscPrintf(PETSC_COMM_WORLD,
778 "Block %d set Young modulus %3.4g\n", block_id,
779 material.data.Young);
780 }
781 if (options_it != block_data.end() && options_it->second.pOisson >= -1) {
782 material.data.Poisson = options_it->second.pOisson;
783 CHKERR PetscPrintf(PETSC_COMM_WORLD,
784 "Block %d set Poisson ratio %3.4g\n", block_id,
785 material.data.Poisson);
786 }
787 CHKERR mmanager_ptr->setAttributesByDataStructure(BLOCKSET, block_id,
788 material);
789 }
790
791 CHKERR m_field.add_finite_element("ELASTIC", MF_ZERO);
792 CHKERR m_field.modify_finite_element_add_field_row("ELASTIC", "U");
793 CHKERR m_field.modify_finite_element_add_field_col("ELASTIC", "U");
794 CHKERR m_field.modify_finite_element_add_field_data("ELASTIC", "U");
795 for (const auto &[id, entities] : elastic_blocks)
796 CHKERR m_field.add_ents_to_finite_element_by_type(entities, MBTET,
797 "ELASTIC");
798
799 ElasticVolume elastic_rhs(m_field);
800 ElasticVolume elastic_lhs(m_field);
801 ElasticVolume elastic_energy_fe(m_field);
802 double elastic_energy = 0;
803 auto elastic_rhs_common =
804 HookeOps::commonDataFactory<SPACE_DIM, GAUSS, DomainEleOp>(
805 m_field, elastic_rhs.getOpPtrVector(), "U", "MAT_ELASTIC",
806 Sev::verbose);
807 CHKERR HookeOps::opFactoryDomainRhs<SPACE_DIM, PETSC, GAUSS, DomainEleOp>(
808 m_field, elastic_rhs.getOpPtrVector(), "U", elastic_rhs_common,
809 Sev::verbose, true);
810 auto elastic_lhs_common =
811 HookeOps::commonDataFactory<SPACE_DIM, GAUSS, DomainEleOp>(
812 m_field, elastic_lhs.getOpPtrVector(), "U", "MAT_ELASTIC",
813 Sev::verbose);
814 CHKERR HookeOps::opFactoryDomainLhs<SPACE_DIM, PETSC, GAUSS, DomainEleOp>(
815 m_field, elastic_lhs.getOpPtrVector(), "U", elastic_lhs_common,
816 Sev::verbose);
817 auto elastic_energy_common =
818 HookeOps::commonDataFactory<SPACE_DIM, GAUSS, DomainEleOp>(
819 m_field, elastic_energy_fe.getOpPtrVector(), "U", "MAT_ELASTIC",
820 Sev::verbose);
821 elastic_energy_fe.getOpPtrVector().push_back(new OpElasticEnergy(
822 elastic_energy_common->getMatStrain(),
823 elastic_energy_common->getMatCauchyStress(), elastic_energy));
824
825 // Add prisms
826 CellEngineering::FatPrism fat_prism_rhs(m_field);
827 CellEngineering::FatPrism fat_prism_lhs(m_field);
828 {
829 CHKERR m_field.add_finite_element("ELASTIC_PRISM", MF_ZERO);
830 CHKERR m_field.modify_finite_element_add_field_row("ELASTIC_PRISM", "U");
831 CHKERR m_field.modify_finite_element_add_field_col("ELASTIC_PRISM", "U");
832 CHKERR m_field.modify_finite_element_add_field_data("ELASTIC_PRISM", "U");
833 auto block_it = elastic_blocks.find(2);
834 if (block_it == elastic_blocks.end()) {
835 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
836 "Elastic material block 2 is required for prism elements");
837 }
838 CHKERR mmanager_ptr->getEntitiesByDimension(2, BLOCKSET, 3,
839 block_it->second);
841 block_it->second, MBPRISM, "ELASTIC_PRISM");
842 // right hand side operators
843 auto inv_jac_ptr = boost::make_shared<MatrixDouble>();
844 fat_prism_rhs.getOpPtrVector().push_back(
845 new MoFEM::OpCalculateInvJacForFatPrism(inv_jac_ptr));
846 fat_prism_rhs.getOpPtrVector().push_back(
847 new MoFEM::OpSetInvJacH1ForFatPrism(inv_jac_ptr));
849 auto prism_rhs_common =
850 HookeOps::commonDataFactory<SPACE_DIM, GAUSS, FatPrismOp>(
851 m_field, fat_prism_rhs.getOpPtrVector(), "U", "MAT_ELASTIC",
852 Sev::verbose);
853 CHKERR HookeOps::opFactoryDomainRhs<SPACE_DIM, PETSC, GAUSS, FatPrismOp>(
854 m_field, fat_prism_rhs.getOpPtrVector(), "U", prism_rhs_common,
855 Sev::verbose, true);
856 // Left hand side operators
857 fat_prism_lhs.getOpPtrVector().push_back(
858 new MoFEM::OpCalculateInvJacForFatPrism(inv_jac_ptr));
859 fat_prism_lhs.getOpPtrVector().push_back(
860 new MoFEM::OpSetInvJacH1ForFatPrism(inv_jac_ptr));
861 auto prism_lhs_common =
862 HookeOps::commonDataFactory<SPACE_DIM, GAUSS, FatPrismOp>(
863 m_field, fat_prism_lhs.getOpPtrVector(), "U", "MAT_ELASTIC",
864 Sev::verbose);
865 CHKERR HookeOps::opFactoryDomainLhs<SPACE_DIM, PETSC, GAUSS, FatPrismOp>(
866 m_field, fat_prism_lhs.getOpPtrVector(), "U", prism_lhs_common,
867 Sev::verbose);
868 }
869
870 // build field
871 CHKERR m_field.build_fields();
872
873 // Control elements
874 CHKERR m_field.add_finite_element("KUPSUPS");
875 CHKERR m_field.modify_finite_element_add_field_row("KUPSUPS", "UPSILON");
876 CHKERR m_field.modify_finite_element_add_field_col("KUPSUPS", "UPSILON");
877 CHKERR m_field.modify_finite_element_add_field_data("KUPSUPS", "UPSILON");
878 CHKERR m_field.add_ents_to_finite_element_by_type(0, MBTET, "KUPSUPS");
879 CHKERR m_field.add_ents_to_finite_element_by_type(0, MBPRISM, "KUPSUPS");
880
881 CHKERR m_field.add_finite_element("DISPLACEMENTS_PENALTY");
882 CHKERR m_field.modify_finite_element_add_field_row("DISPLACEMENTS_PENALTY",
883 "UPSILON");
884 CHKERR m_field.modify_finite_element_add_field_col("DISPLACEMENTS_PENALTY",
885 "U");
886 CHKERR m_field.modify_finite_element_add_field_data("DISPLACEMENTS_PENALTY",
887 "UPSILON");
888 CHKERR m_field.modify_finite_element_add_field_data("DISPLACEMENTS_PENALTY",
889 "U");
890 CHKERR m_field.modify_finite_element_add_field_data("DISPLACEMENTS_PENALTY",
891 "DISP_X");
892 CHKERR m_field.modify_finite_element_add_field_data("DISPLACEMENTS_PENALTY",
893 "DISP_Y");
894 CHKERR m_field.add_ents_to_finite_element_by_type(ents_2nd_layer, MBTRI,
895 "DISPLACEMENTS_PENALTY");
896
897 // Add element to calculate residual on 1st layer
898 CHKERR m_field.add_finite_element("BT");
900 CHKERR m_field.modify_finite_element_add_field_row("BT", "UPSILON");
901 CHKERR m_field.modify_finite_element_add_field_col("BT", "RHO");
903 CHKERR m_field.modify_finite_element_add_field_data("BT", "UPSILON");
904 CHKERR m_field.modify_finite_element_add_field_data("BT", "RHO");
905 CHKERR m_field.add_ents_to_finite_element_by_type(ents_1st_layer, MBTRI,
906 "BT");
907
908 CHKERR m_field.add_finite_element("B");
911 CHKERR m_field.modify_finite_element_add_field_col("B", "UPSILON");
913 CHKERR m_field.modify_finite_element_add_field_data("B", "UPSILON");
915 CHKERR m_field.add_ents_to_finite_element_by_type(ents_1st_layer, MBTRI,
916 "B");
917
918 // Add element to calculate residual on 1st layer
919 CHKERR m_field.add_finite_element("D");
923 CHKERR m_field.add_ents_to_finite_element_by_type(ents_1st_layer, MBTRI,
924 "D");
925
926 // Build finite elements
928 // build adjacencies
929 CHKERR m_field.build_adjacencies(bit_level0);
930
931 // Register MOFEM DM
932 DMType dm_name = "MOFEM";
933 CHKERR DMRegister_MoFEM(dm_name);
934
935 DM dm_control;
936 {
937 // Create the dm_control instance
938 CHKERR DMCreate(PETSC_COMM_WORLD, &dm_control);
939 CHKERR DMSetType(dm_control, dm_name);
940 // Set the dm_control data structure that created the MoFEM data structures
941 CHKERR DMMoFEMCreateMoFEM(dm_control, &m_field, "CONTROL_PROB",
942 bit_level0);
943 CHKERR DMSetFromOptions(dm_control);
944 CHKERR DMMoFEMSetSquareProblem(dm_control, PETSC_TRUE);
945 CHKERR DMMoFEMSetIsPartitioned(dm_control, PETSC_TRUE);
946 // add elements to dm_control
947 CHKERR DMMoFEMAddElement(dm_control, "ELASTIC");
948 CHKERR DMMoFEMAddElement(dm_control, "ELASTIC_PRISM");
949 CHKERR DMMoFEMAddElement(dm_control, "KUPSUPS");
950 CHKERR DMMoFEMAddElement(dm_control, "DISPLACEMENTS_PENALTY");
951 CHKERR DMMoFEMAddElement(dm_control, "B");
952 CHKERR DMMoFEMAddElement(dm_control, "BT");
953 CHKERR DMMoFEMAddElement(dm_control, "D");
954 CHKERR DMSetUp(dm_control);
955 }
956
957 CellEngineering::CommonData common_data;
958
959 ublas::matrix<Mat> nested_matrices(2, 2);
960 ublas::vector<IS> nested_is_rows(2);
961 ublas::vector<IS> nested_is_cols(2);
962 for (int i = 0; i != 2; i++) {
963 nested_is_rows[i] = PETSC_NULLPTR;
964 nested_is_cols[i] = PETSC_NULLPTR;
965 for (int j = 0; j != 2; j++) {
966 nested_matrices(i, j) = PETSC_NULLPTR;
967 }
968 }
969
970 ublas::matrix<Mat> sub_nested_matrices(2, 2);
971 ublas::vector<IS> sub_nested_is_rows(2);
972 ublas::vector<IS> sub_nested_is_cols(2);
973 for (int i = 0; i != 2; i++) {
974 sub_nested_is_rows[i] = PETSC_NULLPTR;
975 sub_nested_is_cols[i] = PETSC_NULLPTR;
976 for (int j = 0; j != 2; j++) {
977 sub_nested_matrices(i, j) = PETSC_NULLPTR;
978 }
979 }
980
981 DM dm_sub_volume_control;
982 {
983 CHKERR DMCreate(PETSC_COMM_WORLD, &dm_sub_volume_control);
984 CHKERR DMSetType(dm_sub_volume_control, dm_name);
985 // set dm_sub_volume_control data structure which created mofem data
986 // structures
987 CHKERR DMMoFEMCreateSubDM(dm_sub_volume_control, dm_control,
988 "SUB_CONTROL_PROB");
989 CHKERR DMMoFEMSetSquareProblem(dm_sub_volume_control, PETSC_TRUE);
990 CHKERR DMMoFEMAddSubFieldRow(dm_sub_volume_control, "U");
991 CHKERR DMMoFEMAddSubFieldRow(dm_sub_volume_control, "UPSILON");
992 CHKERR DMMoFEMAddSubFieldCol(dm_sub_volume_control, "U");
993 CHKERR DMMoFEMAddSubFieldCol(dm_sub_volume_control, "UPSILON");
994 // add elements to dm_sub_volume_control
995 CHKERR DMSetUp(dm_sub_volume_control);
996
997 const Problem *prb_ptr;
998 CHKERR m_field.get_problem("SUB_CONTROL_PROB", &prb_ptr);
999 boost::shared_ptr<Problem::SubProblemData> sub_data =
1000 prb_ptr->getSubData();
1001
1002 CHKERR sub_data->getRowIs(&nested_is_rows[0]);
1003 CHKERR sub_data->getColIs(&nested_is_cols[0]);
1004 // That will be filled at the end
1005 nested_matrices(0, 0) = PETSC_NULLPTR;
1006 }
1007
1008 {
1009 DM dm_sub_sub_elastic;
1010
1011 CHKERR DMCreate(PETSC_COMM_WORLD, &dm_sub_sub_elastic);
1012 CHKERR DMSetType(dm_sub_sub_elastic, dm_name);
1013 // set dm_sub_sub_elastic data structure which created mofem data
1014 // structures
1015 CHKERR DMMoFEMCreateSubDM(dm_sub_sub_elastic, dm_sub_volume_control,
1016 "ELASTIC_PROB");
1017 CHKERR DMMoFEMSetSquareProblem(dm_sub_sub_elastic, PETSC_TRUE);
1018 CHKERR DMMoFEMAddElement(dm_sub_sub_elastic, "ELASTIC");
1019 CHKERR DMMoFEMAddElement(dm_sub_sub_elastic, "ELASTIC_PRISM");
1020 CHKERR DMMoFEMAddSubFieldRow(dm_sub_sub_elastic, "U");
1021 CHKERR DMMoFEMAddSubFieldCol(dm_sub_sub_elastic, "U");
1022 // add elements to dm_sub_sub_elastic
1023 CHKERR DMSetUp(dm_sub_sub_elastic);
1024 CHKERR m_field.getInterface<BcManager>()
1025 ->pushMarkDOFsOnEntities<DisplacementCubitBcData>("ELASTIC_PROB",
1026 "U");
1027
1028 Mat Kuu;
1029 Vec Du, Fu;
1030 CHKERR DMCreateMatrix(dm_sub_sub_elastic, &Kuu);
1031 CHKERR DMCreateGlobalVector(dm_sub_sub_elastic, &Du);
1032 CHKERR DMCreateGlobalVector(dm_sub_sub_elastic, &Fu);
1033 CHKERR MatZeroEntries(Kuu);
1034 CHKERR VecZeroEntries(Du);
1035 CHKERR VecZeroEntries(Fu);
1036 CHKERR DMoFEMMeshToLocalVector(dm_sub_sub_elastic, Du, INSERT_VALUES,
1037 SCATTER_REVERSE);
1038
1039 // Apply displacement constraints with the current core BC machinery.
1040 auto dirichlet_bc_ptr = boost::make_shared<FEMethod>();
1041 dirichlet_bc_ptr->vecAssembleSwitch =
1042 boost::movelib::make_unique<bool>(false);
1043 dirichlet_bc_ptr->matAssembleSwitch =
1044 boost::movelib::make_unique<bool>(false);
1045 dirichlet_bc_ptr->preProcessHook =
1047 m_field, dirichlet_bc_ptr,
1048 std::vector<boost::shared_ptr<ScalingMethod>>{}, false);
1049 dirichlet_bc_ptr->postProcessHook = [&]() {
1051 CHKERR VecGhostUpdateBegin(Fu, ADD_VALUES, SCATTER_REVERSE);
1052 CHKERR VecGhostUpdateEnd(Fu, ADD_VALUES, SCATTER_REVERSE);
1053 CHKERR VecAssemblyBegin(Fu);
1054 CHKERR VecAssemblyEnd(Fu);
1055 CHKERR MatAssemblyBegin(Kuu, MAT_FINAL_ASSEMBLY);
1056 CHKERR MatAssemblyEnd(Kuu, MAT_FINAL_ASSEMBLY);
1058 m_field, dirichlet_bc_ptr, 0., SmartPetscObj<Vec>(Fu, true))();
1060 m_field, dirichlet_bc_ptr, 1., SmartPetscObj<Mat>(Kuu, true))();
1062 };
1063 dirichlet_bc_ptr->snes_ctx = FEMethod::CTX_SNESNONE;
1064 dirichlet_bc_ptr->ts_ctx = FEMethod::CTX_TSNONE;
1065 // preproc
1066 CHKERR DMoFEMPreProcessFiniteElements(dm_sub_sub_elastic,
1067 dirichlet_bc_ptr.get());
1068 CHKERR DMoFEMMeshToLocalVector(dm_sub_sub_elastic, Du, INSERT_VALUES,
1069 SCATTER_REVERSE);
1070 // internal force vector (to take into account Dirichlet boundary
1071 // conditions)
1072 elastic_rhs.snes_f = Fu;
1073 fat_prism_rhs.snes_f = Fu;
1074 CHKERR DMoFEMLoopFiniteElements(dm_sub_sub_elastic, "ELASTIC",
1075 &elastic_rhs);
1076 CHKERR DMoFEMLoopFiniteElements(dm_sub_sub_elastic, "ELASTIC_PRISM",
1077 &fat_prism_rhs);
1078 // elastic element matrix
1079 elastic_lhs.snes_B = Kuu;
1080 fat_prism_lhs.snes_B = Kuu;
1081 CHKERR DMoFEMLoopFiniteElements(dm_sub_sub_elastic, "ELASTIC",
1082 &elastic_lhs);
1083 CHKERR DMoFEMLoopFiniteElements(dm_sub_sub_elastic, "ELASTIC_PRISM",
1084 &fat_prism_lhs);
1085 // postproc
1086 CHKERR DMoFEMPostProcessFiniteElements(dm_sub_sub_elastic,
1087 dirichlet_bc_ptr.get());
1088 CHKERR VecGhostUpdateBegin(Fu, ADD_VALUES, SCATTER_REVERSE);
1089 CHKERR VecGhostUpdateEnd(Fu, ADD_VALUES, SCATTER_REVERSE);
1090 CHKERR VecAssemblyBegin(Fu);
1091 CHKERR VecAssemblyEnd(Fu);
1092 CHKERR VecScale(Fu, -1);
1093 CHKERR VecDestroy(&Du);
1094 CHKERR VecDestroy(&Fu);
1095
1096 const Problem *prb_ptr;
1097 CHKERR m_field.get_problem("ELASTIC_PROB", &prb_ptr);
1098 boost::shared_ptr<Problem::SubProblemData> sub_data =
1099 prb_ptr->getSubData();
1100
1101 CHKERR sub_data->getRowIs(&sub_nested_is_rows[0]);
1102 CHKERR sub_data->getColIs(&sub_nested_is_cols[0]);
1103 sub_nested_matrices(0, 0) = Kuu;
1104 IS isUpsilon;
1105 CHKERR m_field.getInterface<ISManager>()
1106 ->isCreateFromProblemFieldToOtherProblemField(
1107 "ELASTIC_PROB", "U", ROW, "SUB_CONTROL_PROB", "UPSILON", ROW,
1108 PETSC_NULLPTR, &isUpsilon);
1109 sub_nested_is_rows[1] = isUpsilon;
1110 sub_nested_is_cols[1] = isUpsilon;
1111 sub_nested_matrices(1, 1) = Kuu;
1112 PetscObjectReference((PetscObject)Kuu);
1113 PetscObjectReference((PetscObject)isUpsilon);
1114
1115 // Matrix View
1116 if (debug) {
1117 cerr << "Kuu" << endl;
1118 MatView(Kuu, PETSC_VIEWER_DRAW_WORLD);
1119 std::string wait;
1120 std::cin >> wait;
1121 }
1122
1123 CHKERR DMDestroy(&dm_sub_sub_elastic);
1124 }
1125
1126 {
1127 DM dm_sub_disp_penalty;
1128
1129 // Create the dm_control instance
1130 CHKERR DMCreate(PETSC_COMM_WORLD, &dm_sub_disp_penalty);
1131 CHKERR DMSetType(dm_sub_disp_penalty, dm_name);
1132 // set dm_sub_disp_penalty data structure which created mofem
1133 // data structures
1134 CHKERR DMMoFEMCreateSubDM(dm_sub_disp_penalty, dm_sub_volume_control,
1135 "S_PROB");
1136 CHKERR DMMoFEMSetSquareProblem(dm_sub_disp_penalty, PETSC_FALSE);
1137 CHKERR DMMoFEMAddSubFieldRow(dm_sub_disp_penalty, "UPSILON");
1138 CHKERR DMMoFEMAddSubFieldCol(dm_sub_disp_penalty, "U");
1139 // add elements to dm_sub_disp_penalty
1140 CHKERR DMMoFEMAddElement(dm_sub_disp_penalty, "DISPLACEMENTS_PENALTY");
1141 CHKERR DMSetUp(dm_sub_disp_penalty);
1142
1143 Mat S;
1144 CHKERR DMCreateMatrix(dm_sub_disp_penalty, &S);
1145 CHKERR MatZeroEntries(S);
1146
1147 CellEngineering::FaceElement face_element(m_field);
1148 CHKERR AddHOOps<2, 2, 2>::add(face_element.getOpPtrVector(), {H1});
1149 face_element.getOpPtrVector().push_back(new OpCellS(S, eps_u));
1150 CHKERR DMoFEMLoopFiniteElements(dm_sub_disp_penalty,
1151 "DISPLACEMENTS_PENALTY", &face_element);
1152 CHKERR MatAssemblyBegin(S, MAT_FLUSH_ASSEMBLY);
1153 CHKERR MatAssemblyEnd(S, MAT_FLUSH_ASSEMBLY);
1154
1155 // // Matrix View
1156 if (debug) {
1157 cerr << "S" << endl;
1158 MatView(S, PETSC_VIEWER_DRAW_WORLD);
1159 std::string wait;
1160 std::cin >> wait;
1161 }
1162
1163 const Problem *problem_ptr;
1164 CHKERR m_field.get_problem("S_PROB", &problem_ptr);
1165 boost::shared_ptr<Problem::SubProblemData> sub_data =
1166 problem_ptr->getSubData();
1167 // CHKERR sub_data->getRowIs(&sub_nested_is_rows[1]);
1168 // CHKERR sub_data->getColIs(&sub_nested_is_cols[0]);
1169 sub_nested_matrices(1, 0) = S;
1170
1171 CHKERR DMDestroy(&dm_sub_disp_penalty);
1172 }
1173
1174 // Calculate penalty matrix
1175 {
1176 DM dm_sub_force_penalty;
1177
1178 // Create the dm_control instance
1179 CHKERR DMCreate(PETSC_COMM_WORLD, &dm_sub_force_penalty);
1180 CHKERR DMSetType(dm_sub_force_penalty, dm_name);
1181 // set dm_sub_force_penalty data structure which created mofem
1182 // data structures
1183 CHKERR DMMoFEMCreateSubDM(dm_sub_force_penalty, dm_control, "D_PROB");
1184 CHKERR DMMoFEMSetSquareProblem(dm_sub_force_penalty, PETSC_TRUE);
1185 CHKERR DMMoFEMAddSubFieldRow(dm_sub_force_penalty, "RHO");
1186 CHKERR DMMoFEMAddSubFieldCol(dm_sub_force_penalty, "RHO");
1187 // add elements to dm_sub_force_penalty
1188 CHKERR DMMoFEMAddElement(dm_sub_force_penalty, "D");
1189 CHKERR DMSetUp(dm_sub_force_penalty);
1190
1191 Mat D;
1192 CHKERR DMCreateMatrix(dm_sub_force_penalty, &D);
1193 CHKERR MatZeroEntries(D);
1194
1195 {
1196 CellEngineering::FaceElement face_d_matrix(m_field);
1197
1198 if (is_curl) {
1200 {HCURL});
1201 face_d_matrix.getOpPtrVector().push_back(
1202 new OpCellCurlD(D, eps_rho / eps_u, eps_l * eps_u));
1203 } else {
1204 CHKERR AddHOOps<2, 2, 2>::add(face_d_matrix.getOpPtrVector(), {H1});
1205 face_d_matrix.getOpPtrVector().push_back(
1206 new OpCellPotentialD(D, eps_rho / eps_u));
1207 }
1208 CHKERR DMoFEMLoopFiniteElements(dm_sub_force_penalty, "D",
1209 &face_d_matrix);
1210 }
1211 CHKERR MatAssemblyBegin(D, MAT_FINAL_ASSEMBLY);
1212 CHKERR MatAssemblyEnd(D, MAT_FINAL_ASSEMBLY);
1213
1214 const Problem *problem_ptr;
1215 CHKERR m_field.get_problem("D_PROB", &problem_ptr);
1216
1217 // Zero rows, force field is given by gradients of potential field, so one
1218 // of the values has to be fixed like for rigid body motion.
1219 if (is_curl == PETSC_FALSE) {
1220 int nb_dofs_to_fix = 0;
1221 int index_to_fix = 0;
1222 if (!vertex_to_fix.empty()) {
1223 boost::shared_ptr<NumeredDofEntity> dof_ptr;
1225 m_field.get_field_bit_number("RHO"), vertex_to_fix[0], 0, ROW,
1226 dof_ptr);
1227 if (dof_ptr) {
1228 if (dof_ptr->getPart() == m_field.get_comm_rank()) {
1229 nb_dofs_to_fix = 1;
1230 index_to_fix = dof_ptr->getPetscGlobalDofIdx();
1231 cerr << *dof_ptr << endl;
1232 }
1233 }
1234 }
1235 CHKERR MatZeroRowsColumns(D, nb_dofs_to_fix, &index_to_fix,
1236 eps_rho / eps_u, PETSC_NULLPTR,
1237 PETSC_NULLPTR);
1238 } else {
1239 std::vector<int> dofs_to_fix;
1240 for (auto p_eit = edges_to_fix.pair_begin();
1241 p_eit != edges_to_fix.pair_end(); ++p_eit) {
1242 auto bit_number = m_field.get_field_bit_number("RHO");
1243 auto row_dofs = problem_ptr->numeredRowDofsPtr;
1244 auto lo = row_dofs->lower_bound(
1245 FieldEntity::getLoLocalEntityBitNumber(bit_number, p_eit->first));
1246 auto hi =
1247 row_dofs->upper_bound(FieldEntity::getHiLocalEntityBitNumber(
1248 bit_number, p_eit->second));
1249 for (; lo != hi; ++lo)
1250 if ((*lo)->getPart() == m_field.get_comm_rank())
1251 dofs_to_fix.push_back((*lo)->getPetscGlobalDofIdx());
1252 }
1253 CHKERR MatZeroRowsColumns(D, dofs_to_fix.size(), &*dofs_to_fix.begin(),
1254 eps_rho / eps_u, PETSC_NULLPTR,
1255 PETSC_NULLPTR);
1256 }
1257
1258 // Matrix View
1259 if (debug) {
1260 cerr << "D" << endl;
1261 MatView(D, PETSC_VIEWER_DRAW_WORLD);
1262 std::string wait;
1263 std::cin >> wait;
1264 }
1265
1266 boost::shared_ptr<Problem::SubProblemData> sub_data =
1267 problem_ptr->getSubData();
1268 CHKERR sub_data->getRowIs(&nested_is_rows[1]);
1269 CHKERR sub_data->getColIs(&nested_is_cols[1]);
1270 nested_matrices(1, 1) = D;
1271
1272 CHKERR DMDestroy(&dm_sub_force_penalty);
1273 }
1274
1275 {
1276 DM dm_sub_force;
1277
1278 // Create the dm_control instance
1279 CHKERR DMCreate(PETSC_COMM_WORLD, &dm_sub_force);
1280 CHKERR DMSetType(dm_sub_force, dm_name);
1281 // set dm_sub_force data structure which created mofem data structures
1282 CHKERR DMMoFEMCreateSubDM(dm_sub_force, dm_control, "FORCES_PROB");
1283 CHKERR DMMoFEMSetSquareProblem(dm_sub_force, PETSC_FALSE);
1284 CHKERR DMMoFEMAddSubFieldRow(dm_sub_force, "RHO");
1285 CHKERR DMMoFEMAddSubFieldCol(dm_sub_force, "U");
1286 CHKERR DMMoFEMAddSubFieldCol(dm_sub_force, "UPSILON");
1287 // add elements to dm_sub_force
1288 CHKERR DMMoFEMAddElement(dm_sub_force, "B");
1289 CHKERR DMSetUp(dm_sub_force);
1290
1291 Mat UB, UPSILONB;
1292 CHKERR DMCreateMatrix(dm_sub_force, &UB);
1293 CHKERR MatZeroEntries(UB);
1294 // This matrix will be transposed later
1295 CHKERR DMCreateMatrix(dm_sub_force, &UPSILONB);
1296 CHKERR MatZeroEntries(UPSILONB);
1297 {
1298 CellEngineering::FaceElement face_b_matrices(m_field);
1299 if (is_curl) {
1301 {H1, HCURL});
1302 face_b_matrices.getOpPtrVector().push_back(new OpCellCurlB(UB, "U"));
1303 face_b_matrices.getOpPtrVector().push_back(
1304 new OpCellCurlB(UPSILONB, "UPSILON"));
1305 } else {
1307 {H1});
1308 face_b_matrices.getOpPtrVector().push_back(
1309 new OpCellPotentialB(UB, "U"));
1310 face_b_matrices.getOpPtrVector().push_back(
1311 new OpCellPotentialB(UPSILONB, "UPSILON"));
1312 }
1313 CHKERR DMoFEMLoopFiniteElements(dm_sub_force, "B", &face_b_matrices);
1314 }
1315 CHKERR MatAssemblyBegin(UB, MAT_FINAL_ASSEMBLY);
1316 CHKERR MatAssemblyBegin(UPSILONB, MAT_FINAL_ASSEMBLY);
1317 CHKERR MatAssemblyEnd(UB, MAT_FINAL_ASSEMBLY);
1318 CHKERR MatAssemblyEnd(UPSILONB, MAT_FINAL_ASSEMBLY);
1319
1320 const Problem *problem_ptr;
1321 CHKERR m_field.get_problem("FORCES_PROB", &problem_ptr);
1322
1323 // Zero rows, force field is given by gradients of potential field, so one
1324 // of the values has to be fixed like for rigid body motion.
1325 if (is_curl == PETSC_FALSE) {
1326 int nb_dofs_to_fix = 0;
1327 int index_to_fix = 0;
1328 if (!vertex_to_fix.empty()) {
1329 boost::shared_ptr<NumeredDofEntity> dof_ptr;
1331 m_field.get_field_bit_number("RHO"), vertex_to_fix[0], 0, ROW,
1332 dof_ptr);
1333 if (dof_ptr) {
1334 if (dof_ptr->getPart() == m_field.get_comm_rank()) {
1335 nb_dofs_to_fix = 1;
1336 index_to_fix = dof_ptr->getPetscGlobalDofIdx();
1337 cerr << *dof_ptr << endl;
1338 }
1339 }
1340 }
1341 CHKERR MatZeroRows(UB, nb_dofs_to_fix, &index_to_fix, 0, PETSC_NULLPTR,
1342 PETSC_NULLPTR);
1343 CHKERR MatZeroRows(UPSILONB, nb_dofs_to_fix, &index_to_fix, 0,
1344 PETSC_NULLPTR, PETSC_NULLPTR);
1345 } else {
1346 std::vector<int> dofs_to_fix;
1347 for (auto p_eit = edges_to_fix.pair_begin();
1348 p_eit != edges_to_fix.pair_end(); ++p_eit) {
1349 auto bit_number = m_field.get_field_bit_number("RHO");
1350 auto row_dofs = problem_ptr->numeredRowDofsPtr;
1351 auto lo = row_dofs->lower_bound(
1352 FieldEntity::getLoLocalEntityBitNumber(bit_number, p_eit->first));
1353 auto hi =
1354 row_dofs->upper_bound(FieldEntity::getHiLocalEntityBitNumber(
1355 bit_number, p_eit->second));
1356 for (; lo != hi; ++lo)
1357 if ((*lo)->getPart() == m_field.get_comm_rank())
1358 dofs_to_fix.push_back((*lo)->getPetscGlobalDofIdx());
1359 }
1360 CHKERR MatZeroRows(UB, dofs_to_fix.size(), &*dofs_to_fix.begin(), 0,
1361 PETSC_NULLPTR, PETSC_NULLPTR);
1362 CHKERR MatZeroRows(UPSILONB, dofs_to_fix.size(), &*dofs_to_fix.begin(),
1363 0, PETSC_NULLPTR, PETSC_NULLPTR);
1364 }
1365
1366 Mat UBT;
1367 CHKERR MatTranspose(UB, MAT_INITIAL_MATRIX, &UBT);
1368 CHKERR MatDestroy(&UB);
1369
1370 // Matrix View
1371 if (debug) {
1372 cerr << "UBT" << endl;
1373 MatView(UBT, PETSC_VIEWER_DRAW_WORLD);
1374 std::string wait;
1375 std::cin >> wait;
1376 }
1377
1378 boost::shared_ptr<Problem::SubProblemData> sub_data =
1379 problem_ptr->getSubData();
1380 // CHKERR sub_data->getColIs(&nested_is_rows[0]);
1381 // CHKERR sub_data->getRowIs(&nested_is_cols[1]);
1382 nested_matrices(0, 1) = UBT;
1383
1384 if (debug) {
1385 cerr << "UPSILONB" << endl;
1386 MatView(UPSILONB, PETSC_VIEWER_DRAW_WORLD);
1387 std::string wait;
1388 std::cin >> wait;
1389 }
1390
1391 // CHKERR sub_data->getRowIs(&nested_is_rows[1]);
1392 // CHKERR sub_data->getColIs(&nested_is_cols[0]);
1393 nested_matrices(1, 0) = UPSILONB;
1394
1395 CHKERR DMDestroy(&dm_sub_force);
1396 }
1397
1398 Mat SubA;
1399 CHKERR MatCreateNest(PETSC_COMM_WORLD, 2, &sub_nested_is_rows[0], 2,
1400 &sub_nested_is_cols[0], &sub_nested_matrices(0, 0),
1401 &SubA);
1402 nested_matrices(0, 0) = SubA;
1403
1404 CHKERR MatAssemblyBegin(SubA, MAT_FINAL_ASSEMBLY);
1405 CHKERR MatAssemblyEnd(SubA, MAT_FINAL_ASSEMBLY);
1406
1407 if (debug) {
1408 cerr << "Nested SubA" << endl;
1409 MatView(SubA, PETSC_VIEWER_STDOUT_WORLD);
1410 }
1411
1412 Mat A;
1413 CHKERR MatCreateNest(PETSC_COMM_WORLD, 2, &nested_is_rows[0], 2,
1414 &nested_is_cols[0], &nested_matrices(0, 0), &A);
1415
1416 CHKERR MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);
1417 CHKERR MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);
1418
1419 if (debug) {
1420 cerr << "Nested A" << endl;
1421 MatView(A, PETSC_VIEWER_STDOUT_WORLD);
1422 }
1423
1424 Vec D, F;
1425 CHKERR DMCreateGlobalVector(dm_control, &D);
1426 CHKERR DMCreateGlobalVector(dm_control, &F);
1427
1428 // Assemble the right-hand-side vector
1429 {
1430 CellEngineering::FaceElement face_element(m_field);
1431 CHKERR AddHOOps<2, 2, 2>::add(face_element.getOpPtrVector(), {H1});
1432 face_element.getOpPtrVector().push_back(new OpGetDispX(common_data));
1433 face_element.getOpPtrVector().push_back(new OpGetDispY(common_data));
1434 face_element.getOpPtrVector().push_back(
1435 new OpCell_g(F, eps_u, common_data));
1436 CHKERR DMoFEMLoopFiniteElements(dm_control, "DISPLACEMENTS_PENALTY",
1437 &face_element);
1438 CHKERR VecGhostUpdateBegin(F, ADD_VALUES, SCATTER_REVERSE);
1439 CHKERR VecGhostUpdateEnd(F, ADD_VALUES, SCATTER_REVERSE);
1440 CHKERR VecAssemblyBegin(F);
1441 CHKERR VecAssemblyEnd(F);
1442 }
1443
1444 KSP solver;
1445 // KSP solver;
1446 {
1447 CHKERR KSPCreate(PETSC_COMM_WORLD, &solver);
1448 CHKERR KSPSetDM(solver, dm_control);
1449 CHKERR KSPSetFromOptions(solver);
1450 CHKERR KSPSetOperators(solver, A, A);
1451 CHKERR KSPSetDMActive(solver, PETSC_FALSE);
1452 CHKERR KSPSetInitialGuessKnoll(solver, PETSC_FALSE);
1453 CHKERR KSPSetInitialGuessNonzero(solver, PETSC_FALSE);
1454 PC pc;
1455 CHKERR KSPGetPC(solver, &pc);
1456 CHKERR PCSetType(pc, PCFIELDSPLIT);
1457 PetscBool is_pcfs = PETSC_FALSE;
1458 PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &is_pcfs);
1459 if (is_pcfs) {
1460 CHKERR PCSetOperators(pc, A, A);
1461 CHKERR PCFieldSplitSetIS(pc, NULL, nested_is_rows[0]);
1462 CHKERR PCFieldSplitSetIS(pc, NULL, nested_is_rows[1]);
1463 CHKERR PCFieldSplitSetType(pc, PC_COMPOSITE_SCHUR);
1464 CHKERR PCSetUp(pc);
1465 KSP *sub_ksp;
1466 PetscInt n;
1467 CHKERR PCFieldSplitGetSubKSP(pc, &n, &sub_ksp);
1468 {
1469 PC sub_pc_0;
1470 CHKERR KSPGetPC(sub_ksp[0], &sub_pc_0);
1471 CHKERR PCSetOperators(sub_pc_0, SubA, SubA);
1472 CHKERR PCSetType(sub_pc_0, PCFIELDSPLIT);
1473 CHKERR PCFieldSplitSetIS(sub_pc_0, NULL, sub_nested_is_rows[0]);
1474 CHKERR PCFieldSplitSetIS(sub_pc_0, NULL, sub_nested_is_rows[1]);
1475 CHKERR PCFieldSplitSetType(sub_pc_0, PC_COMPOSITE_MULTIPLICATIVE);
1476 // CHKERR
1477 // PCFieldSplitSetSchurFactType(sub_pc_0,PC_FIELDSPLIT_SCHUR_FACT_LOWER);
1478 // CHKERR PCFieldSplitSetType(sub_pc_0,PC_COMPOSITE_SCHUR);
1479 CHKERR PCSetUp(sub_pc_0);
1480 }
1481 } else {
1482 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
1483 "This solver requires the PCFIELDSPLIT preconditioner");
1484 }
1485 CHKERR KSPSetUp(solver);
1486 }
1487
1488 // Solve system of equations
1489 CHKERR KSPSolve(solver, F, D);
1490
1491 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
1492 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
1493 CHKERR DMoFEMMeshToLocalVector(dm_control, D, INSERT_VALUES,
1494 SCATTER_REVERSE);
1495
1496 if (debug) {
1497 CHKERR VecView(D, PETSC_VIEWER_DRAW_WORLD);
1498 std::string wait;
1499 std::cin >> wait;
1500 }
1501
1502 // Clean sub matrices and sub indices
1503 for (int i = 0; i != 2; i++) {
1504 if (sub_nested_is_rows[i]) {
1505 CHKERR ISDestroy(&sub_nested_is_rows[i]);
1506 }
1507 if (sub_nested_is_cols[i]) {
1508 CHKERR ISDestroy(&sub_nested_is_cols[i]);
1509 }
1510 for (int j = 0; j != 2; j++) {
1511 if (sub_nested_matrices(i, j)) {
1512 CHKERR MatDestroy(&sub_nested_matrices(i, j));
1513 }
1514 }
1515 }
1516 for (int i = 0; i != 2; i++) {
1517 if (nested_is_rows[i]) {
1518 CHKERR ISDestroy(&nested_is_rows[i]);
1519 }
1520 if (nested_is_cols[i]) {
1521 CHKERR ISDestroy(&nested_is_cols[i]);
1522 }
1523 for (int j = 0; j != 2; j++) {
1524 if (nested_matrices(i, j)) {
1525 CHKERR MatDestroy(&nested_matrices(i, j));
1526 }
1527 }
1528 }
1529
1530 CHKERR MatDestroy(&SubA);
1531 CHKERR MatDestroy(&A);
1532 CHKERR VecDestroy(&D);
1533 CHKERR VecDestroy(&F);
1534
1535 CHKERR DMDestroy(&dm_sub_volume_control);
1536
1537 using PostProcVolume =
1539 using OpPPVolume = OpPostProcMapInMoab<3, 3>;
1540
1541 PostProcVolume post_proc(m_field, "my");
1542 {
1543 CHKERR AddHOOps<3, 3, 3>::add(post_proc.getOpPtrVector(), {H1});
1544
1545 auto u_ptr = boost::make_shared<MatrixDouble>();
1546 post_proc.getOpPtrVector().push_back(
1547 new OpCalculateVectorFieldValues<3>("U", u_ptr));
1548 auto hooke_common =
1549 HookeOps::commonDataFactory<SPACE_DIM, GAUSS, DomainEleOp>(
1550 m_field, post_proc.getOpPtrVector(), "U", "MAT_ELASTIC",
1551 Sev::verbose);
1552 post_proc.getOpPtrVector().push_back(new OpPPVolume(
1553 post_proc.getPostProcMesh(), post_proc.getMapGaussPts(),
1554 OpPPVolume::DataMapVec{}, OpPPVolume::DataMapMat{{"U", u_ptr}},
1555 OpPPVolume::DataMapMat{{"U_GRAD", hooke_common->matGradPtr}},
1556 OpPPVolume::DataMapMat{
1557 {"STRESS", hooke_common->getMatCauchyStress()}}));
1558 CHKERR post_proc.setTagsToTransfer({block_id_tag});
1559
1560 CHKERR DMoFEMLoopFiniteElements(dm_control, "ELASTIC", &post_proc);
1561 CHKERR post_proc.writeFile("out.h5m");
1562 elastic_energy = 0;
1563 CHKERR DMoFEMLoopFiniteElements(dm_control, "ELASTIC",
1564 &elastic_energy_fe);
1565 double global_elastic_energy = 0;
1566 CHKERR MPI_Allreduce(&elastic_energy, &global_elastic_energy, 1,
1567 MPI_DOUBLE, MPI_SUM, m_field.get_comm());
1568 PetscPrintf(PETSC_COMM_WORLD, "Elastic energy %6.4e\n",
1569 global_elastic_energy);
1570 }
1571
1572 {
1573 using PostProcFace =
1575 PostProcFace post_proc_face(m_field, "my");
1576 if (is_curl) {
1578 {HCURL});
1579 post_proc_face.getOpPtrVector().push_back(
1580 new OpVirtualCurlRho("RHO", common_data));
1581 } else {
1582 CHKERR AddHOOps<2, 2, 2>::add(post_proc_face.getOpPtrVector(), {H1});
1583 post_proc_face.getOpPtrVector().push_back(
1584 new OpVirtualPotentialRho("RHO", common_data));
1585 }
1586 post_proc_face.getOpPtrVector().push_back(
1587 new PostProcTraction(m_field, post_proc_face.getPostProcMesh(),
1588 post_proc_face.getMapGaussPts(), common_data));
1589 CHKERR DMoFEMLoopFiniteElements(dm_control, "D", &post_proc_face);
1590 CHKERR post_proc_face.writeFile("out_tractions.h5m");
1591 }
1592
1593 CHKERR DMDestroy(&dm_control);
1594 }
1596
1598 return 0;
1599}
int main()
static char help[]
constexpr int SPACE_DIM
constexpr int SPACE_DIM
@ ROW
#define CATCH_ERRORS
Catch errors.
@ MF_ZERO
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
@ H1
continuous field
Definition definitions.h:85
@ NOSPACE
Definition definitions.h:83
@ HCURL
field with continuous tangents
Definition definitions.h:86
#define MYPCOMM_INDEX
default communicator number PCOMM
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MAT_ELASTICSET
block name is "MAT_ELASTIC"
@ SIDESET
@ BLOCKSET
@ MOFEM_STD_EXCEPTION_THROW
Definition definitions.h:39
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
@ MOFEM_INVALID_DATA
Definition definitions.h:36
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
constexpr int order
@ F
PetscErrorCode DMMoFEMSetIsPartitioned(DM dm, PetscBool is_partitioned)
Definition DMMoFEM.cpp:1113
PetscErrorCode DMMoFEMCreateSubDM(DM subdm, DM dm, const char problem_name[])
Must be called by user to set Sub DM MoFEM data structures.
Definition DMMoFEM.cpp:215
PetscErrorCode DMMoFEMAddElement(DM dm, std::string fe_name)
add element to dm
Definition DMMoFEM.cpp:488
PetscErrorCode DMMoFEMSetSquareProblem(DM dm, PetscBool square_problem)
set squared problem
Definition DMMoFEM.cpp:450
PetscErrorCode DMMoFEMCreateMoFEM(DM dm, MoFEM::Interface *m_field_ptr, const char problem_name[], const MoFEM::BitRefLevel bit_level, const MoFEM::BitRefLevel bit_mask=MoFEM::BitRefLevel().set())
Must be called by user to set MoFEM data structures.
Definition DMMoFEM.cpp:114
PetscErrorCode DMoFEMPostProcessFiniteElements(DM dm, MoFEM::FEMethod *method)
execute finite element method for each element in dm (problem)
Definition DMMoFEM.cpp:546
PetscErrorCode DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
Definition DMMoFEM.cpp:238
PetscErrorCode DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode, RowColData rc=RowColData::COL)
set local (or ghosted) vector values on mesh for partition only
Definition DMMoFEM.cpp:514
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
Definition DMMoFEM.cpp:43
PetscErrorCode DMoFEMLoopFiniteElements(DM dm, const char fe_name[], MoFEM::FEMethod *method, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
Definition DMMoFEM.cpp:576
PetscErrorCode DMMoFEMAddSubFieldCol(DM dm, const char field_name[])
Definition DMMoFEM.cpp:280
PetscErrorCode DMoFEMPreProcessFiniteElements(DM dm, MoFEM::FEMethod *method)
execute finite element method for each element in dm (problem)
Definition DMMoFEM.cpp:536
virtual const Problem * get_problem(const std::string problem_name) const =0
Get the problem object.
virtual MoFEMErrorCode add_finite_element(const std::string &fe_name, enum MoFEMTypes bh=MF_EXCL, int verb=DEFAULT_VERBOSITY)=0
add finite element
virtual MoFEMErrorCode build_finite_elements(int verb=DEFAULT_VERBOSITY)=0
Build finite elements.
virtual MoFEMErrorCode modify_finite_element_add_field_col(const std::string &fe_name, const std::string name_row)=0
set field col which finite element use
virtual MoFEMErrorCode add_ents_to_finite_element_by_type(const EntityHandle entities, const EntityType type, const std::string name, const bool recursive=true)=0
add entities to finite element
virtual MoFEMErrorCode modify_finite_element_add_field_row(const std::string &fe_name, const std::string name_row)=0
set field row which finite element use
virtual MoFEMErrorCode modify_finite_element_add_field_data(const std::string &fe_name, const std::string name_field)=0
set finite element field data
virtual MoFEMErrorCode build_fields(int verb=DEFAULT_VERBOSITY)=0
virtual MoFEMErrorCode set_field_order(const EntityHandle meshset, const EntityType type, const std::string &name, const ApproximationOrder order, int verb=DEFAULT_VERBOSITY)=0
Set order approximation of the entities in the field.
virtual MoFEMErrorCode add_ents_to_field_by_type(const Range &ents, const EntityType type, const std::string &name, int verb=DEFAULT_VERBOSITY)=0
Add entities to field meshset.
#define _IT_CUBITMESHSETS_BY_BCDATA_TYPE_FOR_LOOP_(MESHSET_MANAGER, CUBITBCTYPE, IT)
Iterator that loops over a specific Cubit MeshSet in a moFEM field.
#define _IT_CUBITMESHSETS_BY_SET_TYPE_FOR_LOOP_(MESHSET_MANAGER, CUBITBCTYPE, IT)
Iterator that loops over a specific Cubit MeshSet having a particular BC meshset in a moFEM field.
FTensor::Index< 'i', SPACE_DIM > i
double D
const double n
refractive index of diffusive medium
FTensor::Index< 'j', 3 > j
std::map< int, Range > ElasticBlockMap
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
std::bitset< BITREFLEVEL_SIZE > BitRefLevel
Bit structure attached to each entity identifying to what mesh entity is attached.
Definition Types.hpp:40
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
decltype(GetFTensor2SymmetricFromMatImpl< Tensor_Dim, S, DL, M >::get(std::declval< M & >(), 0, 0)) GetFTensor2SymmetricFromMatType
static const bool debug
constexpr AssemblyType A
int getRule(int order) override
Calculate and assemble Z matrix.
Calculate and assemble Z matrix.
Calculate and assemble B matrix.
Calculate and assemble D matrix.
Calculate and assemble S matrix.
Calculate and assemble g vector.
boost::shared_ptr< MatrixDouble > stressPtr
boost::shared_ptr< MatrixDouble > strainPtr
MoFEMErrorCode doWork(int, EntityType, EntitiesFieldData::EntData &) override
OpElasticEnergy(boost::shared_ptr< MatrixDouble > strain_ptr, boost::shared_ptr< MatrixDouble > stress_ptr, double &energy)
Post-process tractions.
Shave results on mesh tags for post-processing.
Add operators pushing bases from local to physical configuration.
Boundary condition manager for finite element problem setup.
Managing BitRefLevels.
Managing BitRefLevels.
virtual FieldBitNumber get_field_bit_number(const std::string name) const =0
get field bit number
virtual MoFEMErrorCode build_adjacencies(const Range &ents, int verb=DEFAULT_VERBOSITY)=0
build adjacencies
virtual MoFEMErrorCode add_field(const std::string name, const FieldSpace space, const FieldApproximationBase base, const FieldCoefficientsNumber nb_of_coefficients, const TagType tag_type=MB_TAG_SPARSE, const enum MoFEMTypes bh=MF_EXCL, int verb=DEFAULT_VERBOSITY)=0
Add field.
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
Core (interface) class.
Definition Core.hpp:83
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
Definition Core.cpp:68
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Definition Core.cpp:123
Deprecated interface functions.
Data on single entity (This is passed as argument to DataOperator::doWork)
Class (Function) to enforce essential constrains on the left hand side diagonal.
Definition Essential.hpp:33
Class (Function) to enforce essential constrains on the right hand side diagonal.
Definition Essential.hpp:41
Class (Function) to enforce essential constrains.
Definition Essential.hpp:25
static UId getLoLocalEntityBitNumber(const char bit_number, const EntityHandle ent)
static UId getHiLocalEntityBitNumber(const char bit_number, const EntityHandle ent)
boost::ptr_deque< UserDataOperator > & getOpPtrVector()
Use to push back operator for row operator.
Section manager is used to create indexes and sections.
Definition ISManager.hpp:23
Elastic material data structure.
Interface for managing meshsets containing materials and boundary conditions.
Calculate inverse of jacobian for face element.
Specialization for MatrixDouble vector field values calculation.
Post post-proc data at points from hash maps.
Transform local reference derivatives of shape functions to global derivatives.
auto & getMapGaussPts()
Get vector of vectors associated to integration points.
MoFEMErrorCode writeFile(const std::string file_name)
wrote results in (MOAB) format, use "file_name.h5m"
auto & getPostProcMesh()
Get postprocessing mesh.
keeps basic data about problem
MoFEMErrorCode getDofByNameEntAndEntDofIdx(const int field_bit_number, const EntityHandle ent, const int ent_dof_idx, const RowColData row_or_col, boost::shared_ptr< NumeredDofEntity > &dof_ptr) const
get DOFs from problem
boost::shared_ptr< SubProblemData > & getSubData() const
Get main problem of sub-problem is.
boost::shared_ptr< NumeredDofEntity_multiIndex > numeredRowDofsPtr
store DOFs on rows for this problem
intrusive_ptr for managing petsc objects
Vec & snes_f
Reference to residual vector.
Mat & snes_B
Reference to preconditioner of Jacobian matrix.
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.