v0.16.0
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
449 CHKERR VecGhostUpdateBegin(F, INSERT_VALUES, SCATTER_FORWARD);
450 CHKERR VecGhostUpdateEnd(F, INSERT_VALUES, SCATTER_FORWARD);
451
452 double fnorm;
453 CHKERR VecNorm(F, NORM_2, &fnorm);
454 CHKERR PetscPrintf(PETSC_COMM_WORLD, "F norm = %9.8e\n", fnorm);
455
456 // Scatter result data on the mesh
457 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
458 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
459
460 double dnorm;
461 CHKERR VecNorm(D, NORM_2, &dnorm);
462 CHKERR PetscPrintf(PETSC_COMM_WORLD, "D norm = %9.8e\n", dnorm);
463
464 CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
465
467}
468//! [Solve system]
469
470//! [Output results]
473 auto pipeline_mng = mField.getInterface<PipelineManager>();
474 auto post_proc_fe = boost::make_shared<PostProcEle>(mField);
475
476 // lamda function to calculate electric field
477 auto calculate_e_field = [&](auto &pipeline) {
478 auto u_ptr = boost::make_shared<VectorDouble>();
479 auto x_ptr = boost::make_shared<MatrixDouble>();
480 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
481 auto e_field_ptr = boost::make_shared<MatrixDouble>();
482 // add higher order operator
484 "GEOMETRY");
485 // calculate field values
486 pipeline.push_back(new OpCalculateScalarFieldValues(domainField, u_ptr));
487 pipeline.push_back(
488 new OpCalculateVectorFieldValues<SPACE_DIM>("GEOMETRY", x_ptr));
489
490 // calculate gradient
491 pipeline.push_back(
493 // calculate electric field
494 pipeline.push_back(new OpElectricField(e_field_ptr, grad_u_ptr));
495 return boost::make_tuple(u_ptr, e_field_ptr, x_ptr);
496 };
497
498 auto [u_ptr, e_field_ptr, x_ptr] =
499 calculate_e_field(post_proc_fe->getOpPtrVector());
500
501 auto e_field_times_perm_ptr = boost::make_shared<MatrixDouble>();
502 auto energy_density_ptr = boost::make_shared<VectorDouble>();
503
504 post_proc_fe->getOpPtrVector().push_back(
505 new OpGradTimesPerm(domainField, e_field_ptr, e_field_times_perm_ptr,
507 post_proc_fe->getOpPtrVector().push_back(
508 new OpEnergyDensity(domainField, e_field_ptr, energy_density_ptr,
510
512 post_proc_fe->getOpPtrVector().push_back(new OpPPMap(
513 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
514
515 OpPPMap::DataMapVec{{"POTENTIAL", u_ptr},
516 {"ENERGY_DENSITY", energy_density_ptr}},
518 {"GEOMETRY", x_ptr},
519 {"ELECTRIC_FIELD", e_field_ptr},
520 {"ELECTRIC_DISPLACEMENT", e_field_times_perm_ptr},
521 },
523
525
526 );
527
528 pipeline_mng->getDomainPostProcFE() = post_proc_fe;
529 CHKERR pipeline_mng->loopFiniteElementsPostProc();
530 CHKERR post_proc_fe->writeFile("out.h5m");
531
532 if (out_skin && SPACE_DIM == 3) {
533
534 auto post_proc_skin = boost::make_shared<PostProcFaceEle>(mField);
535 auto op_loop_skin = new OpLoopSide<SideEle>(
536 mField, simpleInterface->getDomainFEName(), SPACE_DIM);
537
538 auto [u_ptr, e_field_ptr, x_ptr] =
539 calculate_e_field(op_loop_skin->getOpPtrVector());
540
541 op_loop_skin->getOpPtrVector().push_back(
542 new OpGradTimesPerm(domainField, e_field_ptr, e_field_times_perm_ptr,
543 permBlockSetsPtr, commonDataPtr));
544 op_loop_skin->getOpPtrVector().push_back(
545 new OpEnergyDensity(domainField, e_field_ptr, energy_density_ptr,
546 permBlockSetsPtr, commonDataPtr));
547
548 // push op to boundary element
549 post_proc_skin->getOpPtrVector().push_back(op_loop_skin);
550
551 post_proc_skin->getOpPtrVector().push_back(new OpPPMap(
552 post_proc_skin->getPostProcMesh(), post_proc_skin->getMapGaussPts(),
553 OpPPMap::DataMapVec{{"POTENTIAL", u_ptr},
554 {"ENERGY_DENSITY", energy_density_ptr}},
555 OpPPMap::DataMapMat{{"ELECTRIC_FIELD", e_field_ptr},
556 {"GEOMETRY", x_ptr},
557 {"ELECTRIC_DISPLACEMENT", e_field_times_perm_ptr}},
559
560 CHKERR DMoFEMLoopFiniteElements(simpleInterface->getDM(), "SKIN",
561 post_proc_skin);
562 CHKERR post_proc_skin->writeFile("out_skin.h5m");
563 }
565}
566//! [Output results]
567
568//! [Get Total Energy]
571 auto pip_energy = mField.getInterface<PipelineManager>();
572
573 auto rule = [this](int, int, int p) { return 2 * p + geomOrder - 1; };
574 CHKERR pip_energy->setEvaluationIntegrationRule(rule);
575 auto &evaluation_pipeline = pip_energy->getOpEvaluationPipeline();
576
577 // gets the map of the internal domain entity range to get the total energy
578
579 boost::shared_ptr<std::map<int, BlockData>> intrnlDomnBlckSetPtr =
580 boost::make_shared<std::map<int, BlockData>>();
581 Range internal_domain; // range of entities marked the internal domain
583 if (bit->getName().compare(0, 10, "DOMAIN_INT") == 0) {
584 const int id = bit->getMeshsetId();
585 auto &block_data = (*intrnlDomnBlckSetPtr)[id];
586
587 CHKERR mField.get_moab().get_entities_by_dimension(
588 bit->getMeshset(), SPACE_DIM, block_data.internalDomainEnts, true);
589 internal_domain.merge(block_data.internalDomainEnts);
590 block_data.iD = id;
591 }
592 }
593 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
594 internal_domain);
595
597 {H1}, "GEOMETRY");
598
599 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
600 auto e_field_ptr = boost::make_shared<MatrixDouble>();
601
602 evaluation_pipeline.push_back(
604 evaluation_pipeline.push_back(new OpElectricField(e_field_ptr, grad_u_ptr));
605
606 commonDataPtr = boost::make_shared<DataAtIntegrationPts>(mField);
607
608 evaluation_pipeline.push_back(
610 intrnlDomnBlckSetPtr, commonDataPtr, petscVecEnergy));
611
612 CHKERR pip_energy->loopFiniteElementsEvaluation();
613 CHKERR VecAssemblyBegin(petscVecEnergy);
614 CHKERR VecAssemblyEnd(petscVecEnergy);
615
616 double total_energy = 0.0; // declaration for total energy
617 if (!mField.get_comm_rank()) {
618 const double *array;
619
620 CHKERR VecGetArrayRead(petscVecEnergy, &array);
621 total_energy = array[ZERO];
622 MOFEM_LOG_CHANNEL("SELF");
623 MOFEM_LOG_C("SELF", Sev::inform, "Total Energy: %6.15f", total_energy);
624 CHKERR VecRestoreArrayRead(petscVecEnergy, &array);
625 }
626
628}
629//! [Get Total Energy]
630
631//! [Get Charges]
634 auto op_loop_side = new OpLoopSide<SideEle>(
636
638 op_loop_side->getOpPtrVector(), {H1}, "GEOMETRY");
639
640 auto grad_u_ptr_charge = boost::make_shared<MatrixDouble>();
641 auto e_ptr_charge = boost::make_shared<MatrixDouble>();
642
643 op_loop_side->getOpPtrVector().push_back(
645 grad_u_ptr_charge));
646
647 op_loop_side->getOpPtrVector().push_back(
648 new OpElectricField(e_ptr_charge, grad_u_ptr_charge));
649 auto d_jump = boost::make_shared<MatrixDouble>();
650 op_loop_side->getOpPtrVector().push_back(new OpElectricDispJump<SPACE_DIM>(
651 domainField, e_ptr_charge, d_jump, commonDataPtr, permBlockSetsPtr));
652
653 electrodeRhsFe = boost::shared_ptr<ForcesAndSourcesCore>(
655 electrodeRhsFe->getRuleHook = [this](int, int, int p) {
656 return 2 * p + geomOrder -1;
657 };
658
659 // push all the operators in on the side to the electrodeRhsFe
660 electrodeRhsFe->getOpPtrVector().push_back(op_loop_side);
661
662 electrodeRhsFe->getOpPtrVector().push_back(new OpElectrodeCharge<SPACE_DIM>(
664 CHKERR VecZeroEntries(petscVec);
666 "ELECTRODE", electrodeRhsFe, 0,
668 CHKERR VecAssemblyBegin(petscVec);
669 CHKERR VecAssemblyEnd(petscVec);
670
671 if (!mField.get_comm_rank()) {
672 const double *array;
673
674 CHKERR(VecGetArrayRead(petscVec, &array));
675 double aLpha = array[0]; // Use explicit index instead of ZERO
676 double bEta = array[1]; // Use explicit index instead of ONE
677 MOFEM_LOG_CHANNEL("SELF");
678 MOFEM_LOG_C("SELF", Sev::inform,
679 "CHARGE_ELEC_1: %6.15f , CHARGE_ELEC_2: %6.15f", aLpha, bEta);
680
681 CHKERR(VecRestoreArrayRead(petscVec, &array));
682 }
683 if (atomTest && !mField.get_comm_rank()) {
684 double cal_charge_elec1;
685 double cal_charge_elec2;
686 double cal_total_energy;
687 const double *c_ptr, *te_ptr;
688
689 // Get a pointer to the PETSc vector data
690 CHKERR(VecGetArrayRead(petscVec, &c_ptr));
691 CHKERR(VecGetArrayRead(petscVecEnergy, &te_ptr));
692
693 // Expected charges at the electrodes
694 double ref_charge_elec1;
695 double ref_charge_elec2;
696 // Expected total energy of the system
697 double ref_tot_energy;
698 double tol;
699 cal_charge_elec1 = c_ptr[0]; // Read charge at the first electrode
700 cal_charge_elec2 = c_ptr[1]; // Read charge at the second electrode
701 cal_total_energy = te_ptr[0]; // Read total energy of the system
702 if (std::isnan(cal_charge_elec1) || std::isnan(cal_charge_elec2) ||
703 std::isnan(cal_total_energy)) {
704 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
705 "Atom test failed! NaN detected in calculated values.");
706 }
707 switch (atomTest) {
708 case 1: // 2D & 3D test
709 case 3: // JSON clear-block 2D test
710 // Expected charges at the electrodes
711 ref_charge_elec1 = 50.0;
712 ref_charge_elec2 = -50.0;
713 // Expected total energy of the system
714 ref_tot_energy = 500.0;
715 tol = 1e-10;
716 break;
717 case 2: // wavy 3D test
718 ref_charge_elec1 = 10.00968352472943;
719 ref_charge_elec2 = 0.0; // no electrode
720 ref_tot_energy = 50.5978;
721 tol = 1e-4;
722 break;
723 default:
724 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
725 "atom test %d does not exist", atomTest);
726 }
727
728 // Validate the results
729 if (std::abs(ref_charge_elec1 - cal_charge_elec1) > tol ||
730 std::abs(ref_charge_elec2 - cal_charge_elec2) > tol ||
731 std::abs(ref_tot_energy - cal_total_energy) > tol) {
732 SETERRQ(
733 PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
734 "atom test %d failed! Calculated values do not match expected values",
735 atomTest);
736 }
737
738 CHKERR(VecRestoreArrayRead(petscVec,
739 &c_ptr)); // Restore the PETSc vector array
740 CHKERR(VecRestoreArrayRead(petscVecEnergy, &te_ptr));
741 }
742
744}
745//! [Get Charges]
746
747//! [Run program]
762//! [Run program]
763
764//! [Main]
765int main(int argc, char *argv[]) {
766 // Initialisation of MoFEM/PETSc and MOAB data structures
767 const char param_file[] = "param_file.petsc";
768 MoFEM::Core::Initialize(&argc, &argv, param_file, help);
769
770 // Error handling
771 try {
772 // Register MoFEM discrete manager in PETSc
773 DMType dm_name = "DMMOFEM";
774 CHKERR DMRegister_MoFEM(dm_name);
775
776 // Create MOAB instance
777 moab::Core mb_instance; // mesh database
778 moab::Interface &moab = mb_instance; // mesh database interface
779
780 // Create MoFEM instance
781 MoFEM::Core core(moab); // finite element database
782 MoFEM::Interface &m_field = core; // finite element interface
783
784 // Run the main analysis
785 Electrostatics Electrostatics_problem(m_field);
786 CHKERR Electrostatics_problem.runProgram();
787 }
789
790 // Finish work: cleaning memory, getting statistics, etc.
792
793 return 0;
794}
795//! [Main]
std::string type
#define MOFEM_LOG_C(channel, severity, format,...)
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:488
PetscErrorCode DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode, RowColData rc=RowColData::COL)
set local (or ghosted) vector values on mesh for partition only
Definition DMMoFEM.cpp:514
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
Definition DMMoFEM.cpp:43
PetscErrorCode 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:627
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
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:557
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.