Garfield++ 3.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
Garfield::ComponentNeBem3d Class Reference

Interface to neBEM. More...

#include <ComponentNeBem3d.hh>

+ Inheritance diagram for Garfield::ComponentNeBem3d:

Public Member Functions

 ComponentNeBem3d ()
 Constructor.
 
 ~ComponentNeBem3d ()
 Destructor.
 
void ElectricField (const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status) override
 
void ElectricField (const double x, const double y, const double z, double &ex, double &ey, double &ez, double &v, Medium *&m, int &status) override
 Calculate the drift field [V/cm] and potential [V] at (x, y, z).
 
bool GetVoltageRange (double &vmin, double &vmax) override
 Calculate the voltage range [V].
 
unsigned int GetNumberOfPrimitives () const
 
bool GetPrimitive (const unsigned int i, double &a, double &b, double &c, std::vector< double > &xv, std::vector< double > &yv, std::vector< double > &zv, int &interface, double &v, double &q, double &lambda) const
 
unsigned int GetNumberOfElements () const
 
bool GetElement (const unsigned int i, std::vector< double > &xv, std::vector< double > &yv, std::vector< double > &zv, int &interface, double &bc, double &lambda) const
 
void Reset () override
 Reset the component.
 
void UpdatePeriodicity () override
 Verify periodicities.
 
bool Initialise ()
 
void SetTargetElementSize (const double length)
 
- Public Member Functions inherited from Garfield::ComponentBase
 ComponentBase ()
 Constructor.
 
virtual ~ComponentBase ()
 Destructor.
 
virtual void SetGeometry (GeometryBase *geo)
 Define the geometry.
 
virtual void Clear ()
 Reset.
 
virtual MediumGetMedium (const double x, const double y, const double z)
 Get the medium at a given location (x, y, z).
 
virtual void ElectricField (const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status)=0
 
virtual void ElectricField (const double x, const double y, const double z, double &ex, double &ey, double &ez, double &v, Medium *&m, int &status)=0
 Calculate the drift field [V/cm] and potential [V] at (x, y, z).
 
virtual bool GetVoltageRange (double &vmin, double &vmax)=0
 Calculate the voltage range [V].
 
virtual void WeightingField (const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label)
 
virtual double WeightingPotential (const double x, const double y, const double z, const std::string &label)
 
virtual void DelayedWeightingField (const double x, const double y, const double z, const double t, double &wx, double &wy, double &wz, const std::string &label)
 
virtual void MagneticField (const double x, const double y, const double z, double &bx, double &by, double &bz, int &status)
 
void SetMagneticField (const double bx, const double by, const double bz)
 Set a constant magnetic field.
 
virtual bool IsReady ()
 Ready for use?
 
