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

Component for importing and interpolating three-dimensional ANSYS field maps. More...

#include <ComponentAnsys123.hh>

+ Inheritance diagram for Garfield::ComponentAnsys123:

Public Member Functions

 ComponentAnsys123 ()
 Constructor.
 
 ~ComponentAnsys123 ()
 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 (std::string elist="ELIST.lis", std::string nlist="NLIST.lis", std::string mplist="MPLIST.lis", std::string prnsol="PRNSOL.lis", std::string unit="cm")
 
bool SetWeightingField (std::string prnsol, std::string label)
 
- 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 and interpolating three-dimensional ANSYS field maps.

Definition at line 10 of file ComponentAnsys123.hh.

Constructor & Destructor Documentation

◆ ComponentAnsys123()

Garfield::ComponentAnsys123::ComponentAnsys123 ( )

Constructor.

Definition at line 10 of file ComponentAnsys123.cc.

11 m_className = "ComponentAnsys123";
12}
std::string m_className
Class name.

◆ ~ComponentAnsys123()

Garfield::ComponentAnsys123::~ComponentAnsys123 ( )
inline

Destructor.

Definition at line 15 of file ComponentAnsys123.hh.

15{}

Member Function Documentation

◆ ElectricField() [1/2]

void Garfield::ComponentAnsys123::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 822 of file ComponentAnsys123.cc.

