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::ComponentElmer Class Reference

Component for importing field maps computed by Elmer. More...

#include <ComponentElmer.hh>

+ Inheritance diagram for Garfield::ComponentElmer:

Public Member Functions

 ComponentElmer ()
 Default constructor.
 
 ComponentElmer (const std::string &header, const std::string &elist, const std::string &nlist, const std::string &mplist, const std::string &volt, const std::string &unit)
 Constructor with a set of field map files, see Initialise().
 
 ~ComponentElmer ()
 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).
 
void WeightingField (const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label) override
 
double WeightingPotential (const double x, const double y, const double z, const std::string &label) override
 
MediumGetMedium (const double x, const double y, const double z) override
 Get the medium at a given location (x, y, z).
 
bool Initialise (const std::string &header="mesh.header", const std::string &elist="mesh.elements", const std::string &nlist="mesh.nodes", const std::string &mplist="dielectrics.dat", const std::string &volt="out.result", const std::string &unit="cm")
 
bool SetWeightingField (std::string prnsol, std::string label)
 Import a list of voltages to be used as weighting field.
 
- Public Member Functions inherited from Garfield::ComponentFieldMap
 ComponentFieldMap ()
 Constructor.
 
virtual ~ComponentFieldMap ()
 Destructor.
 
virtual void SetRange ()
 Calculate x, y, z, V and angular ranges.
 
void PrintRange ()
 Show x, y, z, V and angular ranges.
 
bool IsInBoundingBox (const double x, const double y, const double z) const
 
bool GetBoundingBox (double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
 Get the bounding box coordinates.
 
bool GetVoltageRange (double &vmin, double &vmax) override
 Calculate the voltage range [V].
 
void PrintMaterials ()
 List all currently defined materials.
 
void DriftMedium (const unsigned int imat)
 Flag a field map material as a drift medium.
 
void NotDriftMedium (const unsigned int imat)
 Flag a field map materials as a non-drift medium.
 
unsigned int GetNumberOfMaterials () const
 Return the number of materials in the field map.
 
double GetPermittivity (const unsigned int imat) const
 Return the permittivity of a field map material.
 
double GetConductivity (const unsigned int imat) const
 Return the conductivity of a field map material.
 
void SetMedium (const unsigned int imat, Medium *medium)
 Associate a field map material with a Medium class.
 
MediumGetMedium (const unsigned int i) const
 Return the Medium associated to a field map material.
 
unsigned int GetNumberOfMedia () const
 
int GetNumberOfElements () const
 Return the number of mesh elements.
 
bool GetElement (const unsigned int i, double &vol, double &dmin, double &dmax)
 Return the volume and aspect ratio of a mesh element.
 
void EnableCheckMapIndices ()
 
void DisableCheckMapIndices ()
 
void EnableDeleteBackgroundElements (const bool on=true)
 Option to eliminate mesh elements in conductors (default: on).
 
void EnableTetrahedralTreeForElementSearch (const bool on=true)
 
virtual MediumGetMedium (const double x, const double y, const double z)
 Get the medium at a given location (x, y, z).
 
- 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)
 

Protected Member Functions

void UpdatePeriodicity () override
 Verify periodicities.
 
double GetElementVolume (const unsigned int i) override
 
void GetAspectRatio (const unsigned int i, double &dmin, double &dmax) override
 
- Protected Member Functions inherited from Garfield::ComponentFieldMap
void Reset () override
 Reset the component.
 
void UpdatePeriodicity2d ()
 
void UpdatePeriodicityCommon ()
 
int FindElement5 (const double x, const double y, const double z, double &t1, double &t2, double &t3, double &t4, double jac[4][4], double &det)
 Find the element for a point in curved quadratic quadrilaterals.
 
int FindElement13 (const double x, const double y, const double z, double &t1, double &t2, double &t3, double &t4, double jac[4][4], double &det)
 Find the element for a point in curved quadratic tetrahedra.
 
int FindElementCube (const double x, const double y, const double z, double &t1, double &t2, double &t3, TMatrixD *&jac, std::vector< TMatrixD * > &dN)
 Find the element for a point in a cube.
 
void MapCoordinates (double &xpos, double &ypos, double &zpos, bool &xmirrored, bool &ymirrored, bool &zmirrored, double &rcoordinate, double &rotation) const
 Move (xpos, ypos, zpos) to field map coordinates.
 
void UnmapFields (double &ex, double &ey, double &ez, double &xpos, double &ypos, double &zpos, bool &xmirrored, bool &ymirrored, bool &zmirrored, double &rcoordinate, double &rotation) const
 Move (ex, ey, ez) to global coordinates.
 
int ReadInteger (char *token, int def, bool &error)
 
double ReadDouble (char *token, double def, bool &error)
 
virtual double GetElementVolume (const unsigned int i)=0
 
virtual void GetAspectRatio (const unsigned int i, double &dmin, double &dmax)=0
 
void PrintWarning (const std::string &header)
 
void PrintNotReady (const std::string &header) const
 
void PrintElement (const std::string &header, const double x, const double y, const double z, const double t1, const double t2, const double t3, const double t4, const Element &element, const unsigned int n, const int iw=-1) const
 
virtual void Reset ()=0
 Reset the component.
 
virtual void UpdatePeriodicity ()=0
 Verify periodicities.
 

Additional Inherited Members

- Protected Attributes inherited from Garfield::ComponentFieldMap
bool m_is3d = true
 
int nElements = -1
 
std::vector< Elementelements
 
int nNodes = -1
 
std::vector< Nodenodes
 
unsigned int m_nMaterials = 0
 
std::vector< Materialmaterials
 
int nWeightingFields = 0
 
std::vector< std::string > wfields
 
std::vector< bool > wfieldsOk
 
bool hasBoundingBox = false
 
std::array< double, 3 > m_minBoundingBox
 
