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 CHKERR mField.getInterface<MeshsetsManager>()->setMeshsetFromFile();
69}
70//! [Read mesh]
71
72//! [Setup problem]
75
76 Range domain_ents;
77 CHKERR mField.get_moab().get_entities_by_dimension(0, SPACE_DIM, domain_ents,
78 true);
79 auto get_ents_by_dim = [&](const auto dim) {
80 if (dim == SPACE_DIM) {
81 return domain_ents;
82 } else {
83 Range ents;
84 if (dim == 0)
85 CHKERR mField.get_moab().get_connectivity(domain_ents, ents, true);
86 else
87 CHKERR mField.get_moab().get_entities_by_dimension(0, dim, ents, true);
88 return ents;
89 }
90 };
91
92 // Select base for the field based on the element type
93 auto get_base = [&]() {
94 auto domain_ents = get_ents_by_dim(SPACE_DIM);
95 if (domain_ents.empty())
97 const auto type = type_from_handle(domain_ents[0]);
98 switch (type) {
99 case MBQUAD:
101 case MBHEX:
103 case MBTRI:
105 case MBTET:
107 default:
108 CHK_THROW_MESSAGE(MOFEM_NOT_FOUND, "Element type is not handled");
109 }
110 return NOBASE;
111 };
112
113 auto base = get_base();
116
117 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &oRder, PETSC_NULLPTR);
118
119 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-geom_order", &geomOrder,
120 PETSC_NULLPTR);
121
122 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-atom_test", &atomTest,
123 PETSC_NULLPTR);
125 CHKERR simpleInterface->addDataField("GEOMETRY", H1, base, SPACE_DIM);
127
128 auto project_ho_geometry = [&]() {
129 Projection10NodeCoordsOnField ent_method(mField, "GEOMETRY");
130 return mField.loop_dofs("GEOMETRY", ent_method);
131 };
132
134 CHKERR project_ho_geometry();
135
136 commonDataPtr = boost::make_shared<DataAtIntegrationPts>(mField);
137 auto *json_config = mField.getInterface<JsonConfigManager>();
138
139 // gets the map of the permittivity attributes and the block sets
140 permBlockSetsPtr = boost::make_shared<std::map<int, BlockData>>();
141 Range mat_electr_ents; // range of entities with the permittivity
143 if (bit->getName().compare(0, 12, "MAT_ELECTRIC") == 0) {
144 const int id = bit->getMeshsetId();
145 auto &block_data = (*permBlockSetsPtr)[id];
146
147 CHKERR mField.get_moab().get_entities_by_dimension(
148 bit->getMeshset(), SPACE_DIM, block_data.domainEnts, true);
149 mat_electr_ents.merge(block_data.domainEnts);
150
151 const auto params_from_json =
152 json_config->getParamsFromBlockset("MAT_ELECTRIC", id);
153 if (!params_from_json.empty()) {
154 block_data.epsPermit = params_from_json.at("permittivity");
155 } else {
156 std::vector<double> attributes;
157 bit->getAttributes(attributes);
158 if (attributes.size() < 1) {
159 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
160 " At least one permittivity attributes should be given but "
161 "found %zu",
162 attributes.size());
163 }
164 block_data.epsPermit = attributes[0];
165 }
166 block_data.iD = id; // id of the block
167 }
168 }
169
170 // gets the map of the charge attributes and the block sets
171 intBlockSetsPtr = boost::make_shared<std::map<int, BlockData>>();
172 Range int_electr_ents; // range of entities with the charge
174 if (bit->getName().compare(0, 12, "INT_ELECTRIC") == 0) {
175 const int id = bit->getMeshsetId();
176 auto &block_data = (*intBlockSetsPtr)[id];
177
178 CHKERR mField.get_moab().get_entities_by_dimension(
179 bit->getMeshset(), SPACE_DIM - 1, block_data.interfaceEnts, true);
180 int_electr_ents.merge(block_data.interfaceEnts);
181
182 const auto params_from_json =
183 json_config->getParamsFromBlockset("INT_ELECTRIC", id);
184 if (!params_from_json.empty()) {
185 block_data.chargeDensity = params_from_json.at("charge_density");
186 } else {
187 std::vector<double> attributes;
188 bit->getAttributes(attributes);
189 if (attributes.size() < 1) {
190 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
191 "At least one charge attributes should be given but found %zu",
192 attributes.size());
193 }
194 block_data.chargeDensity = attributes[0];
195 }
196
197 block_data.iD = id; // id-> block ID
198 }
199 }
200 // gets the map of the electrode entity range in the block sets
201 electrodeBlockSetsPtr = boost::make_shared<std::map<int, BlockData>>();
202 Range electrode_ents; // range of entities with the electrode
203 int electrodeCount = 0;
205 if (bit->getName().compare(0, 9, "ELECTRODE") == 0) {
206 const int id = bit->getMeshsetId();
207 auto &block_data = (*electrodeBlockSetsPtr)[id];
208 ++electrodeCount;
209
210 CHKERR mField.get_moab().get_entities_by_dimension(
211 bit->getMeshset(), SPACE_DIM - 1, block_data.electrodeEnts, true);
212 electrode_ents.merge(block_data.electrodeEnts);
213
214
215 if (electrodeCount > 2) {
216 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
217 "Three or more electrode blocksets found");
218 ;
219 }
220 }
221 }
222
223 // sync entities
224 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
225 mat_electr_ents);
226 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
227 int_electr_ents);
228 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
229 electrode_ents);
230
231 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-out_skin", &out_skin,
232 PETSC_NULLPTR);
233 CHKERR PetscOptionsGetBool(PETSC_NULLPTR, "", "-is_partitioned", &is_partitioned,
234 PETSC_NULLPTR);
235 // get the skin entities
236 Skinner skinner(&mField.get_moab());
237 Range skin_tris;
238 CHKERR skinner.find_skin(0, mat_electr_ents, false, skin_tris);
239 Range proc_skin;
240 ParallelComm *pcomm =
241 ParallelComm::get_pcomm(&mField.get_moab(), MYPCOMM_INDEX);
242 if (is_partitioned) {
243 CHKERR pcomm->filter_pstatus(skin_tris,
244 PSTATUS_SHARED | PSTATUS_MULTISHARED,
245 PSTATUS_NOT, -1, &proc_skin);
246 } else {
247 proc_skin = skin_tris;
248 }
249 // add the skin entities to the field
252 "SKIN");
256 // add the interface entities to the field
257 CHKERR mField.add_finite_element("INTERFACE");
261 CHKERR mField.modify_finite_element_add_field_data("INTERFACE", "GEOMETRY");
262
264 SPACE_DIM - 1, "INTERFACE");
265 // add the electrode entities to the field
266 CHKERR mField.add_finite_element("ELECTRODE");
270 CHKERR mField.modify_finite_element_add_field_data("ELECTRODE", "GEOMETRY");
271
273 "ELECTRODE");
274
275 // sync field entities
276 mField.getInterface<CommInterface>()->synchroniseFieldEntities(domainField);
277 mField.getInterface<CommInterface>()->synchroniseFieldEntities("GEOMETRY");
286
290
291 DMType dm_name = "DMMOFEM";
292 CHKERR DMRegister_MoFEM(dm_name);
293
295 dm = createDM(mField.get_comm(), dm_name);
296
297 // create dm instance
298 CHKERR DMSetType(dm, dm_name);
299
301
302 // initialise petsc vector for required processor
303 int local_size;
304 if (mField.get_comm_rank() == 0) // get_comm_rank() gets processor number
305
306 local_size = LAST_ELEMENT; // last element gives size of vector
307
308 else
309 // other processors (e.g. 1, 2, 3, etc.)
310 local_size = 0; // local size of vector is zero on other processors
311
315}
316//! [Setup problem]
317
318//! [Boundary condition]
321
322 auto bc_mng = mField.getInterface<BcManager>();
323
324 // Remove_BCs_from_blockset name "BOUNDARY_CONDITION";
326 simpleInterface->getProblemName(), "BOUNDARY_CONDITION",
327 std::string(domainField), true);
328
330}
331//! [Boundary condition]
332
333//! [Set integration rules]
336
337 auto rule_lhs = [this](int, int, int p) -> int { return 2 * p + geomOrder -1; };
338 auto rule_rhs = [this](int, int, int p) -> int { return 2 * p + geomOrder -1; };
339
340 auto pipeline_mng = mField.getInterface<PipelineManager>();
341 CHKERR pipeline_mng->setDomainLhsIntegrationRule(rule_lhs);
342 CHKERR pipeline_mng->setDomainRhsIntegrationRule(rule_rhs);
343
345}
346//! [Set integration rules]
347
348//! [Assemble system]
351
352 auto pipeline_mng = mField.getInterface<PipelineManager>();
353 commonDataPtr = boost::make_shared<DataAtIntegrationPts>(mField);
354
355 auto add_domain_base_ops = [&](auto &pipeline) {
357 "GEOMETRY");
358
359 pipeline.push_back(
361 };
362
363 add_domain_base_ops(pipeline_mng->getOpDomainLhsPipeline());
364 auto epsilon = [&](const double, const double, const double) {
365 return commonDataPtr->blockPermittivity;
366 };
367
368 { // Push operators to the Pipeline that is responsible for calculating LHS
369 pipeline_mng->getOpDomainLhsPipeline().push_back(
371 }
372
373 { // Push operators to the Pipeline that is responsible for calculating RHS
374 auto set_values_to_bc_dofs = [&](auto &fe) {
375 auto get_bc_hook = [&]() {
377 return hook;
378 };
379 fe->preProcessHook = get_bc_hook();
380 };
381 // Set essential BC
382 auto calculate_residual_from_set_values_on_bc = [&](auto &pipeline) {
383 using OpInternal =
386
387 add_domain_base_ops(pipeline_mng->getOpDomainRhsPipeline());
388
389 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
390 pipeline_mng->getOpDomainRhsPipeline().push_back(
392 grad_u_ptr));
393 auto minus_epsilon = [&](double, double, double) constexpr {
394 return -commonDataPtr->blockPermittivity;
395 };
396 pipeline_mng->getOpDomainRhsPipeline().push_back(
397 new OpInternal(domainField, grad_u_ptr, minus_epsilon));
398 };
399
400 set_values_to_bc_dofs(pipeline_mng->getDomainRhsFE());
401 calculate_residual_from_set_values_on_bc(
402 pipeline_mng->getOpDomainRhsPipeline());
403
404 auto bodySourceTerm = [&](const double, const double, const double) {
405 return bodySource;
406 };
407 pipeline_mng->getOpDomainRhsPipeline().push_back(
408 new OpBodySourceVectorb(domainField, bodySourceTerm));
409 }
410
411 interFaceRhsFe = boost::shared_ptr<ForcesAndSourcesCore>(
413 interFaceRhsFe->getRuleHook = [this](int, int, int p) {
414 return 2 * p + geomOrder -1;
415 };
416
417 {
418
420 interFaceRhsFe->getOpPtrVector(), {NOSPACE}, "GEOMETRY");
421
422 interFaceRhsFe->getOpPtrVector().push_back(
424
425 auto sIgma = [&](const double, const double, const double) {
426 return commonDataPtr->blockChrgDens;
427 };
428
429 interFaceRhsFe->getOpPtrVector().push_back(
431 }
432
434}
435//! [Assemble system]
436
437//! [Solve system]
440
441 auto pipeline_mng = mField.getInterface<PipelineManager>();
442
443 auto ksp_solver = pipeline_mng->createKSP();
444
445 boost::shared_ptr<ForcesAndSourcesCore> null; ///< Null element does
446 DM dm;
448
449 CHKERR DMMoFEMKSPSetComputeRHS(dm, "INTERFACE", interFaceRhsFe, null, null);
450
451 CHKERR KSPSetFromOptions(ksp_solver);
452
453 // Create RHS and solution vectors
454 auto F = createDMVector(dm);
455 auto D = vectorDuplicate(F);
456 // Solve the system
457 CHKERR KSPSetUp(ksp_solver);
458 CHKERR KSPSolve(ksp_solver, F, D);
459
460 CHKERR VecGhostUpdateBegin(F, INSERT_VALUES, SCATTER_FORWARD);
461 CHKERR VecGhostUpdateEnd(F, INSERT_VALUES, SCATTER_FORWARD);
462
463 double fnorm;
464 CHKERR VecNorm(F, NORM_2, &fnorm);
465 CHKERR PetscPrintf(PETSC_COMM_WORLD, "F norm = %9.8e\n", fnorm);
466
467 // Scatter result data on the mesh
468 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
469 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
470
471 double dnorm;
472 CHKERR VecNorm(D, NORM_2, &dnorm);
473 CHKERR PetscPrintf(PETSC_COMM_WORLD, "D norm = %9.8e\n", dnorm);
474
475 CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
476
478}
479//! [Solve system]
480
481//! [Output results]
484 auto pipeline_mng = mField.getInterface<PipelineManager>();
485 pipeline_mng->getDomainRhsFE().reset();
486 pipeline_mng->getBoundaryLhsFE().reset();
487 pipeline_mng->getBoundaryRhsFE().reset(); //
488 pipeline_mng->getDomainLhsFE().reset();
489 auto post_proc_fe = boost::make_shared<PostProcEle>(mField);
490
491 // lamda function to calculate electric field
492 auto calculate_e_field = [&](auto &pipeline) {
493 auto u_ptr = boost::make_shared<VectorDouble>();
494 auto x_ptr = boost::make_shared<MatrixDouble>();
495 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
496 auto e_field_ptr = boost::make_shared<MatrixDouble>();
497 // add higher order operator
499 "GEOMETRY");
500 // calculate field values
501 pipeline.push_back(new OpCalculateScalarFieldValues(domainField, u_ptr));
502 pipeline.push_back(
503 new OpCalculateVectorFieldValues<SPACE_DIM>("GEOMETRY", x_ptr));
504
505 // calculate gradient
506 pipeline.push_back(
508 // calculate electric field
509 pipeline.push_back(new OpElectricField(e_field_ptr, grad_u_ptr));
510 return boost::make_tuple(u_ptr, e_field_ptr, x_ptr);
511 };
512
513 auto [u_ptr, e_field_ptr, x_ptr] =
514 calculate_e_field(post_proc_fe->getOpPtrVector());
515
516 auto e_field_times_perm_ptr = boost::make_shared<MatrixDouble>();
517 auto energy_density_ptr = boost::make_shared<VectorDouble>();
518
519 post_proc_fe->getOpPtrVector().push_back(
520 new OpGradTimesPerm(domainField, e_field_ptr, e_field_times_perm_ptr,
522 post_proc_fe->getOpPtrVector().push_back(
523 new OpEnergyDensity(domainField, e_field_ptr, energy_density_ptr,
525
527 post_proc_fe->getOpPtrVector().push_back(new OpPPMap(
528 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
529
530 OpPPMap::DataMapVec{{"POTENTIAL", u_ptr},
531 {"ENERGY_DENSITY", energy_density_ptr}},
533 {"GEOMETRY", x_ptr},
534 {"ELECTRIC_FIELD", e_field_ptr},
535 {"ELECTRIC_DISPLACEMENT", e_field_times_perm_ptr},
536 },
538
540
541 );
542
543 pipeline_mng->getDomainRhsFE() = post_proc_fe;
544 CHKERR pipeline_mng->loopFiniteElements();
545 CHKERR post_proc_fe->writeFile("out.h5m");
546
547 if (out_skin && SPACE_DIM == 3) {
548
549 auto post_proc_skin = boost::make_shared<PostProcFaceEle>(mField);
550 auto op_loop_skin = new OpLoopSide<SideEle>(
551 mField, simpleInterface->getDomainFEName(), SPACE_DIM);
552
553 auto [u_ptr, e_field_ptr, x_ptr] =
554 calculate_e_field(op_loop_skin->getOpPtrVector());
555
556 op_loop_skin->getOpPtrVector().push_back(
557 new OpGradTimesPerm(domainField, e_field_ptr, e_field_times_perm_ptr,
558 permBlockSetsPtr, commonDataPtr));
559 op_loop_skin->getOpPtrVector().push_back(
560 new OpEnergyDensity(domainField, e_field_ptr, energy_density_ptr,
561 permBlockSetsPtr, commonDataPtr));
562
563 // push op to boundary element
564 post_proc_skin->getOpPtrVector().push_back(op_loop_skin);
565
566 post_proc_skin->getOpPtrVector().push_back(new OpPPMap(
567 post_proc_skin->getPostProcMesh(), post_proc_skin->getMapGaussPts(),
568 OpPPMap::DataMapVec{{"POTENTIAL", u_ptr},
569 {"ENERGY_DENSITY", energy_density_ptr}},
570 OpPPMap::DataMapMat{{"ELECTRIC_FIELD", e_field_ptr},
571 {"GEOMETRY", x_ptr},
572 {"ELECTRIC_DISPLACEMENT", e_field_times_perm_ptr}},
574
575 CHKERR DMoFEMLoopFiniteElements(simpleInterface->getDM(), "SKIN",
576 post_proc_skin);
577 CHKERR post_proc_skin->writeFile("out_skin.h5m");
578 }
580}
581//! [Output results]
582
583//! [Get Total Energy]
586 auto pip_energy = mField.getInterface<PipelineManager>();
587 pip_energy->getDomainRhsFE().reset();
588 pip_energy->getDomainLhsFE().reset();
589 pip_energy->getBoundaryLhsFE().reset();
590 pip_energy->getBoundaryRhsFE().reset();
591 pip_energy->getOpDomainRhsPipeline().clear();
592 pip_energy->getOpDomainLhsPipeline().clear();
593
594 // gets the map of the internal domain entity range to get the total energy
595
596 boost::shared_ptr<std::map<int, BlockData>> intrnlDomnBlckSetPtr =
597 boost::make_shared<std::map<int, BlockData>>();
598 Range internal_domain; // range of entities marked the internal domain
600 if (bit->getName().compare(0, 10, "DOMAIN_INT") == 0) {
601 const int id = bit->getMeshsetId();
602 auto &block_data = (*intrnlDomnBlckSetPtr)[id];
603
604 CHKERR mField.get_moab().get_entities_by_dimension(
605 bit->getMeshset(), SPACE_DIM, block_data.internalDomainEnts, true);
606 internal_domain.merge(block_data.internalDomainEnts);
607 block_data.iD = id;
608 }
609 }
610 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
611 internal_domain);
612
614 pip_energy->getOpDomainRhsPipeline(), {H1}, "GEOMETRY");
615
616 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
617 auto e_field_ptr = boost::make_shared<MatrixDouble>();
618
619 pip_energy->getOpDomainRhsPipeline().push_back(
621 pip_energy->getOpDomainRhsPipeline().push_back(
622 new OpElectricField(e_field_ptr, grad_u_ptr));
623
624 commonDataPtr = boost::make_shared<DataAtIntegrationPts>(mField);
625
626 pip_energy->getOpDomainRhsPipeline().push_back(
628 intrnlDomnBlckSetPtr, commonDataPtr, petscVecEnergy));
629
630 pip_energy->loopFiniteElements();
631 CHKERR VecAssemblyBegin(petscVecEnergy);
632 CHKERR VecAssemblyEnd(petscVecEnergy);
633
634 double total_energy = 0.0; // declaration for total energy
635 if (!mField.get_comm_rank()) {
636 const double *array;
637
638 CHKERR VecGetArrayRead(petscVecEnergy, &array);
639 total_energy = array[ZERO];
640 MOFEM_LOG_CHANNEL("SELF");
641 MOFEM_LOG_C("SELF", Sev::inform, "Total Energy: %6.15f", total_energy);
642 CHKERR VecRestoreArrayRead(petscVecEnergy, &array);
643 }
644
646}
647//! [Get Total Energy]
648
649//! [Get Charges]
652 auto op_loop_side = new OpLoopSide<SideEle>(
654
656 op_loop_side->getOpPtrVector(), {H1}, "GEOMETRY");
657
658 auto grad_u_ptr_charge = boost::make_shared<MatrixDouble>();
659 auto e_ptr_charge = boost::make_shared<MatrixDouble>();
660
661 op_loop_side->getOpPtrVector().push_back(
663 grad_u_ptr_charge));
664
665 op_loop_side->getOpPtrVector().push_back(
666 new OpElectricField(e_ptr_charge, grad_u_ptr_charge));
667 auto d_jump = boost::make_shared<MatrixDouble>();
668 op_loop_side->getOpPtrVector().push_back(new OpElectricDispJump<SPACE_DIM>(
669 domainField, e_ptr_charge, d_jump, commonDataPtr, permBlockSetsPtr));
670
671 electrodeRhsFe = boost::shared_ptr<ForcesAndSourcesCore>(
673 electrodeRhsFe->getRuleHook = [this](int, int, int p) {
674 return 2 * p + geomOrder -1;
675 };
676
677 // push all the operators in on the side to the electrodeRhsFe
678 electrodeRhsFe->getOpPtrVector().push_back(op_loop_side);
679
680 electrodeRhsFe->getOpPtrVector().push_back(new OpElectrodeCharge<SPACE_DIM>(
682 CHKERR VecZeroEntries(petscVec);
684 "ELECTRODE", electrodeRhsFe, 0,
686 CHKERR VecAssemblyBegin(petscVec);
687 CHKERR VecAssemblyEnd(petscVec);
688
689 if (!mField.get_comm_rank()) {
690 const double *array;
691
692 CHKERR(VecGetArrayRead(petscVec, &array));
693 double aLpha = array[0]; // Use explicit index instead of ZERO
694 double bEta = array[1]; // Use explicit index instead of ONE
695 MOFEM_LOG_CHANNEL("SELF");
696 MOFEM_LOG_C("SELF", Sev::inform,
697 "CHARGE_ELEC_1: %6.15f , CHARGE_ELEC_2: %6.15f", aLpha, bEta);
698
699 CHKERR(VecRestoreArrayRead(petscVec, &array));
700 }
701 if (atomTest && !mField.get_comm_rank()) {
702 double cal_charge_elec1;
703 double cal_charge_elec2;
704 double cal_total_energy;
705 const double *c_ptr, *te_ptr;
706
707 // Get a pointer to the PETSc vector data
708 CHKERR(VecGetArrayRead(petscVec, &c_ptr));
709 CHKERR(VecGetArrayRead(petscVecEnergy, &te_ptr));
710
711 // Expected charges at the electrodes
712 double ref_charge_elec1;
713 double ref_charge_elec2;
714 // Expected total energy of the system
715 double ref_tot_energy;
716 double tol;
717 cal_charge_elec1 = c_ptr[0]; // Read charge at the first electrode
718 cal_charge_elec2 = c_ptr[1]; // Read charge at the second electrode
719 cal_total_energy = te_ptr[0]; // Read total energy of the system
720 if (std::isnan(cal_charge_elec1) || std::isnan(cal_charge_elec2) ||
721 std::isnan(cal_total_energy)) {
722 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
723 "Atom test failed! NaN detected in calculated values.");
724 }
725 switch (atomTest) {
726 case 1: // 2D & 3D test
727 case 3: // JSON clear-block 2D test
728 // Expected charges at the electrodes
729 ref_charge_elec1 = 50.0;
730 ref_charge_elec2 = -50.0;
731 // Expected total energy of the system
732 ref_tot_energy = 500.0;
733 tol = 1e-10;
734 break;
735 case 2: // wavy 3D test
736 ref_charge_elec1 = 10.00968352472943;
737 ref_charge_elec2 = 0.0; // no electrode
738 ref_tot_energy = 50.5978;
739 tol = 1e-4;
740 break;
741 default:
742 SETERRQ(PETSC_COMM_SELF, MOFEM_INVALID_DATA,
743 "atom test %d does not exist", atomTest);
744 }
745
746 // Validate the results
747 if (std::abs(ref_charge_elec1 - cal_charge_elec1) > tol ||
748 std::abs(ref_charge_elec2 - cal_charge_elec2) > tol ||
749 std::abs(ref_tot_energy - cal_total_energy) > tol) {
750 SETERRQ(
751 PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
752 "atom test %d failed! Calculated values do not match expected values",
753 atomTest);
754 }
755
756 CHKERR(VecRestoreArrayRead(petscVec,
757 &c_ptr)); // Restore the PETSc vector array
758 CHKERR(VecRestoreArrayRead(petscVecEnergy, &te_ptr));
759 }
760
762}
763//! [Get Charges]
764
765//! [Run program]
780//! [Run program]
781
782//! [Main]
783int main(int argc, char *argv[]) {
784 // Initialisation of MoFEM/PETSc and MOAB data structures
785 const char param_file[] = "param_file.petsc";
786 MoFEM::Core::Initialize(&argc, &argv, param_file, help);
787
788 // Error handling
789 try {
790 // Register MoFEM discrete manager in PETSc
791 DMType dm_name = "DMMOFEM";
792 CHKERR DMRegister_MoFEM(dm_name);
793
794 // Create MOAB instance
795 moab::Core mb_instance; // mesh database
796 moab::Interface &moab = mb_instance; // mesh database interface
797
798 // Create MoFEM instance
799 MoFEM::Core core(moab); // finite element database
800 MoFEM::Interface &m_field = core; // finite element interface
801
802 // Run the main analysis
803 Electrostatics Electrostatics_problem(m_field);
804 CHKERR Electrostatics_problem.runProgram();
805 }
807
808 // Finish work: cleaning memory, getting statistics, etc.
810
811 return 0;
812}
813//! [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
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
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.
boost::shared_ptr< FEMethod > & getDomainRhsFE()
Get domain right-hand side 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.
double tol