825 {
826 // Copy the coordinates
827 double x = xin, y = yin, z = zin;
828
829 // Map the coordinates onto field map coordinates
830 bool xmirr, ymirr, zmirr;
831 double rcoordinate, rotation;
832 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
833
834 // Initial values
835 ex = ey = ez = volt = 0.;
836 status = 0;
837 m = nullptr;
838
839 // Do not proceed if not properly initialised.
840 if (!m_ready) {
841 status = -10;
842 PrintNotReady("ElectricField");
843 return;
844 }
845
846 if (m_warning) PrintWarning("ElectricField");
847
848 // Find the element that contains this point
849 double t1, t2, t3, t4, jac[4][4], det;
850 const int imap = FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
851 if (imap < 0) {
852 if (m_debug) {
853 std::cerr << m_className << "::ElectricField: Point (" << x << ", " << y
854 << ", " << z << ") not in the mesh.\n";
855 }
856 status = -6;
857 return;
858 }
859
860 const Element& element = elements[imap];
861 if (m_debug) {
862 PrintElement("ElectricField", x, y, z, t1, t2, t3, t4, element, 10);
863 }
864 const Node& n0 = nodes[element.emap[0]];
865 const Node& n1 = nodes[element.emap[1]];
866 const Node& n2 = nodes[element.emap[2]];
867 const Node& n3 = nodes[element.emap[3]];
868 const Node& n4 = nodes[element.emap[4]];
869 const Node& n5 = nodes[element.emap[5]];
870 const Node& n6 = nodes[element.emap[6]];
871 const Node& n7 = nodes[element.emap[7]];
872 const Node& n8 = nodes[element.emap[8]];
873 const Node& n9 = nodes[element.emap[9]];
874 // Shorthands.
875 const double fourt1 = 4 * t1;
876 const double fourt2 = 4 * t2;
877 const double fourt3 = 4 * t3;
878 const double fourt4 = 4 * t4;
879 const double invdet = 1. / det;
880 // Tetrahedral field
881 volt = n0.v * t1 * (2 * t1 - 1) + n1.v * t2 * (2 * t2 - 1) +
882 n2.v * t3 * (2 * t3 - 1) + n3.v * t4 * (2 * t4 - 1) +
883 n4.v * fourt1 * t2 + n5.v * fourt1 * t3 + n6.v * fourt1 * t4 +
884 n7.v * fourt2 * t3 + n8.v * fourt2 * t4 + n9.v * fourt3 * t4;
885 ex = -(n0.v * (fourt1 - 1) * jac[0][1] + n1.v * (fourt2 - 1) * jac[1][1] +
886 n2.v * (fourt3 - 1) * jac[2][1] + n3.v * (fourt4 - 1) * jac[3][1] +
887 n4.v * (fourt2 * jac[0][1] + fourt1 * jac[1][1]) +
888 n5.v * (fourt3 * jac[0][1] + fourt1 * jac[2][1]) +
889 n6.v * (fourt4 * jac[0][1] + fourt1 * jac[3][1]) +
890 n7.v * (fourt3 * jac[1][1] + fourt2 * jac[2][1]) +
891 n8.v * (fourt4 * jac[1][1] + fourt2 * jac[3][1]) +
892 n9.v * (fourt4 * jac[2][1] + fourt3 * jac[3][1])) *
893 invdet;
894
895 ey = -(n0.v * (fourt1 - 1) * jac[0][2] + n1.v * (fourt2 - 1) * jac[1][2] +
896 n2.v * (fourt3 - 1) * jac[2][2] + n3.v * (fourt4 - 1) * jac[3][2] +
897 n4.v * (fourt2 * jac[0][2] + fourt1 * jac[1][2]) +
898 n5.v * (fourt3 * jac[0][2] + fourt1 * jac[2][2]) +
899 n6.v * (fourt4 * jac[0][2] + fourt1 * jac[3][2]) +
900 n7.v * (fourt3 * jac[1][2] + fourt2 * jac[2][2]) +
901 n8.v * (fourt4 * jac[1][2] + fourt2 * jac[3][2]) +
902 n9.v * (fourt4 * jac[2][2] + fourt3 * jac[3][2])) *
903 invdet;
904
905 ez = -(n0.v * (fourt1 - 1) * jac[0][3] + n1.v * (fourt2 - 1) * jac[1][3] +
906 n2.v * (fourt3 - 1) * jac[2][3] + n3.v * (fourt4 - 1) * jac[3][3] +
907 n4.v * (fourt2 * jac[0][3] + fourt1 * jac[1][3]) +
908 n5.v * (fourt3 * jac[0][3] + fourt1 * jac[2][3]) +
909 n6.v * (fourt4 * jac[0][3] + fourt1 * jac[3][3]) +
910 n7.v * (fourt3 * jac[1][3] + fourt2 * jac[2][3]) +
911 n8.v * (fourt4 * jac[1][3] + fourt2 * jac[3][3]) +
912 n9.v * (fourt4 * jac[2][3] + fourt3 * jac[3][3])) *
913 invdet;
914
915 // Transform field to global coordinates
916 UnmapFields(ex, ey, ez, x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
917
918 // Drift medium?
919 if (m_debug) {
920 std::cout << m_className << "::ElectricField:\n";
921 std::cout << " Material " << element.matmap << ", drift flag "
922 << materials[element.matmap].driftmedium << ".\n";
923 }
924 m = materials[element.matmap].medium;
925 status = -5;
926 if (materials[element.matmap].driftmedium) {
927 if (m && m->IsDriftable()) status = 0;
928 }
929}
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::ComponentAnsys123::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 815 of file ComponentAnsys123.cc.

817 {
818 double v = 0.;
819 ElectricField(x, y, z, ex, ey, ez, v, m, status);
820}
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::ComponentAnsys123::GetAspectRatio ( const unsigned int  i,
double &  dmin,
double &  dmax 
)
overrideprotectedvirtual

Implements Garfield::ComponentFieldMap.

Definition at line 1156 of file ComponentAnsys123.cc.

1157 {
1158 if (i >= elements.size()) {
1159 dmin = dmax = 0.;
1160 return;
1161 }
1162
1163 const Element& element = elements[i];
1164 const int np = 4;
1165 // Loop over all pairs of vertices.
1166 for (int j = 0; j < np - 1; ++j) {
1167 const Node& nj = nodes[element.emap[j]];
1168 for (int k = j + 1; k < np; ++k) {
1169 const Node& nk = nodes[element.emap[k]];
1170 // Compute distance.
1171 const double dx = nj.x - nk.x;
1172 const double dy = nj.y - nk.y;
1173 const double dz = nj.z - nk.z;
1174 const double dist = sqrt(dx * dx + dy * dy + dz * dz);
1175 if (k == 1) {
1176 dmin = dmax = dist;
1177 } else {
1178 if (dist < dmin) dmin = dist;
1179 if (dist > dmax) dmax = dist;
1180 }
1181 }
1182 }
1183}
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:314

◆ GetElementVolume()

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

Implements Garfield::ComponentFieldMap.

Definition at line 1138 of file ComponentAnsys123.cc.

1138 {
1139 if (i >= elements.size()) return 0.;
1140 const Element& element = elements[i];
1141 const Node& n0 = nodes[element.emap[0]];
1142 const Node& n1 = nodes[element.emap[1]];
1143 const Node& n2 = nodes[element.emap[2]];
1144 const Node& n3 = nodes[element.emap[3]];
1145 const double vol =
1146 fabs((n3.x - n0.x) *
1147 ((n1.y - n0.y) * (n2.z - n0.z) - (n2.y - n0.y) * (n1.z - n0.z)) +
1148 (n3.y - n0.y) *
1149 ((n1.z - n0.z) * (n2.x - n0.x) - (n2.z - n0.z) * (n1.x - n0.x)) +
1150 (n3.z - n0.z) * ((n1.x - n0.x) * (n2.y - n0.y) -
1151 (n3.x - n0.x) * (n1.y - n0.y))) /
1152 6.;
1153 return vol;
1154}
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:615

◆ GetMedium()

Medium * Garfield::ComponentAnsys123::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 1091 of file ComponentAnsys123.cc.

1092 {
1093 // Copy the coordinates.
1094 double x = xin, y = yin, z = zin;
1095
1096 // Map the coordinates onto field map coordinates.
1097 bool xmirr, ymirr, zmirr;
1098 double rcoordinate, rotation;
1099 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
1100
1101 // Do not proceed if not properly initialised.
1102 if (!m_ready) {
1103 std::cerr << m_className << "::GetMedium:\n";
1104 std::cerr << " Field map not available for interpolation.\n";
1105 return NULL;
1106 }
1107 if (m_warning) PrintWarning("GetMedium");
1108
1109 // Find the element that contains this point.
1110 double t1, t2, t3, t4, jac[4][4], det;
1111 const int imap = FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
1112 if (imap < 0) {
1113 if (m_debug) {
1114 std::cerr << m_className << "::GetMedium:\n";
1115 std::cerr << " Point (" << x << ", " << y << ", " << z
1116 << ") not in the mesh.\n";
1117 }
1118 return NULL;
1119 }
1120 const Element& element = elements[imap];
1121 if (element.matmap >= m_nMaterials) {
1122 if (m_debug) {
1123 std::cerr << m_className << "::GetMedium:\n";
1124 std::cerr << " Point (" << x << ", " << y << ", " << z << ")"
1125 << " has out of range material number " << imap << ".\n";
1126 }
1127 return NULL;
1128 }
1129
1130 if (m_debug) {
1131 PrintElement("GetMedium", x, y, z, t1, t2, t3, t4, element, 10);
1132 }
1133
1134 // Assign a medium.
1135 return materials[element.matmap].medium;
1136}

◆ Initialise()

bool Garfield::ComponentAnsys123::Initialise ( std::string  elist = "ELIST.lis",
std::string  nlist = "NLIST.lis",
std::string  mplist = "MPLIST.lis",
std::string  prnsol = "PRNSOL.lis",
std::string  unit = "cm" 
)

Definition at line 14 of file ComponentAnsys123.cc.

16 {
17 m_ready = false;
18 m_warning = false;
19 m_nWarnings = 10;
20 // Keep track of the success.
21 bool ok = true;
22
23 // Buffer for reading
24 const int size = 100;
25 char line[size];
26
27 // Open the material list.
28 std::ifstream fmplist;
29 fmplist.open(mplist.c_str(), std::ios::in);
30 if (fmplist.fail()) {
31 std::cerr << m_className << "::Initialise:\n";
32 std::cerr << " Could not open material file " << mplist
33 << " for reading.\n",
34 std::cerr << " The file perhaps does not exist.\n";
35 return false;
36 }
37
38 // Read the material list.
39 m_nMaterials = 0;
40 long il = 0;
41 unsigned int icurrmat = 0;
42 bool readerror = false;
43 while (fmplist.getline(line, size, '\n')) {
44 il++;
45 // Skip page feed
46 if (strcmp(line, "1") == 0) {
47 fmplist.getline(line, size, '\n');
48 il++;
49 fmplist.getline(line, size, '\n');
50 il++;
51 fmplist.getline(line, size, '\n');
52 il++;
53 fmplist.getline(line, size, '\n');
54 il++;
55 fmplist.getline(line, size, '\n');
56 il++;
57 continue;
58 }
59 // Split the line in tokens
60 char* token = NULL;
61 token = strtok(line, " ");
62 // Skip blank lines and headers
63 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
64 strcmp(token, "TEMPERATURE") == 0 || strcmp(token, "PROPERTY=") == 0 ||
65 int(token[0]) == 10 || int(token[0]) == 13)
66 continue;
67 // Read number of materials,
68 // ensure it does not exceed the maximum and initialise the list
69 if (strcmp(token, "LIST") == 0) {
70 token = strtok(NULL, " ");
71 token = strtok(NULL, " ");
72 token = strtok(NULL, " ");
73 token = strtok(NULL, " ");
74 m_nMaterials = ReadInteger(token, -1, readerror);
75 if (readerror) {
76 std::cerr << m_className << "::Initialise:\n";
77 std::cerr << " Error reading file " << mplist << " (line " << il
78 << ").\n";
79 fmplist.close();
80 ok = false;
81 return false;
82 }
83 materials.resize(m_nMaterials);
84 for (unsigned int i = 0; i < m_nMaterials; ++i) {
85 materials[i].ohm = -1;
86 materials[i].eps = -1;
87 materials[i].medium = nullptr;
88 }
89 if (m_debug) {
90 std::cout << m_className << "::Initialise:\n";
91 std::cout << " Number of materials: " << m_nMaterials << "\n";
92 }
93 } else if (strcmp(token, "MATERIAL") == 0) {
94 // Version 12 format: read material number
95 token = strtok(NULL, " ");
96 token = strtok(NULL, " ");
97 const int imat = ReadInteger(token, -1, readerror);
98 if (readerror || imat < 0) {
99 std::cerr << m_className << "::Initialise:\n";
100 std::cerr << " Error reading file " << mplist << " (line " << il
101 << ").\n";
102 fmplist.close();
103 ok = false;
104 return false;
105 }
106 icurrmat = imat;
107 } else if (strcmp(token, "TEMP") == 0) {
108 // Version 12 format: read property tag and value
109 token = strtok(NULL, " ");
110 int itype = 0;
111 if (strncmp(token, "PERX", 4) == 0) {
112 itype = 1;
113 } else if (strncmp(token, "RSVX", 4) == 0) {
114 itype = 2;
115 } else {
116 std::cerr << m_className << "::Initialise:\n";
117 std::cerr << " Found unknown material property flag " << token
118 << "\n";
119 std::cerr << " on material properties file " << mplist << " (line "
120 << il << ").\n";
121 ok = false;
122 }
123 fmplist.getline(line, size, '\n');
124 il++;
125 token = NULL;
126 token = strtok(line, " ");
127 if (icurrmat < 1 || icurrmat > m_nMaterials) {
128 std::cerr << m_className << "::Initialise:\n";
129 std::cerr << " Found out-of-range current material index "
130 << icurrmat << "\n";
131 std::cerr << " in material properties file " << mplist << ".\n";
132 ok = false;
133 readerror = false;
134 } else if (itype == 1) {
135 materials[icurrmat - 1].eps = ReadDouble(token, -1, readerror);
136 } else if (itype == 2) {
137 materials[icurrmat - 1].ohm = ReadDouble(token, -1, readerror);
138 }
139 if (readerror) {
140 std::cerr << m_className << "::Initialise:\n";
141 std::cerr << " Error reading file " << mplist << " line " << il
142 << ").\n";
143 fmplist.close();
144 ok = false;
145 return false;
146 }
147 } else if (strcmp(token, "PROPERTY") == 0) {
148 // Version 11 format
149 token = strtok(NULL, " ");
150 token = strtok(NULL, " ");
151 int itype = 0;
152 if (strcmp(token, "PERX") == 0) {
153 itype = 1;
154 } else if (strcmp(token, "RSVX") == 0) {
155 itype = 2;
156 } else {
157 std::cerr << m_className << "::Initialise:\n";
158 std::cerr << " Found unknown material property flag " << token
159 << "\n";
160 std::cerr << " on material properties file " << mplist << " (line "
161 << il << ").\n";
162 ok = false;
163 }
164 token = strtok(NULL, " ");
165 token = strtok(NULL, " ");
166 int imat = ReadInteger(token, -1, readerror);
167 if (readerror) {
168 std::cerr << m_className << "::Initialise:\n";
169 std::cerr << " Error reading file " << mplist << " (line " << il
170 << ").\n";
171 fmplist.close();
172 ok = false;
173 return false;
174 } else if (imat < 1 || imat > (int)m_nMaterials) {
175 std::cerr << m_className << "::Initialise:\n";
176 std::cerr << " Found out-of-range material index " << imat << "\n";
177 std::cerr << " in material properties file " << mplist << ".\n";
178 ok = false;
179 } else {
180 fmplist.getline(line, size, '\n');
181 il++;
182 fmplist.getline(line, size, '\n');
183 il++;
184 token = NULL;
185 token = strtok(line, " ");
186 token = strtok(NULL, " ");
187 if (itype == 1) {
188 materials[imat - 1].eps = ReadDouble(token, -1, readerror);
189 } else if (itype == 2) {
190 materials[imat - 1].ohm = ReadDouble(token, -1, readerror);
191 }
192 if (readerror) {
193 std::cerr << m_className << "::Initialise:\n";
194 std::cerr << " Error reading file " << mplist << " (line " << il
195 << ").\n";
196 fmplist.close();
197 ok = false;
198 return false;
199 }
200 }
201 }
202 }
203
204 // Close the file
205 fmplist.close();
206
207 // Find the lowest epsilon, check for eps = 0, set default drift media
208 double epsmin = -1;
209 unsigned int iepsmin = 0;
210 for (unsigned int imat = 0; imat < m_nMaterials; ++imat) {
211 if (materials[imat].eps < 0) continue;
212 if (materials[imat].eps == 0) {
213 std::cerr << m_className << "::Initialise:\n";
214 std::cerr << " Material " << imat
215 << " has been assigned a permittivity\n";
216 std::cerr << " equal to zero in " << mplist << ".\n";
217 ok = false;
218 } else if (epsmin < 0. || epsmin > materials[imat].eps) {
219 epsmin = materials[imat].eps;
220 iepsmin = imat;
221 }
222 }
223
224 if (epsmin < 0.) {
225 std::cerr << m_className << "::Initialise:\n";
226 std::cerr << " No material with positive permittivity found \n";
227 std::cerr << " in material list " << mplist << ".\n";
228 ok = false;
229 } else {
230 for (unsigned int imat = 0; imat < m_nMaterials; ++imat) {
231 if (imat == iepsmin) {
232 materials[imat].driftmedium = true;
233 } else {
234 materials[imat].driftmedium = false;
235 }
236 }
237 }
238
239 // Tell how many lines read
240 std::cout << m_className << "::Initialise:\n";
241 std::cout << " Read properties of " << m_nMaterials
242 << " materials from file " << mplist << ".\n";
243 if (m_debug) PrintMaterials();
244
245 // Open the element list
246 std::ifstream felist;
247 felist.open(elist.c_str(), std::ios::in);
248 if (felist.fail()) {
249 std::cerr << m_className << "::Initialise:\n";
250 std::cerr << " Could not open element file " << elist
251 << " for reading.\n";
252 std::cerr << " The file perhaps does not exist.\n";
253 return false;
254 }
255
256 // Read the element list
257 elements.clear();
258 nElements = 0;
259 Element newElement;
260 int nbackground = 0;
261 il = 0;
262 int highestnode = 0;
263 while (felist.getline(line, size, '\n')) {
264 il++;
265 // Skip page feed
266 if (strcmp(line, "1") == 0) {
267 felist.getline(line, size, '\n');
268 il++;
269 felist.getline(line, size, '\n');
270 il++;
271 felist.getline(line, size, '\n');
272 il++;
273 felist.getline(line, size, '\n');
274 il++;
275 felist.getline(line, size, '\n');
276 il++;
277 continue;
278 }
279 // Skip page feed if ansys > v15.x
280 if (strstr(line,"***") != NULL) {
281 felist.getline(line, size, '\n');
282 il++;
283 felist.getline(line, size, '\n');
284 il++;
285 felist.getline(line, size, '\n');
286 il++;
287 continue;
288 }
289 // Split the line in tokens
290 char* token = NULL;
291 // Split into tokens
292 token = strtok(line, " ");
293 // Skip blank lines and headers
294 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
295 int(token[0]) == 10 || int(token[0]) == 13 ||
296 strcmp(token, "LIST") == 0 || strcmp(token, "ELEM") == 0) {
297 continue;
298 }
299 // Read the element
300 int ielem = ReadInteger(token, -1, readerror);
301 token = strtok(NULL, " ");
302 int imat = ReadInteger(token, -1, readerror);
303 token = strtok(NULL, " ");
304 token = strtok(NULL, " ");
305 token = strtok(NULL, " ");
306 token = strtok(NULL, " ");
307 token = strtok(NULL, " ");
308 int in0 = ReadInteger(token, -1, readerror);
309 token = strtok(NULL, " ");
310 int in1 = ReadInteger(token, -1, readerror);
311 token = strtok(NULL, " ");
312 int in2 = ReadInteger(token, -1, readerror);
313 token = strtok(NULL, " ");
314 int in3 = ReadInteger(token, -1, readerror);
315 token = strtok(NULL, " ");
316 int in4 = ReadInteger(token, -1, readerror);
317 token = strtok(NULL, " ");
318 int in5 = ReadInteger(token, -1, readerror);
319 token = strtok(NULL, " ");
320 int in6 = ReadInteger(token, -1, readerror);
321 token = strtok(NULL, " ");
322 int in7 = ReadInteger(token, -1, readerror);
323 if (!felist.getline(line, size, '\n')) {
324 std::cerr << m_className << "::Initialise:\n";
325 std::cerr << " Error reading element " << ielem << ".\n";
326 ok = false;
327 break;
328 }
329 ++il;
330 token = NULL;
331 token = strtok(line, " ");
332 int in8 = ReadInteger(token, -1, readerror);
333 token = strtok(NULL, " ");
334 int in9 = ReadInteger(token, -1, readerror);
335
336 // Check synchronisation
337 if (readerror) {
338 std::cerr << m_className << "::Initialise:\n";
339 std::cerr << " Error reading file " << elist << " (line " << il
340 << ").\n";
341 felist.close();
342 ok = false;
343 return false;
344 } else if (ielem - 1 != nElements + nbackground) {
345 std::cerr << m_className << "::Initialise:\n";
346 std::cerr << " Synchronisation lost on file " << elist << " (line "
347 << il << ").\n";
348 std::cerr << " Element: " << ielem << " (expected " << nElements
349 << "), material: " << imat << ",\n";
350 std::cerr << " nodes: (" << in0 << ", " << in1 << ", " << in2 << ", "
351 << in3 << ", " << in4 << ", " << in5 << ", " << in6 << ", "
352 << in7 << ", " << in8 << ", " << in9 << ")\n";
353 ok = false;
354 }
355
356 // Check the material number and ensure that epsilon is non-negative
357 if (imat < 1 || imat > (int)m_nMaterials) {
358 std::cerr << m_className << "::Initialise:\n";
359 std::cerr << " Out-of-range material number on file " << elist
360 << " (line " << il << ").\n";
361 std::cerr << " Element: " << ielem << ", material: " << imat << ",\n";
362 std::cerr << " nodes: (" << in0 << ", " << in1 << ", " << in2 << ", "
363 << in3 << ", " << in4 << ", " << in5 << ", " << in6 << ", "
364 << in7 << ", " << in8 << ", " << in9 << ")\n";
365 ok = false;
366 }
367 if (materials[imat - 1].eps < 0) {
368 std::cerr << m_className << "::Initialise:\n";
369 std::cerr << " Element " << ielem << " in element list " << elist
370 << "\n";
371 std::cerr << " uses material " << imat
372 << " which has not been assigned\n";
373 std::cerr << " a positive permittivity in material list " << mplist
374 << ".\n";
375 ok = false;
376 }
377
378 // Check the node numbers
379 if (in0 < 1 || in1 < 1 || in2 < 1 || in3 < 1 || in4 < 1 || in5 < 1 ||
380 in6 < 1 || in7 < 1 || in8 < 1 || in9 < 1) {
381 std::cerr << m_className << "::Initialise:\n";
382 std::cerr << " Found a node number < 1 on file " << elist << " (line "
383 << il << ").\n";
384 std::cerr << " Element: " << ielem << ", material: " << imat << ",\n";
385 std::cerr << " nodes: (" << in0 << ", " << in1 << ", " << in2 << ", "
386 << in3 << ", " << in4 << ", " << in5 << ", " << in6 << ", "
387 << in7 << ", " << in8 << ", " << in9 << ")\n";
388 ok = false;
389 }
390 if (in0 > highestnode) highestnode = in0;
391 if (in1 > highestnode) highestnode = in1;
392 if (in2 > highestnode) highestnode = in2;
393 if (in3 > highestnode) highestnode = in3;
394 if (in4 > highestnode) highestnode = in4;
395 if (in5 > highestnode) highestnode = in5;
396 if (in6 > highestnode) highestnode = in6;
397 if (in7 > highestnode) highestnode = in7;
398 if (in8 > highestnode) highestnode = in8;
399 if (in9 > highestnode) highestnode = in9;
400
401 // Skip elements in conductors.
402 if (m_deleteBackground && materials[imat - 1].ohm == 0) {
403 nbackground++;
404 continue;
405 }
406
407 // These elements must not be degenerate.
408 if (in0 == in1 || in0 == in2 || in0 == in3 || in0 == in4 || in0 == in5 ||
409 in0 == in6 || in0 == in7 || in0 == in8 || in0 == in9 || in1 == in2 ||
410 in1 == in3 || in1 == in4 || in1 == in5 || in1 == in6 || in1 == in7 ||
411 in1 == in8 || in1 == in9 || in2 == in3 || in2 == in4 || in2 == in5 ||
412 in2 == in6 || in2 == in7 || in2 == in8 || in2 == in9 || in3 == in4 ||
413 in3 == in5 || in3 == in6 || in3 == in7 || in3 == in8 || in3 == in9 ||
414 in4 == in5 || in4 == in6 || in4 == in7 || in4 == in8 || in4 == in9 ||
415 in5 == in6 || in5 == in7 || in5 == in8 || in5 == in9 || in6 == in7 ||
416 in6 == in8 || in6 == in9 || in7 == in8 || in7 == in9 || in8 == in9) {
417 std::cerr << m_className << "::Initialise:\n";
418 std::cerr << " Element " << ielem << " of file " << elist
419 << " is degenerate,\n";
420 std::cerr << " no such elements allowed in this type of map.\n";
421 ok = false;
422 }
423
424 newElement.degenerate = false;
425
426 // Store the material reference
427 newElement.matmap = imat - 1;
428
429 // Node references
430 newElement.emap[0] = in0 - 1;
431 newElement.emap[1] = in1 - 1;
432 newElement.emap[2] = in2 - 1;
433 newElement.emap[3] = in3 - 1;
434 newElement.emap[4] = in4 - 1;
435 newElement.emap[7] = in5 - 1;
436 newElement.emap[5] = in6 - 1;
437 newElement.emap[6] = in7 - 1;
438 newElement.emap[8] = in8 - 1;
439 newElement.emap[9] = in9 - 1;
440 elements.push_back(newElement);
441 nElements++;
442 }
443 // Close the file
444 felist.close();
445
446 // Tell how many lines read.
447 std::cout << m_className << "::Initialise:\n";
448 std::cout << " Read " << nElements << " elements from file " << elist
449 << ",\n";
450 std::cout << " highest node number: " << highestnode << ",\n";
451 std::cout << " background elements skipped: " << nbackground << "\n";
452 // Check the value of the unit
453 double funit;
454 if (strcmp(unit.c_str(), "mum") == 0 || strcmp(unit.c_str(), "micron") == 0 ||
455 strcmp(unit.c_str(), "micrometer") == 0) {
456 funit = 0.0001;
457 } else if (strcmp(unit.c_str(), "mm") == 0 ||
458 strcmp(unit.c_str(), "millimeter") == 0) {
459 funit = 0.1;
460 } else if (strcmp(unit.c_str(), "cm") == 0 ||
461 strcmp(unit.c_str(), "centimeter") == 0) {
462 funit = 1.0;
463 } else if (strcmp(unit.c_str(), "m") == 0 ||
464 strcmp(unit.c_str(), "meter") == 0) {
465 funit = 100.0;
466 } else {
467 std::cerr << m_className << "::Initialise:\n";
468 std::cerr << " Unknown length unit " << unit << ".\n";
469 ok = false;
470 funit = 1.0;
471 }
472 if (m_debug) {
473 std::cout << m_className << ":Initialise:\n";
474 std::cout << " Unit scaling factor = " << funit << ".\n";
475 }
476
477 // Open the node list
478 std::ifstream fnlist;
479 fnlist.open(nlist.c_str(), std::ios::in);
480 if (fnlist.fail()) {
481 std::cerr << m_className << "::Initialise:\n";
482 std::cerr << " Could not open nodes file " << nlist << " for reading.\n";
483 std::cerr << " The file perhaps does not exist.\n";
484 return false;
485 }
486
487 // Read the node list
488 nodes.clear();
489 nNodes = 0;
490 Node newNode;
491 newNode.w.clear();
492 il = 0;
493 while (fnlist.getline(line, size, '\n')) {
494 il++;
495 // Skip page feed
496 if (strcmp(line, "1") == 0) {
497 fnlist.getline(line, size, '\n');
498 il++;
499 fnlist.getline(line, size, '\n');
500 il++;
501 fnlist.getline(line, size, '\n');
502 il++;
503 fnlist.getline(line, size, '\n');
504 il++;
505 fnlist.getline(line, size, '\n');
506 il++;
507 continue;
508 }
509 // Skip page feed if ansys > v15.x
510 if (strstr(line,"***") != NULL) {
511 fnlist.getline(line, size, '\n');
512 il++;
513 fnlist.getline(line, size, '\n');
514 il++;
515 fnlist.getline(line, size, '\n');
516 il++;
517 continue;
518 }
519 // Split the line in tokens
520 char* token = NULL;
521 token = strtok(line, " ");
522 // Skip blank lines and headers
523 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
524 int(token[0]) == 10 || int(token[0]) == 13 ||
525 strcmp(token, "LIST") == 0 || strcmp(token, "NODE") == 0)
526 continue;
527 // Read the element
528 int inode = ReadInteger(token, -1, readerror);
529 token = strtok(NULL, " ");
530 double xnode = ReadDouble(token, -1, readerror);
531 token = strtok(NULL, " ");
532 double ynode = ReadDouble(token, -1, readerror);
533 token = strtok(NULL, " ");
534 double znode = ReadDouble(token, -1, readerror);
535 // Check syntax
536 if (readerror) {
537 std::cerr << m_className << "::Initialise:\n";
538 std::cerr << " Error reading file " << nlist << " (line " << il
539 << ").\n";
540 fnlist.close();
541 ok = false;
542 return false;
543 }
544 // Check synchronisation
545 if (inode - 1 != nNodes) {
546 std::cerr << m_className << "::Initialise:\n";
547 std::cerr << " Synchronisation lost on file " << nlist << " (line "
548 << il << ").\n";
549 std::cerr << " Node: " << inode << " (expected " << nNodes
550 << "), (x,y,z) = (" << xnode << ", " << ynode << ", " << znode
551 << ")\n";
552 ok = false;
553 }
554 // Store the point coordinates
555 newNode.x = xnode * funit;
556 newNode.y = ynode * funit;
557 newNode.z = znode * funit;
558 nodes.push_back(newNode);
559 nNodes++;
560 }
561 // Close the file
562 fnlist.close();
563 // Tell how many lines read
564 std::cout << m_className << "::Initialise:\n";
565 std::cout << " Read " << nNodes << " nodes from file " << nlist << ".\n";
566 // Check number of nodes
567 if (nNodes != highestnode) {
568 std::cerr << m_className << "::Initialise:\n";
569 std::cerr << " Number of nodes read (" << nNodes << ") on " << nlist
570 << "\n";
571 std::cerr << " does not match element list (" << highestnode << ").\n";
572 ok = false;
573 }
574
575 // Open the voltage list
576 std::ifstream fprnsol;
577 fprnsol.open(prnsol.c_str(), std::ios::in);
578 if (fprnsol.fail()) {
579 std::cerr << m_className << "::Initialise:\n";
580 std::cerr << " Could not open potential file " << prnsol
581 << " for reading.\n";
582 std::cerr << " The file perhaps does not exist.\n";
583 return false;
584 }
585
586 // Read the voltage list
587 il = 0;
588 int nread = 0;
589 while (fprnsol.getline(line, size, '\n')) {
590 il++;
591 // Skip page feed
592 if (strcmp(line, "1") == 0) {
593 fprnsol.getline(line, size, '\n');
594 il++;
595 fprnsol.getline(line, size, '\n');
596 il++;
597 fprnsol.getline(line, size, '\n');
598 il++;
599 fprnsol.getline(line, size, '\n');
600 il++;
601 fprnsol.getline(line, size, '\n');
602 il++;
603 continue;
604 }
605// Skip page feed if ansys > v15.x
606 if (strstr(line,"***") != NULL) {
607 fprnsol.getline(line, size, '\n');
608 il++;
609 fprnsol.getline(line, size, '\n');
610 il++;
611 fprnsol.getline(line, size, '\n');
612 il++;
613 continue;
614 }
615 // Split the line in tokens
616 char* token = NULL;
617 token = strtok(line, " ");
618 // Skip blank lines and headers
619 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
620 int(token[0]) == 10 || int(token[0]) == 13 ||
621 strcmp(token, "PRINT") == 0 || strcmp(token, "*****") == 0 ||
622 strcmp(token, "LOAD") == 0 || strcmp(token, "TIME=") == 0 ||
623 strcmp(token, "MAXIMUM") == 0 || strcmp(token, "VALUE") == 0 ||
624 strcmp(token, "NODE") == 0)
625 continue;
626 // Read the element
627 int inode = ReadInteger(token, -1, readerror);
628 token = strtok(NULL, " ");
629 double volt = ReadDouble(token, -1, readerror);
630 // Check syntax
631 if (readerror) {
632 std::cerr << m_className << "::Initialise:\n";
633 std::cerr << " Error reading file " << prnsol << " (line << " << il
634 << ").\n";
635 fprnsol.close();
636 ok = false;
637 return false;
638 }
639 // Check node number and store if OK
640 if (inode < 1 || inode > highestnode) {
641 std::cerr << m_className << "::Initialise:\n";
642 std::cerr << " Node number " << inode << " out of range\n";
643 std::cerr << " on potential file " << prnsol << " (line " << il
644 << ").\n";
645 ok = false;
646 } else {
647 nodes[inode - 1].v = volt;
648 nread++;
649 }
650 }
651 // Close the file
652 fprnsol.close();
653 // Tell how many lines read
654 std::cout << m_className << "::Initialise:\n";
655 std::cout << " Read " << nread << " potentials from file " << prnsol
656 << ".\n";
657 // Check number of nodes
658 if (nread != nNodes) {
659 std::cerr << m_className << "::Initialise:\n";
660 std::cerr << " Number of nodes read (" << nread << ") on potential file "
661 << prnsol << "\n";
662 std::cerr << " does not match the node list (" << nNodes << ").\n";
663 ok = false;
664 }
665
666 // Set the ready flag
667 if (ok) {
668 m_ready = true;
669 } else {
670 std::cerr << m_className << "::Initialise:\n";
671 std::cerr
672 << " Field map could not be read and can not be interpolated.\n";
673 return false;
674 }
675
676 // Remove weighting fields (if any).
677 wfields.clear();
678 wfieldsOk.clear();
680
681 // Establish the ranges
682 SetRange();
684 return true;
685}
void UpdatePeriodicity() override
Verify periodicities.
void PrintMaterials()
List all currently defined materials.
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