std::array< double, 3 > m_maxBoundingBox
 
std::array< double, 3 > m_mapmin
 
std::array< double, 3 > m_mapmax
 
std::array< double, 3 > m_mapamin
 
std::array< double, 3 > m_mapamax
 
std::array< double, 3 > m_mapna
 
std::array< double, 3 > m_cells
 
double m_mapvmin
 
double m_mapvmax
 
std::array< bool, 3 > m_setang
 
bool m_deleteBackground = true
 
bool m_warning = false
 
unsigned int m_nWarnings = 0
 
- 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

Component for importing field maps computed by Elmer.

Definition at line 12 of file ComponentElmer.hh.

Constructor & Destructor Documentation

◆ ComponentElmer() [1/2]

Garfield::ComponentElmer::ComponentElmer ( )

Default constructor.

Definition at line 28 of file ComponentElmer.cc.

29 m_className = "ComponentElmer";
30}
std::string m_className
Class name.

◆ ComponentElmer() [2/2]

Garfield::ComponentElmer::ComponentElmer ( const std::string &  header,
const std::string &  elist,
const std::string &  nlist,
const std::string &  mplist,
const std::string &  volt,
const std::string &  unit 
)

Constructor with a set of field map files, see Initialise().

Definition at line 32 of file ComponentElmer.cc.

38 m_className = "ComponentElmer";
39 Initialise(header, elist, nlist, mplist, volt, unit);
40}
bool Initialise(const std::string &header="mesh.header", const std::string &elist="mesh.elements", const std::string &nlist="mesh.nodes", const std::string &mplist="dielectrics.dat", const std::string &volt="out.result", const std::string &unit="cm")

◆ ~ComponentElmer()

Garfield::ComponentElmer::~ComponentElmer ( )
inline

Destructor.

Definition at line 21 of file ComponentElmer.hh.

21{}

Member Function Documentation

◆ ElectricField() [1/2]

void Garfield::ComponentElmer::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 541 of file ComponentElmer.cc.

