v0.16.0
Loading...
Searching...
No Matches
gradient.cpp
Go to the documentation of this file.
1/**
2 * @file gradient.cpp
3 */
4
5#include <boost/python.hpp>
6#include <boost/python/def.hpp>
7#include <boost/python/numpy.hpp>
8namespace bp = boost::python;
9namespace np = boost::python::numpy;
10
11#include <MoFEM.hpp>
12
13using namespace MoFEM;
14
15//! [Constants and material properties]
16constexpr int BASE_DIM = 1; ///< Dimension of the base functions
17
18//! [Define dimension]
19constexpr int SPACE_DIM =
20 EXECUTABLE_DIMENSION; ///< Space dimension of problem (2D or 3D), set at compile time
21
22//! [Define dimension]
23constexpr AssemblyType A =
24 AssemblyType::PETSC; ///< Use PETSc for matrix/vector assembly
25constexpr IntegrationType I =
26 IntegrationType::GAUSS; ///< Use Gauss quadrature for integration
27
28//! [Material properties for linear elasticity]
29constexpr double young_modulus = 1; ///< Young's modulus E
30constexpr double poisson_ratio = 0.3; ///< Poisson's ratio ν
31constexpr double bulk_modulus_K =
33 (3 * (1 - 2 * poisson_ratio)); ///< Bulk modulus K = E/(3(1-2ν))
34constexpr double shear_modulus_G =
35 young_modulus / (2 * (1 + poisson_ratio)); ///< Shear modulus G = E/(2(1+ν))
36
37PetscBool is_plane_strain =
38 PETSC_FALSE; ///< Flag for plane strain vs plane stress in 2D
39//! [Constants and material properties]
40
41//! [Define finite element types and operators]
42using EntData =
43 EntitiesFieldData::EntData; ///< Entity data for field operations
45 SPACE_DIM>::DomainEle; ///< Domain finite elements
47 SPACE_DIM>::BoundaryEle; ///< Boundary finite elements
48using DomainEleOp = DomainEle::UserDataOperator; ///< Domain element operators
50 BoundaryEle::UserDataOperator; ///< Boundary element operators
51//! [Define finite element types and operators]
52
53//! [Boundary condition types]
54struct DomainBCs {}; ///< Domain boundary conditions marker
55struct BoundaryBCs {}; ///< Boundary conditions marker
56
57//! [Natural boundary condition operators]
59 I>; ///< Domain RHS natural BCs
61 DomainRhsBCs::OpFlux<DomainBCs, 1, SPACE_DIM>; ///< Domain flux operator
63 I>; ///< Boundary RHS natural BCs
66 SPACE_DIM>; ///< Boundary flux operator
68 I>; ///< Boundary LHS natural BCs
71 SPACE_DIM>; ///< Boundary LHS flux operator
72
73template <int DIM> struct PostProcEleByDim;
74
75template <> struct PostProcEleByDim<2> {
79};
80
81template <> struct PostProcEleByDim<3> {
85};
86// Here you can see how the template is being used
90// Forward declaration
91template <int SPACE_DIM, IntegrationType I, typename OpBase>
92struct OpAdJointTestOp;
93
95
97
98#include <ElasticSpring.hpp>
99#include <FluidLevel.hpp>
100#include <CalculateTraction.hpp>
101#include <NaturalDomainBC.hpp>
102#include <NaturalBoundaryBC.hpp>
103#include <HookeOps.hpp>
104#include <ElasticPostProc.hpp>
105
107using namespace ShapeOptimization;
108
110 const std::string block_name, int dim);
111
112MoFEMErrorCode save_range(moab::Interface &moab, const std::string name,
113 const Range r);
114struct Example {
115
116 Example(MoFEM::Interface &m_field) : mField(m_field) {}
117
118 /// Main driver function for the optimization process
120
121private:
122 MoFEM::Interface &mField; ///< Reference to MoFEM interface
123
124 boost::shared_ptr<MatrixDouble> vectorFieldPtr =
125 nullptr; ///< Field values at evaluation points
126
127 // Problem setup methods
133
134 // Analysis methods
135 MoFEMErrorCode solveElastic(); ///< Solve forward elastic problem
137 int iter, SmartPetscObj<Vec> gradient_vector = nullptr,
138 SmartPetscObj<Vec> adjoint_vector = nullptr,
139 SmartPetscObj<Vec> dJ_du = nullptr); ///< Post-process and output results
140
141 /// Calculate objective function gradient using adjoint method
142 MoFEMErrorCode calculateGradient(PetscReal *objective_function_value,
143 Vec objective_function_gradient,
144 Vec adjoint_vector, Vec dJ_du);
145
146 MoFEMErrorCode testGradient(Vec gradient_vector);
147
148 // Problem configuration
149 FieldApproximationBase base; ///< Choice of finite element basis functions
150 int fieldOrder = 2; ///< Polynomial order for approximation
151
152 // Solver and data management
153 SmartPetscObj<KSP> kspElastic; ///< Linear solver for elastic problem
154 SmartPetscObj<DM> adjointDM; ///< Data manager for adjoint problem
155 boost::shared_ptr<ObjectiveFunctionData>
156 pythonPtr; ///< Interface to Python objective function
157};
158
159//! [Run topology optimization problem]
162
163 // Read objective function from Python file
164 char objective_function_file_name[255] = "objective_function.py";
166 PETSC_NULLPTR, PETSC_NULLPTR, "-objective_function",
167 objective_function_file_name, 255, PETSC_NULLPTR);
168
169 // Verify that the Python objective function file exists
170 auto file_exists = [](std::string myfile) {
171 std::ifstream file(myfile.c_str());
172 if (file) {
173 return true;
174 }
175 return false;
176 };
177 if (!file_exists(objective_function_file_name)) {
178 MOFEM_LOG("WORLD", Sev::error) << "Objective function file NOT found: "
179 << objective_function_file_name;
180 CHK_THROW_MESSAGE(MOFEM_NOT_FOUND, "file NOT found");
181 }
182
183 // Create Python interface for objective function
184 pythonPtr = create_python_objective_function(objective_function_file_name);
185
186 char sensitivity_method_name[32] = "adjoint";
187 CHKERR PetscOptionsGetString(PETSC_NULLPTR, PETSC_NULLPTR,
188 "-sensitivity_method", sensitivity_method_name,
189 sizeof(sensitivity_method_name), PETSC_NULLPTR);
190 std::string sensitivity_method = sensitivity_method_name;
191 std::transform(sensitivity_method.begin(), sensitivity_method.end(),
192 sensitivity_method.begin(),
193 [](unsigned char c) { return std::tolower(c); });
194 if (sensitivity_method == "direct") {
196 } else if (sensitivity_method == "adjoint") {
198 } else {
199 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
200 "Unknown -sensitivity_method. Use 'direct' or 'adjoint'.");
201 }
202 MOFEM_LOG("WORLD", Sev::inform)
203 << "Sensitivity method: " << sensitivity_method;
204
205 // Setup finite element problems
206 CHKERR readMesh(); // Read mesh and meshsets
207 CHKERR setupProblem(); // Setup displacement field and geometry field
208 CHKERR setupAdJoint(); // Setup adjoint field for sensitivity analysis
209 CHKERR boundaryCondition(); // Apply essential boundary conditions
210 CHKERR assembleSystem(); // Setup finite element operators
211
212 // Create linear solver for elastic problem
213 auto pip = mField.getInterface<PipelineManager>();
214 kspElastic = pip->createKSP();
215 CHKERR KSPSetFromOptions(kspElastic);
216
217 // Solve initial elastic problem
219 CHKERR postprocessElastic(-1); // Post-process initial solution
220
221 double f;
224 auto adjoint_vector = createDMVector(simple->getDM());
225 auto dJ_du = createDMVector(simple->getDM());
226 CHKERR calculateGradient(&f, g, adjoint_vector, dJ_du);
227 MOFEM_LOG("WORLD", Sev::inform) << "Objective function value: " << f;
228
229 auto grad = createDMVector(simple->getDM());
230 CHKERR DMoFEMMeshToLocalVector(adjointDM, g, INSERT_VALUES, SCATTER_REVERSE,
232 CHKERR mField.getInterface<VecManager>()->setOtherLocalGhostVector(
233 simple->getProblemName(), "U", "ADJOINT_FIELD", RowColData::ROW, grad,
234 INSERT_VALUES, SCATTER_FORWARD);
235 CHKERR postprocessElastic(0, grad, adjoint_vector,
236 dJ_du); // Post-process initial solution
237
238 // Testing gradient
240
241 // Optimization complete - results available in solution vectors
242 MOFEM_LOG("WORLD", Sev::inform) << "Topology optimization completed";
243
245};
246//! [Run problem]
247
248//! [Read mesh]
249/**
250 * @brief Read mesh from file and setup material/boundary condition meshsets
251 *
252 * This function loads the finite element mesh from file and processes
253 * associated meshsets that define material properties and boundary conditions.
254 * The mesh is typically generated using CUBIT and exported in .h5m format.
255 *
256 * Meshsets are used to group elements/faces by:
257 * - Material properties (for different material blocks)
258 * - Boundary conditions (for applying loads and constraints)
259 * - Optimization regions (for topology optimization)
260 *
261 * @return MoFEMErrorCode Success or error code
262 */
266 CHKERR simple->getOptions(); // Read command line options
267 CHKERR simple->loadFile(); // Load mesh from file
268 // Add meshsets if config file provided
269 CHKERR mField.getInterface<MeshsetsManager>()->setMeshsetFromFile();
271}
272//! [Read mesh]
273
274//! [Set up problem]
275/**
276 * @brief Setup finite element fields, approximation spaces and degrees of freedom
277 *
278 * This function configures the finite element problem by:
279 * 1. Setting up the displacement field "U" with vector approximation
280 * 2. Setting up the geometry field "GEOMETRY" for mesh deformation
281 * 3. Defining polynomial approximation order and basis functions
282 * 4. Creating degrees of freedom on mesh entities
283 *
284 * The displacement field uses H1 vector space for standard elasticity.
285 * The geometry field allows mesh modification during topology optimization.
286 * Different basis functions (Ainsworth-Legendre vs Demkowicz) can be selected.
287 *
288 * @return MoFEMErrorCode Success or error code
289 */
293
294 // Select basis functions for finite element approximation
295 enum bases { AINSWORTH, DEMKOWICZ, LASBASETOPT };
296 const char *list_bases[LASBASETOPT] = {"ainsworth", "demkowicz"};
297 PetscInt choice_base_value = AINSWORTH;
298 CHKERR PetscOptionsGetEList(PETSC_NULLPTR, NULL, "-base", list_bases,
299 LASBASETOPT, &choice_base_value, PETSC_NULLPTR);
300
301 switch (choice_base_value) {
302 case AINSWORTH:
304 MOFEM_LOG("WORLD", Sev::inform)
305 << "Set AINSWORTH_LEGENDRE_BASE for displacements";
306 break;
307 case DEMKOWICZ:
309 MOFEM_LOG("WORLD", Sev::inform)
310 << "Set DEMKOWICZ_JACOBI_BASE for displacements";
311 break;
312 default:
313 base = LASTBASE;
314 break;
315 }
316
317 // Add finite element fields
318 /**
319 * Setup displacement field "U" - the primary unknown in elasticity
320 * This field represents displacement vector at each node/DOF
321 */
322 CHKERR simple->addDomainField("U", H1, base, SPACE_DIM);
323 CHKERR simple->addBoundaryField("U", H1, base, SPACE_DIM);
324 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &fieldOrder,
325 PETSC_NULLPTR);
326
327 /**
328 * Setup geometry field "GEOMETRY" - used for mesh deformation in optimization
329 * This field stores current nodal coordinates and can be modified
330 * during topology optimization to represent design changes
331 */
332 CHKERR simple->addDataField("GEOMETRY", H1, base, SPACE_DIM);
333
334 // Set polynomial approximation order for both fields
335 CHKERR simple->setFieldOrder("U", fieldOrder);
336 CHKERR simple->setFieldOrder("GEOMETRY", fieldOrder);
337 CHKERR simple->setUp();
338
339 // Project higher-order geometry representation onto geometry field
340 /**
341 * For higher-order elements, this projects the exact geometry
342 * onto the geometry field to maintain curved boundaries accurately
343 */
344 auto project_ho_geometry = [&]() {
345 Projection10NodeCoordsOnField ent_method(mField, "GEOMETRY");
346 return mField.loop_dofs("GEOMETRY", ent_method);
347 };
348 CHKERR project_ho_geometry();
349
350 // Check if plane strain assumption should be used
351 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-plane_strain",
352 &is_plane_strain, PETSC_NULLPTR);
353
355}
356//! [Set up problem]
357
358//! [Setup adjoint]
362
363 // Create adjoint data manager and field
364 auto create_adjoint_dm = [&]() {
365 auto adjoint_dm = createDM(mField.get_comm(), "DMMOFEM");
366
367 constexpr int adjoint_field_order = 1;
368
369 auto add_field = [&]() {
371 CHKERR mField.add_field("ADJOINT_FIELD", H1, base, SPACE_DIM);
372 CHKERR mField.add_ents_to_field_by_dim(simple->getBoundaryMeshSet(),
373 SPACE_DIM - 1, "ADJOINT_FIELD");
374 for (auto tt = MBEDGE;
375 tt <= moab::CN::TypeDimensionMap[SPACE_DIM - 1].second; ++tt)
376 CHKERR mField.set_field_order(simple->getBoundaryMeshSet(), tt,
377 "ADJOINT_FIELD", adjoint_field_order);
378 CHKERR mField.set_field_order(simple->getBoundaryMeshSet(), MBVERTEX,
379 "ADJOINT_FIELD", 1);
382 };
383
384 auto add_adjoint_fe_impl = [&]() {
386 CHKERR mField.add_finite_element("ADJOINT_DOMAIN_FE");
388 "ADJOINT_FIELD");
390 "U");
392 "ADJOINT_FIELD");
394 "U");
396 "GEOMETRY");
397
398 CHKERR mField.add_finite_element("ADJOINT_BOUNDARY_FE");
400 "ADJOINT_FIELD");
402 "U");
404 "ADJOINT_FIELD");
406 "U");
408 "GEOMETRY");
409
411 simple->getMeshset(), SPACE_DIM, "ADJOINT_DOMAIN_FE");
413 simple->getBoundaryMeshSet(), SPACE_DIM - 1, "ADJOINT_BOUNDARY_FE");
414 CHKERR mField.build_finite_elements("ADJOINT_DOMAIN_FE");
415 CHKERR mField.build_finite_elements("ADJOINT_BOUNDARY_FE");
416
417 CHKERR mField.build_adjacencies(simple->getBitRefLevel(),
418 simple->getBitRefLevelMask());
419
421 };
422
423 auto set_adjoint_dm_imp = [&]() {
425 CHKERR DMMoFEMCreateMoFEM(adjoint_dm, &mField, "ADJOINT",
426 simple->getBitRefLevel(),
427 simple->getBitRefLevelMask());
428 CHKERR DMMoFEMSetDestroyProblem(adjoint_dm, PETSC_TRUE);
429 CHKERR DMSetFromOptions(adjoint_dm);
430 CHKERR DMMoFEMAddElement(adjoint_dm, "ADJOINT_DOMAIN_FE");
431 CHKERR DMMoFEMAddElement(adjoint_dm, "ADJOINT_BOUNDARY_FE");
432 CHKERR DMMoFEMSetSquareProblem(adjoint_dm, PETSC_FALSE);
433 CHKERR DMMoFEMSetIsPartitioned(adjoint_dm, PETSC_TRUE);
434 mField.getInterface<ProblemsManager>()->buildProblemFromFields =
435 PETSC_TRUE;
436 CHKERR DMSetUp(adjoint_dm);
437 mField.getInterface<ProblemsManager>()->buildProblemFromFields =
438 PETSC_FALSE;
440 };
441
442 CHK_THROW_MESSAGE(add_field(), "add adjoint field");
443 CHK_THROW_MESSAGE(add_adjoint_fe_impl(), "add adjoint fe");
444 CHK_THROW_MESSAGE(set_adjoint_dm_imp(), "set adjoint dm");
445
446 return adjoint_dm;
447 };
448
449 adjointDM = create_adjoint_dm();
450
452}
453//! [Setup adjoint]
454
455//! [Boundary condition]
459 auto bc_mng = mField.getInterface<BcManager>();
460
461 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_X",
462 "U", 0, 0);
463 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Y",
464 "U", 1, 1);
465 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(), "REMOVE_Z",
466 "U", 2, 2);
467 CHKERR bc_mng->removeBlockDOFsOnEntities(simple->getProblemName(),
468 "REMOVE_ALL", "U", 0, 3);
469 CHKERR bc_mng->pushMarkDOFsOnEntities<DisplacementCubitBcData>(
470 simple->getProblemName(), "U");
471
472 CHKERR bc_mng->removeBlockDOFsOnEntities("ADJOINT", "REMOVE_X",
473 "ADJOINT_FIELD", 0, 0);
474 CHKERR bc_mng->removeBlockDOFsOnEntities("ADJOINT", "REMOVE_Y",
475 "ADJOINT_FIELD", 1, 1);
476 CHKERR bc_mng->removeBlockDOFsOnEntities("ADJOINT", "REMOVE_Z",
477 "ADJOINT_FIELD", 2, 2);
478 CHKERR bc_mng->removeBlockDOFsOnEntities("ADJOINT", "REMOVE_ALL",
479 "ADJOINT_FIELD", 0, 3);
480 CHKERR bc_mng->removeBlockDOFsOnEntities("ADJOINT", "FIX_X", "ADJOINT_FIELD",
481 0, 0);
482 CHKERR bc_mng->removeBlockDOFsOnEntities("ADJOINT", "FIX_Y", "ADJOINT_FIELD",
483 1, 1);
484 CHKERR bc_mng->removeBlockDOFsOnEntities("ADJOINT", "FIX_Z", "ADJOINT_FIELD",
485 2, 2);
486 CHKERR bc_mng->removeBlockDOFsOnEntities("ADJOINT", "FIX_ALL",
487 "ADJOINT_FIELD", 0, 3);
488
490}
491//! [Boundary condition]
492
493//! [Push operators to pipeline]
496 auto pip = mField.getInterface<PipelineManager>();
497
498 //! [Integration rule]
499 auto integration_rule = [](int, int, int approx_order) {
500 return 2 * approx_order + 1;
501 };
502
503 auto integration_rule_bc = [](int, int, int approx_order) {
504 return 2 * approx_order + 1;
505 };
506
508 CHKERR pip->setDomainLhsIntegrationRule(integration_rule);
509 CHKERR pip->setBoundaryRhsIntegrationRule(integration_rule_bc);
510 CHKERR pip->setBoundaryLhsIntegrationRule(integration_rule_bc);
511 //! [Integration rule]
512
514 pip->getOpDomainLhsPipeline(), {H1}, "GEOMETRY");
516 pip->getOpDomainRhsPipeline(), {H1}, "GEOMETRY");
518 pip->getOpBoundaryRhsPipeline(), {NOSPACE}, "GEOMETRY");
520 pip->getOpBoundaryLhsPipeline(), {NOSPACE}, "GEOMETRY");
521
522 //! [Push domain stiffness matrix to pipeline]
523 // Add LHS operator for elasticity (stiffness matrix)
524 CHKERR HookeOps::opFactoryDomainLhs<SPACE_DIM, A, I, DomainEleOp>(
525 mField, pip->getOpDomainLhsPipeline(), "U", "MAT_ELASTIC", Sev::noisy);
526 //! [Push domain stiffness matrix to pipeline]
527
528 // Add RHS operator for internal forces
529 CHKERR HookeOps::opFactoryDomainRhs<SPACE_DIM, A, I, DomainEleOp>(
530 mField, pip->getOpDomainRhsPipeline(), "U", "MAT_ELASTIC", Sev::noisy);
531
532 //! [Push Body forces]
534 pip->getOpDomainRhsPipeline(), mField, "U", Sev::inform);
535 //! [Push Body forces]
536
537 //! [Push natural boundary conditions]
538 // Add force boundary condition
540 pip->getOpBoundaryRhsPipeline(), mField, "U", -1, Sev::inform);
541 // Add case for mix type of BCs
543 pip->getOpBoundaryLhsPipeline(), mField, "U", Sev::noisy);
544 //! [Push natural boundary conditions]
546}
547//! [Push operators to pipeline]
548
549//! [Solve]
553 auto dm = simple->getDM();
554 auto f = createDMVector(dm);
555 auto d = vectorDuplicate(f);
556 CHKERR VecZeroEntries(d);
557 CHKERR DMoFEMMeshToLocalVector(dm, d, INSERT_VALUES, SCATTER_REVERSE);
558
559 auto set_essential_bc = [&]() {
561 // This is low level pushing finite elements (pipelines) to solver
562
563 auto ksp_ctx_ptr = getDMKspCtx(dm);
564 auto pre_proc_rhs = boost::make_shared<FEMethod>();
565 auto post_proc_rhs = boost::make_shared<FEMethod>();
566 auto post_proc_lhs = boost::make_shared<FEMethod>();
567
568 auto get_pre_proc_hook = [&]() {
570 {});
571 };
572 pre_proc_rhs->preProcessHook = get_pre_proc_hook();
573
574 auto get_post_proc_hook_rhs = [this, post_proc_rhs]() {
576
578 post_proc_rhs, 1.)();
580 };
581
582 auto get_post_proc_hook_lhs = [this, post_proc_lhs]() {
584
586 post_proc_lhs, 1.)();
588 };
589
590 post_proc_rhs->postProcessHook = get_post_proc_hook_rhs;
591 post_proc_lhs->postProcessHook = get_post_proc_hook_lhs;
592
593 ksp_ctx_ptr->getPreProcComputeRhs().push_front(pre_proc_rhs);
594 ksp_ctx_ptr->getPostProcComputeRhs().push_back(post_proc_rhs);
595 ksp_ctx_ptr->getPostProcSetOperators().push_back(post_proc_lhs);
597 };
598
599 auto setup_and_solve = [&](auto solver) {
601 BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
602 MOFEM_LOG("TIMER", Sev::noisy) << "KSPSetUp";
603 CHKERR KSPSetUp(solver);
604 MOFEM_LOG("TIMER", Sev::noisy) << "KSPSetUp <= Done";
605 MOFEM_LOG("TIMER", Sev::noisy) << "KSPSolve";
606 CHKERR KSPSolve(solver, f, d);
607 MOFEM_LOG("TIMER", Sev::noisy) << "KSPSolve <= Done";
609 };
610
611 MOFEM_LOG_CHANNEL("TIMER");
612 MOFEM_LOG_TAG("TIMER", "timer");
613
614 CHKERR set_essential_bc();
615 CHKERR setup_and_solve(kspElastic);
616
617 CHKERR VecGhostUpdateBegin(d, INSERT_VALUES, SCATTER_FORWARD);
618 CHKERR VecGhostUpdateEnd(d, INSERT_VALUES, SCATTER_FORWARD);
619 CHKERR DMoFEMMeshToLocalVector(dm, d, INSERT_VALUES, SCATTER_REVERSE);
620
621 auto evaluate_field_at_the_point = [&]() {
623
624 int coords_dim = 3;
625 std::array<double, 3> field_eval_coords{0.0, 0.0, 0.0};
626 PetscBool do_eval_field = PETSC_FALSE;
627 CHKERR PetscOptionsGetRealArray(NULL, NULL, "-field_eval_coords",
628 field_eval_coords.data(), &coords_dim,
630
631 if (do_eval_field) {
632
633 vectorFieldPtr = boost::make_shared<MatrixDouble>();
634 auto field_eval_data =
635 mField.getInterface<FieldEvaluatorInterface>()->getData<DomainEle>();
636
638 ->buildTree<SPACE_DIM>(field_eval_data, simple->getDomainFEName());
639
640 field_eval_data->setEvalPoints(field_eval_coords.data(), 1);
641 auto no_rule = [](int, int, int) { return -1; };
642 auto field_eval_fe_ptr = field_eval_data->feMethodPtr;
643 field_eval_fe_ptr->getRuleHook = no_rule;
644
645 field_eval_fe_ptr->getOpPtrVector().push_back(
647
649 ->evalFEAtThePoint<SPACE_DIM>(
650 field_eval_coords.data(), 1e-12, simple->getProblemName(),
651 simple->getDomainFEName(), field_eval_data,
653 QUIET);
654
655 if (vectorFieldPtr->size1()) {
656 auto t_disp = getFTensor1FromMat<SPACE_DIM>(*vectorFieldPtr);
657 if constexpr (SPACE_DIM == 2)
658 MOFEM_LOG("FieldEvaluator", Sev::inform)
659 << "U_X: " << t_disp(0) << " U_Y: " << t_disp(1);
660 else
661 MOFEM_LOG("FieldEvaluator", Sev::inform)
662 << "U_X: " << t_disp(0) << " U_Y: " << t_disp(1)
663 << " U_Z: " << t_disp(2);
664 }
665
667 }
669 };
670
671 CHKERR evaluate_field_at_the_point();
672
674}
675//! [Solve]
676
677//! [Postprocess results]
679 SmartPetscObj<Vec> gradient_vector,
680 SmartPetscObj<Vec> adjoint_vector,
681 SmartPetscObj<Vec> dJ_du) {
684 std::vector<std::pair<std::string, SmartPetscObj<Vec>>> additional_vecs;
685 if (gradient_vector) {
686 additional_vecs.emplace_back("GRADIENT", gradient_vector);
687 }
688 if (adjoint_vector) {
689 additional_vecs.emplace_back("ADJOINT", adjoint_vector);
690 }
691 if (dJ_du) {
692 additional_vecs.emplace_back("dJ_dU", dJ_du);
693 }
696 mField, simple->getDM(), simple->getDomainFEName(),
697 "out_elastic_" + std::to_string(iter) + ".h5m", additional_vecs,
698 {}, Sev::noisy);
700}
701//! [Postprocess results]
702
704
705struct OpStateSensitivity : public DomainBaseOp {
708 boost::shared_ptr<ObjectiveFunctionData> python_ptr,
709 boost::shared_ptr<HookeOps::CommonData> comm_ptr,
710 boost::shared_ptr<MatrixDouble> u_ptr)
711 : OP(field_name, field_name, DomainEleOp::OPROW), pythonPtr(python_ptr),
712 commPtr(comm_ptr), uPtr(u_ptr) {}
713
720
721 constexpr auto symm_size = (SPACE_DIM * (SPACE_DIM + 1)) / 2;
722 auto nb_gauss_pts = getGaussPts().size2();
723
724 auto objective_dstress =
725 boost::make_shared<MatrixDouble>(nb_gauss_pts, symm_size);
726 auto objective_dstrain =
727 boost::make_shared<MatrixDouble>(nb_gauss_pts, symm_size);
728 auto objective_du =
729 boost::make_shared<MatrixDouble>(nb_gauss_pts, SPACE_DIM);
730
731 auto evaluate_python = [&]() {
733 auto &coords = OP::getCoordsAtGaussPts();
734 CHKERR pythonPtr->evalInteriorObjectiveGradientStress(
735 coords, uPtr, commPtr->getMatCauchyStress(), commPtr->getMatStrain(),
736 objective_dstress);
737 CHKERR pythonPtr->evalInteriorObjectiveGradientStrain(
738 coords, uPtr, commPtr->getMatCauchyStress(), commPtr->getMatStrain(),
739 objective_dstrain);
740 CHKERR pythonPtr->evalInteriorObjectiveGradientU(
741 coords, uPtr, commPtr->getMatCauchyStress(), commPtr->getMatStrain(),
742 objective_du);
743
744 auto vol = OP::getMeasure();
745 auto t_w = OP::getFTensor0IntegrationWeight();
746
747 auto t_D =
748 getFTensor4DdgFromMat<SPACE_DIM, SPACE_DIM, 0>(*(commPtr->matDPtr));
749 auto t_row_grad = data.getFTensor1DiffN<SPACE_DIM>();
750 auto t_row_base = data.getFTensor0N();
751
752 auto t_obj_dstress =
753 getFTensor2SymmetricFromMat<SPACE_DIM>(*objective_dstress);
754 auto t_obj_dstrain =
755 getFTensor2SymmetricFromMat<SPACE_DIM>(*objective_dstrain);
756 auto t_obj_du = getFTensor1FromMat<SPACE_DIM>(*objective_du);
757
758 for (int gg = 0; gg != nb_gauss_pts; ++gg) {
759 const double alpha = t_w * vol;
761 t_adjoint_stress(i, j) =
762 t_D(i, j, k, l) * t_obj_dstress(k, l) + t_obj_dstrain(i, j);
763
764 auto t_nf = OP::template getNf<SPACE_DIM>();
765 int rr = 0;
766 for (; rr != OP::nbRows / SPACE_DIM; rr++) {
767 t_nf(j) += alpha * t_row_grad(i) * t_adjoint_stress(i, j);
768 t_nf(j) += alpha * t_row_base * t_obj_du(j);
769
770 ++t_row_grad;
771 ++t_row_base;
772 ++t_nf;
773 }
774
775 for (; rr < OP::nbRowBaseFunctions; ++rr) {
776 ++t_row_grad;
777 ++t_row_base;
778 }
779 ++t_obj_dstrain;
780 ++t_obj_dstress;
781 ++t_obj_du;
782 ++t_w;
783 }
785 };
786 CHKERR evaluate_python();
788 }
789
790private:
791 boost::shared_ptr<ObjectiveFunctionData> pythonPtr;
792 boost::shared_ptr<HookeOps::CommonData> commPtr;
793 boost::shared_ptr<MatrixDouble> uPtr;
794};
797
798 OpObjective(boost::shared_ptr<ObjectiveFunctionData> python_ptr,
799 boost::shared_ptr<HookeOps::CommonData> comm_ptr,
800 boost::shared_ptr<MatrixDouble> jac_ptr,
801 boost::shared_ptr<MatrixDouble> u_ptr,
802 boost::shared_ptr<double> glob_objective_ptr)
803 : OP(NOSPACE, OP::OPSPACE), pythonPtr(python_ptr), commPtr(comm_ptr),
804 jacPtr(jac_ptr), uPtr(u_ptr), globObjectivePtr(glob_objective_ptr) {}
805
806 /**
807 * @brief Compute objective function contributions at element level
808 *
809 * Evaluates Python objective function with current displacement and stress
810 * state, and accumulates global objective value and gradients.
811 */
812 MoFEMErrorCode doWork(int side, EntityType type,
815
816 auto nb_gauss_pts =
817 getGaussPts().size2(); // number of gauss points in the element
818
819 auto objective_ptr = boost::make_shared<MatrixDouble>(
820 1, nb_gauss_pts); // objective function values at gauss points
821
822 auto evaluate_python = [&]() {
824 auto &coords = OP::getCoordsAtGaussPts();
825 CHKERR pythonPtr->evalInteriorObjectiveFunction(
826 coords, uPtr, commPtr->getMatCauchyStress(), commPtr->getMatStrain(),
827 objective_ptr);
828
829 auto t_obj = getFTensor0FromMat(*objective_ptr);
830
831 auto vol = OP::getMeasure();
832 auto t_w = getFTensor0IntegrationWeight();
833 for (auto gg = 0; gg != nb_gauss_pts; ++gg) {
834
835 auto alpha = t_w * vol;
836 (*globObjectivePtr) += alpha * t_obj;
837
838 ++t_w;
839
840 ++t_obj;
841 }
843 };
844
845 CHKERR evaluate_python();
846
848 }
849
850private:
851 boost::shared_ptr<ObjectiveFunctionData> pythonPtr;
852 boost::shared_ptr<HookeOps::CommonData> commPtr;
853 boost::shared_ptr<MatrixDouble> jacPtr;
854 boost::shared_ptr<MatrixDouble> uPtr;
855 boost::shared_ptr<double> globObjectivePtr;
856};
857
858struct OpAdJointObjective : public DomainBaseOp {
860
861 OpAdJointObjective(boost::shared_ptr<ObjectiveFunctionData> python_ptr,
862 boost::shared_ptr<HookeOps::CommonData> comm_ptr,
863 boost::shared_ptr<MatrixDouble> jac_ptr,
864 boost::shared_ptr<MatrixDouble> u_ptr,
865 boost::shared_ptr<MatrixDouble> grad_lambda_u_ptr,
866 boost::shared_ptr<double> glob_objective_ptr)
867 : OP("ADJOINT_FIELD", "ADJOINT_FIELD", OP::OPROW), pythonPtr(python_ptr),
868 commPtr(comm_ptr), jacPtr(jac_ptr), uPtr(u_ptr),
869 gradLambdaUPtr(grad_lambda_u_ptr),
870 globObjectivePtr(glob_objective_ptr) {}
871
872 /**
873 * @brief Compute objective function contributions at element level
874 *
875 * Evaluates Python objective function with current displacement and stress
876 * state, and accumulates global objective value and gradients.
877 */
880
881 const auto nb_gauss_pts =
882 getGaussPts().size2(); // number of gauss points in the element
883 const auto nb_dofs = data.getIndices().size();
884 const auto nb_base_funcs = data.getN().size2() / SPACE_DIM;
885
886 // Define tensor indices for calculations
891
894
895 constexpr auto symm_size = (SPACE_DIM * (SPACE_DIM + 1)) /
896 2; // size of symmetric tensor in Voigt notation
897
898 auto t_diff_symm = FTensor::diff_symmetrize<double>();
899 // fourth order tensor for symmetrization to convert from gradient to strain
900
901 auto objective_ptr = boost::make_shared<MatrixDouble>(
902 1, nb_gauss_pts); // objective function values at gauss points
903 auto objective_dstress = boost::make_shared<MatrixDouble>(
904 nb_gauss_pts,
905 symm_size); // objective function gradient w.r.t. stress at gauss points
906 auto objective_dstrain = boost::make_shared<MatrixDouble>(
907 nb_gauss_pts,
908 symm_size); // objective function gradient w.r.t. strain at gauss points
909 // The dJ/du contribution is assembled separately by OpStateSensitivity.
910
911 auto evaluate_python = [&]() {
913 auto &coords = OP::getCoordsAtGaussPts();
914 CHKERR pythonPtr->evalInteriorObjectiveFunction(
915 coords, uPtr, commPtr->getMatCauchyStress(), commPtr->getMatStrain(),
916 objective_ptr);
917 CHKERR pythonPtr->evalInteriorObjectiveGradientStress(
918 coords, uPtr, commPtr->getMatCauchyStress(), commPtr->getMatStrain(),
919 objective_dstress);
920 CHKERR pythonPtr->evalInteriorObjectiveGradientStrain(
921 coords, uPtr, commPtr->getMatCauchyStress(), commPtr->getMatStrain(),
922 objective_dstrain);
923
924 auto t_grad_u =
925 getFTensor2FromMat<SPACE_DIM, SPACE_DIM>(*(commPtr->matGradPtr));
926 auto t_D =
927 getFTensor4DdgFromMat<SPACE_DIM, SPACE_DIM, 0>(*(commPtr->matDPtr));
928 auto t_jac = getFTensor2FromMat<SPACE_DIM, SPACE_DIM>(*(jacPtr));
929 auto t_grad_lambda_u =
930 getFTensor2FromMat<SPACE_DIM, SPACE_DIM>(*gradLambdaUPtr);
931
932 auto t_obj = getFTensor0FromMat(*objective_ptr);
933 auto t_obj_dstress =
934 getFTensor2SymmetricFromMat<SPACE_DIM>(*objective_dstress);
935 auto t_obj_dstrain =
936 getFTensor2SymmetricFromMat<SPACE_DIM>(*objective_dstrain);
937
938 auto vol = OP::getMeasure();
939 auto t_w = getFTensor0IntegrationWeight();
940 auto t_base_diff = data.getFTensor1DiffN<SPACE_DIM>();
941 for (auto gg = 0; gg != nb_gauss_pts; ++gg) {
942 auto alpha = t_w * vol;
943 (*globObjectivePtr) += alpha * t_obj;
944
945 auto t_det = determinantTensor(t_jac);
947 CHKERR invertTensor(t_jac, t_det, t_inv_jac);
948
950 t_diff_inv_jac;
951 t_diff_inv_jac(i, j, I, J) =
952 -t_inv_jac(i, I) * t_inv_jac(J, j);
954 t_diff_grad;
955 t_diff_grad(i, j, I, J) = t_grad_u(i, k) * t_diff_inv_jac(k, j, I, J);
957 t_d_strain;
958 t_d_strain(i, j, I, J) =
959 t_diff_symm(i, j, k, l) * t_diff_grad(k, l, I, J);
960
961 auto t_local_grad_vector = OP::template getNf<SPACE_DIM>();
962 int bb = 0;
963 for (; bb != nb_dofs/ SPACE_DIM; bb++) {
964
966 t_coef(I) = (t_inv_jac(J, I) * t_base_diff(J)) * t_det;
967
968 t_local_grad_vector(I) +=
969 alpha * (
970
971 ((t_obj_dstress(k, l) * t_D(k, l, i, j)) +
972 t_obj_dstrain(i, j)) *
973 (t_d_strain(i, j, I, J) * t_base_diff(J))
974
975 +
976
977 t_obj * t_coef(I)
978
979 );
980
981 t_local_grad_vector(I) -=
982 alpha * (t_grad_lambda_u(i, j) * t_D(i, j, k, l)) *
983 (t_d_strain(k, l, I, J) * t_base_diff(J));
984
985 ++t_local_grad_vector;
986 ++t_base_diff;
987 }
988 for (; bb < nb_base_funcs; ++bb) {
989 ++t_base_diff;
990 }
991
992 ++t_w;
993 ++t_jac;
994
995 ++t_obj;
996 ++t_obj_dstress;
997 ++t_obj_dstrain;
998
999 ++t_grad_u;
1000 ++t_grad_lambda_u;
1001 }
1003 };
1004
1005 CHKERR evaluate_python();
1006
1008 }
1009
1010private:
1011 boost::shared_ptr<ObjectiveFunctionData> pythonPtr;
1012 boost::shared_ptr<HookeOps::CommonData> commPtr;
1013 boost::shared_ptr<MatrixDouble> jacPtr;
1014 boost::shared_ptr<MatrixDouble> uPtr;
1015 boost::shared_ptr<MatrixDouble> gradLambdaUPtr;
1016
1017 boost::shared_ptr<double> globObjectivePtr;
1018};
1019
1020MoFEMErrorCode Example::calculateGradient(PetscReal *objective_function_value,
1021 Vec objective_function_gradient,
1022 Vec lambda, Vec dJ_du) {
1023 MOFEM_LOG_CHANNEL("WORLD");
1025 auto simple = mField.getInterface<Simple>();
1026 auto dm = simple->getDM();
1027
1028 auto get_essential_fe = [this]() {
1029 auto post_proc_rhs = boost::make_shared<FEMethod>();
1030 auto get_post_proc_hook_rhs = [this, post_proc_rhs]() {
1033 post_proc_rhs, 0)();
1035 };
1036 post_proc_rhs->postProcessHook = get_post_proc_hook_rhs;
1037 return post_proc_rhs;
1038 };
1039
1040 auto get_objective_fe = [&](auto lambda_vec, auto glob_objective_ptr,
1041 auto fe_rule) {
1042 auto fe_obj = boost::make_shared<DomainEle>(mField);
1043 fe_obj->getRuleHook = fe_rule;
1044 auto &pip = fe_obj->getOpPtrVector();
1046
1047 auto jac_ptr = boost::make_shared<MatrixDouble>();
1048 auto u_ptr = boost::make_shared<MatrixDouble>();
1049 auto grad_lambda_ptr = boost::make_shared<MatrixDouble>();
1050
1052 "GEOMETRY", jac_ptr));
1053 pip.push_back(new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
1054 auto lambda_smart_vec = SmartPetscObj<Vec>(lambda_vec, true);
1056 "U", grad_lambda_ptr, lambda_smart_vec));
1057
1058 auto common_ptr = HookeOps::commonDataFactory<SPACE_DIM, I, DomainEleOp>(
1059 mField, pip, "U", "MAT_ELASTIC", Sev::noisy);
1060 pip.push_back(new OpAdJointObjective(pythonPtr, common_ptr, jac_ptr, u_ptr,
1061 grad_lambda_ptr,
1062 glob_objective_ptr));
1063 return fe_obj;
1064 };
1065
1066 auto evaluate_objective_terms =
1067 [&](auto objective_fe, auto objective_ptr) {
1069 *objective_ptr = 0.0;
1070 CHKERR VecZeroEntries(objective_function_gradient);
1071 CHKERR VecGhostUpdateBegin(lambda, INSERT_VALUES, SCATTER_FORWARD);
1072 CHKERR VecGhostUpdateEnd(lambda, INSERT_VALUES, SCATTER_FORWARD);
1073 objective_fe->f = objective_function_gradient;
1074 CHKERR DMoFEMLoopFiniteElements(adjointDM, "ADJOINT_DOMAIN_FE",
1075 objective_fe);
1076 MPI_Allreduce(MPI_IN_PLACE, objective_ptr.get(), 1, MPI_DOUBLE, MPI_SUM,
1077 mField.get_comm());
1078 CHKERR VecAssemblyBegin(objective_function_gradient);
1079 CHKERR VecAssemblyEnd(objective_function_gradient);
1080 CHKERR VecGhostUpdateBegin(objective_function_gradient, ADD_VALUES,
1081 SCATTER_REVERSE);
1082 CHKERR VecGhostUpdateEnd(objective_function_gradient, ADD_VALUES,
1083 SCATTER_REVERSE);
1085 };
1086
1087 auto calculate_variance_of_objective_function_dJ_du = [&]() {
1089 auto fe = boost::make_shared<DomainEle>(mField);
1090 fe->getRuleHook = [](int, int, int p_data) {
1091 return 2 * p_data + p_data - 1;
1092 };
1093 auto &pip = fe->getOpPtrVector();
1095 auto u_ptr = boost::make_shared<MatrixDouble>();
1096 pip.push_back(new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
1097 auto common_ptr = HookeOps::commonDataFactory<SPACE_DIM, I, DomainEleOp>(
1098 mField, pip, "U", "MAT_ELASTIC", Sev::noisy);
1099 pip.push_back(new OpStateSensitivity("U", pythonPtr, common_ptr, u_ptr));
1100 CHKERR VecZeroEntries(dJ_du);
1101 fe->f = dJ_du;
1103 CHKERR VecAssemblyBegin(dJ_du);
1104 CHKERR VecAssemblyEnd(dJ_du);
1105 auto post_proc_rhs = get_essential_fe();
1106 post_proc_rhs->f = dJ_du;
1108 post_proc_rhs.get());
1110 };
1111
1112 auto calculate_adjoint_lambda = [&]() {
1114
1115 MOFEM_LOG("WORLD", Sev::inform) << "Solving for adjoint variable lambda";
1116 CHKERR VecZeroEntries(lambda);
1117 CHKERR KSPSolveTranspose(kspElastic, dJ_du, lambda);
1118 CHKERR VecGhostUpdateBegin(lambda, INSERT_VALUES, SCATTER_FORWARD);
1119 CHKERR VecGhostUpdateEnd(lambda, INSERT_VALUES, SCATTER_FORWARD);
1121 };
1122
1123 auto fe_rule = [](int, int, int p_data) { return 2 * p_data + p_data - 1; };
1124 auto objective_ptr_value = boost::make_shared<double>(0.0);
1125 auto objective_fe = get_objective_fe(lambda, objective_ptr_value, fe_rule);
1126
1127 auto adjoint = [&]() {
1129
1130 CHKERR calculate_variance_of_objective_function_dJ_du();
1131 CHKERR calculate_adjoint_lambda();
1132 CHKERR evaluate_objective_terms(objective_fe, objective_ptr_value);
1133 *objective_function_value = *objective_ptr_value;
1134
1135 MOFEM_LOG("WORLD", Sev::verbose)
1136 << "Objective function: " << *objective_function_value;
1137
1138 CHKERR VecAssemblyBegin(objective_function_gradient);
1139 CHKERR VecAssemblyEnd(objective_function_gradient);
1140 CHKERR VecGhostUpdateBegin(lambda, INSERT_VALUES, SCATTER_FORWARD);
1141 CHKERR VecGhostUpdateEnd(lambda, INSERT_VALUES, SCATTER_FORWARD);
1142
1144 };
1145
1146 switch (derivative_type) {
1147
1148 case ADJOINT:
1149 MOFEM_LOG("WORLD", Sev::inform) << "Running Adjoint Sensitivity...";
1150 CHKERR adjoint();
1151 break;
1152
1153 default:
1154 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
1155 "Wrong sensitivity type selected");
1156 }
1157
1158 CHKERR VecAssemblyBegin(objective_function_gradient);
1159 CHKERR VecAssemblyEnd(objective_function_gradient);
1160
1162}
1163//! [calculateGradient]
1164
1165//! [Finite difference check]
1168
1169 PetscBool gradient_fd_check = PETSC_FALSE;
1170 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, PETSC_NULLPTR, "-gradient_fd_check",
1171 &gradient_fd_check, PETSC_NULLPTR);
1172 if (gradient_fd_check) {
1173
1174 PetscInt nb_modes = 5;
1175 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, PETSC_NULLPTR,
1176 "-gradient_nb_modes", &nb_modes, PETSC_NULLPTR);
1177
1178 auto simple = mField.getInterface<Simple>();
1179 auto dm = simple->getDM();
1180 auto *adj_problem_ptr = getProblemPtr(adjointDM);
1181
1182 auto fe_rule = [](int, int, int p_data) { return 2 * p_data + p_data - 1; };
1183 auto get_objective_fe = [&](auto glob_objective_ptr, auto fe_rule) {
1184 auto fe_obj_fe = boost::make_shared<DomainEle>(mField);
1185 fe_obj_fe->getRuleHook = fe_rule;
1186 auto &pip = fe_obj_fe->getOpPtrVector();
1188 auto jac_ptr = boost::make_shared<MatrixDouble>();
1189 auto u_ptr = boost::make_shared<MatrixDouble>();
1191 "GEOMETRY", jac_ptr));
1192 pip.push_back(new OpCalculateVectorFieldValues<SPACE_DIM>("U", u_ptr));
1193 auto common_ptr = HookeOps::commonDataFactory<SPACE_DIM, I, DomainEleOp>(
1194 mField, pip, "U", "MAT_ELASTIC", Sev::noisy);
1195 pip.push_back(new OpObjective(pythonPtr, common_ptr, jac_ptr, u_ptr,
1196 glob_objective_ptr));
1197 return fe_obj_fe;
1198 };
1199
1200 auto f = boost::make_shared<double>(0.);
1201 auto fe_obj = get_objective_fe(f, fe_rule);
1202 CacheTupleSharedPtr tmp_cache_ptr = boost::make_shared<CacheTuple>();
1203 CHKERR mField.cache_problem_entities(simple->getProblemName(),
1204 tmp_cache_ptr);
1205
1206 auto evaluate_objective_terms = [&](auto objective_fe, auto objective_ptr,
1207 double &objective_value) {
1209 *objective_ptr = 0.0;
1211 objective_fe);
1212 MPI_Allreduce(MPI_IN_PLACE, objective_ptr.get(), 1, MPI_DOUBLE, MPI_SUM,
1213 mField.get_comm());
1214 objective_value = *objective_ptr;
1216 };
1217
1218 auto geometry_bit_number = mField.get_field_bit_number("GEOMETRY");
1219 for (PetscInt mode = 0; mode < nb_modes; ++mode) {
1220 MOFEM_LOG_CHANNEL("WORLD");
1221 MOFEM_LOG("WORLD", Sev::verbose) << "Processing mode: " << mode;
1222
1223 auto &adj_dofs =
1224 adj_problem_ptr->getNumeredRowDofsPtr()->get<PetscGlobalIdx_mi_tag>();
1225 auto &dofs = mField.get_dofs()->get<Unique_mi_tag>();
1226
1227 auto a_dof = adj_dofs.find(mode);
1228 if (a_dof != adj_dofs.end()) {
1229 auto ent = (*a_dof)->getEnt();
1230 auto dof_idx = (*a_dof)->getEntDofIdx();
1232 dof_idx,
1233 FieldEntity::getLocalUniqueIdCalculate(geometry_bit_number, ent));
1234 auto dof = dofs.find(uid);
1235 if (dof != dofs.end()) {
1236 auto org_geom_val = (*dof)->getFieldData();
1237 constexpr double eps = 1e-6;
1238
1239 (*dof)->getFieldData() = org_geom_val + eps;
1240 CHKERR KSPReset(kspElastic);
1242 double f_plus;
1243 CHKERR evaluate_objective_terms(fe_obj, f, f_plus);
1244
1245 (*dof)->getFieldData() = org_geom_val - eps;
1246 CHKERR KSPReset(kspElastic);
1248 double f_minus;
1249 CHKERR evaluate_objective_terms(fe_obj, f, f_minus);
1250
1251 double *g_array;
1252 CHKERR VecGetArray(gradient_vector, &g_array);
1253 if ((*a_dof)->getHasLocalIndex()) {
1254 auto adjoint_grad = g_array[(*a_dof)->getPetscLocalDofIdx()];
1255 auto finite_diff_grad = (f_plus - f_minus) / (2 * eps);
1256 auto err = std::abs(adjoint_grad - finite_diff_grad) /
1257 std::max(std::abs(adjoint_grad),
1258 std::abs(finite_diff_grad));
1259 MOFEM_LOG("WORLD", Sev::inform)
1260 << "Mode: " << mode << ", Adjoint gradient: " << adjoint_grad
1261 << ", Finite difference gradient: " << finite_diff_grad
1262 << ", Relative error: "
1263 << std::abs(adjoint_grad - finite_diff_grad) /
1264 std::max(std::abs(adjoint_grad),
1265 std::abs(finite_diff_grad));
1266 constexpr double tol = 1e-4;
1267 if (err > tol) {
1268 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
1269 "Gradient check failed for mode %d: relative error %e is "
1270 "greater than tolerance %e",
1271 mode, err, tol);
1272 }
1273 }
1274
1275 CHKERR VecRestoreArray(gradient_vector, &g_array);
1276
1277 constexpr bool restore_solution = false;
1278 if constexpr (restore_solution) {
1279 (*dof)->getFieldData() = org_geom_val;
1280 CHKERR KSPReset(kspElastic);
1282 }
1283 }
1284 }
1285 }
1286 }
1287
1289}
1290//! [Finite difference check]
1291
1292static char help[] = "...\n\n";
1293
1294int main(int argc, char *argv[]) {
1295
1296 // Initialize Python environment for objective function interface
1297 Py_Initialize();
1298 np::initialize();
1299
1300 // Initialize MoFEM/PETSc and MOAB data structures
1301 const char param_file[] = "param_file.petsc";
1302 MoFEM::Core::Initialize(&argc, &argv, param_file, help);
1303
1304 auto core_log = logging::core::get();
1305 core_log->add_sink(
1307
1308 core_log->add_sink(
1309 LogManager::createSink(LogManager::getStrmSync(), "FieldEvaluator"));
1310 LogManager::setLog("FieldEvaluator");
1311 MOFEM_LOG_TAG("FieldEvaluator", "field_eval");
1312
1313 try {
1314
1315 //! [Register MoFEM discrete manager in PETSc]
1316 DMType dm_name = "DMMOFEM";
1317 CHKERR DMRegister_MoFEM(dm_name);
1318 DMType dm_name_mg = "DMMOFEM_MG";
1320 //! [Register MoFEM discrete manager in PETSc
1321
1322 //! [Create MoAB]
1323 moab::Core mb_instance; ///< mesh database
1324 moab::Interface &moab = mb_instance; ///< mesh database interface
1325 //! [Create MoAB]
1326
1327 //! [Create MoFEM]
1328 MoFEM::Core core(moab); ///< finite element database
1329 MoFEM::Interface &m_field = core; ///< finite element database interface
1330 //! [Create MoFEM]
1331
1332 //! [Example]
1333
1334 Example ex(m_field);
1335 CHKERR ex.runProblem();
1336 //! [Example]
1337 }
1339
1341
1342 if (Py_FinalizeEx() < 0) {
1343 exit(120);
1344 }
1345}
1346
1348 const std::string block_name, int dim) {
1349 Range r;
1350
1351 auto mesh_mng = m_field.getInterface<MeshsetsManager>();
1352 auto bcs = mesh_mng->getCubitMeshsetPtr(
1353
1354 std::regex((boost::format("%s(.*)") % block_name).str())
1355
1356 );
1357
1358 for (auto bc : bcs) {
1359 Range faces;
1360 CHK_MOAB_THROW(bc->getMeshsetIdEntitiesByDimension(m_field.get_moab(), dim,
1361 faces, true),
1362 "get meshset ents");
1363 r.merge(faces);
1364 }
1365
1366 for (auto dd = dim - 1; dd >= 0; --dd) {
1367 if (dd >= 0) {
1368 Range ents;
1369 CHK_MOAB_THROW(m_field.get_moab().get_adjacencies(r, dd, false, ents,
1370 moab::Interface::UNION),
1371 "get adjs");
1372 r.merge(ents);
1373 } else {
1374 Range verts;
1375 CHK_MOAB_THROW(m_field.get_moab().get_connectivity(r, verts),
1376 "get verts");
1377 r.merge(verts);
1378 }
1380 m_field.getInterface<CommInterface>()->synchroniseEntities(r), "comm");
1381 }
1382
1383 return r;
1384};
1385
1386MoFEMErrorCode save_range(moab::Interface &moab, const std::string name,
1387 const Range r) {
1389 auto out_meshset = get_temp_meshset_ptr(moab);
1390 CHKERR moab.add_entities(*out_meshset, r);
1391 CHKERR moab.write_file(name.c_str(), "VTK", "", out_meshset->get_ptr(), 1);
1393};
std::string type
#define MOFEM_LOG_SYNCHRONISE(comm)
Synchronise "SYNC" channel.
Interface for Python-based objective function evaluation in topology optimization.
#define FTENSOR_INDEX(DIM, I)
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
SensitivityMethod derivative_type
Definition adjoint.cpp:109
SensitivityMethod
Definition adjoint.cpp:107
@ DIRECT
Definition adjoint.cpp:107
@ ADJOINT
Definition adjoint.cpp:107
int main()
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
ElementsAndOps< SPACE_DIM >::BoundaryEle BoundaryEle
@ QUIET
@ ROW
#define CATCH_ERRORS
Catch errors.
@ MF_EXIST
FieldApproximationBase
approximation base
Definition definitions.h:58
@ LASTBASE
Definition definitions.h:69
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
@ DEMKOWICZ_JACOBI_BASE
Definition definitions.h:66
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
@ H1
continuous field
Definition definitions.h:85
@ NOSPACE
Definition definitions.h:83
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define CHK_MOAB_THROW(err, msg)
Check error code of MoAB function and throw MoFEM exception.
@ MOFEM_NOT_FOUND
Definition definitions.h:33
@ MOFEM_ATOM_TEST_INVALID
Definition definitions.h:40
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
#define MoFEMFunctionBeginHot
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
PostProcEleByDim< SPACE_DIM >::PostProcEleDomain PostProcEleDomain
PostProcEleByDim< SPACE_DIM >::PostProcEleBdy PostProcEleBdy
auto integration_rule
static char help[]
[Finite difference check]
PetscBool is_plane_strain
Definition gradient.cpp:37
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::DomainEle DomainEle
Domain finite elements.
Definition gradient.cpp:45
constexpr int SPACE_DIM
[Define dimension]
Definition gradient.cpp:19
SensitivityMethod derivative_type
Definition gradient.cpp:96
constexpr double poisson_ratio
Poisson's ratio ν
Definition gradient.cpp:30
constexpr int BASE_DIM
[Constants and material properties]
Definition gradient.cpp:16
constexpr double shear_modulus_G
Shear modulus G = E/(2(1+ν))
Definition gradient.cpp:34
constexpr IntegrationType I
Use Gauss quadrature for integration.
Definition gradient.cpp:25
constexpr double bulk_modulus_K
Bulk modulus K = E/(3(1-2ν))
Definition gradient.cpp:31
@ DIRECT
Definition gradient.cpp:94
@ ADJOINT
Definition gradient.cpp:94
FormsIntegrators< DomainEleOp >::Assembly< A >::OpBase DomainBaseOp
[Postprocess results]
Definition gradient.cpp:703
constexpr AssemblyType A
[Define dimension]
Definition gradient.cpp:23
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::BoundaryEle BoundaryEle
Boundary finite elements.
Definition gradient.cpp:47
Range get_range_from_block(MoFEM::Interface &m_field, const std::string block_name, int dim)
constexpr double young_modulus
[Material properties for linear elasticity]
Definition gradient.cpp:29
PetscErrorCode DMMoFEMSetIsPartitioned(DM dm, PetscBool is_partitioned)
Definition DMMoFEM.cpp:1113
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 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
MoFEMErrorCode DMRegister_MGViaApproxOrders(const char sname[])
Register DM for Multi-Grid via approximation orders.
PetscErrorCode DMoFEMLoopFiniteElements(DM dm, const char fe_name[], MoFEM::FEMethod *method, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
Definition DMMoFEM.cpp:576
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
Definition DMMoFEM.hpp:1237
virtual const DofEntity_multiIndex * get_dofs() const =0
Get the dofs object.
virtual MoFEMErrorCode add_ents_to_finite_element_by_dim(const EntityHandle entities, const int dim, const std::string name, const bool recursive=true)=0
add entities to finite element
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 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 add_ents_to_field_by_dim(const Range &ents, const int dim, const std::string &name, int verb=DEFAULT_VERBOSITY)=0
Add entities to field meshset.
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.
IntegrationType
Form integrator integration types.
AssemblyType
[Storage and set boundary conditions]
static LoggerType & setLog(const std::string channel)
Set ans resset chanel logger.
#define MOFEM_LOG(channel, severity)
Log.
#define MOFEM_LOG_TAG(channel, tag)
Tag channel.
#define MOFEM_LOG_CHANNEL(channel)
Set and reset channel.
virtual MoFEMErrorCode loop_dofs(const Problem *problem_ptr, const std::string &field_name, RowColData rc, DofMethod &method, int lower_rank, int upper_rank, int verb=DEFAULT_VERBOSITY)=0
Make a loop over dofs.
MoFEMErrorCode getCubitMeshsetPtr(const int ms_id, const CubitBCType cubit_bc_type, const CubitMeshSets **cubit_meshset_ptr) const
get cubit meshset
FTensor::Index< 'i', SPACE_DIM > i
static double lambda
const double c
speed of light (cm/ns)
FTensor::Index< 'J', DIM1 > J
Definition level_set.cpp:30
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
double tol
MoFEMErrorCode postProcessElasticResults(MoFEM::Interface &mField, SmartPetscObj< DM > dm, const std::string &domain_fe_name, const std::string &out_file_name, std::vector< std::pair< std::string, SmartPetscObj< Vec > > > extra_vectors={}, const std::vector< std::string > &tags_to_transfer={}, const Sev hooke_ops_sev=Sev::verbose)
const double eps
Definition HenckyOps.hpp:13
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
PetscErrorCode DMMoFEMSetDestroyProblem(DM dm, PetscBool destroy_problem)
Definition DMMoFEM.cpp:434
PetscErrorCode PetscOptionsGetInt(PetscOptions *, const char pre[], const char name[], PetscInt *ivalue, PetscBool *set)
PetscErrorCode PetscOptionsGetBool(PetscOptions *, const char pre[], const char name[], PetscBool *bval, PetscBool *set)
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
PetscErrorCode PetscOptionsGetRealArray(PetscOptions *, const char pre[], const char name[], PetscReal dval[], PetscInt *nmax, PetscBool *set)
auto getDMKspCtx(DM dm)
Get KSP context data structure used by DM.
Definition DMMoFEM.hpp:1251
static MoFEMErrorCode invertTensor(FTensor::Tensor2< T1, DIM, DIM > &t, T2 &det, FTensor::Tensor2< T3, DIM, DIM > &inv_t)
static auto determinantTensor(FTensor::Tensor2< T, DIM, DIM > &t)
Calculate the determinant of a tensor of rank DIM.
PetscErrorCode PetscOptionsGetEList(PetscOptions *, const char pre[], const char name[], const char *const *list, PetscInt next, PetscInt *value, PetscBool *set)
PetscErrorCode PetscOptionsGetString(PetscOptions *, const char pre[], const char name[], char str[], size_t size, PetscBool *set)
auto getFTensor0FromMat(M &data)
Get tensor rank 0 (scalar) form data vector.
auto get_temp_meshset_ptr(moab::Interface &moab)
Create smart pointer to temporary meshset.
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
boost::shared_ptr< CacheTuple > CacheTupleSharedPtr
auto getProblemPtr(DM dm)
get problem pointer from DM
Definition DMMoFEM.hpp:1182
boost::shared_ptr< ObjectiveFunctionData > create_python_objective_function(std::string)
constexpr auto field_name
static constexpr int approx_order
PetscBool is_plane_strain
Definition seepage.cpp:177
constexpr double g
Boundary conditions marker.
[Define entities]
Definition elastic.cpp:38
[Example]
Definition plastic.cpp:217
MoFEMErrorCode boundaryCondition()
MoFEMErrorCode assembleSystem()
MoFEMErrorCode readMesh()
boost::shared_ptr< ObjectiveFunctionData > pythonPtr
Interface to Python objective function.
Definition adjoint.cpp:170
SmartPetscObj< DM > adjointDM
Data manager for adjoint problem.
Definition adjoint.cpp:168
FieldApproximationBase base
Choice of finite element basis functions.
Definition plot_base.cpp:68
SmartPetscObj< KSP > kspElastic
Linear solver for elastic problem.
Definition adjoint.cpp:167
MoFEMErrorCode testGradient(Vec gradient_vector)
[calculateGradient]
int fieldOrder
Polynomial order for approximation.
Definition adjoint.cpp:164
Example(MoFEM::Interface &m_field)
Definition gradient.cpp:116
MoFEMErrorCode runProblem()
Main driver function for the optimization process.
MoFEMErrorCode calculateGradient(PetscReal *objective_function_value, Vec objective_function_gradient, Vec adjoint_vector)
Calculate objective function gradient using adjoint method.
Definition adjoint.cpp:1726
MoFEMErrorCode setupAdJoint()
MoFEM::Interface & mField
Reference to MoFEM interface.
Definition plastic.cpp:227
MoFEMErrorCode setupProblem()
MoFEMErrorCode postprocessElastic(int iter, SmartPetscObj< Vec > adjoint_vector=nullptr)
Post-process and output results.
Definition adjoint.cpp:1326
MoFEMErrorCode solveElastic()
Solve forward elastic problem.
boost::shared_ptr< MatrixDouble > vectorFieldPtr
Field values at evaluation points.
Definition adjoint.cpp:137
Add operators pushing bases from local to physical configuration.
Boundary condition manager for finite element problem setup.
Managing BitRefLevels.
MoFEMErrorCode synchroniseEntities(Range &ent, std::map< int, Range > *received_ents, int verb=DEFAULT_VERBOSITY)
synchronize entity range on processors (collective)
virtual FieldBitNumber get_field_bit_number(const std::string name) const =0
get field bit number
virtual moab::Interface & get_moab()=0
virtual MoFEMErrorCode cache_problem_entities(const std::string prb_name, CacheTupleWeakPtr cache_ptr)=0
Cache variables.
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.
Definition of the displacement bc data structure.
Definition BCData.hpp:72
static UId getUniqueIdCalculate(const DofIdx dof, UId ent_uid)
Data on single entity (This is passed as argument to DataOperator::doWork)
FTensor::Tensor0< FTensor::PackPtr< double *, 1 > > getFTensor0N(const FieldApproximationBase base)
Get base function as Tensor0.
auto getFTensor1DiffN(const FieldApproximationBase base)
Get derivatives of base functions.
MatrixDouble & getN(const FieldApproximationBase base)
get base functions this return matrix (nb. of rows is equal to nb. of Gauss pts, nb....
const VectorInt & getIndices() const
Get global indices of degrees of freedom on entity.
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
UId getLocalUniqueIdCalculate()
Get the Local Unique Id Calculate object.
Field evaluator interface.
static boost::shared_ptr< SinkType > createSink(boost::shared_ptr< std::ostream > stream_ptr, std::string comm_filter)
Create a sink object.
static boost::shared_ptr< std::ostream > getStrmWorld()
Get the strm world object.
static boost::shared_ptr< std::ostream > getStrmSync()
Get the strm sync object.
Interface for managing meshsets containing materials and boundary conditions.
Assembly methods.
Definition Natural.hpp:65
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Specialization for MatrixDouble vector field values calculation.
Template struct for dimension-specific finite element types.
PipelineManager interface.
MoFEMErrorCode setDomainRhsIntegrationRule(RuleHookFun rule)
Set integration rule for domain right-hand side finite element.
Problem manager is used to build and partition problems.
Projection of edge entities with one mid-node on hierarchical basis.
Simple interface for fast problem set-up.
Definition Simple.hpp:27
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180
MoFEMErrorCode getDM(DM *dm)
Get DM.
Definition Simple.cpp:799
const std::string getDomainFEName() const
Get the Domain FE Name.
Definition Simple.hpp:429
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
Vector manager is used to create vectors \mofem_vectors.
boost::shared_ptr< HookeOps::CommonData > commPtr
Definition adjoint.cpp:1714
ForcesAndSourcesCore::UserDataOperator OP
Definition adjoint.cpp:1552
boost::shared_ptr< double > globObjectivePtr
Definition adjoint.cpp:1722
OpAdJointObjective(boost::shared_ptr< ObjectiveFunctionData > python_ptr, boost::shared_ptr< HookeOps::CommonData > comm_ptr, boost::shared_ptr< MatrixDouble > jac_ptr, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< MatrixDouble > grad_lambda_u_ptr, boost::shared_ptr< double > glob_objective_ptr)
Definition gradient.cpp:861
boost::shared_ptr< ObjectiveFunctionData > pythonPtr
Definition adjoint.cpp:1713
boost::shared_ptr< MatrixDouble > gradLambdaUPtr
boost::shared_ptr< MatrixDouble > uPtr
Definition adjoint.cpp:1720
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &data)
Compute objective function contributions at element level.
Definition gradient.cpp:878
boost::shared_ptr< MatrixDouble > jacPtr
Definition adjoint.cpp:1715
boost::shared_ptr< double > globObjectivePtr
Definition gradient.cpp:855
ForcesAndSourcesCore::UserDataOperator OP
Definition gradient.cpp:796
boost::shared_ptr< MatrixDouble > jacPtr
Definition gradient.cpp:853
OpObjective(boost::shared_ptr< ObjectiveFunctionData > python_ptr, boost::shared_ptr< HookeOps::CommonData > comm_ptr, boost::shared_ptr< MatrixDouble > jac_ptr, boost::shared_ptr< MatrixDouble > u_ptr, boost::shared_ptr< double > glob_objective_ptr)
Definition gradient.cpp:798
boost::shared_ptr< MatrixDouble > uPtr
Definition gradient.cpp:854
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Compute objective function contributions at element level.
Definition gradient.cpp:812
boost::shared_ptr< HookeOps::CommonData > commPtr
Definition gradient.cpp:852
boost::shared_ptr< ObjectiveFunctionData > pythonPtr
Definition gradient.cpp:851
boost::shared_ptr< HookeOps::CommonData > commPtr
Definition adjoint.cpp:1548
OpStateSensitivity(const std::string field_name, boost::shared_ptr< ObjectiveFunctionData > python_ptr, boost::shared_ptr< HookeOps::CommonData > comm_ptr, boost::shared_ptr< MatrixDouble > u_ptr)
Definition gradient.cpp:707
MoFEMErrorCode iNtegrate(EntitiesFieldData::EntData &data)
Definition gradient.cpp:714
boost::shared_ptr< MatrixDouble > uPtr
Definition adjoint.cpp:1549
boost::shared_ptr< ObjectiveFunctionData > pythonPtr
Definition adjoint.cpp:1547
PipelineManager::ElementsAndOpsByDim< 2 >::FaceSideEle SideEle
PipelineManager::ElementsAndOpsByDim< 3 >::FaceSideEle SideEle
#define EXECUTABLE_DIMENSION
Definition plastic.cpp:13
PetscBool do_eval_field
Evaluate field.
Definition plastic.cpp:120
ElementsAndOps< SPACE_DIM >::SideEle SideEle
Definition plastic.cpp:62
auto save_range
constexpr int SPACE_DIM
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::BoundaryEle BoundaryEle
PostProcEleByDim< SPACE_DIM >::SideEle SideEle
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::DomainEle DomainEle