v0.16.3
Loading...
Searching...
No Matches
electrostatics.cpp
Go to the documentation of this file.
1/**
2 * @file Electrostatics.cpp
3 * \example mofem/tutorials/scl-12_electrostatics/electrostatics.cpp
4 * */
5
6#ifndef EXECUTABLE_DIMENSION
7#define EXECUTABLE_DIMENSION 3
8#endif
9
10#include <electrostatics.hpp>
11static char help[] = "...\n\n";
13public:
15
16 // Declaration of the main function to run analysis
18
19private:
20 // Declaration of other main functions called in runProgram()
30
31 int oRder = 2; // default order
32 int geomOrder = 1; // default gemoetric order
35 std::string domainField;
36 boost::shared_ptr<std::map<int, BlockData>> permBlockSetsPtr;
37 boost::shared_ptr<std::map<int, BlockData>> intBlockSetsPtr;
38 boost::shared_ptr<std::map<int, BlockData>> electrodeBlockSetsPtr;
39 boost::shared_ptr<DataAtIntegrationPts> commonDataPtr;
40
41 boost::shared_ptr<ForcesAndSourcesCore> interFaceRhsFe;
42 boost::shared_ptr<ForcesAndSourcesCore> electrodeRhsFe;
43
44 double aLpha = 0.0; // declaration for total charge on first electrode
45 double bEta = 0.0; // declaration for total charge on second electrode
46 SmartPetscObj<Vec> petscVec; // petsc vector for the charge solution
47 SmartPetscObj<Vec> petscVecEnergy; // petsc vector for the energy solution
48 PetscBool out_skin = PETSC_FALSE; //
49 PetscBool is_partitioned = PETSC_FALSE;
50 enum VecElements { ZERO = 0, ONE = 1, LAST_ELEMENT };
51 int atomTest = 0;
52};
53
55 : domainField("POTENTIAL"), mField(m_field) {}
56
57//! [Read mesh]
62
64 true; // create lower dimensional element to ensure sharing of partitioed
65 // entities at the boundaries.
67 {"permittivity", "charge_density"});
69 CHKERR mField.getInterface<MeshsetsManager>()->setMeshsetFromFile();
71}
72//! [Read mesh]
73
74//! [Setup problem]
77
78 Range domain_ents;
79 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM, domain_ents,
80 true);
81 auto get_ents_by_dim = [&](const auto dim) {
82 if (dim == SPACE_DIM) {
83 return domain_ents;
84 } else {
85 Range ents;
86 if (dim == 0)
87 CHKERR mField.get_moab().get_connectivity(domain_ents, ents, true);
88 else
89 CHKERR mField.get_moab().get_entities_by_dimension(0, dim, ents, true);
90 return ents;
91 }
92 };
93
94 // Select base for the field based on the element type
95 auto get_base = [&]() {
96 auto domain_ents = get_ents_by_dim(SPACE_DIM);
97 if (domain_ents.empty())
99 const auto type = type_from_handle(domain_ents[0]);
100 switch (type) {
101 case MBQUAD:
103 case MBHEX:
105 case MBTRI:
107 case MBTET:
109 default:
110 CHK_THROW_MESSAGE(MOFEM_NOT_FOUND, "Element type is not handled");
111 }
112 return NOBASE;
113 };
114
115 auto base = get_base();
118
119 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &oRder, PETSC_NULLPTR);
120
121 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-geom_order", &geomOrder,
122 PETSC_NULLPTR);
123
124 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-atom_test", &atomTest,
125 PETSC_NULLPTR);
127 CHKERR simpleInterface->addDataField("GEOMETRY", H1, base, SPACE_DIM);
129
130 auto project_ho_geometry = [&]() {
131 Projection10NodeCoordsOnField ent_method(mField, "GEOMETRY");
132 return mField.loop_dofs("GEOMETRY", ent_method);
133 };
134
136 CHKERR project_ho_geometry();
137
138 commonDataPtr = boost::make_shared<DataAtIntegrationPts>(mField);
139
140 // gets the map of the permittivity attributes and the block sets
141 permBlockSetsPtr = boost::make_shared<std::map<int, BlockData>>();
142 Range mat_electr_ents; // range of entities with the permittivity
144 if (bit->getName().compare(0, 12, "MAT_ELECTRIC") == 0) {
145 const int id = bit->getMeshsetId();
146 auto &block_data = (*permBlockSetsPtr)[id];
147
148 CHKERR mField.get_moab().get_entities_by_dimension(
149 bit->getMeshset(), SPACE_DIM, block_data.domainEnts, true);
150 mat_electr_ents.merge(block_data.domainEnts);
151
152 std::vector<double> attributes;
153 bit->getAttributes(attributes);
154 if (attributes.size() < 1) {
155 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
156 " At least one permittivity attributes should be given but "
157 "found %zu",
158 attributes.size());
159 }
160 block_data.epsPermit = attributes[0];
161 block_data.iD = id; // id of the block
162 }
163 }
164
165 // gets the map of the charge attributes and the block sets
166 intBlockSetsPtr = boost::make_shared<std::map<int, BlockData>>();
167 Range int_electr_ents; // range of entities with the charge
169 if (bit->getName().compare(0, 12, "INT_ELECTRIC") == 0) {
170 const int id = bit->getMeshsetId();
171 auto &block_data = (*intBlockSetsPtr)[id];
172
173 CHKERR mField.get_moab().get_entities_by_dimension(
174 bit->getMeshset(), SPACE_DIM - 1, block_data.interfaceEnts, true);
175 int_electr_ents.merge(block_data.interfaceEnts);
176
177 std::vector<double> attributes;
178 bit->getAttributes(attributes);
179 if (attributes.size() < 1) {
180 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
181 "At least one charge attributes should be given but found %zu",
182 attributes.size());
183 }
184 block_data.chargeDensity = attributes[0];
185
186 block_data.iD = id; // id-> block ID
187 }
188 }
189 // gets the map of the electrode entity range in the block sets
190 electrodeBlockSetsPtr = boost::make_shared<std::map<int, BlockData>>();
191 Range electrode_ents; // range of entities with the electrode
192 int electrodeCount = 0;
194 if (bit->getName().compare(0, 9, "ELECTRODE") == 0) {
195 const int id = bit->getMeshsetId();
196 auto &block_data = (*electrodeBlockSetsPtr)[id];
197 ++electrodeCount;
198
199 CHKERR mField.get_moab().get_entities_by_dimension(
200 bit->getMeshset(), SPACE_DIM - 1, block_data.electrodeEnts, true);
201 electrode_ents.merge(block_data.electrodeEnts);
202
203
204 if (electrodeCount > 2) {
205 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
206 "Three or more electrode blocksets found");
207 ;
208 }
209 }
210 }
211
212 // sync entities
213 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
214 mat_electr_ents);
215 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
216 int_electr_ents);
217 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
218 electrode_ents);
219
220 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-out_skin", &out_skin,
221 PETSC_NULLPTR);
222 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-is_partitioned", &is_partitioned,
223 PETSC_NULLPTR);
224 // get the skin entities
225 Skinner skinner(&mField.get_moab());
226 Range skin_tris;
227 CHKERR skinner.find_skin(0, mat_electr_ents, false, skin_tris);
228 Range proc_skin;
229 ParallelComm *pcomm =
230 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
231 if (is_partitioned) {
232 CHKERR pcomm->filter_pstatus(skin_tris,
233 PSTATUS_SHARED | PSTATUS_MULTISHARED,
234 PSTATUS_NOT, -1, &proc_skin);
235 } else {
236 proc_skin = skin_tris;
237 }
238 // add the skin entities to the field
241 "SKIN");
245 // add the interface entities to the field
246 CHKERR mField.add_finite_element("INTERFACE");
250 CHKERR mField.modify_finite_element_add_field_data("INTERFACE", "GEOMETRY");
251
253 SPACE_DIM - 1, "INTERFACE");
254 // add the electrode entities to the field
255 CHKERR mField.add_finite_element("ELECTRODE");
259 CHKERR mField.modify_finite_element_add_field_data("ELECTRODE", "GEOMETRY");
260
262 "ELECTRODE");
263
264 // sync field entities
265 mField.getInterface<CommInterface>()->synchroniseFieldEntities(domainField);
266 mField.getInterface<CommInterface>()->synchroniseFieldEntities("GEOMETRY");
275
279
280 DMType dm_name = "DMMOFEM";
281 CHKERR DMRegister_MoFEM(dm_name);
282
284 dm = createDM(mField.get_comm(), dm_name);
285
286 // create dm instance
287 CHKERR DMSetType(dm, dm_name);
288
290
291 // initialise petsc vector for required processor
292 int local_size;
293 if (mField.get_comm_rank() == 0) // get_comm_rank() gets processor number
294
295 local_size = LAST_ELEMENT; // last element gives size of vector
296
297 else
298 // other processors (e.g. 1, 2, 3, etc.)
299 local_size = 0; // local size of vector is zero on other processors
300
304}
305//! [Setup problem]
306
307//! [Boundary condition]
310
311 auto bc_mng = mField.getInterface<BcManager>();
312
313 // Remove_BCs_from_blockset name "BOUNDARY_CONDITION";
315 simpleInterface->getProblemName(), "BOUNDARY_CONDITION",
316 std::string(domainField), true);
317
319}
320//! [Boundary condition]
321
322//! [Set integration rules]
325
326 auto rule_lhs = [this](int, int, int p) -> int { return 2 * p + geomOrder -1; };
327 auto rule_rhs = [this](int, int, int p) -> int { return 2 * p + geomOrder -1; };
328
329 auto pipeline_mng = mField.getInterface<PipelineManager>();
330 CHKERR pipeline_mng->setDomainLhsIntegrationRule(rule_lhs);
331 CHKERR pipeline_mng->setDomainRhsIntegrationRule(rule_rhs);
332
334}
335//! [Set integration rules]
336
337//! [Assemble system]
340
341 auto pipeline_mng = mField.getInterface<PipelineManager>();
342 commonDataPtr = boost::make_shared<DataAtIntegrationPts>(mField);
343
344 auto add_domain_base_ops = [&](auto &pipeline) {
346 "GEOMETRY");
347
348 pipeline.push_back(
350 };
351
352 add_domain_base_ops(pipeline_mng->getOpDomainLhsPipeline());
353 auto epsilon = [&](const double, const double, const double) {
354 return commonDataPtr->blockPermittivity;
355 };
356
357 { // Push operators to the Pipeline that is responsible for calculating LHS
358 pipeline_mng->getOpDomainLhsPipeline().push_back(
360 }
361
362 { // Push operators to the Pipeline that is responsible for calculating RHS
363 auto set_values_to_bc_dofs = [&](auto &fe) {
364 auto get_bc_hook = [&]() {
366 return hook;
367 };
368 fe->preProcessHook = get_bc_hook();
369 };
370 // Set essential BC
371 auto calculate_residual_from_set_values_on_bc = [&](auto &pipeline) {
372 using OpInternal =
375
376 add_domain_base_ops(pipeline_mng->getOpDomainRhsPipeline());
377
378 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
379 pipeline_mng->getOpDomainRhsPipeline().push_back(
381 grad_u_ptr));
382 auto minus_epsilon = [&](double, double, double) constexpr {
383 return -commonDataPtr->blockPermittivity;
384 };
385 pipeline_mng->getOpDomainRhsPipeline().push_back(
386 new OpInternal(domainField, grad_u_ptr, minus_epsilon));
387 };
388
389 set_values_to_bc_dofs(pipeline_mng->getDomainRhsFE());
390 calculate_residual_from_set_values_on_bc(
391 pipeline_mng->getOpDomainRhsPipeline());
392
393 auto bodySourceTerm = [&](const double, const double, const double) {
394 return bodySource;
395 };
396 pipeline_mng->getOpDomainRhsPipeline().push_back(
397 new OpBodySourceVectorb(domainField, bodySourceTerm));
398 }
399
400 interFaceRhsFe = boost::shared_ptr<ForcesAndSourcesCore>(
402 interFaceRhsFe->getRuleHook = [this](int, int, int p) {
403 return 2 * p + geomOrder -1;
404 };
405
406 {
407
409 interFaceRhsFe->getOpPtrVector(), {NOSPACE}, "GEOMETRY");
410
411 interFaceRhsFe->getOpPtrVector().push_back(
413
414 auto sIgma = [&](const double, const double, const double) {
415 return commonDataPtr->blockChrgDens;
416 };
417
418 interFaceRhsFe->getOpPtrVector().push_back(
420 }
421
423}
424//! [Assemble system]
425
426//! [Solve system]
429
430 auto pipeline_mng = mField.getInterface<PipelineManager>();
431
432 auto ksp_solver = pipeline_mng->createKSP();
433
434 boost::shared_ptr<ForcesAndSourcesCore> null; ///< Null element does
435 DM dm;
437
438 CHKERR DMMoFEMKSPSetComputeRHS(dm, "INTERFACE", interFaceRhsFe, null, null);
439
440 CHKERR KSPSetFromOptions(ksp_solver);
441
442 // Create RHS and solution vectors
443 auto F = createDMVector(dm);
444 auto D = vectorDuplicate(F);
445 // Solve the system
446 CHKERR KSPSetUp(ksp_solver);
447 CHKERR KSPSolve(ksp_solver, F, D);
448 CHKERR mField.getInterface<TestingInterface>()->checkSolver(ksp_solver,
449 "electrostatics");
450
451 CHKERR VecGhostUpdateBegin(F, INSERT_VALUES, SCATTER_FORWARD);
452 CHKERR VecGhostUpdateEnd(F, INSERT_VALUES, SCATTER_FORWARD);
453
454 double fnorm;
455 CHKERR VecNorm(F, NORM_2, &fnorm);
456 CHKERR PetscPrintf(PETSC_COMM_WORLD, "F norm = %9.8e\n", fnorm);
457
458 // Scatter result data on the mesh
459 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
460 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
461
462 double dnorm;
463 CHKERR VecNorm(D, NORM_2, &dnorm);
464 CHKERR PetscPrintf(PETSC_COMM_WORLD, "D norm = %9.8e\n", dnorm);
465
466 CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
467
469}
470//! [Solve system]
471
472//! [Output results]
475 auto pipeline_mng = mField.getInterface<PipelineManager>();
476 auto post_proc_fe = boost::make_shared<PostProcEle>(mField);
477
478 // lamda function to calculate electric field
479 auto calculate_e_field = [&](auto &pipeline) {
480 auto u_ptr = boost::make_shared<VectorDouble>();
481 auto x_ptr = boost::make_shared<MatrixDouble>();
482 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
483 auto e_field_ptr = boost::make_shared<MatrixDouble>();
484 // add higher order operator
486 "GEOMETRY");
487 // calculate field values
488 pipeline.push_back(new OpCalculateScalarFieldValues(domainField, u_ptr));
489 pipeline.push_back(
490 new OpCalculateVectorFieldValues<SPACE_DIM>("GEOMETRY", x_ptr));
491
492 // calculate gradient
493 pipeline.push_back(
495 // calculate electric field
496 pipeline.push_back(new OpElectricField(e_field_ptr, grad_u_ptr));
497 return boost::make_tuple(u_ptr, e_field_ptr, x_ptr);
498 };
499
500 auto [u_ptr, e_field_ptr, x_ptr] =
501 calculate_e_field(post_proc_fe->getOpPtrVector());
502
503 auto e_field_times_perm_ptr = boost::make_shared<MatrixDouble>();
504 auto energy_density_ptr = boost::make_shared<VectorDouble>();
505
506 post_proc_fe->getOpPtrVector().push_back(
507 new OpGradTimesPerm(domainField, e_field_ptr, e_field_times_perm_ptr,
509 post_proc_fe->getOpPtrVector().push_back(
510 new OpEnergyDensity(domainField, e_field_ptr, energy_density_ptr,
512
514 post_proc_fe->getOpPtrVector().push_back(new OpPPMap(
515 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
516
517 OpPPMap::DataMapVec{{"POTENTIAL", u_ptr},
518 {"ENERGY_DENSITY", energy_density_ptr}},
520 {"GEOMETRY", x_ptr},
521 {"ELECTRIC_FIELD", e_field_ptr},
522 {"ELECTRIC_DISPLACEMENT", e_field_times_perm_ptr},
523 },
525
527
528 );
529
530 pipeline_mng->getDomainPostProcFE() = post_proc_fe;
531 CHKERR pipeline_mng->loopFiniteElementsPostProc();
532 CHKERR post_proc_fe->writeFile("out.h5m");
533
534 if (out_skin && SPACE_DIM == 3) {
535
536 auto post_proc_skin = boost::make_shared<PostProcFaceEle>(mField);
537 auto op_loop_skin = new OpLoopSide<SideEle>(
538 mField, simpleInterface->getDomainFEName(), SPACE_DIM);
539
540 auto [u_ptr, e_field_ptr, x_ptr] =
541 calculate_e_field(op_loop_skin->getOpPtrVector());
542
543 op_loop_skin->getOpPtrVector().push_back(
544 new OpGradTimesPerm(domainField, e_field_ptr, e_field_times_perm_ptr,
545 permBlockSetsPtr, commonDataPtr));
546 op_loop_skin->getOpPtrVector().push_back(
547 new OpEnergyDensity(domainField, e_field_ptr, energy_density_ptr,
548 permBlockSetsPtr, commonDataPtr));
549
550 // push op to boundary element
551 post_proc_skin->getOpPtrVector().push_back(op_loop_skin);
552
553 post_proc_skin->getOpPtrVector().push_back(new OpPPMap(
554 post_proc_skin->getPostProcMesh(), post_proc_skin->getMapGaussPts(),
555 OpPPMap::DataMapVec{{"POTENTIAL", u_ptr},
556 {"ENERGY_DENSITY", energy_density_ptr}},
557 OpPPMap::DataMapMat{{"ELECTRIC_FIELD", e_field_ptr},
558 {"GEOMETRY", x_ptr},
559 {"ELECTRIC_DISPLACEMENT", e_field_times_perm_ptr}},
561
562 CHKERR DMoFEMLoopFiniteElements(simpleInterface->getDM(), "SKIN",
563 post_proc_skin);
564 CHKERR post_proc_skin->writeFile("out_skin.h5m");
565 }
567}
568//! [Output results]
569
570//! [Get Total Energy]
573 auto pip_energy = mField.getInterface<PipelineManager>();
574
575 auto rule = [this](int, int, int p) { return 2 * p + geomOrder - 1; };
576 CHKERR pip_energy->setEvaluationIntegrationRule(rule);
577 auto &evaluation_pipeline = pip_energy->getOpEvaluationPipeline();
578
579 // gets the map of the internal domain entity range to get the total energy
580
581 boost::shared_ptr<std::map<int, BlockData>> intrnlDomnBlckSetPtr =
582 boost::make_shared<std::map<int, BlockData>>();
583 Range internal_domain; // range of entities marked the internal domain
585 if (bit->getName().compare(0, 10, "DOMAIN_INT") == 0) {
586 const int id = bit->getMeshsetId();
587 auto &block_data = (*intrnlDomnBlckSetPtr)[id];
588
589 CHKERR mField.get_moab().get_entities_by_dimension(
590 bit->getMeshset(), SPACE_DIM, block_data.internalDomainEnts, true);
591 internal_domain.merge(block_data.internalDomainEnts);
592 block_data.iD = id;
593 }
594 }
595 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
596 internal_domain);
597
599 {H1}, "GEOMETRY");
600
601 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
602 auto e_field_ptr = boost::make_shared<MatrixDouble>();
603
604 evaluation_pipeline.push_back(
606 evaluation_pipeline.push_back(new OpElectricField(e_field_ptr, grad_u_ptr));
607
608 commonDataPtr = boost::make_shared<DataAtIntegrationPts>(mField);
609
610 evaluation_pipeline.push_back(
612 intrnlDomnBlckSetPtr, commonDataPtr, petscVecEnergy));
613
614 CHKERR pip_energy->loopFiniteElementsEvaluation();
615 CHKERR VecAssemblyBegin(petscVecEnergy);
616 CHKERR VecAssemblyEnd(petscVecEnergy);
617
618 double total_energy = 0.0; // declaration for total energy
619 if (!mField.get_comm_rank()) {
620 const double *array;
621
622 CHKERR VecGetArrayRead(petscVecEnergy, &array);
623 total_energy = array[ZERO];
624 MOFEM_LOG_CHANNEL("SELF");
625 MOFEM_LOG_C("SELF", Sev::inform, "Total Energy: %6.15f", total_energy);
626 CHKERR VecRestoreArrayRead(petscVecEnergy, &array);
627 }
628
630}
631//! [Get Total Energy]
632
633//! [Get Charges]
636 auto op_loop_side = new OpLoopSide<SideEle>(
638
640 op_loop_side->getOpPtrVector(), {H1}, "GEOMETRY");
641
642 auto grad_u_ptr_charge = boost::make_shared<MatrixDouble>();
643 auto e_ptr_charge = boost::make_shared<MatrixDouble>();
644
645 op_loop_side->getOpPtrVector().push_back(
647 grad_u_ptr_charge));
648
649 op_loop_side->getOpPtrVector().push_back(
650 new OpElectricField(e_ptr_charge, grad_u_ptr_charge));
651 auto d_jump = boost::make_shared<MatrixDouble>();
652 op_loop_side->getOpPtrVector().push_back(new OpElectricDispJump<SPACE_DIM>(
653 domainField, e_ptr_charge, d_jump, commonDataPtr, permBlockSetsPtr));
654
655 electrodeRhsFe = boost::shared_ptr<ForcesAndSourcesCore>(
657 electrodeRhsFe->getRuleHook = [this](int, int, int p) {
658 return 2 * p + geomOrder -1;
659 };
660
661 // push all the operators in on the side to the electrodeRhsFe
662 electrodeRhsFe->getOpPtrVector().push_back(op_loop_side);
663
664 electrodeRhsFe->getOpPtrVector().push_back(new OpElectrodeCharge<SPACE_DIM>(
666 CHKERR VecZeroEntries(petscVec);
668 "ELECTRODE", electrodeRhsFe, 0,
670 CHKERR VecAssemblyBegin(petscVec);
671 CHKERR VecAssemblyEnd(petscVec);
672
673 if (!mField.get_comm_rank()) {
674 const double *array;
675
676 CHKERR(VecGetArrayRead(petscVec, &array));
677 double aLpha = array[0]; // Use explicit index instead of ZERO
678 double bEta = array[1]; // Use explicit index instead of ONE
679 MOFEM_LOG_CHANNEL("SELF");
680 MOFEM_LOG_C("SELF", Sev::inform,
681 "CHARGE_ELEC_1: %6.15f , CHARGE_ELEC_2: %6.15f", aLpha, bEta);
682
683 CHKERR(VecRestoreArrayRead(petscVec, &array));
684 }
685 if (atomTest && !mField.get_comm_rank()) {
686 double cal_charge_elec1;
687 double cal_charge_elec2;
688 double cal_total_energy;
689 const double *c_ptr, *te_ptr;
690
691 // Get a pointer to the PETSc vector data
692 CHKERR(VecGetArrayRead(petscVec, &c_ptr));
693 CHKERR(VecGetArrayRead(petscVecEnergy, &te_ptr));
694
695 // Expected charges at the electrodes
696 double ref_charge_elec1;
697 double ref_charge_elec2;
698 // Expected total energy of the system
699 double ref_tot_energy;
700 double tol;
701 cal_charge_elec1 = c_ptr[0]; // Read charge at the first electrode
702 cal_charge_elec2 = c_ptr[1]; // Read charge at the second electrode
703 cal_total_energy = te_ptr[0]; // Read total energy of the system
704 if (std::isnan(cal_charge_elec1) || std::isnan(cal_charge_elec2) ||
705 std::isnan(cal_total_energy)) {
706 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
707 "Atom test failed! NaN detected in calculated values.");
708 }
709 switch (atomTest) {
710 case 1: // 2D & 3D test
711 case 3: // JSON clear-block 2D test
712 // Expected charges at the electrodes
713 ref_charge_elec1 = 50.0;
714 ref_charge_elec2 = -50.0;
715 // Expected total energy of the system
716 ref_tot_energy = 500.0;
717 tol = 1e-10;
718 break;
719 case 2: // wavy 3D test
720 ref_charge_elec1 = 10.00968352472943;
721 ref_charge_elec2 = 0.0; // no electrode
722 ref_tot_energy = 50.5978;
723 tol = 1e-4;
724 break;
725 default:
726 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
727 "atom test %d does not exist", atomTest);
728 }
729
730 // Validate the results
731 if (std::abs(ref_charge_elec1 - cal_charge_elec1) > tol ||
732 std::abs(ref_charge_elec2 - cal_charge_elec2) > tol ||
733 std::abs(ref_tot_energy - cal_total_energy) > tol) {
734 SETERRQ(
735 PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
736 "atom test %d failed! Calculated values do not match expected values",
737 atomTest);
738 }
739
740 CHKERR(VecRestoreArrayRead(petscVec,
741 &c_ptr)); // Restore the PETSc vector array
742 CHKERR(VecRestoreArrayRead(petscVecEnergy, &te_ptr));
743 }
744
746}
747//! [Get Charges]
748
749//! [Run program]
764//! [Run program]
765
766//! [Main]
767int main(int argc, char *argv[]) {
768 // Initialisation of MoFEM/PETSc and MOAB data structures
769 const char param_file[] = "param_file.petsc";
770 MoFEM::Core::Initialize(&argc, &argv, param_file, help);
771
772 // Error handling
773 try {
774 // Register MoFEM discrete manager in PETSc
775 DMType dm_name = "DMMOFEM";
776 CHKERR DMRegister_MoFEM(dm_name);
777
778 // Create MOAB instance
779 moab::Core mb_instance; // mesh database
780 moab::Interface &moab = mb_instance; // mesh database interface
781
782 // Create MoFEM instance
783 MoFEM::Core core(moab); // finite element database
784 MoFEM::Interface &m_field = core; // finite element interface
785
786 // Run the main analysis
787 Electrostatics Electrostatics_problem(m_field);
788 CHKERR Electrostatics_problem.runProgram();
789 }
791
792 // Finish work: cleaning memory, getting statistics, etc.
794
795 return 0;
796}
797//! [Main]
std::string type
#define MOFEM_LOG_C(channel, severity, format,...)
TestHook hook
int main()
constexpr int SPACE_DIM
#define CATCH_ERRORS
Catch errors.
@ MF_ZERO
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
@ NOBASE
Definition definitions.h:59
@ DEMKOWICZ_JACOBI_BASE
Definition definitions.h:66
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
@ H1
continuous field
Definition definitions.h:85
#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 ...
@ BLOCKSET
@ MOFEM_NOT_FOUND
Definition definitions.h:33
@ MOFEM_ATOM_TEST_INVALID
Definition definitions.h:40
@ 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.
static char help[]
FormsIntegrators< IntEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpSource< BASE_DIM, FIELD_DIM > OpInterfaceRhsVectorF
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpGradGrad< BASE_DIM, FIELD_DIM, SPACE_DIM > OpDomainLhsMatrixK
constexpr auto domainField
intPostProc< SPACE_DIM >::intEle IntElementForcesAndSourcesCore
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpSource< BASE_DIM, FIELD_DIM > OpBodySourceVectorb
const double bodySource
@ F
PetscErrorCode DMMoFEMAddElement(DM dm, std::string fe_name)
add element to dm
Definition DMMoFEM.cpp:517
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:543
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
Definition DMMoFEM.cpp:43
PetscErrorCode DMMoFEMKSPSetComputeRHS(DM dm, const char fe_name[], MoFEM::FEMethod *method, MoFEM::BasicMethod *pre_only, MoFEM::BasicMethod *post_only)
set KSP right hand side evaluation function
Definition DMMoFEM.cpp:656
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:605
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
Definition DMMoFEM.hpp:1250
PetscErrorCode DMoFEMLoopFiniteElementsUpAndLowRank(DM dm, const char fe_name[], MoFEM::FEMethod *method, int low_rank, int up_rank, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
Definition DMMoFEM.cpp:586
SmartPetscObj< KSP > createKSP(SmartPetscObj< DM > dm=nullptr)
Create KSP (linear) solver.
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
@ GAUSS
Gaussian quadrature integration.
@ PETSC
Standard PETSc assembly.
#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.
#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.
MoFEMErrorCode removeBlockDOFsOnEntities(const std::string problem_name, const std::string block_name, const std::string field_name, int lo, int hi, bool get_low_dim_ents=true, bool is_distributed_mesh=true)
Remove DOFs from problem based on block entities.
Definition BcManager.cpp:72
auto bit
set bit
double D
double tol
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
auto type_from_handle(const EntityHandle h)
get type from entity handle
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.
auto createVectorMPI(MPI_Comm comm, PetscInt n, PetscInt N)
Create MPI Vector.
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
FormsIntegrators< DomainEleOp >::Assembly< A >::LinearForm< I >::OpGradTimesTensor< 1, FIELD_DIM, SPACE_DIM > OpGradTimesTensor
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
boost::shared_ptr< ForcesAndSourcesCore > electrodeRhsFe
boost::shared_ptr< ForcesAndSourcesCore > interFaceRhsFe
boost::shared_ptr< std::map< int, BlockData > > intBlockSetsPtr
SmartPetscObj< Vec > petscVec
boost::shared_ptr< DataAtIntegrationPts > commonDataPtr
MoFEM::Interface & mField
std::string domainField
MoFEMErrorCode runProgram()
[Get Charges]
MoFEMErrorCode setupProblem()
[Read mesh]
MoFEMErrorCode outputResults()
[Solve system]
MoFEMErrorCode setIntegrationRules()
[Boundary condition]
Electrostatics(MoFEM::Interface &m_field)
MoFEMErrorCode getElectrodeCharge()
[Get Total Energy]
MoFEMErrorCode readMesh()
[Read mesh]
Simple * simpleInterface
SmartPetscObj< Vec > petscVecEnergy
boost::shared_ptr< std::map< int, BlockData > > permBlockSetsPtr
MoFEMErrorCode assembleSystem()
[Set integration rules]
PetscBool is_partitioned
boost::shared_ptr< std::map< int, BlockData > > electrodeBlockSetsPtr
MoFEMErrorCode getTotalEnergy()
[Output results]
MoFEMErrorCode boundaryCondition()
[Setup problem]
MoFEMErrorCode solveSystem()
[Assemble system]
Add operators pushing bases from local to physical configuration.
Boundary condition manager for finite element problem setup.
Template specialization for scalar field boundary conditions.
Managing BitRefLevels.
virtual int get_comm_size() const =0
virtual moab::Interface & get_moab()=0
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.
Class (Function) to enforce essential constrains.
Definition Essential.hpp:25
static MoFEMErrorCode addCanonicalAttributeNames(const std::vector< std::string > &names)
Interface for managing meshsets containing materials and boundary conditions.
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Specialization for double precision scalar field values calculation.
Specialization for MatrixDouble vector field values calculation.
Element used to execute operators on side of the element.
Post post-proc data at points from hash maps.
std::map< std::string, ScalarDataPtr > DataMapVec
std::map< std::string, boost::shared_ptr< MatrixDouble > > DataMapMat
PipelineManager interface.
MoFEMErrorCode setEvaluationIntegrationRule(RuleHookFun rule)
Set integration rule for domain evaluation finite element.
boost::shared_ptr< FEMethod > & getDomainPostProcFE()
Get domain postprocessing finite element.
MoFEMErrorCode setDomainLhsIntegrationRule(RuleHookFun rule)
Set integration rule for domain left-hand side finite element.
Projection of edge entities with one mid-node on hierarchical basis.
Simple interface for fast problem set-up.
Definition Simple.hpp:27
MoFEMErrorCode buildProblem()
Build problem.
Definition Simple.cpp:721
MoFEMErrorCode addDomainField(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_ZERO, int verb=-1)
Add field on domain.
Definition Simple.cpp:261
MoFEMErrorCode defineFiniteElements()
Define finite elements.
Definition Simple.cpp:471
MoFEMErrorCode loadFile(const std::string options, const std::string mesh_file_name, LoadFileFunc loadFunc=defaultLoadFileFunc)
Load mesh file.
Definition Simple.cpp:191
MoFEMErrorCode buildFiniteElements()
Build finite elements.
Definition Simple.cpp:659
MoFEMErrorCode addBoundaryField(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_ZERO, int verb=-1)
Add field on boundary.
Definition Simple.cpp:355
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180
MoFEMErrorCode getDM(DM *dm)
Get DM.
Definition Simple.cpp:799
MoFEMErrorCode buildFields()
Build fields.
Definition Simple.cpp:584
MoFEMErrorCode setFieldOrder(const std::string field_name, const int order, const Range *ents=NULL)
Set field order.
Definition Simple.cpp:575
MoFEMErrorCode defineProblem(const PetscBool is_partitioned=PETSC_TRUE)
define problem
Definition Simple.cpp:551
MoFEMErrorCode addDataField(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_ZERO, int verb=-1)
Add data field.
Definition Simple.cpp:393
bool & getAddSkeletonFE()
Get the addSkeletonFE flag.
Definition Simple.hpp:536
MoFEMErrorCode setUp(const PetscBool is_partitioned=PETSC_TRUE)
Setup problem.
Definition Simple.cpp:735
const std::string getProblemName() const
Get the Problem Name.
Definition Simple.hpp:450
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.