virtual bool GetBoundingBox (double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
 Get the bounding box coordinates.
 
double IntegrateFluxCircle (const double xc, const double yc, const double r, const unsigned int nI=50)
 
double IntegrateFluxSphere (const double xc, const double yc, const double zc, const double r, const unsigned int nI=20)
 
double IntegrateFlux (const double x0, const double y0, const double z0, const double dx1, const double dy1, const double dz1, const double dx2, const double dy2, const double dz2, const unsigned int nU=20, const unsigned int nV=20)
 
virtual bool IsWireCrossed (const double x0, const double y0, const double z0, const double x1, const double y1, const double z1, double &xc, double &yc, double &zc, const bool centre, double &rc)
 
virtual bool IsInTrapRadius (const double q0, const double x0, const double y0, const double z0, double &xw, double &yw, double &rw)
 
void EnablePeriodicityX (const bool on=true)
 Enable simple periodicity in the $x$ direction.
 
void DisablePeriodicityX ()
 
void EnablePeriodicityY (const bool on=true)
 Enable simple periodicity in the $y$ direction.
 
void DisablePeriodicityY ()
 
void EnablePeriodicityZ (const bool on=true)
 Enable simple periodicity in the $z$ direction.
 
void DisablePeriodicityZ ()
 
void EnableMirrorPeriodicityX (const bool on=true)
 Enable mirror periodicity in the $x$ direction.
 
void DisableMirrorPeriodicityX ()
 
void EnableMirrorPeriodicityY (const bool on=true)
 Enable mirror periodicity in the $y$ direction.
 
void DisableMirrorPeriodicityY ()
 
void EnableMirrorPeriodicityZ (const bool on=true)
 Enable mirror periodicity in the $y$ direction.
 
void DisableMirrorPeriodicityZ ()
 
void EnableAxialPeriodicityX (const bool on=true)
 Enable axial periodicity in the $x$ direction.
 
void DisableAxialPeriodicityX ()
 
void EnableAxialPeriodicityY (const bool on=true)
 Enable axial periodicity in the $y$ direction.
 
void DisableAxialPeriodicityY ()
 
void EnableAxialPeriodicityZ (const bool on=true)
 Enable axial periodicity in the $z$ direction.
 
void DisableAxialPeriodicityZ ()
 
void EnableRotationSymmetryX (const bool on=true)
 Enable rotation symmetry around the $x$ axis.
 
void DisableRotationSymmetryX ()
 
void EnableRotationSymmetryY (const bool on=true)
 Enable rotation symmetry around the $y$ axis.
 
void DisableRotationSymmetryY ()
 
void EnableRotationSymmetryZ (const bool on=true)
 Enable rotation symmetry around the $z$ axis.
 
void DisableRotationSymmetryZ ()
 
void EnableDebugging ()
 Switch on debugging messages.
 
void DisableDebugging ()
 Switch off debugging messages.
 
void ActivateTraps ()
 Request trapping to be taken care of by the component (for TCAD).
 
void DeactivateTraps ()
 
bool IsTrapActive ()
 
void ActivateVelocityMap ()
 Request velocity to be taken care of by the component (for TCAD).
 
void DectivateVelocityMap ()
 
bool IsVelocityActive ()
 
virtual bool ElectronAttachment (const double, const double, const double, double &eta)
 Get the electron attachment coefficient.
 
virtual bool HoleAttachment (const double, const double, const double, double &eta)
 Get the hole attachment coefficient.
 
virtual void ElectronVelocity (const double, const double, const double, double &vx, double &vy, double &vz, Medium *&, int &status)
 Get the electron drift velocity.
 
virtual void HoleVelocity (const double, const double, const double, double &vx, double &vy, double &vz, Medium *&, int &status)
 Get the hole drift velocity.
 
virtual bool GetElectronLifetime (const double, const double, const double, double &etau)
 
virtual bool GetHoleLifetime (const double, const double, const double, double &htau)
 

Additional Inherited Members

virtual void Reset ()=0
 Reset the component.
 
virtual void UpdatePeriodicity ()=0
 Verify periodicities.
 
- Protected Attributes inherited from Garfield::ComponentBase
std::string m_className = "ComponentBase"
 Class name.
 
GeometryBasem_geometry = nullptr
 Pointer to the geometry.
 
bool m_ready = false
 Ready for use?
 
bool m_activeTraps = false
 Does the component have traps?
 
bool m_hasVelocityMap = false
 Does the component have velocity maps?
 
std::array< bool, 3 > m_periodic = {{false, false, false}}
 Simple periodicity in x, y, z.
 
std::array< bool, 3 > m_mirrorPeriodic = {{false, false, false}}
 Mirror periodicity in x, y, z.
 
std::array< bool, 3 > m_axiallyPeriodic = {{false, false, false}}
 Axial periodicity in x, y, z.
 
std::array< bool, 3 > m_rotationSymmetric = {{false, false, false}}
 Rotation symmetry around x-axis, y-axis, z-axis.
 
double m_bx0 = 0.
 
double m_by0 = 0.
 
double m_bz0 = 0.
 
bool m_debug = false
 Switch on/off debugging messages.
 

Detailed Description

Interface to neBEM.

Definition at line 9 of file ComponentNeBem3d.hh.

Constructor & Destructor Documentation

◆ ComponentNeBem3d()

Garfield::ComponentNeBem3d::ComponentNeBem3d ( )

Constructor.

Definition at line 377 of file ComponentNeBem3d.cc.

377 : ComponentBase() {
378 m_className = "ComponentNeBem3d";
379}
ComponentBase()
Constructor.
Definition: ComponentBase.cc:9
std::string m_className
Class name.

◆ ~ComponentNeBem3d()

Garfield::ComponentNeBem3d::~ComponentNeBem3d ( )
inline

Destructor.

Definition at line 14 of file ComponentNeBem3d.hh.

14{}

Member Function Documentation

◆ ElectricField() [1/2]

void Garfield::ComponentNeBem3d::ElectricField ( const double  x,
const double  y,
const double  z,
double &  ex,
double &  ey,
double &  ez,
double &  v,
Medium *&  m,
int &  status 
)
overridevirtual

Calculate the drift field [V/cm] and potential [V] at (x, y, z).

Implements Garfield::ComponentBase.

Definition at line 381 of file ComponentNeBem3d.cc.

384 {
385 ex = ey = ez = v = 0.;
386 status = 0;
387 // Check if the requested point is inside a medium
388 m = GetMedium(x, y, z);
389 if (!m) {
390 status = -6;
391 return;
392 }
393
394 if (!m_ready) {
395 if (!Initialise()) {
396 std::cerr << m_className << "::ElectricField: Initialisation failed.\n";
397 status = -11;
398 return;
399 }
400 m_ready = true;
401 }
402}
bool m_ready
Ready for use?
virtual Medium * GetMedium(const double x, const double y, const double z)
Get the medium at a given location (x, y, z).

◆ ElectricField() [2/2]

void Garfield::ComponentNeBem3d::ElectricField ( const double  x,
const double  y,
const double  z,
double &  ex,
double &  ey,
double &  ez,
Medium *&  m,
int &  status 
)
overridevirtual

Calculate the drift field at given point.

Parameters
x,y,zcoordinates [cm].
ex,ey,ezcomponents of the electric field [V/cm].
mpointer to the medium at this location.
statusstatus flag

Status flags:

        0: Inside an active medium
      > 0: Inside a wire of type X
-4 ... -1: On the side of a plane where no wires are
       -5: Inside the mesh but not in an active medium
       -6: Outside the mesh
      -10: Unknown potential type (should not occur)
    other: Other cases (should not occur)

Implements Garfield::ComponentBase.

Definition at line 404 of file ComponentNeBem3d.cc.

406 {
407 double v = 0.;
408 ElectricField(x, y, z, ex, ey, ez, v, m, status);
409}
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status) override