544 {
545 // Copy the coordinates
546 double x = xin, y = yin, z = zin;
547
548 // Map the coordinates onto field map coordinates
549 bool xmirr, ymirr, zmirr;
550 double rcoordinate, rotation;
551 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
552
553 // Initial values
554 ex = ey = ez = volt = 0.;
555 status = 0;
556 m = nullptr;
557
558 // Do not proceed if not properly initialised.
559 if (!m_ready) {
560 status = -10;
561 PrintNotReady("ElectricField");
562 return;
563 }
564
565 if (m_warning) PrintWarning("ElectricField");
566
567 // Find the element that contains this point
568 double t1, t2, t3, t4, jac[4][4], det;
569 const int imap = FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
570 if (imap < 0) {
571 if (m_debug) {
572 std::cout << m_className << "::ElectricField:\n Point (" << x << ", "
573 << y << ", " << z << ") is not in the mesh.\n";
574 }
575 status = -6;
576 return;
577 }
578
579 const Element& element = elements[imap];
580 if (m_debug) {
581 PrintElement("ElectricField", x, y, z, t1, t2, t3, t4, element, 10);
582 }
583 const Node& n0 = nodes[element.emap[0]];
584 const Node& n1 = nodes[element.emap[1]];
585 const Node& n2 = nodes[element.emap[2]];
586 const Node& n3 = nodes[element.emap[3]];
587 const Node& n4 = nodes[element.emap[4]];
588 const Node& n5 = nodes[element.emap[5]];
589 const Node& n6 = nodes[element.emap[6]];
590 const Node& n7 = nodes[element.emap[7]];
591 const Node& n8 = nodes[element.emap[8]];
592 const Node& n9 = nodes[element.emap[9]];
593 // Shorthands.
594 const double fourt1 = 4 * t1;
595 const double fourt2 = 4 * t2;
596 const double fourt3 = 4 * t3;
597 const double fourt4 = 4 * t4;
598 const double invdet = 1. / det;
599 // Tetrahedral field
600 volt = n0.v * t1 * (2 * t1 - 1) + n1.v * t2 * (2 * t2 - 1) +
601 n2.v * t3 * (2 * t3 - 1) + n3.v * t4 * (2 * t4 - 1) +
602 4 * n4.v * t1 * t2 + 4 * n5.v * t1 * t3 + 4 * n6.v * t1 * t4 +
603 4 * n7.v * t2 * t3 + 4 * n8.v * t2 * t4 + 4 * n9.v * t3 * t4;
604 ex = -(n0.v * (fourt1 - 1) * jac[0][1] + n1.v * (fourt2 - 1) * jac[1][1] +
605 n2.v * (fourt3 - 1) * jac[2][1] + n3.v * (fourt4 - 1) * jac[3][1] +
606 n4.v * (fourt2 * jac[0][1] + fourt1 * jac[1][1]) +
607 n5.v * (fourt3 * jac[0][1] + fourt1 * jac[2][1]) +
608 n6.v * (fourt4 * jac[0][1] + fourt1 * jac[3][1]) +
609 n7.v * (fourt3 * jac[1][1] + fourt2 * jac[2][1]) +
610 n8.v * (fourt4 * jac[1][1] + fourt2 * jac[3][1]) +
611 n9.v * (fourt4 * jac[2][1] + fourt3 * jac[3][1])) *
612 invdet;
613 ey = -(n0.v * (fourt1 - 1) * jac[0][2] + n1.v * (fourt2 - 1) * jac[1][2] +
614 n2.v * (fourt3 - 1) * jac[2][2] + n3.v * (fourt4 - 1) * jac[3][2] +
615 n4.v * (fourt2 * jac[0][2] + fourt1 * jac[1][2]) +
616 n5.v * (fourt3 * jac[0][2] + fourt1 * jac[2][2]) +
617 n6.v * (fourt4 * jac[0][2] + fourt1 * jac[3][2]) +
618 n7.v * (fourt3 * jac[1][2] + fourt2 * jac[2][2]) +
619 n8.v * (fourt4 * jac[1][2] + fourt2 * jac[3][2]) +
620 n9.v * (fourt4 * jac[2][2] + fourt3 * jac[3][2])) *
621 invdet;
622 ez = -(n0.v * (fourt1 - 1) * jac[0][3] + n1.v * (fourt2 - 1) * jac[1][3] +
623 n2.v * (fourt3 - 1) * jac[2][3] + n3.v * (fourt4 - 1) * jac[3][3] +
624 n4.v * (fourt2 * jac[0][3] + fourt1 * jac[1][3]) +
625 n5.v * (fourt3 * jac[0][3] + fourt1 * jac[2][3]) +
626 n6.v * (fourt4 * jac[0][3] + fourt1 * jac[3][3]) +
627 n7.v * (fourt3 * jac[1][3] + fourt2 * jac[2][3]) +
628 n8.v * (fourt4 * jac[1][3] + fourt2 * jac[3][3]) +
629 n9.v * (fourt4 * jac[2][3] + fourt3 * jac[3][3])) *
630 invdet;
631
632 // Transform field to global coordinates
633 UnmapFields(ex, ey, ez, x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
634
635 // Drift medium?
636 const Material& mat = materials[element.matmap];
637 if (m_debug) {
638 std::cout << m_className << "::ElectricField:\n Material "
639 << element.matmap << ", drift flag " << mat.driftmedium << ".\n";
640 }
641 m = mat.medium;
642 status = -5;
643 if (mat.driftmedium && m && m->IsDriftable()) status = 0;
644}
bool m_ready
Ready for use?
bool m_debug
Switch on/off debugging messages.
void MapCoordinates(double &xpos, double &ypos, double &zpos, bool &xmirrored, bool &ymirrored, bool &zmirrored, double &rcoordinate, double &rotation) const
Move (xpos, ypos, zpos) to field map coordinates.
void PrintWarning(const std::string &header)
std::vector< Material > materials
int FindElement13(const double x, const double y, const double z, double &t1, double &t2, double &t3, double &t4, double jac[4][4], double &det)
Find the element for a point in curved quadratic tetrahedra.
void PrintElement(const std::string &header, const double x, const double y, const double z, const double t1, const double t2, const double t3, const double t4, const Element &element, const unsigned int n, const int iw=-1) const
std::vector< Element > elements
void UnmapFields(double &ex, double &ey, double &ez, double &xpos, double &ypos, double &zpos, bool &xmirrored, bool &ymirrored, bool &zmirrored, double &rcoordinate, double &rotation) const
Move (ex, ey, ez) to global coordinates.
void PrintNotReady(const std::string &header) const

◆ ElectricField() [2/2]

void Garfield::ComponentElmer::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 534 of file ComponentElmer.cc.

536 {
537 double v = 0.;
538 ElectricField(x, y, z, ex, ey, ez, v, m, status);
539}
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().

◆ GetAspectRatio()

void Garfield::ComponentElmer::GetAspectRatio ( const unsigned int  i,
double &  dmin,
double &  dmax 
)
overrideprotectedvirtual

Implements Garfield::ComponentFieldMap.

Definition at line 869 of file ComponentElmer.cc.

870 {
871 if (i >= elements.size()) {
872 dmin = dmax = 0.;
873 return;
874 }
875
876 const Element& element = elements[i];
877 const int np = 4;
878 // Loop over all pairs of vertices.
879 for (int j = 0; j < np - 1; ++j) {
880 const Node& nj = nodes[element.emap[j]];
881 for (int k = j + 1; k < np; ++k) {
882 const Node& nk = nodes[element.emap[k]];
883 // Compute distance.
884 const double dx = nj.x - nk.x;
885 const double dy = nj.y - nk.y;
886 const double dz = nj.z - nk.z;
887 const double dist = sqrt(dx * dx + dy * dy + dz * dz);
888 if (k == 1) {
889 dmin = dmax = dist;
890 } else {
891 if (dist < dmin) dmin = dist;
892 if (dist > dmax) dmax = dist;
893 }
894 }
895 }
896}
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:314

◆ GetElementVolume()

double Garfield::ComponentElmer::GetElementVolume ( const unsigned int  i)
overrideprotectedvirtual

Implements Garfield::ComponentFieldMap.

Definition at line 848 of file ComponentElmer.cc.

848 {
849 if (i >= elements.size()) return 0.;
850 const Element& element = elements[i];
851 const Node& n0 = nodes[element.emap[0]];
852 const Node& n1 = nodes[element.emap[1]];
853 const Node& n2 = nodes[element.emap[2]];
854 const Node& n3 = nodes[element.emap[3]];
855
856 // Uses formula V = |a (dot) b x c|/6
857 // with a => "3", b => "1", c => "2" and origin "0"
858 const double vol =
859 fabs((n3.x - n0.x) *
860 ((n1.y - n0.y) * (n2.z - n0.z) - (n2.y - n0.y) * (n1.z - n0.z)) +
861 (n3.y - n0.y) *
862 ((n1.z - n0.z) * (n2.x - n0.x) - (n2.z - n0.z) * (n1.x - n0.x)) +
863 (n3.z - n0.z) * ((n1.x - n0.x) * (n2.y - n0.y) -
864 (n3.x - n0.x) * (n1.y - n0.y))) /
865 6.;
866 return vol;
867}
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:615

◆ GetMedium()

Medium * Garfield::ComponentElmer::GetMedium ( const double  x,
const double  y,
const double  z 
)
overridevirtual

Get the medium at a given location (x, y, z).

Reimplemented from Garfield::ComponentBase.

Definition at line 806 of file ComponentElmer.cc.

807 {
808 // Copy the coordinates
809 double x = xin, y = yin, z = zin;
810
811 // Map the coordinates onto field map coordinates
812 bool xmirr, ymirr, zmirr;
813 double rcoordinate, rotation;
814 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
815
816 // Do not proceed if not properly initialised.
817 if (!m_ready) {
818 PrintNotReady("GetMedium");
819 return nullptr;
820 }
821 if (m_warning) PrintWarning("GetMedium");
822
823 // Find the element that contains this point
824 double t1, t2, t3, t4, jac[4][4], det;
825 const int imap = FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
826 if (imap < 0) {
827 if (m_debug) {
828 std::cout << m_className << "::GetMedium:\n Point (" << x << ", " << y
829 << ", " << z << ") is not in the mesh.\n";
830 }
831 return nullptr;
832 }
833 const Element& element = elements[imap];
834 if (element.matmap >= m_nMaterials) {
835 if (m_debug) {
836 std::cerr << m_className << "::GetMedium:\n Point (" << x << ", " << y
837 << ", " << z << ") has out of range material number " << imap
838 << ".\n";
839 }
840 return nullptr;
841 }
842
843 if (m_debug) PrintElement("GetMedium", x, y, z, t1, t2, t3, t4, element, 10);
844
845 return materials[element.matmap].medium;
846}

◆ Initialise()

bool Garfield::ComponentElmer::Initialise ( const std::string &  header = "mesh.header",
const std::string &  elist = "mesh.elements",
const std::string &  nlist = "mesh.nodes",
const std::string &  mplist = "dielectrics.dat",
const std::string &  volt = "out.result",
const std::string &  unit = "cm" 
)

Import a field map from a set of files.

Parameters
headername of the header file (contains the number of elements and nodes).
elistname of the file that contains the list of mesh elements
nlistname of the file that contains the list of mesh nodes
mplistname of the file that contains the material properties
voltoutput of the field solver (list of voltages)
unitlength unit to be used

Definition at line 42 of file ComponentElmer.cc.

47 {
48 const std::string hdr = m_className + "::Initialise:";
49 m_debug = false;
50 m_ready = false;
51 m_warning = false;
52 m_nWarnings = 0;
53
54 // Keep track of the success.
55 bool ok = true;
56
57 // Buffer for reading
58 const int size = 100;
59 char line[size];
60
61 // Open the header.
62 std::ifstream fheader;
63 fheader.open(header.c_str(), std::ios::in);
64 if (fheader.fail()) {
65 PrintErrorOpeningFile(hdr, "header", header);
66 }
67
68 // Temporary variables for use in file reading
69 char* token = NULL;
70 bool readerror = false;
71 bool readstop = false;
72 int il = 0;
73
74 // Read the header to get the number of nodes and elements.
75 fheader.getline(line, size, '\n');
76 token = strtok(line, " ");
77 nNodes = ReadInteger(token, 0, readerror);
78 token = strtok(NULL, " ");
79 nElements = ReadInteger(token, 0, readerror);
80 std::cout << hdr << "\n Read " << nNodes << " nodes and " << nElements
81 << " elements from file " << header << ".\n";
82 if (readerror) {
83 PrintErrorReadingFile(hdr, header, il);
84 fheader.close();
85 return false;
86 }
87
88 // Close the header file.
89 fheader.close();
90
91 // Open the nodes list.
92 std::ifstream fnodes;
93 fnodes.open(nlist.c_str(), std::ios::in);
94 if (fnodes.fail()) {
95 PrintErrorOpeningFile(hdr, "nodes", nlist);
96 }
97
98 // Check the value of the unit.
99 double funit;
100 if (strcmp(unit.c_str(), "mum") == 0 || strcmp(unit.c_str(), "micron") == 0 ||
101 strcmp(unit.c_str(), "micrometer") == 0) {
102 funit = 0.0001;
103 } else if (strcmp(unit.c_str(), "mm") == 0 ||
104 strcmp(unit.c_str(), "millimeter") == 0) {
105 funit = 0.1;
106 } else if (strcmp(unit.c_str(), "cm") == 0 ||
107 strcmp(unit.c_str(), "centimeter") == 0) {
108 funit = 1.0;
109 } else if (strcmp(unit.c_str(), "m") == 0 ||
110 strcmp(unit.c_str(), "meter") == 0) {
111 funit = 100.0;
112 } else {
113 std::cerr << hdr << " Unknown length unit " << unit << ".\n";
114 ok = false;
115 funit = 1.0;
116 }
117 if (m_debug) std::cout << hdr << " Unit scaling factor = " << funit << ".\n";
118
119 // Read the nodes from the file.
120 for (il = 0; il < nNodes; il++) {
121 // Get a line from the nodes file.
122 fnodes.getline(line, size, '\n');
123
124 // Ignore the first two characters.
125 token = strtok(line, " ");
126 token = strtok(NULL, " ");
127
128 // Get the node coordinates.
129 token = strtok(NULL, " ");
130 double xnode = ReadDouble(token, -1, readerror);
131 token = strtok(NULL, " ");
132 double ynode = ReadDouble(token, -1, readerror);
133 token = strtok(NULL, " ");
134 double znode = ReadDouble(token, -1, readerror);
135 if (readerror) {
136 PrintErrorReadingFile(hdr, nlist, il);
137 fnodes.close();
138 return false;
139 }
140
141 // Set up and create a new node.
142 Node newNode;
143 newNode.w.clear();
144 newNode.x = xnode * funit;
145 newNode.y = ynode * funit;
146 newNode.z = znode * funit;
147 nodes.push_back(std::move(newNode));
148 }
149
150 // Close the nodes file.
151 fnodes.close();
152
153 // Open the potential file.
154 std::ifstream fvolt;
155 fvolt.open(volt.c_str(), std::ios::in);
156 if (fvolt.fail()) {
157 PrintErrorOpeningFile(hdr, "potentials", volt);
158 }
159
160 // Reset the line counter.
161 il = 1;
162
163 // Read past the header.
164 while (!readstop && fvolt.getline(line, size, '\n')) {
165 token = strtok(line, " ");
166 if (strcmp(token, "Perm:") == 0) readstop = true;
167 il++;
168 }
169
170 // Should have stopped: if not, print error message.
171 if (!readstop) {
172 std::cerr << hdr << "\n Error reading past header of potentials file "
173 << volt << ".\n";
174 fvolt.close();
175 return false;
176 }
177
178 // Read past the permutation map (number of lines = nNodes).
179 for (int tl = 0; tl < nNodes; tl++) {
180 fvolt.getline(line, size, '\n');
181 il++;
182 }
183
184 // Read the potentials.
185 for (int tl = 0; tl < nNodes; tl++) {
186 fvolt.getline(line, size, '\n');
187 token = strtok(line, " ");
188 double v = ReadDouble(token, -1, readerror);
189 if (readerror) {
190 PrintErrorReadingFile(hdr, volt, il);
191 fvolt.close();
192 return false;
193 }
194 // Place the voltage in its appropriate node.
195 nodes[tl].v = v;
196 }
197
198 // Close the potentials file.
199 fvolt.close();
200
201 // Open the materials file.
202 std::ifstream fmplist;
203 fmplist.open(mplist.c_str(), std::ios::in);
204 if (fmplist.fail()) {
205 PrintErrorOpeningFile(hdr, "materials", mplist);
206 }
207
208 // Read the dielectric constants from the materials file.
209 fmplist.getline(line, size, '\n');
210 token = strtok(line, " ");
211 if (readerror) {
212 std::cerr << hdr << "\n Error reading number of materials from "
213 << mplist << ".\n";
214 fmplist.close();
215 ok = false;
216 return false;
217 }
218 m_nMaterials = ReadInteger(token, 0, readerror);
219 materials.resize(m_nMaterials);
220 for (unsigned int i = 0; i < m_nMaterials; ++i) {
221 materials[i].ohm = -1;
222 materials[i].eps = -1;
223 materials[i].medium = nullptr;
224 }
225 for (il = 2; il < ((int)m_nMaterials + 2); il++) {
226 fmplist.getline(line, size, '\n');
227 token = strtok(line, " ");
228 ReadInteger(token, -1, readerror);
229 token = strtok(NULL, " ");
230 double dc = ReadDouble(token, -1.0, readerror);
231 if (readerror) {
232 PrintErrorReadingFile(hdr, mplist, il);
233 fmplist.close();
234 ok = false;
235 return false;
236 }
237 materials[il - 2].eps = dc;
238 std::cout << hdr << "\n Set material " << il - 2 << " of "
239 << m_nMaterials << " to eps " << dc << ".\n";
240 }
241
242 // Close the materials file.
243 fmplist.close();
244
245 // Find the lowest epsilon, check for eps = 0, set default drift media.
246 double epsmin = -1.;
247 unsigned int iepsmin = 0;
248 for (unsigned int imat = 0; imat < m_nMaterials; ++imat) {
249 if (materials[imat].eps < 0) continue;
250 if (materials[imat].eps == 0) {
251 std::cerr << hdr << "\n Material " << imat
252 << " has been assigned a permittivity equal to zero in\n "
253 << mplist << ".\n";
254 ok = false;
255 } else if (epsmin < 0. || epsmin > materials[imat].eps) {
256 epsmin = materials[imat].eps;
257 iepsmin = imat;
258 }
259 }
260
261 if (epsmin < 0.) {
262 std::cerr << hdr << "\n No material with positive permittivity found \n"
263 << " in material list " << mplist << ".\n";
264 ok = false;
265 } else {
266 for (unsigned int imat = 0; imat < m_nMaterials; ++imat) {
267 materials[imat].driftmedium = imat == iepsmin ? true : false;
268 }
269 }
270
271 // Open the elements file.
272 std::ifstream felems;
273 felems.open(elist.c_str(), std::ios::in);
274 if (felems.fail()) {
275 PrintErrorOpeningFile(hdr, "elements", elist);
276 }
277
278 // Read the elements and their material indices.
279 elements.clear();
280 int highestnode = 0;
281 Element newElement;
282 for (il = 0; il < nElements; il++) {
283 // Get a line
284 felems.getline(line, size, '\n');
285
286 // Split into tokens.
287 token = strtok(line, " ");
288 // Read the 2nd-order element
289 // Note: Ordering of Elmer elements can be described in the
290 // ElmerSolver manual (appendix D. at the time of this comment)
291 // If the order read below is compared to the shape functions used
292 // eg. in ElectricField, the order is wrong, but note at the
293 // end of this function the order of elements 5,6,7 will change to
294 // 7,5,6 when actually recorded in newElement.emap to correct for this
295 token = strtok(NULL, " ");
296 int imat = ReadInteger(token, -1, readerror) - 1;
297 token = strtok(NULL, " ");
298 token = strtok(NULL, " ");
299 int in0 = ReadInteger(token, -1, readerror);
300 token = strtok(NULL, " ");
301 int in1 = ReadInteger(token, -1, readerror);
302 token = strtok(NULL, " ");
303 int in2 = ReadInteger(token, -1, readerror);
304 token = strtok(NULL, " ");
305 int in3 = ReadInteger(token, -1, readerror);
306 token = strtok(NULL, " ");
307 int in4 = ReadInteger(token, -1, readerror);
308 token = strtok(NULL, " ");
309 int in5 = ReadInteger(token, -1, readerror);
310 token = strtok(NULL, " ");
311 int in6 = ReadInteger(token, -1, readerror);
312 token = strtok(NULL, " ");
313 int in7 = ReadInteger(token, -1, readerror);
314 token = strtok(NULL, " ");
315 int in8 = ReadInteger(token, -1, readerror);
316 token = strtok(NULL, " ");
317 int in9 = ReadInteger(token, -1, readerror);
318
319 if (m_debug && il < 10) {
320 std::cout << " Read nodes " << in0 << ", " << in1 << ", " << in2
321 << ", " << in3 << ", ... from element " << il + 1 << " of "
322 << nElements << " with mat " << imat << ".\n";
323 }
324
325 // Check synchronisation.
326 if (readerror) {
327 PrintErrorReadingFile(hdr, elist, il);
328 felems.close();
329 ok = false;
330 return false;
331 }
332
333 // Check the material number and ensure that epsilon is non-negative.
334 if (imat < 0 || imat > (int)m_nMaterials) {
335 std::cerr << hdr << "\n Out-of-range material number on file " << elist
336 << " (line " << il << ").\n";
337 std::cerr << " Element: " << il << ", material: " << imat << "\n";
338 std::cerr << " nodes: (" << in0 << ", " << in1 << ", " << in2 << ", "
339 << in3 << ", " << in4 << ", " << in5 << ", " << in6 << ", "
340 << in7 << ", " << in8 << ", " << in9 << ")\n";
341 ok = false;
342 }
343 if (materials[imat].eps < 0) {
344 std::cerr << hdr << "\n Element " << il << " in element list " << elist
345 << "\n uses material " << imat
346 << " which has not been assigned a positive permittivity in "
347 << mplist << ".\n";
348 ok = false;
349 }
350
351 // Check the node numbers.
352 if (in0 < 1 || in1 < 1 || in2 < 1 || in3 < 1 || in4 < 1 || in5 < 1 ||
353 in6 < 1 || in7 < 1 || in8 < 1 || in9 < 1) {
354 std::cerr << hdr << "\n Found a node number < 1 on file " << elist
355 << " (line " << il << ").\n Element: " << il
356 << ", material: " << imat << "\n nodes: (" << in0 << ", "
357 << in1 << ", " << in2 << ", " << in3 << ", " << in4 << ", "
358 << in5 << ", " << in6 << ", " << in7 << ", " << in8 << ", "
359 << in9 << ")\n";
360 ok = false;
361 }
362 if (in0 > highestnode) highestnode = in0;
363 if (in1 > highestnode) highestnode = in1;
364 if (in2 > highestnode) highestnode = in2;
365 if (in3 > highestnode) highestnode = in3;
366 if (in4 > highestnode) highestnode = in4;
367 if (in5 > highestnode) highestnode = in5;
368 if (in6 > highestnode) highestnode = in6;
369 if (in7 > highestnode) highestnode = in7;
370 if (in8 > highestnode) highestnode = in8;
371 if (in9 > highestnode) highestnode = in9;
372
373 // These elements must not be degenerate.
374 if (in0 == in1 || in0 == in2 || in0 == in3 || in0 == in4 || in0 == in5 ||
375 in0 == in6 || in0 == in7 || in0 == in8 || in0 == in9 || in1 == in2 ||
376 in1 == in3 || in1 == in4 || in1 == in5 || in1 == in6 || in1 == in7 ||
377 in1 == in8 || in1 == in9 || in2 == in3 || in2 == in4 || in2 == in5 ||
378 in2 == in6 || in2 == in7 || in2 == in8 || in2 == in9 || in3 == in4 ||
379 in3 == in5 || in3 == in6 || in3 == in7 || in3 == in8 || in3 == in9 ||
380 in4 == in5 || in4 == in6 || in4 == in7 || in4 == in8 || in4 == in9 ||
381 in5 == in6 || in5 == in7 || in5 == in8 || in5 == in9 || in6 == in7 ||
382 in6 == in8 || in6 == in9 || in7 == in8 || in7 == in9 || in8 == in9) {
383 std::cerr << hdr << "\n Element " << il << " of file " << elist
384 << " is degenerate,\n"
385 << " no such elements are allowed in this type of map.\n";
386 ok = false;
387 }
388
389 newElement.degenerate = false;
390
391 // Store the material reference.
392 newElement.matmap = imat;
393
394 // Node references
395 newElement.emap[0] = in0 - 1;
396 newElement.emap[1] = in1 - 1;
397 newElement.emap[2] = in2 - 1;
398 newElement.emap[3] = in3 - 1;
399 newElement.emap[4] = in4 - 1;
400 newElement.emap[7] = in5 - 1;
401 newElement.emap[5] = in6 - 1;
402 newElement.emap[6] = in7 - 1;
403 newElement.emap[8] = in8 - 1;
404 newElement.emap[9] = in9 - 1;
405 elements.push_back(newElement);
406 }
407
408 // Close the elements file.
409 felems.close();
410
411 // Set the ready flag.
412 if (ok) {
413 m_ready = true;
414 } else {
415 std::cerr << hdr << "\n Field map could not be "
416 << "read and cannot be interpolated.\n";
417 return false;
418 }
419
420 std::cout << hdr << " Finished.\n";
421
422 // Remove weighting fields (if any).
423 wfields.clear();
424 wfieldsOk.clear();
426
427 // Establish the ranges.
428 SetRange();
430 return true;
431}
void UpdatePeriodicity() override
Verify periodicities.
double ReadDouble(char *token, double def, bool &error)
int ReadInteger(char *token, int def, bool &error)
virtual void SetRange()
Calculate x, y, z, V and angular ranges.
std::vector< std::string > wfields

Referenced by ComponentElmer().

◆ SetWeightingField()

bool Garfield::ComponentElmer::SetWeightingField ( std::string  prnsol,
std::string  label 
)

Import a list of voltages to be used as weighting field.

Definition at line 433 of file ComponentElmer.cc.

433 {
434 const std::string hdr = m_className + "::SetWeightingField:";
435 if (!m_ready) {
436 PrintNotReady("SetWeightingField");
437 std::cerr << " Weighting field cannot be added.\n";
438 return false;
439 }
440
441 // Keep track of the success.
442 bool ok = true;
443
444 // Open the voltage list.
445 std::ifstream fwvolt;
446 fwvolt.open(wvolt.c_str(), std::ios::in);
447 if (fwvolt.fail()) {
448 PrintErrorOpeningFile(hdr, "potential", wvolt);
449 return false;
450 }
451
452 // Check if a weighting field with the same label already exists.
453 int iw = nWeightingFields;
454 for (int i = nWeightingFields; i--;) {
455 if (wfields[i] == label) {
456 iw = i;
457 break;
458 }
459 }
460 if (iw == nWeightingFields) {
464 for (int j = nNodes; j--;) {
465 nodes[j].w.resize(nWeightingFields);
466 }
467 } else {
468 std::cout << hdr << "\n Replacing existing weighting field " << label
469 << ".\n";
470 }
471 wfields[iw] = label;
472 wfieldsOk[iw] = false;
473
474 // Temporary variables for use in file reading
475 const int size = 100;
476 char line[size];
477 char* token = NULL;
478 bool readerror = false;
479 bool readstop = false;
480 int il = 1;
481
482 // Read past the header.
483 while (!readstop && fwvolt.getline(line, size, '\n')) {
484 token = strtok(line, " ");
485 if (strcmp(token, "Perm:") == 0) readstop = true;
486 il++;
487 }
488
489 // Should have stopped: if not, print error message.
490 if (!readstop) {
491 std::cerr << hdr << "\n Error reading past header of potentials file "
492 << wvolt << ".\n";
493 fwvolt.close();
494 ok = false;
495 return false;
496 }
497
498 // Read past the permutation map (number of lines = nNodes).
499 for (int tl = 0; tl < nNodes; tl++) {
500 fwvolt.getline(line, size, '\n');
501 il++;
502 }
503
504 // Read the potentials.
505 for (int tl = 0; tl < nNodes; tl++) {
506 double v;
507 fwvolt.getline(line, size, '\n');
508 token = strtok(line, " ");
509 v = ReadDouble(token, -1, readerror);
510 if (readerror) {
511 PrintErrorReadingFile(hdr, wvolt, il);
512 fwvolt.close();
513 ok = false;
514 return false;
515 }
516 // Place the weighting potential at its appropriate node and index.
517 nodes[tl].w[iw] = v;
518 }
519
520 // Close the potentials file.
521 fwvolt.close();
522 std::cout << hdr << "\n Read potentials from file " << wvolt << ".\n";
523
524 // Set the ready flag.
525 wfieldsOk[iw] = ok;
526 if (!ok) {
527 std::cerr << hdr << "\n Field map could not "
528 << "be read and cannot be interpolated.\n";
529 return false;
530 }
531 return true;
532}

◆ UpdatePeriodicity()

void Garfield::ComponentElmer::UpdatePeriodicity ( )
inlineoverrideprotectedvirtual

Verify periodicities.

Implements Garfield::ComponentBase.

Definition at line 57 of file ComponentElmer.hh.

Referenced by Initialise().

◆ WeightingField()

void Garfield::ComponentElmer::WeightingField ( const double  x,
const double  y,
const double  z,
double &  wx,
double &  wy,
double &  wz,
const std::string &  label 
)
overridevirtual

Calculate the weighting field at a given point and for a given electrode.

Parameters
x,y,zcoordinates [cm].
wx,wy,wzcomponents of the weighting field [1/cm].
labelname of the electrode

Reimplemented from Garfield::ComponentBase.

Definition at line 646 of file ComponentElmer.cc.

648 {
649 // Initial values
650 wx = wy = wz = 0;
651
652 // Do not proceed if not properly initialised.
653 if (!m_ready) return;
654
655 // Look for the label.
656 int iw = 0;
657 bool found = false;
658 for (int i = nWeightingFields; i--;) {
659 if (wfields[i] == label) {
660 iw = i;
661 found = true;
662 break;
663 }
664 }
665
666 // Do not proceed if the requested weighting field does not exist.
667 if (!found) return;
668 // Check if the weighting field is properly initialised.
669 if (!wfieldsOk[iw]) return;
670
671 // Copy the coordinates.
672 double x = xin, y = yin, z = zin;
673
674 // Map the coordinates onto field map coordinates
675 bool xmirr, ymirr, zmirr;
676 double rcoordinate, rotation;
677 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
678
679 if (m_warning) PrintWarning("WeightingField");
680
681 // Find the element that contains this point.
682 double t1, t2, t3, t4, jac[4][4], det;
683 const int imap = FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
684 // Check if the point is in the mesh.
685 if (imap < 0) return;
686
687 const Element& element = elements[imap];
688 if (m_debug) {
689 PrintElement("WeightingField", x, y, z, t1, t2, t3, t4, element, 10, iw);
690 }
691 const Node& n0 = nodes[element.emap[0]];
692 const Node& n1 = nodes[element.emap[1]];
693 const Node& n2 = nodes[element.emap[2]];
694 const Node& n3 = nodes[element.emap[3]];
695 const Node& n4 = nodes[element.emap[4]];
696 const Node& n5 = nodes[element.emap[5]];
697 const Node& n6 = nodes[element.emap[6]];
698 const Node& n7 = nodes[element.emap[7]];
699 const Node& n8 = nodes[element.emap[8]];
700 const Node& n9 = nodes[element.emap[9]];
701 // Shorthands.
702 const double fourt1 = 4 * t1;
703 const double fourt2 = 4 * t2;
704 const double fourt3 = 4 * t3;
705 const double fourt4 = 4 * t4;
706 const double invdet = 1. / det;
707 // Tetrahedral field
708 wx = -(n0.w[iw] * (fourt1 - 1) * jac[0][1] +
709 n1.w[iw] * (fourt2 - 1) * jac[1][1] +
710 n2.w[iw] * (fourt3 - 1) * jac[2][1] +
711 n3.w[iw] * (fourt4 - 1) * jac[3][1] +
712 n4.w[iw] * (fourt2 * jac[0][1] + fourt1 * jac[1][1]) +
713 n5.w[iw] * (fourt3 * jac[0][1] + fourt1 * jac[2][1]) +
714 n6.w[iw] * (fourt4 * jac[0][1] + fourt1 * jac[3][1]) +
715 n7.w[iw] * (fourt3 * jac[1][1] + fourt2 * jac[2][1]) +
716 n8.w[iw] * (fourt4 * jac[1][1] + fourt2 * jac[3][1]) +
717 n9.w[iw] * (fourt4 * jac[2][1] + fourt3 * jac[3][1])) *
718 invdet;
719 wy = -(n0.w[iw] * (fourt1 - 1) * jac[0][2] +
720 n1.w[iw] * (fourt2 - 1) * jac[1][2] +
721 n2.w[iw] * (fourt3 - 1) * jac[2][2] +
722 n3.w[iw] * (fourt4 - 1) * jac[3][2] +
723 n4.w[iw] * (fourt2 * jac[0][2] + fourt1 * jac[1][2]) +
724 n5.w[iw] * (fourt3 * jac[0][2] + fourt1 * jac[2][2]) +
725 n6.w[iw] * (fourt4 * jac[0][2] + fourt1 * jac[3][2]) +
726 n7.w[iw] * (fourt3 * jac[1][2] + fourt2 * jac[2][2]) +
727 n8.w[iw] * (fourt4 * jac[1][2] + fourt2 * jac[3][2]) +
728 n9.w[iw] * (fourt4 * jac[2][2] + fourt3 * jac[3][2])) *
729 invdet;
730 wz = -(n0.w[iw] * (fourt1 - 1) * jac[0][3] +
731 n1.w[iw] * (fourt2 - 1) * jac[1][3] +
732 n2.w[iw] * (fourt3 - 1) * jac[2][3] +
733 n3.w[iw] * (fourt4 - 1) * jac[3][3] +
734 n4.w[iw] * (fourt2 * jac[0][3] + fourt1 * jac[1][3]) +
735 n5.w[iw] * (fourt3 * jac[0][3] + fourt1 * jac[2][3]) +
736 n6.w[iw] * (fourt4 * jac[0][3] + fourt1 * jac[3][3]) +
737 n7.w[iw] * (fourt3 * jac[1][3] + fourt2 * jac[2][3]) +
738 n8.w[iw] * (fourt4 * jac[1][3] + fourt2 * jac[3][3]) +
739 n9.w[iw] * (fourt4 * jac[2][3] + fourt3 * jac[3][3])) *
740 invdet;
741
742 // Transform field to global coordinates
743 UnmapFields(wx, wy, wz, x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
744}

◆ WeightingPotential()

double Garfield::ComponentElmer::WeightingPotential ( const double  x,
const double  y,
const double  z,
const std::string &  label 
)
overridevirtual

Calculate the weighting potential at a given point.

Parameters
x,y,zcoordinates [cm].
labelname of the electrode.
Returns
weighting potential [dimensionless].

Reimplemented from Garfield::ComponentBase.

Definition at line 746 of file ComponentElmer.cc.

748 {
749 // Do not proceed if not properly initialised.
750 if (!m_ready) return 0.;
751
752 // Look for the label.
753 int iw = 0;
754 bool found = false;
755 for (int i = nWeightingFields; i--;) {
756 if (wfields[i] == label) {
757 iw = i;
758 found = true;
759 break;
760 }
761 }
762
763 // Do not proceed if the requested weighting field does not exist.
764 if (!found) return 0.;
765 // Check if the weighting field is properly initialised.
766 if (!wfieldsOk[iw]) return 0.;
767
768 // Copy the coordinates.
769 double x = xin, y = yin, z = zin;
770
771 // Map the coordinates onto field map coordinates.
772 bool xmirr, ymirr, zmirr;
773 double rcoordinate, rotation;
774 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
775
776 if (m_warning) PrintWarning("WeightingPotential");
777
778 // Find the element that contains this point.
779 double t1, t2, t3, t4, jac[4][4], det;
780 const int imap = FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
781 if (imap < 0) return 0.;
782
783 const Element& element = elements[imap];
784 if (m_debug) {
785 PrintElement("WeightingPotential", x, y, z, t1, t2, t3, t4, element, 10,
786 iw);
787 }
788 const Node& n0 = nodes[element.emap[0]];
789 const Node& n1 = nodes[element.emap[1]];
790 const Node& n2 = nodes[element.emap[2]];
791 const Node& n3 = nodes[element.emap[3]];
792 const Node& n4 = nodes[element.emap[4]];
793 const Node& n5 = nodes[element.emap[5]];
794 const Node& n6 = nodes[element.emap[6]];
795 const Node& n7 = nodes[element.emap[7]];
796 const Node& n8 = nodes[element.emap[8]];
797 const Node& n9 = nodes[element.emap[9]];
798 // Tetrahedral field
799 return n0.w[iw] * t1 * (2 * t1 - 1) + n1.w[iw] * t2 * (2 * t2 - 1) +
800 n2.w[iw] * t3 * (2 * t3 - 1) + n3.w[iw] * t4 * (2 * t4 - 1) +
801 4 * n4.w[iw] * t1 * t2 + 4 * n5.w[iw] * t1 * t3 +
802 4 * n6.w[iw] * t1 * t4 + 4 * n7.w[iw] * t2 * t3 +
803 4 * n8.w[iw] * t2 * t4 + 4 * n9.w[iw] * t3 * t4;
804}

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