◆ SetWeightingField()

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

Definition at line 687 of file ComponentAnsys123.cc.

688 {
689 if (!m_ready) {
690 PrintNotReady("SetWeightingField");
691 std::cerr << " Weighting field cannot be added.\n";
692 return false;
693 }
694
695 // Open the voltage list.
696 std::ifstream fprnsol;
697 fprnsol.open(prnsol.c_str(), std::ios::in);
698 if (fprnsol.fail()) {
699 std::cerr << m_className << "::SetWeightingField:\n";
700 std::cerr << " Could not open potential file " << prnsol
701 << " for reading.\n";
702 std::cerr << " The file perhaps does not exist.\n";
703 return false;
704 }
705
706 // Check if a weighting field with the same label already exists.
707 int iw = nWeightingFields;
708 for (int i = nWeightingFields; i--;) {
709 if (wfields[i] == label) {
710 iw = i;
711 break;
712 }
713 }
714 if (iw == nWeightingFields) {
718 for (int j = nNodes; j--;) {
719 nodes[j].w.resize(nWeightingFields);
720 }
721 } else {
722 std::cout << m_className << "::SetWeightingField:\n";
723 std::cout << " Replacing existing weighting field " << label << ".\n";
724 }
725 wfields[iw] = label;
726 wfieldsOk[iw] = false;
727
728 // Buffer for reading
729 const int size = 100;
730 char line[size];
731
732 bool ok = true;
733 // Read the voltage list.
734 int il = 0;
735 int nread = 0;
736 bool readerror = false;
737
738 while (fprnsol.getline(line, size, '\n')) {
739 il++;
740 // Skip page feed
741 if (strcmp(line, "1") == 0) {
742 fprnsol.getline(line, size, '\n');
743 il++;
744 fprnsol.getline(line, size, '\n');
745 il++;
746 fprnsol.getline(line, size, '\n');
747 il++;
748 fprnsol.getline(line, size, '\n');
749 il++;
750 fprnsol.getline(line, size, '\n');
751 il++;
752 continue;
753 }
754 // Split the line in tokens.
755 char* token = NULL;
756 token = strtok(line, " ");
757 // Skip blank lines and headers.
758 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
759 int(token[0]) == 10 || int(token[0]) == 13 ||
760 strcmp(token, "PRINT") == 0 || strcmp(token, "*****") == 0 ||
761 strcmp(token, "LOAD") == 0 || strcmp(token, "TIME=") == 0 ||
762 strcmp(token, "MAXIMUM") == 0 || strcmp(token, "VALUE") == 0 ||
763 strcmp(token, "NODE") == 0)
764 continue;
765 // Read the element.
766 int inode = ReadInteger(token, -1, readerror);
767 token = strtok(NULL, " ");
768 double volt = ReadDouble(token, -1, readerror);
769 // Check the syntax.
770 if (readerror) {
771 std::cerr << m_className << "::SetWeightingField:\n";
772 std::cerr << " Error reading file " << prnsol.c_str() << " (line "
773 << il << ").\n";
774 fprnsol.close();
775 return false;
776 }
777 // Check node number and store if OK.
778 if (inode < 1 || inode > nNodes) {
779 std::cerr << m_className << "::SetWeightingField:\n";
780 std::cerr << " Node number " << inode << " out of range\n";
781 std::cerr << " on potential file " << prnsol.c_str() << " (line " << il
782 << ").\n";
783 ok = false;
784 } else {
785 nodes[inode - 1].w[iw] = volt;
786 nread++;
787 }
788 }
789 // Close the file.
790 fprnsol.close();
791
792 std::cout << m_className << "::SetWeightingField:\n";
793 std::cout << " Read " << nread << " potentials from file "
794 << prnsol.c_str() << ".\n";
795 // Check the number of nodes.
796 if (nread != nNodes) {
797 std::cerr << m_className << "::SetWeightingField:\n";
798 std::cerr << " Number of nodes read (" << nread << ") "
799 << " on potential file " << prnsol.c_str() << "\n";
800 std::cerr << " does not match the node list (" << nNodes << ").\n";
801 ok = false;
802 }
803
804 // Set the ready flag.
805 wfieldsOk[iw] = ok;
806 if (!ok) {
807 std::cerr << m_className << "::SetWeightingField:\n";
808 std::cerr << " Field map could not be read "
809 << "and cannot be interpolated.\n";
810 return false;
811 }
812 return true;
813}

◆ UpdatePeriodicity()

void Garfield::ComponentAnsys123::UpdatePeriodicity ( )
inlineoverrideprotectedvirtual

Verify periodicities.

Implements Garfield::ComponentBase.

Definition at line 41 of file ComponentAnsys123.hh.

Referenced by Initialise().

◆ WeightingField()

void Garfield::ComponentAnsys123::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 931 of file ComponentAnsys123.cc.

933 {
934 // Initial values
935 wx = wy = wz = 0;
936
937 // Do not proceed if not properly initialised.
938 if (!m_ready) return;
939
940 // Look for the label.
941 int iw = 0;
942 bool found = false;
943 for (int i = nWeightingFields; i--;) {
944 if (wfields[i] == label) {
945 iw = i;
946 found = true;
947 break;
948 }
949 }
950
951 // Do not proceed if the requested weighting field does not exist.
952 if (!found) return;
953 // Check if the weighting field is properly initialised.
954 if (!wfieldsOk[iw]) return;
955
956 // Copy the coordinates.
957 double x = xin, y = yin, z = zin;
958
959 // Map the coordinates onto field map coordinates
960 bool xmirr, ymirr, zmirr;
961 double rcoordinate, rotation;
962 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
963
964 if (m_warning) PrintWarning("WeightingField");
965
966 // Find the element that contains this point.
967 double t1, t2, t3, t4, jac[4][4], det;
968 const int imap = FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
969 // Check if the point is in the mesh.
970 if (imap < 0) return;
971
972 const Element& element = elements[imap];
973 if (m_debug) {
974 PrintElement("WeightingField", x, y, z, t1, t2, t3, t4, element, 10, iw);
975 }
976 const Node& n0 = nodes[element.emap[0]];
977 const Node& n1 = nodes[element.emap[1]];
978 const Node& n2 = nodes[element.emap[2]];
979 const Node& n3 = nodes[element.emap[3]];
980 const Node& n4 = nodes[element.emap[4]];
981 const Node& n5 = nodes[element.emap[5]];
982 const Node& n6 = nodes[element.emap[6]];
983 const Node& n7 = nodes[element.emap[7]];
984 const Node& n8 = nodes[element.emap[8]];
985 const Node& n9 = nodes[element.emap[9]];
986 // Tetrahedral field
987 const double invdet = 1. / det;
988 const double fourt1 = 4 * t1;
989 const double fourt2 = 4 * t2;
990 const double fourt3 = 4 * t3;
991 const double fourt4 = 4 * t4;
992 wx = -(n0.w[iw] * (fourt1 - 1) * jac[0][1] +
993 n1.w[iw] * (fourt2 - 1) * jac[1][1] +
994 n2.w[iw] * (fourt3 - 1) * jac[2][1] +
995 n3.w[iw] * (fourt4 - 1) * jac[3][1] +
996 n4.w[iw] * (fourt2 * jac[0][1] + fourt1 * jac[1][1]) +
997 n5.w[iw] * (fourt3 * jac[0][1] + fourt1 * jac[2][1]) +
998 n6.w[iw] * (fourt4 * jac[0][1] + fourt1 * jac[3][1]) +
999 n7.w[iw] * (fourt3 * jac[1][1] + fourt2 * jac[2][1]) +
1000 n8.w[iw] * (fourt4 * jac[1][1] + fourt2 * jac[3][1]) +
1001 n9.w[iw] * (fourt4 * jac[2][1] + fourt3 * jac[3][1])) *
1002 invdet;
1003
1004 wy = -(n0.w[iw] * (fourt1 - 1) * jac[0][2] +
1005 n1.w[iw] * (fourt2 - 1) * jac[1][2] +
1006 n2.w[iw] * (fourt3 - 1) * jac[2][2] +
1007 n3.w[iw] * (fourt4 - 1) * jac[3][2] +
1008 n4.w[iw] * (fourt2 * jac[0][2] + fourt1 * jac[1][2]) +
1009 n5.w[iw] * (fourt3 * jac[0][2] + fourt1 * jac[2][2]) +
1010 n6.w[iw] * (fourt4 * jac[0][2] + fourt1 * jac[3][2]) +
1011 n7.w[iw] * (fourt3 * jac[1][2] + fourt2 * jac[2][2]) +
1012 n8.w[iw] * (fourt4 * jac[1][2] + fourt2 * jac[3][2]) +
1013 n9.w[iw] * (fourt4 * jac[2][2] + fourt3 * jac[3][2])) *
1014 invdet;
1015
1016 wz = -(n0.w[iw] * (fourt1 - 1) * jac[0][3] +
1017 n1.w[iw] * (fourt2 - 1) * jac[1][3] +
1018 n2.w[iw] * (fourt3 - 1) * jac[2][3] +
1019 n3.w[iw] * (fourt4 - 1) * jac[3][3] +
1020 n4.w[iw] * (fourt2 * jac[0][3] + fourt1 * jac[1][3]) +
1021 n5.w[iw] * (fourt3 * jac[0][3] + fourt1 * jac[2][3]) +
1022 n6.w[iw] * (fourt4 * jac[0][3] + fourt1 * jac[3][3]) +
1023 n7.w[iw] * (fourt3 * jac[1][3] + fourt2 * jac[2][3]) +
1024 n8.w[iw] * (fourt4 * jac[1][3] + fourt2 * jac[3][3]) +
1025 n9.w[iw] * (fourt4 * jac[2][3] + fourt3 * jac[3][3])) *
1026 invdet;
1027
1028 // Transform field to global coordinates
1029 UnmapFields(wx, wy, wz, x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
1030}

◆ WeightingPotential()

double Garfield::ComponentAnsys123::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 1032 of file ComponentAnsys123.cc.

1034 {
1035 // Do not proceed if not properly initialised.
1036 if (!m_ready) return 0.;
1037
1038 // Look for the label.
1039 int iw = 0;
1040 bool found = false;
1041 for (int i = nWeightingFields; i--;) {
1042 if (wfields[i] == label) {
1043 iw = i;
1044 found = true;
1045 break;
1046 }
1047 }
1048
1049 // Do not proceed if the requested weighting field does not exist.
1050 if (!found) return 0.;
1051 // Check if the weighting field is properly initialised.
1052 if (!wfieldsOk[iw]) return 0.;
1053
1054 // Copy the coordinates.
1055 double x = xin, y = yin, z = zin;
1056
1057 // Map the coordinates onto field map coordinates.
1058 bool xmirr, ymirr, zmirr;
1059 double rcoordinate, rotation;
1060 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
1061
1062 if (m_warning) PrintWarning("WeightingPotential");
1063
1064 // Find the element that contains this point.
1065 double t1, t2, t3, t4, jac[4][4], det;
1066 const int imap = FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
1067 if (imap < 0) return 0.;
1068
1069 const Element& element = elements[imap];
1070 if (m_debug) {
1071 PrintElement("WeightingPotential", x, y, z, t1, t2, t3, t4, element, 10,
1072 iw);
1073 }
1074 const Node& n0 = nodes[element.emap[0]];
1075 const Node& n1 = nodes[element.emap[1]];
1076 const Node& n2 = nodes[element.emap[2]];
1077 const Node& n3 = nodes[element.emap[3]];
1078 const Node& n4 = nodes[element.emap[4]];
1079 const Node& n5 = nodes[element.emap[5]];
1080 const Node& n6 = nodes[element.emap[6]];
1081 const Node& n7 = nodes[element.emap[7]];
1082 const Node& n8 = nodes[element.emap[8]];
1083 const Node& n9 = nodes[element.emap[9]];
1084 return n0.w[iw] * t1 * (2 * t1 - 1) + n1.w[iw] * t2 * (2 * t2 - 1) +
1085 n2.w[iw] * t3 * (2 * t3 - 1) + n3.w[iw] * t4 * (2 * t4 - 1) +
1086 4 * n4.w[iw] * t1 * t2 + 4 * n5.w[iw] * t1 * t3 +
1087 4 * n6.w[iw] * t1 * t4 + 4 * n7.w[iw] * t2 * t3 +
1088 4 * n8.w[iw] * t2 * t4 + 4 * n9.w[iw] * t3 * t4;
1089}

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