Referenced by ElectricField().

◆ GetElement()

bool Garfield::ComponentNeBem3d::GetElement ( const unsigned int  i,
std::vector< double > &  xv,
std::vector< double > &  yv,
std::vector< double > &  zv,
int &  interface,
double &  bc,
double &  lambda 
) const

Definition at line 2499 of file ComponentNeBem3d.cc.

2503 {
2504
2505 if (i >= m_elements.size()) {
2506 std::cerr << m_className << "::GetElement: Index out of range.\n";
2507 return false;
2508 }
2509 const auto& element = m_elements[i];
2510 xv = element.xv;
2511 yv = element.yv;
2512 zv = element.zv;
2513 interface = element.interface;
2514 bc = element.bc;
2515 lambda = element.lambda;
2516 return true;
2517}

◆ GetNumberOfElements()

unsigned int Garfield::ComponentNeBem3d::GetNumberOfElements ( ) const
inline

Definition at line 28 of file ComponentNeBem3d.hh.

28{ return m_elements.size(); }

◆ GetNumberOfPrimitives()

unsigned int Garfield::ComponentNeBem3d::GetNumberOfPrimitives ( ) const
inline

Definition at line 23 of file ComponentNeBem3d.hh.

23{ return m_primitives.size(); }

◆ GetPrimitive()

bool Garfield::ComponentNeBem3d::GetPrimitive ( const unsigned int  i,
double &  a,
double &  b,
double &  c,
std::vector< double > &  xv,
std::vector< double > &  yv,
std::vector< double > &  zv,
int &  interface,
double &  v,
double &  q,
double &  lambda 
) const

Definition at line 2475 of file ComponentNeBem3d.cc.

2480 {
2481 if (i >= m_primitives.size()) {
2482 std::cerr << m_className << "::GetPrimitive: Index out of range.\n";
2483 return false;
2484 }
2485 const auto& primitive = m_primitives[i];
2486 a = primitive.a;
2487 b = primitive.b;
2488 c = primitive.c;
2489 xv = primitive.xv;
2490 yv = primitive.yv;
2491 zv = primitive.zv;
2492 interface = primitive.interface;
2493 v = primitive.v;
2494 q = primitive.q;
2495 lambda = primitive.lambda;
2496 return true;
2497}

◆ GetVoltageRange()

bool Garfield::ComponentNeBem3d::GetVoltageRange ( double &  vmin,
double &  vmax 
)
overridevirtual

Calculate the voltage range [V].

Implements Garfield::ComponentBase.

Definition at line 411 of file ComponentNeBem3d.cc.

411 {
412 // Voltage and other bc have to come from the solids
413 vmin = vmax = 0;
414 return true;
415}

◆ Initialise()

bool Garfield::ComponentNeBem3d::Initialise ( )

Retrieve surface panels, remove contacts and cut polygons to rectangles and right-angle triangles.

Definition at line 427 of file ComponentNeBem3d.cc.

427 {
428 // Reset the lists.
429 m_primitives.clear();
430 m_elements.clear();
431
432 if (!m_geometry) {
433 std::cerr << m_className << "::Initialise: Geometry not set.\n";
434 return false;
435 }
436 // Be sure we won't have intersections with the bounding box.
437 // TODO! Loop over the solids and call PLACYE, PLACHE, PLABXE, PLASPE, ...
438 // Loop over the solids.
439 std::map<int, Solid*> solids;
440 std::map<int, Solid::BoundaryCondition> bc;
441 std::map<int, double> volt;
442 std::map<int, double> eps;
443 std::map<int, double> charge;
444 const unsigned int nSolids = m_geometry->GetNumberOfSolids();
445 std::vector<Panel> panelsIn;
446 for (unsigned int i = 0; i < nSolids; ++i) {
447 Medium* medium = nullptr;
448 const auto solid = m_geometry->GetSolid(i, medium);
449 if (!solid) continue;
450 // Get the panels.
451 solid->SolidPanels(panelsIn);
452 // Get the boundary condition.
453 const auto id = solid->GetId();
454 solids[id] = solid;
455 bc[id] = solid->GetBoundaryConditionType();
456 volt[id] = solid->GetBoundaryPotential();
457 charge[id] = solid->GetBoundaryChargeDensity();
458 if (!medium) {
459 eps[id] = 1.;
460 } else {
461 eps[id] = medium->GetDielectricConstant();
462 }
463 }
464 // Apply cuts.
465 // CALL CELSCT('APPLY')
466 // Reduce to basic periodic copy.
467 // CALL BEMBAS
468
469 // Find contact panels and split into primitives.
470
471 // *---------------------------------------------------------------------
472 // * PLABEM - Prepares panels for BEM applications: removes the contacts
473 // * and cuts polygons to rectangles and right-angle triangles.
474 // *---------------------------------------------------------------------
475
476 // Establish tolerances.
477 const double epsang = 1.e-6; // BEMEPA
478 const double epsxyz = 1.e-6; // BEMEPD
479 // CALL EPSSET('SET',EPSXYZ,EPSXYZ,EPSXYZ)
480
481 const unsigned int nIn = panelsIn.size();
482 if (m_debug) {
483 std::cout << m_className << "::Initialise: Retrieved "
484 << nIn << " panels from the solids.\n";
485 }
486 // Keep track of which panels have been processed.
487 std::vector<bool> mark(nIn, false);
488 // Pick up panels which coincide potentially.
489 for (unsigned int i = 0; i < nIn; ++i) {
490 // Skip panels already done.
491 if (mark[i]) continue;
492 // Fetch panel parameters.
493 const double a1 = panelsIn[i].a;
494 const double b1 = panelsIn[i].b;
495 const double c1 = panelsIn[i].c;
496 const auto& xp1 = panelsIn[i].xv;
497 const auto& yp1 = panelsIn[i].yv;
498 const auto& zp1 = panelsIn[i].zv;
499 const unsigned int np1 = xp1.size();
500 // Establish its norm and offset.
501 const double d1 = a1 * xp1[0] + b1 * yp1[0] + c1 * zp1[0];
502 if (m_debug) {
503 std::cout << " Panel " << i << "\n Norm vector: "
504 << a1 << ", " << b1 << ", " << c1 << ", " << d1 << ".\n";
505 }
506 // Rotation matrix.
507 std::array<std::array<double, 3>, 3> rot;
508 if (fabs(c1) <= fabs(a1) && fabs(c1) <= fabs(b1)) {
509 // Rotation: removing C
510 rot[0][0] = b1 / sqrt(a1 * a1 + b1 * b1);
511 rot[0][1] = -a1 / sqrt(a1 * a1 + b1 * b1);
512 rot[0][2] = 0.;
513 } else if (fabs(b1) <= fabs(a1) && fabs(b1) <= fabs(c1)) {
514 // Rotation: removing B
515 rot[0][0] = c1 / sqrt(a1 * a1 + c1 * c1);
516 rot[0][1] = 0.;
517 rot[0][2] = -a1 / sqrt(a1 * a1 + c1 * c1);
518 } else {
519 // Rotation: removing A
520 rot[0][0] = 0.;
521 rot[0][1] = c1 / sqrt(b1 * b1 + c1 * c1);
522 rot[0][2] = -b1 / sqrt(b1 * b1 + c1 * c1);
523 }
524 rot[2][0] = a1;
525 rot[2][1] = b1;
526 rot[2][2] = c1;
527 rot[1][0] = rot[2][1] * rot[0][2] - rot[2][2] * rot[0][1];
528 rot[1][1] = rot[2][2] * rot[0][0] - rot[2][0] * rot[0][2];
529 rot[1][2] = rot[2][0] * rot[0][1] - rot[2][1] * rot[0][0];
530 // Rotate to the x, y plane.
531 std::vector<double> xp(np1, 0.);
532 std::vector<double> yp(np1, 0.);
533 std::vector<double> zp(np1, 0.);
534 double zm = 0.;
535 for (unsigned int k = 0; k < np1; ++k) {
536 xp[k] = rot[0][0] * xp1[k] + rot[0][1] * yp1[k] + rot[0][2] * zp1[k];
537 yp[k] = rot[1][0] * xp1[k] + rot[1][1] * yp1[k] + rot[1][2] * zp1[k];
538 zp[k] = rot[2][0] * xp1[k] + rot[2][1] * yp1[k] + rot[2][2] * zp1[k];
539 zm += zp[k];
540 }
541 zm /= np1;
542 // Store it.
543 std::vector<Panel> newPanels;
544 std::vector<int> vol1;
545 std::vector<int> vol2;
546 Panel panel1 = panelsIn[i];
547 panel1.xv = xp;
548 panel1.yv = yp;
549 panel1.zv = zp;
550 vol1.push_back(panel1.volume);
551 vol2.push_back(-1);
552 newPanels.push_back(std::move(panel1));
553 // Pick up all matching planes.
554 for (unsigned int j = i + 1; j < nIn; ++j) {
555 if (mark[j]) continue;
556 const double a2 = panelsIn[j].a;
557 const double b2 = panelsIn[j].b;
558 const double c2 = panelsIn[j].c;
559 const auto& xp2 = panelsIn[j].xv;
560 const auto& yp2 = panelsIn[j].yv;
561 const auto& zp2 = panelsIn[j].zv;
562 const unsigned int np2 = xp2.size();
563 // See whether this matches the first.
564 const double d2 = a2 * xp2[0] + b2 * yp2[0] + c2 * zp2[0];
565 // Inner product.
566 const double dot = a1 * a2 + b1 * b2 + c1 * c2;
567 // Offset between the two planes.
568 const double offset = d1 - d2 * dot;
569 if (fabs(fabs(dot) - 1.) > epsang || fabs(offset) > epsxyz) continue;
570 // Found a match.
571 mark[j] = true;
572 if (m_debug) std::cout << " Match with panel " << j << ".\n";
573 // Rotate this plane too.
574 xp.assign(np2, 0.);
575 yp.assign(np2, 0.);
576 zp.assign(np2, 0.);
577 zm = 0.;
578 for (unsigned int k = 0; k < np2; ++k) {
579 xp[k] = rot[0][0] * xp2[k] + rot[0][1] * yp2[k] + rot[0][2] * zp2[k];
580 yp[k] = rot[1][0] * xp2[k] + rot[1][1] * yp2[k] + rot[1][2] * zp2[k];
581 zp[k] = rot[2][0] * xp2[k] + rot[2][1] * yp2[k] + rot[2][2] * zp2[k];
582 zm += zp[k];
583 }
584 zm /= np2;
585 // Store it.
586 Panel panel2 = panelsIn[j];
587 panel2.xv = xp;
588 panel2.yv = yp;
589 panel2.zv = zp;
590 vol1.push_back(panel2.volume);
591 vol2.push_back(-1);
592 newPanels.push_back(std::move(panel2));
593 }
594 std::vector<bool> obsolete(newPanels.size(), false);
595 // Cut them as long as needed till no contacts remain.
596 unsigned int jmin = 0;
597 bool change = true;
598 while (change) {
599 change = false;
600 const unsigned int n = newPanels.size();
601 for (unsigned int j = 0; j < n; ++j) {
602 if (obsolete[j] || j < jmin) continue;
603 if (vol1[j] >= 0 && vol2[j] >= 0) continue;
604 const auto& panelj = newPanels[j];
605 for (unsigned int k = j + 1; k < n; ++k) {
606 if (obsolete[k]) continue;
607 if (vol1[k] >= 0 && vol2[k] >= 0) continue;
608 const auto& panelk = newPanels[k];
609 if (m_debug) std::cout << " Cutting " << j << ", " << k << ".\n";
610 // Separate contact and non-contact areas.
611 std::vector<Panel> panelsOut;
612 std::vector<int> itypo;
613 EliminateOverlaps(panelj, panelk, panelsOut, itypo);
614 const unsigned int nOut = panelsOut.size();
615 if (nOut == 2) {
616 // TODO: retrieve epsx, epsy from overlap finding?
617 const double epsx = epsxyz;
618 const double epsy = epsxyz;
619 // If there are just 2 panels, see whether there is a new one.
620 const bool equal1 = Equal(panelj, panelsOut[0], epsx, epsy);
621 const bool equal2 = Equal(panelj, panelsOut[1], epsx, epsy);
622 const bool equal3 = Equal(panelk, panelsOut[0], epsx, epsy);
623 const bool equal4 = Equal(panelk, panelsOut[1], epsx, epsy);
624 if ((equal1 || equal3) && (equal2 || equal4)) {
625 if (m_debug) {
626 std::cout << " Original and new panels are identical.\n";
627 }
628 } else {
629 change = true;
630 }
631 } else {
632 change = true;
633 }
634 if (m_debug) std::cout << " Change flag: " << change << ".\n";
635 // If there is no change, keep the two panels and proceed.
636 if (!change) continue;
637 // Flag the existing panels as inactive.
638 obsolete[j] = true;
639 obsolete[k] = true;
640
641 // Add the new panels.
642 for (unsigned int l = 0; l < nOut; ++l) {
643 if (itypo[l] == 1) {
644 vol1.push_back(std::max(vol1[j], vol2[j]));
645 vol2.push_back(-1);
646 } else if (itypo[l] == 2) {
647 vol1.push_back(std::max(vol1[k], vol2[k]));
648 vol2.push_back(-1);
649 } else {
650 vol1.push_back(std::max(vol1[j], vol2[j]));
651 vol2.push_back(std::max(vol1[k], vol2[k]));
652 }
653 newPanels.push_back(std::move(panelsOut[l]));
654 obsolete.push_back(false);
655 }
656 jmin = j + 1;
657 // Restart the loops.
658 break;
659 }
660 if (change) break;
661 }
662 }
663 // And rotate the panels back in place.
664 const unsigned int nNew = newPanels.size();
665 for (unsigned int j = 0; j < nNew; ++j) {
666 if (obsolete[j]) continue;
667 // Examine the boundary conditions.
668 int interfaceType = 0;
669 double potential = 0.;
670 double lambda = 0.;
671 double chargeDensity = 0.;
672 if (m_debug) {
673 std::cout << " Volume 1: " << vol1[j]
674 << ". Volume 2: " << vol2[j] << ".\n";
675 }
676 if (vol1[j] < 0 && vol2[j] < 0) {
677 // Shouldn't happen.
678 continue;
679 } else if (vol1[j] < 0 || vol2[j] < 0) {
680 // Interface between a solid and vacuum/background.
681 const auto vol = vol1[j] < 0 ? vol2[j] : vol1[j];
682 interfaceType = InterfaceType(bc[vol]);
683 if (bc[vol] == Solid::Dielectric ||
684 bc[vol] == Solid::DielectricCharge) {
685 if (fabs(eps[vol] - 1.) < 1.e-6) {
686 // Same epsilon on both sides. Skip.
687 interfaceType = 0;
688 } else {
689 lambda = (eps[vol] - 1.) / (eps[vol] + 1.);
690 }
691 } else if (bc[vol] == Solid::Voltage) {
692 potential = volt[vol];
693 }
694 if (bc[vol] == Solid::Charge || bc[vol] == Solid::DielectricCharge) {
695 chargeDensity = charge[vol];
696 }
697 } else {
698 const auto bc1 = bc[vol1[j]];
699 const auto bc2 = bc[vol2[j]];
700 if (bc1 == Solid::Voltage || bc1 == Solid::Charge ||
701 bc1 == Solid::Float) {
702 interfaceType = InterfaceType(bc1);
703 // First volume is a conductor. Other volume must be a dielectric.
704 if (bc2 == Solid::Dielectric || bc2 == Solid::DielectricCharge) {
705 if (bc1 == Solid::Voltage) {
706 potential = volt[vol1[j]];
707 } else if (bc1 == Solid::Charge) {
708 chargeDensity = charge[vol1[j]];
709 }
710 } else {
711 interfaceType = -1;
712 }
713 if (bc1 == Solid::Voltage && bc2 == Solid::Voltage) {
714 const double v1 = volt[vol1[j]];
715 const double v2 = volt[vol2[j]];
716 if (fabs(v1 - v2) < 1.e-6 * (1. + fabs(v1) + fabs(v2))) {
717 interfaceType = 0;
718 }
719 }
720 } else if (bc1 == Solid::Dielectric ||
722 interfaceType = InterfaceType(bc2);
723 // First volume is a dielectric.
724 if (bc2 == Solid::Voltage) {
725 potential = volt[vol2[j]];
726 } else if (bc2 == Solid::Charge) {
727 chargeDensity = charge[vol2[j]];
728 } else if (bc2 == Solid::Dielectric ||
730 const double eps1 = eps[vol1[j]];
731 const double eps2 = eps[vol2[j]];
732 if (fabs(eps1 - eps2) < 1.e-6 * (1. + fabs(eps1) + fabs(eps2))) {
733 // Same epsilon. Skip.
734 interfaceType = 0;
735 } else {
736 lambda = (eps1 - eps2) / (eps1 + eps2);
737 }
738 }
739 }
740 }
741 if (m_debug) {
742 if (interfaceType < 0) {
743 std::cout << " Conflicting boundary conditions. Skip.\n";
744 } else if (interfaceType < 1) {
745 std::cout << " Trivial interface. Skip.\n";
746 } else if (interfaceType > 5) {
747 std::cout << " Interface type " << interfaceType
748 << " is not implemented. Skip.\n";
749 }
750 }
751 if (interfaceType < 1 || interfaceType > 5) continue;
752
753 std::vector<Panel> panelsOut;
754 // Reduce to rectangles and right-angle triangles.
755 if (m_debug) std::cout << " Creating primitives.\n";
756 MakePrimitives(newPanels[j], panelsOut);
757 // Loop over the rectangles and triangles.
758 for (auto& panel : panelsOut) {
759 const auto& up = panel.xv;
760 const auto& vp = panel.yv;
761 const auto& wp = panel.zv;
762 const unsigned int np = up.size();
763 // Rotate.
764 xp.assign(np, 0.);
765 yp.assign(np, 0.);
766 zp.assign(np, 0.);
767 for (unsigned int k = 0; k < np; ++k) {
768 xp[k] = rot[0][0] * up[k] + rot[1][0] * vp[k] + rot[2][0] * wp[k];
769 yp[k] = rot[0][1] * up[k] + rot[1][1] * vp[k] + rot[2][1] * wp[k];
770 zp[k] = rot[0][2] * up[k] + rot[1][2] * vp[k] + rot[2][2] * wp[k];
771 }
772 Primitive primitive;
773 primitive.a = panel.a;
774 primitive.b = panel.b;
775 primitive.c = panel.c;
776 primitive.xv = xp;
777 primitive.yv = yp;
778 primitive.zv = zp;
779 primitive.v = potential;
780 primitive.q = chargeDensity;
781 primitive.lambda = lambda;
782 primitive.interface = interfaceType;
783 // Set the requested discretization level (target element size).
784 primitive.elementSize = -1.;
785 if (solids.find(vol1[j]) != solids.end()) {
786 const auto solid = solids[vol1[j]];
787 if (solid) {
788 primitive.elementSize = solid->GetDiscretisationLevel(panel);
789 }
790 }
791 m_primitives.push_back(std::move(primitive));
792 }
793 }
794 }
795
796 if (m_debug) {
797 std::cout << m_className << "::Initialise:\n"
798 << " Created " << m_primitives.size() << " primitives.\n";
799 }
800
801 // Discretize the primitives.
802 for (const auto& primitive : m_primitives) {
803 const auto nVertices = primitive.xv.size();
804 if (nVertices < 2 || nVertices > 4) continue;
805 std::vector<Element> elements;
806 // Get the target element size.
807 double targetSize = primitive.elementSize;
808 if (targetSize < MinDist) targetSize = m_targetElementSize;
809 if (nVertices == 2) {
810 DiscretizeWire(primitive, targetSize, elements);
811 } else if (nVertices == 3) {
812 DiscretizeTriangle(primitive, targetSize, elements);
813 } else if (nVertices == 4) {
814 DiscretizeRectangle(primitive, targetSize, elements);
815 }
816 for (auto& element: elements) {
817 element.interface = primitive.interface;
818 element.lambda = primitive.lambda;
819 element.bc = primitive.v;
820 element.assigned = primitive.q;
821 element.solution = 0.;
822 }
823 m_elements.insert(m_elements.end(),
824 std::make_move_iterator(elements.begin()),
825 std::make_move_iterator(elements.end()));
826 }
827 return true;
828}
GeometryBase * m_geometry
Pointer to the geometry.
bool m_debug
Switch on/off debugging messages.
virtual unsigned int GetNumberOfSolids() const
Return the number of solids in the geometry.
Definition: GeometryBase.hh:25
virtual Solid * GetSolid(const unsigned int) const
Get a solid from the list.
Definition: GeometryBase.hh:27
@ DielectricCharge
Definition: Solid.hh:130
virtual bool SolidPanels(std::vector< Panel > &panels)=0
Retrieve the surface panels of the solid.
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:615
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:314

Referenced by ElectricField().

◆ Reset()

void Garfield::ComponentNeBem3d::Reset ( )
overridevirtual

Reset the component.

Implements Garfield::ComponentBase.

Definition at line 2519 of file ComponentNeBem3d.cc.

2519 {
2520 m_primitives.clear();
2521 m_elements.clear();
2522 m_ready = false;
2523}

◆ SetTargetElementSize()

void Garfield::ComponentNeBem3d::SetTargetElementSize ( const double  length)

Set the default value of the target linear size of the elements produced by neBEM's discretisation process.

Definition at line 417 of file ComponentNeBem3d.cc.

417 {
418
419 if (length < MinDist) {
420 std::cerr << m_className << "::SetTargetElementSize: Value must be > "
421 << MinDist << ".\n";
422 return;
423 }
424 m_targetElementSize = length;
425}

◆ UpdatePeriodicity()

void Garfield::ComponentNeBem3d::UpdatePeriodicity ( )
overridevirtual

Verify periodicities.

Implements Garfield::ComponentBase.

Definition at line 2525 of file ComponentNeBem3d.cc.

2525 {
2526 std::cerr << m_className << "::UpdatePeriodicity:\n"
2527 << " Periodicities are not supported.\n";
2528}

The documentation for this class was generated from the following files: