17 m_regions.reserve(10);
18 m_vertices.reserve(10000);
19 m_elements.reserve(10000);
23 const double eXsec,
const double hXsec,
25 if (donorNumber >= m_donors.size()) {
26 std::cerr <<
m_className <<
"::SetDonor: Index out of range.\n";
29 m_donors[donorNumber].xsece = eXsec;
30 m_donors[donorNumber].xsech = hXsec;
31 m_donors[donorNumber].conc = conc;
33 m_validTraps = CheckTraps();
38 const double eXsec,
const double hXsec,
40 if (acceptorNumber >= m_acceptors.size()) {
41 std::cerr <<
m_className <<
"::SetAcceptor: Index out of range.\n";
44 m_acceptors[acceptorNumber].xsece = eXsec;
45 m_acceptors[acceptorNumber].xsech = hXsec;
46 m_acceptors[acceptorNumber].conc = conc;
48 m_validTraps = CheckTraps();
53 const double z,
double& eta) {
56 std::cerr <<
m_className <<
"::ElectronAttachment:\n"
57 <<
" Trap cross-sections or concentrations are invalid.\n";
61 if (m_donors.empty() && m_acceptors.empty()) {
63 std::cerr <<
m_className <<
"::ElectronAttachment: No traps defined.\n";
68 const unsigned int nAcceptors = m_acceptors.size();
69 for (
unsigned int i = 0; i < nAcceptors; ++i) {
70 const Defect& acceptor = m_acceptors[i];
73 eta += acceptor.conc * acceptor.xsece * (1. - f);
75 const unsigned int nDonors = m_donors.size();
76 for (
unsigned int i = 0; i < nDonors; ++i) {
77 const Defect& donor = m_donors[i];
80 eta += donor.conc * donor.xsece * f;
86 const double z,
double& eta) {
90 <<
" Trap cross-sections or concentrations are invalid.\n";
94 if (m_donors.empty() && m_acceptors.empty()) {
96 std::cerr <<
m_className <<
"::HoleAttachment: No traps defined.\n";
101 const unsigned int nAcceptors = m_acceptors.size();
102 for (
unsigned int i = 0; i < nAcceptors; ++i) {
103 const Defect& acceptor = m_acceptors[i];
106 eta += acceptor.conc * acceptor.xsech * f;
108 const unsigned int nDonors = m_donors.size();
109 for (
unsigned int i = 0; i < nDonors; ++i) {
110 const Defect& donor = m_donors[i];
113 eta += donor.conc * donor.xsech * (1. - f);
119 const double zin,
double& wx,
double& wy,
120 double& wz,
const std::string& ) {
123 std::cerr <<
m_className <<
"::WeightingField: Not available.\n";
127 double x = xin, y = yin, z = zin;
128 bool xmirr =
false, ymirr =
false;
129 MapCoordinates(x, y, xmirr, ymirr);
131 if (!InsideBoundingBox(x, y, z))
return;
133 std::array<double, nMaxVertices> w;
134 const unsigned int i = FindElement(x, y, w);
135 if (i >= m_elements.size())
return;
137 const Element& element = m_elements[i];
138 const unsigned int nVertices = element.type + 1;
139 for (
unsigned int j = 0; j < nVertices; ++j) {
140 const auto& f = m_wf[element.vertex[j]];
150 const std::string& ) {
153 std::cerr <<
m_className <<
"::WeightingPotential: Not available.\n";
157 double x = xin, y = yin, z = zin;
158 bool xmirr =
false, ymirr =
false;
159 MapCoordinates(x, y, xmirr, ymirr);
161 if (!InsideBoundingBox(x, y, z))
return 0.;
163 std::array<double, nMaxVertices> w;
164 const unsigned int i = FindElement(x, y, w);
165 if (i >= m_elements.size())
return 0.;
168 const Element& element = m_elements[i];
169 const unsigned int nVertices = element.type + 1;
170 for (
unsigned int j = 0; j < nVertices; ++j) {
171 v += w[j] * m_wp[element.vertex[j]];
177 const double zin,
double& ex,
double& ey,
178 double& ez,
double& p,
Medium*& m,
183 ex = ey = ez = p = 0.;
189 <<
" Field map is not available for interpolation.\n";
195 double x = xin, y = yin, z = zin;
196 bool xmirr =
false, ymirr =
false;
197 MapCoordinates(x, y, xmirr, ymirr);
199 if (!InsideBoundingBox(x, y, z)) {
204 std::array<double, nMaxVertices> w;
205 const unsigned int i = FindElement(x, y, w);
206 if (i >= m_elements.size()) {
212 const Element& element = m_elements[i];
213 const unsigned int nVertices = element.type + 1;
214 for (
unsigned int j = 0; j < nVertices; ++j) {
215 const Vertex& vj = m_vertices[element.vertex[j]];
222 m = m_regions[element.region].medium;
223 if (!m_regions[element.region].drift || !m) status = -5;
228 const double zin,
double& vx,
double& vy,
229 double& vz,
Medium*& m,
int& status) {
237 std::cerr <<
m_className <<
"::ElectronVelocity:\n"
238 <<
" Field map is not available for interpolation.\n";
243 double x = xin, y = yin, z = zin;
245 bool xmirr =
false, ymirr =
false;
246 MapCoordinates(x, y, xmirr, ymirr);
247 if (!InsideBoundingBox(x, y, z)) {
252 std::array<double, nMaxVertices> w;
253 const unsigned int i = FindElement(x, y, w);
254 if (i >= m_elements.size()) {
260 const Element& element = m_elements[i];
261 const unsigned int nVertices = element.type + 1;
262 for (
unsigned int j = 0; j < nVertices; ++j) {
263 const Vertex& vj = m_vertices[element.vertex[j]];
269 m = m_regions[element.region].medium;
270 if (!m_regions[element.region].drift || !m) status = -5;
275 const double zin,
double& vx,
double& vy,
276 double& vz,
Medium*& m,
int& status) {
287 <<
" Field map is not available for interpolation.\n";
292 double x = xin, y = yin, z = zin;
294 bool xmirr =
false, ymirr =
false;
295 MapCoordinates(x, y, xmirr, ymirr);
296 if (!InsideBoundingBox(x, y, z)) {
301 std::array<double, nMaxVertices> w;
302 const unsigned int i = FindElement(x, y, w);
303 if (i >= m_elements.size()) {
309 const Element& element = m_elements[i];
310 const unsigned int nVertices = element.type + 1;
311 for (
unsigned int j = 0; j < nVertices; ++j) {
312 const Vertex& vj = m_vertices[element.vertex[j]];
318 m = m_regions[element.region].medium;
319 if (!m_regions[element.region].drift || !m) status = -5;
328 <<
" Field map not available for interpolation.\n";
332 double x = xin, y = yin, z = zin;
334 bool xmirr =
false, ymirr =
false;
335 MapCoordinates(x, y, xmirr, ymirr);
337 if (!InsideBoundingBox(x, y, z))
return nullptr;
340 std::array<double, nMaxVertices> w;
341 const unsigned int i = FindElement(x, y, w);
342 if (i >= m_elements.size()) {
347 const Element& element = m_elements[i];
348 return m_regions[element.region].medium;
352 const double zin,
double& tau) {
356 std::cerr <<
m_className <<
"::GetElectronLifetime:\n"
357 <<
" Field map is not available for interpolation.\n";
361 double x = xin, y = yin, z = zin;
363 bool xmirr =
false, ymirr =
false;
364 MapCoordinates(x, y, xmirr, ymirr);
366 if (!InsideBoundingBox(x, y, z))
return false;
368 std::array<double, nMaxVertices> w;
369 const unsigned int i = FindElement(x, y, w);
370 if (i >= m_elements.size()) {
375 const Element& element = m_elements[i];
376 const unsigned int nVertices = element.type + 1;
377 for (
unsigned int j = 0; j < nVertices; ++j) {
378 const Vertex& vj = m_vertices[element.vertex[j]];
379 tau += w[j] * vj.eTau;
385 const double zin,
double& tau) {
390 <<
" Field map is not available for interpolation.\n";
394 double x = xin, y = yin, z = zin;
396 bool xmirr =
false, ymirr =
false;
397 MapCoordinates(x, y, xmirr, ymirr);
399 if (!InsideBoundingBox(x, y, z))
return false;
401 std::array<double, nMaxVertices> w;
402 const unsigned int i = FindElement(x, y, w);
403 if (i >= m_elements.size()) {
408 const Element& element = m_elements[i];
409 const unsigned int nVertices = element.type + 1;
410 for (
unsigned int j = 0; j < nVertices; ++j) {
411 const Vertex& vj = m_vertices[element.vertex[j]];
412 tau += w[j] * vj.hTau;
419 const double zin,
double& emob,
426 <<
" Field map is not available for interpolation.\n";
430 double x = xin, y = yin, z = zin;
432 bool xmirr =
false, ymirr =
false;
433 MapCoordinates(x, y, xmirr, ymirr);
435 if (!InsideBoundingBox(x, y, z))
return false;
437 std::array<double, nMaxVertices> w;
438 const unsigned int i = FindElement(x, y, w);
439 if (i >= m_elements.size()) {
444 const Element& element = m_elements[i];
445 const unsigned int nVertices = element.type + 1;
446 for (
unsigned int j = 0; j < nVertices; ++j) {
447 const Vertex& vj = m_vertices[element.vertex[j]];
448 emob += w[j] * vj.emob;
449 hmob += w[j] * vj.hmob;
457 const unsigned int donorNumber,
460 if (donorNumber >= m_donors.size()) {
461 std::cerr <<
m_className <<
"::GetDonorOccupation:\n"
462 <<
" Donor " << donorNumber <<
" does not exist.\n";
468 std::cerr <<
m_className <<
"::GetDonorOccupation:\n"
469 <<
" Field map is not available for interpolation.\n";
473 double x = xin, y = yin, z = zin;
475 bool xmirr =
false, ymirr =
false;
476 MapCoordinates(x, y, xmirr, ymirr);
478 if (!InsideBoundingBox(x, y, z))
return false;
480 std::array<double, nMaxVertices> w;
481 const unsigned int i = FindElement(x, y, w);
482 if (i >= m_elements.size()) {
487 const Element& element = m_elements[i];
488 const unsigned int nVertices = element.type + 1;
489 for (
unsigned int j = 0; j < nVertices; ++j) {
490 const Vertex& vj = m_vertices[element.vertex[j]];
491 f += w[j] * vj.donorOcc[donorNumber];
499 const unsigned int acceptorNumber,
502 if (acceptorNumber >= m_acceptors.size()) {
503 std::cerr <<
m_className <<
"::GetAcceptorOccupation:\n"
504 <<
" Acceptor " << acceptorNumber <<
" does not exist.\n";
510 std::cerr <<
m_className <<
"::GetAcceptorOccupation:\n"
511 <<
" Field map is not available for interpolation.\n";
515 double x = xin, y = yin, z = zin;
517 bool xmirr =
false, ymirr =
false;
518 MapCoordinates(x, y, xmirr, ymirr);
520 if (!InsideBoundingBox(x, y, z))
return false;
522 std::array<double, nMaxVertices> w;
523 const unsigned int i = FindElement(x, y, w);
524 if (i >= m_elements.size()) {
529 const Element& element = m_elements[i];
530 const unsigned int nVertices = element.type + 1;
531 for (
unsigned int j = 0; j < nVertices; ++j) {
532 const Vertex& vj = m_vertices[element.vertex[j]];
533 f += w[j] * vj.acceptorOcc[acceptorNumber];
540 const std::string& datafilename) {
543 m_hasPotential = m_hasField =
false;
544 m_hasElectronMobility = m_hasHoleMobility =
false;
545 m_validTraps =
false;
550 if (!LoadGrid(gridfilename)) {
552 <<
" Importing mesh data failed.\n";
558 if (!LoadData(datafilename)) {
560 <<
" Importing electric field and potential failed.\n";
565 m_xMaxBB = m_xMinBB = m_vertices[m_elements[0].vertex[0]].x;
566 m_yMaxBB = m_yMinBB = m_vertices[m_elements[0].vertex[0]].y;
567 m_pMax = m_pMin = m_vertices[m_elements[0].vertex[0]].p;
568 for (
auto& element : m_elements) {
569 const Vertex& v0 = m_vertices[element.vertex[0]];
570 const Vertex& v1 = m_vertices[element.vertex[1]];
571 double xmin = std::min(v0.x, v1.x);
572 double xmax = std::max(v0.x, v1.x);
573 double ymin = std::min(v0.y, v1.y);
574 double ymax = std::max(v0.y, v1.y);
575 m_pMin = std::min(m_pMin, std::min(v0.p, v1.p));
576 m_pMax = std::max(m_pMax, std::max(v0.p, v1.p));
577 if (element.type > 1) {
578 const Vertex& v2 = m_vertices[element.vertex[2]];
579 xmin = std::min(xmin, v2.x);
580 xmax = std::max(xmax, v2.x);
581 ymin = std::min(ymin, v2.y);
582 ymax = std::max(ymax, v2.y);
583 m_pMin = std::min(m_pMin, v2.p);
584 m_pMax = std::max(m_pMax, v2.p);
586 if (element.type > 2) {
587 const Vertex& v3 = m_vertices[element.vertex[3]];
588 xmin = std::min(xmin, v3.x);
589 xmax = std::max(xmax, v3.x);
590 ymin = std::min(ymin, v3.y);
591 ymax = std::max(ymax, v3.y);
592 m_pMin = std::min(m_pMin, v3.p);
593 m_pMax = std::max(m_pMax, v3.p);
595 constexpr double tol = 1.e-6;
596 element.xmin = xmin - tol;
597 element.xmax = xmax + tol;
598 element.ymin = ymin - tol;
599 element.ymax = ymax + tol;
600 m_xMinBB = std::min(m_xMinBB, xmin);
601 m_xMaxBB = std::max(m_xMaxBB, xmax);
602 m_yMinBB = std::min(m_yMinBB, ymin);
603 m_yMaxBB = std::max(m_yMaxBB, ymax);
607 <<
" Available data:\n";
608 if (m_hasPotential) {
609 std::cout <<
" Electrostatic potential\n";
612 std::cout <<
" Electric field\n";
614 if (m_hasElectronMobility) {
615 std::cout <<
" Electron mobility\n";
617 if (m_hasHoleMobility) {
618 std::cout <<
" Hole mobility\n";
620 if (m_hasElectronVelocity) {
621 std::cout <<
" Electron velocity\n";
623 if (m_hasHoleVelocity) {
624 std::cout <<
" Hole velocity\n";
626 if (m_hasElectronLifetime) {
627 std::cout <<
" Electron lifetimes\n";
629 if (m_hasHoleLifetime) {
630 std::cout <<
" Hole lifetimes\n";
632 if (!m_donors.empty()) {
633 std::cout <<
" " << m_donors.size() <<
" donor-type traps\n";
635 if (!m_acceptors.empty()) {
636 std::cout <<
" " << m_acceptors.size() <<
" acceptor-type traps\n";
638 std::cout <<
" Bounding box:\n"
639 <<
" " << m_xMinBB <<
" < x [cm] < " << m_xMaxBB <<
"\n"
640 <<
" " << m_yMinBB <<
" < y [cm] < " << m_yMaxBB <<
"\n"
641 <<
" Voltage range:\n"
642 <<
" " << m_pMin <<
" < V < " << m_pMax <<
"\n";
647 const int nRegions = m_regions.size();
648 std::vector<int> nElementsRegion(nRegions, 0);
651 unsigned int nLines = 0;
652 unsigned int nTriangles = 0;
653 unsigned int nRectangles = 0;
654 unsigned int nOtherShapes = 0;
657 unsigned int nLoose = 0;
658 std::vector<int> looseElements;
661 unsigned int nDegenerate = 0;
662 std::vector<int> degenerateElements;
664 const unsigned int nElements = m_elements.size();
665 for (
unsigned int i = 0; i < nElements; ++i) {
666 const Element& element = m_elements[i];
667 if (element.type == 1) {
669 if (element.vertex[0] == element.vertex[1]) {
670 degenerateElements.push_back(i);
673 }
else if (element.type == 2) {
675 if (element.vertex[0] == element.vertex[1] ||
676 element.vertex[1] == element.vertex[2] ||
677 element.vertex[2] == element.vertex[0]) {
678 degenerateElements.push_back(i);
681 }
else if (element.type == 3) {
683 if (element.vertex[0] == element.vertex[1] ||
684 element.vertex[0] == element.vertex[2] ||
685 element.vertex[0] == element.vertex[3] ||
686 element.vertex[1] == element.vertex[2] ||
687 element.vertex[1] == element.vertex[3] ||
688 element.vertex[2] == element.vertex[3]) {
689 degenerateElements.push_back(i);
696 if (element.region >= 0 && element.region < nRegions) {
697 ++nElementsRegion[element.region];
699 looseElements.push_back(i);
704 if (nDegenerate > 0) {
706 <<
" The following elements are degenerate:\n";
707 for (
unsigned int i = 0; i < nDegenerate; ++i) {
708 std::cerr <<
" " << degenerateElements[i] <<
"\n";
715 <<
" The following elements are not part of any region:\n";
716 for (
unsigned int i = 0; i < nLoose; ++i) {
717 std::cerr <<
" " << looseElements[i] <<
"\n";
723 <<
" Number of regions: " << nRegions <<
"\n";
724 for (
int i = 0; i < nRegions; ++i) {
725 std::cout <<
" " << i <<
": " << m_regions[i].name <<
", "
726 << nElementsRegion[i] <<
" elements\n";
729 std::cout <<
" Number of elements: " << nElements <<
"\n";
731 std::cout <<
" " << nLines <<
" lines\n";
733 if (nTriangles > 0) {
734 std::cout <<
" " << nTriangles <<
" triangles\n";
736 if (nRectangles > 0) {
737 std::cout <<
" " << nRectangles <<
" rectangles\n";
739 if (nOtherShapes > 0) {
740 std::cerr <<
" " << nOtherShapes <<
" elements of unknown type.\n"
741 <<
" Program bug!\n";
747 std::cout <<
" Number of vertices: " << m_vertices.size() <<
"\n";
751 <<
" Looking for neighbouring elements. Be patient...\n";
762 std::cout <<
m_className <<
"::Initialise: Initialisation finished.\n";
767 const std::string& datfile2,
771 std::cerr <<
m_className <<
"::SetWeightingField:\n"
772 <<
" Mesh is not available. Call Initialise first.\n";
776 std::cerr <<
m_className <<
"::SetWeightingField:\n"
777 <<
" Voltage difference must be > 0.\n";
780 const double s = 1. / dv;
785 std::vector<std::array<double, 2> > wf1;
786 std::vector<double> wp1;
787 if (!LoadWeightingField(datfile1, wf1, wp1)) {
788 std::cerr <<
m_className <<
"::SetWeightingField:\n"
789 <<
" Could not import data from " << datfile1 <<
".\n";
794 std::vector<std::array<double, 2> > wf2;
795 std::vector<double> wy2;
796 std::vector<double> wp2;
797 if (!LoadWeightingField(datfile2, wf2, wp2)) {
798 std::cerr <<
m_className <<
"::SetWeightingField:\n"
799 <<
" Could not import data from " << datfile2 <<
".\n";
802 const unsigned int nVertices = m_vertices.size();
803 bool foundField =
true;
804 if (wf1.size() != nVertices || wf2.size() != nVertices) {
806 std::cerr <<
m_className <<
"::SetWeightingField:\n"
807 <<
" Could not load electric field values.\n";
809 bool foundPotential =
true;
810 if (wp1.size() != nVertices || wp2.size() != nVertices) {
811 foundPotential =
false;
812 std::cerr <<
m_className <<
"::SetWeightingField:\n"
813 <<
" Could not load electrostatic potentials.\n";
815 if (!foundField && !foundPotential)
return false;
817 m_wf.assign(nVertices, {0., 0.});
818 for (
unsigned int i = 0; i < nVertices; ++i) {
819 m_wf[i][0] = (wf2[i][0] - wf1[i][0]) * s;
820 m_wf[i][1] = (wf2[i][1] - wf1[i][1]) * s;
823 if (foundPotential) {
824 m_wp.assign(nVertices, 0.);
825 for (
unsigned int i = 0; i < nVertices; ++i) {
826 m_wp[i] = (wp2[i] - wp1[i]) * s;
833 double& xmax,
double& ymax,
double& zmax) {
859 if (fabs(zmax - zmin) <= 0.) {
860 std::cerr <<
m_className <<
"::SetRangeZ: Zero range is not permitted.\n";
863 m_zMinBB = std::min(zmin, zmax);
864 m_zMaxBB = std::max(zmin, zmax);
879 <<
" Field map not yet initialised.\n";
883 if (m_regions.empty()) {
885 <<
" No regions are currently defined.\n";
889 const unsigned int nRegions = m_regions.size();
891 <<
" Currently " << nRegions <<
" regions are defined.\n"
892 <<
" Index Name Medium\n";
893 for (
unsigned int i = 0; i < nRegions; ++i) {
894 std::cout <<
" " << i <<
" " << m_regions[i].name;
895 if (!m_regions[i].medium) {
896 std::cout <<
" none ";
898 std::cout <<
" " << m_regions[i].medium->GetName();
900 if (m_regions[i].drift) {
901 std::cout <<
" (active region)\n";
909 bool& active)
const {
910 if (i >= m_regions.size()) {
911 std::cerr <<
m_className <<
"::GetRegion: Index out of range.\n";
914 name = m_regions[i].name;
915 active = m_regions[i].drift;
919 if (i >= m_regions.size()) {
920 std::cerr <<
m_className <<
"::SetDriftRegion: Index out of range.\n";
923 m_regions[i].drift =
true;
927 if (i >= m_regions.size()) {
928 std::cerr <<
m_className <<
"::UnsetDriftRegion: Index out of range.\n";
931 m_regions[i].drift =
false;
935 if (i >= m_regions.size()) {
936 std::cerr <<
m_className <<
"::SetMedium: Index out of range.\n";
941 std::cerr <<
m_className <<
"::SetMedium: Null pointer.\n";
945 m_regions[i].medium = medium;
949 if (i >= m_regions.size()) {
950 std::cerr <<
m_className <<
"::GetMedium: Index out of range.\n";
954 return m_regions[i].medium;
958 double& dmin,
double& dmax,
int& type)
const {
959 if (i >= m_elements.size()) {
960 std::cerr <<
m_className <<
"::GetElement: Index out of range.\n";
964 const Element& element = m_elements[i];
965 if (element.type == 1) {
966 const Vertex& v0 = m_vertices[element.vertex[0]];
967 const Vertex& v1 = m_vertices[element.vertex[1]];
968 const double dx = v1.x - v0.x;
969 const double dy = v1.y - v0.y;
970 const double d = sqrt(dx * dx + dy * dy);
971 dmin = dmax = vol = d;
972 }
else if (m_elements[i].type == 2) {
973 const Vertex& v0 = m_vertices[element.vertex[0]];
974 const Vertex& v1 = m_vertices[element.vertex[1]];
975 const Vertex& v2 = m_vertices[element.vertex[2]];
977 fabs((v2.x - v0.x) * (v1.y - v0.y) - (v2.y - v0.y) * (v1.x - v0.x));
978 const double a = sqrt(pow(v1.x - v0.x, 2) + pow(v1.y - v0.y, 2));
979 const double b = sqrt(pow(v2.x - v0.x, 2) + pow(v2.y - v0.y, 2));
980 const double c = sqrt(pow(v1.x - v2.x, 2) + pow(v1.y - v2.y, 2));
981 dmin = std::min(std::min(a, b), c);
982 dmax = std::max(std::max(a, b), c);
983 }
else if (m_elements[i].type == 3) {
984 const Vertex& v0 = m_vertices[element.vertex[0]];
985 const Vertex& v1 = m_vertices[element.vertex[1]];
986 const Vertex& v3 = m_vertices[element.vertex[3]];
987 const double a = sqrt(pow(v1.x - v0.x, 2) + pow(v1.y - v0.y, 2));
988 const double b = sqrt(pow(v3.x - v0.x, 2) + pow(v3.y - v0.y, 2));
990 dmin = std::min(a, b);
991 dmax = sqrt(a * a + b * b);
994 <<
" Unexpected element type (" << type <<
")\n";
1001 double& dmin,
double& dmax,
int& type,
1002 int& node1,
int& node2,
int& node3,
int& node4,
1004 if (!
GetElement(i, vol, dmin, dmax, type))
return false;
1005 const Element& element = m_elements[i];
1006 node1 = element.vertex[0];
1007 node2 = element.vertex[1];
1008 node3 = element.vertex[2];
1009 node4 = element.vertex[3];
1010 reg = element.region;
1015 double& v,
double& ex,
double& ey)
const {
1016 if (i >= m_vertices.size()) {
1017 std::cerr <<
m_className <<
"::GetNode: Index out of range.\n";
1021 x = m_vertices[i].x;
1022 y = m_vertices[i].y;
1023 v = m_vertices[i].p;
1024 ex = m_vertices[i].ex;
1025 ey = m_vertices[i].ey;
1029bool ComponentTcad2d::LoadData(
const std::string& datafilename) {
1030 std::ifstream datafile;
1031 datafile.open(datafilename.c_str(), std::ios::in);
1034 <<
" Could not open file " << datafilename <<
".\n";
1038 const unsigned int nVertices = m_vertices.size();
1039 std::vector<unsigned int> fillCount(nVertices, 0);
1040 for (
unsigned int i = 0; i < nVertices; ++i) {
1041 m_vertices[i].p = 0.;
1042 m_vertices[i].ex = 0.;
1043 m_vertices[i].ey = 0.;
1044 m_vertices[i].emob = 0.;
1045 m_vertices[i].hmob = 0.;
1046 m_vertices[i].donorOcc.clear();
1047 m_vertices[i].acceptorOcc.clear();
1050 m_acceptors.clear();
1052 while (!datafile.fail()) {
1055 std::getline(datafile, line);
1058 if (line.substr(0, 8) !=
"function")
continue;
1060 const std::string::size_type pEq = line.find(
'=');
1061 if (pEq == std::string::npos) {
1064 <<
" Error reading file " << datafilename <<
".\n"
1065 <<
" Line:\n " << line <<
"\n";
1070 line = line.substr(pEq + 1);
1071 std::string dataset;
1072 std::istringstream data;
1075 if (dataset ==
"ElectrostaticPotential") {
1076 if (!ReadDataset(datafile, dataset))
return false;
1077 m_hasPotential =
true;
1078 }
else if (dataset ==
"ElectricField") {
1079 if (!ReadDataset(datafile, dataset))
return false;
1081 }
else if (dataset ==
"eDriftVelocity") {
1082 if (!ReadDataset(datafile, dataset))
return false;
1083 m_hasElectronVelocity =
true;
1084 }
else if (dataset ==
"hDriftVelocity") {
1085 if (!ReadDataset(datafile, dataset))
return false;
1086 m_hasHoleVelocity =
true;
1087 }
else if (dataset ==
"eMobility") {
1088 if (!ReadDataset(datafile, dataset))
return false;
1089 m_hasElectronMobility =
true;
1090 }
else if (dataset ==
"hMobility") {
1091 if (!ReadDataset(datafile, dataset))
return false;
1092 m_hasHoleMobility =
true;
1093 }
else if (dataset ==
"eLifetime") {
1094 if (!ReadDataset(datafile, dataset))
return false;
1095 m_hasElectronLifetime =
true;
1096 }
else if (dataset ==
"hLifetime") {
1097 if (!ReadDataset(datafile, dataset))
return false;
1098 m_hasHoleLifetime =
true;
1099 }
else if (dataset.substr(0, 14) ==
"TrapOccupation" &&
1100 dataset.substr(17, 2) ==
"Do") {
1101 if (!ReadDataset(datafile, dataset))
return false;
1106 m_donors.push_back(donor);
1107 }
else if (dataset.substr(0, 14) ==
"TrapOccupation" &&
1108 dataset.substr(17, 2) ==
"Ac") {
1109 if (!ReadDataset(datafile, dataset))
return false;
1111 acceptor.xsece = -1.;
1112 acceptor.xsech = -1.;
1113 acceptor.conc = -1.;
1114 m_acceptors.push_back(acceptor);
1117 if (datafile.fail() && !datafile.eof()) {
1119 <<
" Error reading file " << datafilename <<
"\n";
1130bool ComponentTcad2d::ReadDataset(std::ifstream& datafile,
1131 const std::string& dataset) {
1133 ElectrostaticPotential,
1141 DonorTrapOccupation,
1142 AcceptorTrapOccupation,
1145 DataSet ds = Unknown;
1146 if (dataset ==
"ElectrostaticPotential") {
1147 ds = ElectrostaticPotential;
1148 }
else if (dataset ==
"ElectricField") {
1150 }
else if (dataset ==
"eDriftVelocity") {
1151 ds = eDriftVelocity;
1152 }
else if (dataset ==
"hDriftVelocity") {
1153 ds = hDriftVelocity;
1154 }
else if (dataset ==
"eMobility") {
1156 }
else if (dataset ==
"hMobility") {
1158 }
else if (dataset ==
"eLifetime") {
1160 }
else if (dataset ==
"hLifetime") {
1162 }
else if (dataset.substr(0, 14) ==
"TrapOccupation") {
1163 if (dataset.substr(17, 2) ==
"Do") {
1164 ds = DonorTrapOccupation;
1165 }
else if (dataset.substr(17, 2) ==
"Ac") {
1166 ds = AcceptorTrapOccupation;
1170 <<
" Unexpected dataset " << dataset <<
".\n";
1174 bool isVector =
false;
1175 if (ds == EField || ds == eDriftVelocity || ds == hDriftVelocity) {
1179 if (!datafile.is_open())
return false;
1181 std::getline(datafile, line);
1182 std::getline(datafile, line);
1183 std::getline(datafile, line);
1184 std::getline(datafile, line);
1186 std::string::size_type bra = line.find(
'[');
1187 std::string::size_type ket = line.find(
']');
1188 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1190 <<
" Cannot extract region name.\n"
1191 <<
" Line:\n " << line <<
"\n";
1196 line = line.substr(bra + 1, ket - bra - 1);
1198 std::istringstream data;
1203 const int index = FindRegion(name);
1206 <<
" Unknown region " << name <<
".\n";
1212 std::getline(datafile, line);
1213 bra = line.find(
'(');
1214 ket = line.find(
')');
1215 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1217 <<
" Cannot extract number of values to be read.\n"
1218 <<
" Line:\n " << line <<
"\n";
1223 line = line.substr(bra + 1, ket - bra - 1);
1228 if (isVector) nValues = nValues / 2;
1230 const unsigned int nVertices = m_vertices.size();
1231 std::vector<bool> isInRegion(nVertices,
false);
1232 const unsigned int nElements = m_elements.size();
1233 for (
unsigned int j = 0; j < nElements; ++j) {
1234 if (m_elements[j].region != index)
continue;
1235 for (
int k = 0; k <= m_elements[j].type; ++k) {
1236 isInRegion[m_elements[j].vertex[k]] =
true;
1240 unsigned int ivertex = 0;
1241 for (
int j = 0; j < nValues; ++j) {
1245 datafile >> val1 >> val2;
1250 while (ivertex < nVertices) {
1251 if (isInRegion[ivertex])
break;
1256 if (ivertex >= nVertices) {
1258 <<
" Dataset " << dataset
1259 <<
" has more values than vertices in region " << name <<
"\n";
1265 case ElectrostaticPotential:
1266 m_vertices[ivertex].p = val1;
1269 m_vertices[ivertex].ex = val1;
1270 m_vertices[ivertex].ey = val2;
1272 case eDriftVelocity:
1274 m_vertices[ivertex].eVx = val1 * 1.e-9;
1275 m_vertices[ivertex].eVy = val2 * 1.e-9;
1277 case hDriftVelocity:
1279 m_vertices[ivertex].hVx = val1 * 1.e-9;
1280 m_vertices[ivertex].hVy = val2 * 1.e-9;
1284 m_vertices[ivertex].emob = val1 * 1.e-9;
1288 m_vertices[ivertex].hmob = val1 * 1.e-9;
1292 m_vertices[ivertex].eTau = val1 * 1.e9;
1296 m_vertices[ivertex].hTau = val1 * 1.e9;
1298 case DonorTrapOccupation:
1299 m_vertices[ivertex].donorOcc.push_back(val1);
1301 case AcceptorTrapOccupation:
1302 m_vertices[ivertex].acceptorOcc.push_back(val1);
1306 <<
" Unexpected dataset (" << ds <<
"). Program bug!\n";
1316bool ComponentTcad2d::LoadWeightingField(
const std::string& datafilename,
1317 std::vector<std::array<double, 2> >& wf, std::vector<double>& wp) {
1318 std::ifstream datafile;
1319 datafile.open(datafilename.c_str(), std::ios::in);
1321 std::cerr <<
m_className <<
"::LoadWeightingField:\n"
1322 <<
" Could not open file " << datafilename <<
".\n";
1326 const unsigned int nVertices = m_vertices.size();
1328 while (!datafile.fail()) {
1331 std::getline(datafile, line);
1334 if (line.substr(0, 8) !=
"function")
continue;
1336 const std::string::size_type pEq = line.find(
'=');
1337 if (pEq == std::string::npos) {
1339 std::cerr <<
m_className <<
"::LoadWeightingField:\n"
1340 <<
" Error reading file " << datafilename <<
".\n"
1341 <<
" Line:\n " << line <<
"\n";
1345 line = line.substr(pEq + 1);
1346 std::string dataset;
1347 std::istringstream data;
1351 if (dataset !=
"ElectrostaticPotential" && dataset !=
"ElectricField") {
1355 if (dataset ==
"ElectricField") {
1356 wf.assign(nVertices, {0., 0.});
1359 wp.assign(nVertices, 0.);
1361 std::getline(datafile, line);
1362 std::getline(datafile, line);
1363 std::getline(datafile, line);
1364 std::getline(datafile, line);
1366 auto bra = line.find(
'[');
1367 auto ket = line.find(
']');
1368 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1369 std::cerr <<
m_className <<
"::LoadWeightingField:\n"
1370 <<
" Cannot extract region name.\n"
1371 <<
" Line:\n " << line <<
"\n";
1375 line = line.substr(bra + 1, ket - bra - 1);
1381 const int index = FindRegion(name);
1383 std::cerr <<
m_className <<
"::LoadWeightingField:\n"
1384 <<
" Unknown region " << name <<
".\n";
1389 std::getline(datafile, line);
1390 bra = line.find(
'(');
1391 ket = line.find(
')');
1392 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1393 std::cerr <<
m_className <<
"::LoadWeightingField:\n"
1394 <<
" Cannot extract number of values to be read.\n"
1395 <<
" Line:\n " << line <<
"\n";
1399 line = line.substr(bra + 1, ket - bra - 1);
1404 if (field) nValues /= 2;
1406 std::vector<bool> isInRegion(nVertices,
false);
1407 const unsigned int nElements = m_elements.size();
1408 for (
unsigned int j = 0; j < nElements; ++j) {
1409 if (m_elements[j].region != index)
continue;
1410 for (
int k = 0; k <= m_elements[j].type; ++k) {
1411 isInRegion[m_elements[j].vertex[k]] =
true;
1414 unsigned int ivertex = 0;
1415 for (
int j = 0; j < nValues; ++j) {
1419 datafile >> val1 >> val2;
1424 while (ivertex < nVertices) {
1425 if (isInRegion[ivertex])
break;
1430 if (ivertex >= nVertices) {
1431 std::cerr <<
m_className <<
"::LoadWeightingField:\n"
1432 <<
" Dataset " << dataset
1433 <<
" has more values than vertices in region " << name <<
"\n";
1438 wf[ivertex] = {val1, val2};
1446 if (!ok || (datafile.fail() && !datafile.eof())) {
1447 std::cerr <<
m_className <<
"::LoadWeightingField:\n"
1448 <<
" Error reading file " << datafilename <<
"\n";
1459bool ComponentTcad2d::LoadGrid(
const std::string& gridfilename) {
1461 std::ifstream gridfile;
1462 gridfile.open(gridfilename.c_str(), std::ios::in);
1465 <<
" Could not open file " << gridfilename <<
".\n";
1472 unsigned int iLine = 0;
1474 unsigned int nRegions = 0;
1475 while (!gridfile.fail()) {
1478 std::getline(gridfile, line);
1482 if (line.substr(0, 10) !=
"nb_regions")
continue;
1483 const std::string::size_type pEq = line.find(
'=');
1484 if (pEq == std::string::npos) {
1487 <<
" Could not read number of regions.\n";
1492 line = line.substr(pEq + 1);
1493 std::istringstream data;
1498 if (gridfile.eof()) {
1501 <<
" Could not find entry 'nb_regions' in file\n"
1502 <<
" " << gridfilename <<
".\n";
1506 }
else if (gridfile.fail()) {
1509 <<
" Error reading file " << gridfilename <<
" (line " << iLine
1515 m_regions.resize(nRegions);
1516 for (
unsigned int j = 0; j < nRegions; ++j) {
1517 m_regions[j].name =
"";
1518 m_regions[j].drift =
false;
1519 m_regions[j].medium =
nullptr;
1524 <<
" Found " << nRegions <<
" regions.\n";
1528 while (!gridfile.fail()) {
1530 std::getline(gridfile, line);
1534 if (line.substr(0, 7) !=
"regions")
continue;
1536 const std::string::size_type bra = line.find(
'[');
1537 const std::string::size_type ket = line.find(
']');
1538 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1541 <<
" Could not read region names.\n";
1546 line = line.substr(bra + 1, ket - bra - 1);
1547 std::istringstream data;
1549 for (
unsigned int j = 0; j < nRegions; ++j) {
1550 data >> m_regions[j].name;
1553 m_regions[j].drift =
true;
1554 m_regions[j].medium =
nullptr;
1558 if (gridfile.eof()) {
1561 <<
" Could not find entry 'regions' in file\n"
1562 <<
" " << gridfilename <<
".\n";
1566 }
else if (gridfile.fail()) {
1569 <<
" Error reading file " << gridfilename <<
" (line " << iLine
1577 unsigned int nVertices = 0;
1578 while (!gridfile.fail()) {
1580 std::getline(gridfile, line);
1584 if (line.substr(0, 8) !=
"Vertices")
continue;
1586 const std::string::size_type bra = line.find(
'(');
1587 const std::string::size_type ket = line.find(
')');
1588 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1591 <<
" Could not read number of vertices.\n";
1596 line = line.substr(bra + 1, ket - bra - 1);
1597 std::istringstream data;
1600 m_vertices.resize(nVertices);
1602 for (
unsigned int j = 0; j < nVertices; ++j) {
1603 gridfile >> m_vertices[j].x >> m_vertices[j].y;
1605 m_vertices[j].x *= 1.e-4;
1606 m_vertices[j].y *= 1.e-4;
1611 if (gridfile.eof()) {
1613 <<
" Could not find section 'Vertices' in file\n"
1614 <<
" " << gridfilename <<
".\n";
1618 }
else if (gridfile.fail()) {
1620 <<
" Error reading file " << gridfilename <<
" (line " << iLine
1630 std::vector<int> edgeP1;
1631 std::vector<int> edgeP2;
1632 while (!gridfile.fail()) {
1634 std::getline(gridfile, line);
1638 if (line.substr(0, 5) !=
"Edges")
continue;
1640 const std::string::size_type bra = line.find(
'(');
1641 const std::string::size_type ket = line.find(
')');
1642 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1645 <<
" Could not read number of edges.\n";
1650 line = line.substr(bra + 1, ket - bra - 1);
1651 std::istringstream data;
1654 edgeP1.resize(nEdges);
1655 edgeP2.resize(nEdges);
1657 for (
int j = 0; j < nEdges; ++j) {
1658 gridfile >> edgeP1[j] >> edgeP2[j];
1663 if (gridfile.eof()) {
1665 <<
" Could not find section 'Edges' in file\n"
1666 <<
" " << gridfilename <<
".\n";
1670 }
else if (gridfile.fail()) {
1672 <<
" Error reading file " << gridfilename <<
" (line " << iLine
1679 for (
int i = 0; i < nEdges; ++i) {
1681 if (edgeP1[i] < 0 || edgeP1[i] >= (
int)nVertices || edgeP2[i] < 0 ||
1682 edgeP2[i] >= (
int)nVertices) {
1684 <<
" Vertex index of edge " << i <<
" out of range.\n";
1690 if (edgeP1[i] == edgeP2[i]) {
1692 <<
" Edge " << i <<
" is degenerate.\n";
1700 int edge0, edge1, edge2, edge3;
1702 unsigned int nElements = 0;
1703 while (!gridfile.fail()) {
1705 std::getline(gridfile, line);
1709 if (line.substr(0, 8) !=
"Elements")
continue;
1711 const std::string::size_type bra = line.find(
'(');
1712 const std::string::size_type ket = line.find(
')');
1713 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1716 <<
" Could not read number of elements.\n";
1721 line = line.substr(bra + 1, ket - bra - 1);
1722 std::istringstream data;
1726 m_elements.resize(nElements);
1728 for (
unsigned int j = 0; j < nElements; ++j) {
1729 for (
int k = nMaxVertices; k--;) m_elements[j].vertex[k] = -1;
1730 m_elements[j].neighbours.clear();
1736 gridfile >> edge0 >> edge1;
1737 if (edge0 < 0) edge0 = -edge0 - 1;
1738 if (edge1 < 0) edge1 = -edge1 - 1;
1740 if (edge0 >= nEdges || edge1 >= nEdges) {
1742 <<
" Error reading file " << gridfilename <<
" (line "
1744 <<
" Edge index out of range.\n";
1754 if (m_vertices[edgeP1[edge0]].x > m_vertices[edgeP2[edge0]].x) {
1755 m_elements[j].vertex[0] = edgeP2[edge0];
1756 m_elements[j].vertex[1] = edgeP1[edge0];
1758 m_elements[j].vertex[0] = edgeP1[edge0];
1759 m_elements[j].vertex[1] = edgeP2[edge0];
1764 gridfile >> edge0 >> edge1 >> edge2;
1766 if (edge0 < 0) edge0 = -edge0 - 1;
1767 if (edge1 < 0) edge1 = -edge1 - 1;
1768 if (edge2 < 0) edge2 = -edge2 - 1;
1769 if (edge0 >= nEdges || edge1 >= nEdges || edge2 >= nEdges) {
1771 <<
" Error reading file " << gridfilename <<
" (line "
1773 <<
" Edge index out of range.\n";
1778 m_elements[j].vertex[0] = edgeP1[edge0];
1779 m_elements[j].vertex[1] = edgeP2[edge0];
1780 if (edgeP1[edge1] != m_elements[j].vertex[0] &&
1781 edgeP1[edge1] != m_elements[j].vertex[1]) {
1782 m_elements[j].vertex[2] = edgeP1[edge1];
1784 m_elements[j].vertex[2] = edgeP2[edge1];
1787 while (m_vertices[m_elements[j].vertex[0]].x >
1788 m_vertices[m_elements[j].vertex[1]].x ||
1789 m_vertices[m_elements[j].vertex[0]].x >
1790 m_vertices[m_elements[j].vertex[2]].x) {
1791 const int tmp = m_elements[j].vertex[0];
1792 m_elements[j].vertex[0] = m_elements[j].vertex[1];
1793 m_elements[j].vertex[1] = m_elements[j].vertex[2];
1794 m_elements[j].vertex[2] = tmp;
1799 gridfile >> edge0 >> edge1 >> edge2 >> edge3;
1801 if (edge0 >= nEdges || -edge0 - 1 >= nEdges || edge1 >= nEdges ||
1802 -edge1 - 1 >= nEdges || edge2 >= nEdges || -edge2 - 1 >= nEdges ||
1803 edge3 >= nEdges || -edge3 - 1 >= nEdges) {
1805 <<
" Error reading file " << gridfilename <<
" (line "
1807 <<
" Edge index out of range.\n";
1813 m_elements[j].vertex[0] = edgeP1[edge0];
1815 m_elements[j].vertex[0] = edgeP2[-edge0 - 1];
1817 m_elements[j].vertex[1] = edgeP1[edge1];
1819 m_elements[j].vertex[1] = edgeP2[-edge1 - 1];
1821 m_elements[j].vertex[2] = edgeP1[edge2];
1823 m_elements[j].vertex[2] = edgeP2[-edge2 - 1];
1825 m_elements[j].vertex[3] = edgeP1[edge3];
1827 m_elements[j].vertex[3] = edgeP2[-edge3 - 1];
1830 while (m_vertices[m_elements[j].vertex[0]].x >
1831 m_vertices[m_elements[j].vertex[1]].x ||
1832 m_vertices[m_elements[j].vertex[0]].x >
1833 m_vertices[m_elements[j].vertex[2]].x ||
1834 m_vertices[m_elements[j].vertex[0]].x >
1835 m_vertices[m_elements[j].vertex[3]].x) {
1836 const int tmp = m_elements[j].vertex[0];
1837 m_elements[j].vertex[0] = m_elements[j].vertex[1];
1838 m_elements[j].vertex[1] = m_elements[j].vertex[2];
1839 m_elements[j].vertex[2] = m_elements[j].vertex[3];
1840 m_elements[j].vertex[3] = tmp;
1846 <<
" Error reading file " << gridfilename <<
" (line "
1848 std::cerr <<
" Invalid element type (" << type
1849 <<
") for 2d mesh.\n";
1855 m_elements[j].type = type;
1856 m_elements[j].region = -1;
1860 if (gridfile.eof()) {
1862 std::cerr <<
" Could not find section 'Elements' in file\n";
1863 std::cerr <<
" " << gridfilename <<
".\n";
1867 }
else if (gridfile.fail()) {
1869 std::cerr <<
" Error reading file " << gridfilename <<
" (line " << iLine
1878 while (!gridfile.fail()) {
1880 std::getline(gridfile, line);
1883 if (line.substr(0, 6) !=
"Region")
continue;
1885 std::string::size_type bra = line.find(
'(');
1886 std::string::size_type ket = line.find(
')');
1887 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1889 <<
" Could not read region name.\n";
1894 line = line.substr(bra + 1, ket - bra - 1);
1895 std::istringstream data;
1899 const int index = FindRegion(name);
1903 <<
" Error reading file " << gridfilename <<
".\n"
1904 <<
" Unknown region " << name <<
".\n";
1907 std::getline(gridfile, line);
1908 std::getline(gridfile, line);
1909 bra = line.find(
'(');
1910 ket = line.find(
')');
1911 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1914 std::cerr <<
" Error reading file " << gridfilename <<
".\n";
1915 std::cerr <<
" Could not read number of elements in region " << name
1921 line = line.substr(bra + 1, ket - bra - 1);
1922 int nElementsRegion;
1925 data >> nElementsRegion;
1927 for (
int j = 0; j < nElementsRegion; ++j) {
1928 gridfile >> iElement;
1929 m_elements[iElement].region = index;
1934 if (gridfile.fail() && !gridfile.eof()) {
1936 std::cerr <<
" Error reading file " << gridfilename <<
".\n";
1944void ComponentTcad2d::FindNeighbours() {
1945 const unsigned int nElements = m_elements.size();
1946 std::vector<std::vector<bool> > adjacent(nElements,
1947 std::vector<bool>(nElements,
false));
1949 const double tol = 5.e-4;
1950 for (
unsigned int i = 0; i < nElements; ++i) {
1951 const Element& ei = m_elements[i];
1952 for (
unsigned int j = 0; j < nElements; ++j) {
1953 if (i == j || adjacent[i][j])
continue;
1954 const Element& ej = m_elements[j];
1955 if (ei.xmin > ej.xmax + tol || ei.xmax < ej.xmin - tol)
continue;
1956 if (ei.ymin > ej.ymax + tol || ei.ymax < ej.ymin - tol)
continue;
1957 for (
unsigned int m = 0; m < nMaxVertices; ++m) {
1958 if (ei.vertex[m] < 0)
break;
1959 for (
unsigned int n = 0; n < nMaxVertices; ++n) {
1960 if (ei.vertex[n] < 0)
break;
1961 if (ei.vertex[m] == ej.vertex[n]) {
1962 adjacent[i][j] = adjacent[j][i] =
true;
1966 if (adjacent[i][j])
break;
1971 for (
unsigned int i = 0; i < nElements; ++i) {
1972 m_elements[i].neighbours.clear();
1973 for (
unsigned int j = 0; j < nElements; ++j) {
1974 if (adjacent[i][j]) {
1975 m_elements[i].neighbours.push_back(j);
1981void ComponentTcad2d::Cleanup() {
1993unsigned int ComponentTcad2d::FindElement(
1994 const double x,
const double y,
1995 std::array<double, nMaxVertices>& w)
const {
1998 if (m_lastElement >= 0) {
2000 const Element&
last = m_elements[m_lastElement];
2001 if (x >=
last.xmin && x <= last.xmax && y >=
last.ymin && y <=
last.ymax) {
2002 if (CheckElement(x, y, last, w))
return m_lastElement;
2006 const unsigned int nNeighbours =
last.neighbours.size();
2007 for (
unsigned int i = 0; i < nNeighbours; ++i) {
2008 const Element& element = m_elements[
last.neighbours[i]];
2009 if (x < element.xmin || x > element.xmax || y < element.ymin ||
2012 if (!CheckElement(x, y, element, w))
continue;
2013 return last.neighbours[i];
2019 const unsigned int nElements = m_elements.size();
2020 for (
unsigned int i = 0; i < nElements; ++i) {
2021 const Element& element = m_elements[i];
2022 if (x < element.xmin || x > element.xmax || y < element.ymin ||
2025 if (CheckElement(x, y, element, w))
return i;
2030 <<
" Point (" <<
x <<
", " <<
y <<
") is outside the mesh.\n";
2035bool ComponentTcad2d::CheckElement(
const double x,
const double y,
2036 const Element& element,
2037 std::array<double, nMaxVertices>& w)
const {
2038 switch (element.type) {
2040 return CheckLine(x, y, element, w);
2043 return CheckTriangle(x, y, element, w);
2046 return CheckRectangle(x, y, element, w);
2050 <<
" Unknown element type. Program bug!\n";
2056bool ComponentTcad2d::CheckRectangle(
const double x,
const double y,
2057 const Element& element,
2058 std::array<double, nMaxVertices>& w)
const {
2059 const Vertex& v0 = m_vertices[element.vertex[0]];
2060 const Vertex& v1 = m_vertices[element.vertex[1]];
2061 const Vertex& v3 = m_vertices[element.vertex[3]];
2062 if (y < v0.y || x > v3.x || y > v1.y)
return false;
2065 const double u = (
x - 0.5 * (v0.x + v3.x)) / (v3.x - v0.x);
2066 const double v = (
y - 0.5 * (v0.y + v1.y)) / (v1.y - v0.y);
2068 w[0] = (0.5 - u) * (0.5 - v);
2069 w[1] = (0.5 - u) * (0.5 + v);
2070 w[2] = (0.5 + u) * (0.5 + v);
2071 w[3] = (0.5 + u) * (0.5 - v);
2075bool ComponentTcad2d::CheckTriangle(
const double x,
const double y,
2076 const Element& element,
2077 std::array<double, nMaxVertices>& w)
const {
2078 const Vertex& v0 = m_vertices[element.vertex[0]];
2079 const Vertex& v1 = m_vertices[element.vertex[1]];
2080 const Vertex& v2 = m_vertices[element.vertex[2]];
2081 if (x > v1.x && x > v2.x)
return false;
2082 if (y < v0.y && y < v1.y && y < v2.y)
return false;
2083 if (y > v0.y && y > v1.y && y > v2.y)
return false;
2089 const double v1x = v1.x - v0.x;
2090 const double v1y = v1.y - v0.y;
2091 const double v2x = v2.x - v0.x;
2092 const double v2y = v2.y - v0.y;
2094 w[1] = ((
x - v0.x) * v2y - (y - v0.y) * v2x) / (v1x * v2y - v1y * v2x);
2095 if (w[1] < 0. || w[1] > 1.)
return false;
2096 w[2] = ((v0.x -
x) * v1y - (v0.y - y) * v1x) / (v1x * v2y - v1y * v2x);
2097 if (w[2] < 0. || w[1] + w[2] > 1.)
return false;
2100 w[0] = 1. - w[1] - w[2];
2105bool ComponentTcad2d::CheckLine(
const double x,
const double y,
2106 const Element& element,
2107 std::array<double, nMaxVertices>& w)
const {
2108 const Vertex& v0 = m_vertices[element.vertex[0]];
2109 const Vertex& v1 = m_vertices[element.vertex[1]];
2110 if (x > v1.x)
return false;
2111 if (y < v0.y && y < v1.y)
return false;
2112 if (y > v0.y && y > v1.y)
return false;
2113 const double tx = (
x - v0.x) / (v1.x - v0.x);
2114 if (tx < 0. || tx > 1.)
return false;
2115 const double ty = (
y - v0.y) / (v1.y - v0.y);
2116 if (ty < 0. || ty > 1.)
return false;
2126void ComponentTcad2d::Reset() {
2128 m_hasRangeZ =
false;
2132void ComponentTcad2d::UpdatePeriodicity() {
2134 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
2135 <<
" Field map not available.\n";
2140 for (
unsigned int i = 0; i < 3; ++i) {
2142 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
2143 <<
" Both simple and mirror periodicity requested. Reset.\n";
2149 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
2150 <<
" Axial symmetry is not supported. Reset.\n";
2156 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
2157 <<
" Rotation symmetry is not supported. Reset.\n";
2162int ComponentTcad2d::FindRegion(
const std::string& name)
const {
2163 const unsigned int nRegions = m_regions.size();
2164 for (
unsigned int j = 0; j < nRegions; ++j) {
2165 if (name == m_regions[j].name)
return j;
2170void ComponentTcad2d::MapCoordinates(
double& x,
double& y,
bool& xmirr,
2171 bool& ymirr)
const {
2174 const double cellsx = m_xMaxBB - m_xMinBB;
2176 x = m_xMinBB + fmod(x - m_xMinBB, cellsx);
2177 if (x < m_xMinBB)
x += cellsx;
2179 double xNew = m_xMinBB + fmod(x - m_xMinBB, cellsx);
2180 if (xNew < m_xMinBB) xNew += cellsx;
2181 const int nx = int(floor(0.5 + (xNew - x) / cellsx));
2182 if (nx != 2 * (nx / 2)) {
2183 xNew = m_xMinBB + m_xMaxBB - xNew;
2189 const double cellsy = m_yMaxBB - m_yMinBB;
2191 y = m_yMinBB + fmod(y - m_yMinBB, cellsy);
2192 if (y < m_yMinBB)
y += cellsy;
2194 double yNew = m_yMinBB + fmod(y - m_yMinBB, cellsy);
2195 if (yNew < m_yMinBB) yNew += cellsy;
2196 const int ny = int(floor(0.5 + (yNew - y) / cellsy));
2197 if (ny != 2 * (ny / 2)) {
2198 yNew = m_yMinBB + m_yMaxBB - yNew;
2205bool ComponentTcad2d::CheckTraps()
const {
2206 for (
const auto& trap : m_donors) {
2207 if (trap.xsece < 0. || trap.xsech < 0. || trap.conc < 0.)
return false;
2210 for (
const auto& trap : m_acceptors) {
2211 if (trap.xsece < 0. || trap.xsech < 0. || trap.conc < 0.)
return false;
Abstract base class for components.
std::array< bool, 3 > m_periodic
Simple periodicity in x, y, z.
std::array< bool, 3 > m_rotationSymmetric
Rotation symmetry around x-axis, y-axis, z-axis.
std::array< bool, 3 > m_axiallyPeriodic
Axial periodicity in x, y, z.
bool m_ready
Ready for use?
std::array< bool, 3 > m_mirrorPeriodic
Mirror periodicity in x, y, z.
std::string m_className
Class name.
bool m_debug
Switch on/off debugging messages.
bool SetWeightingField(const std::string &datfile1, const std::string &datfile2, const double dv)
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the bounding box coordinates.
bool GetDonorOccupation(const double x, const double y, const double z, const unsigned int donorNumber, double &occupationFraction)
bool GetVoltageRange(double &vmin, double &vmax) override
Calculate the voltage range [V].
void GetRegion(const unsigned int i, std::string &name, bool &active) const
bool GetNode(const unsigned int i, double &x, double &y, double &v, double &ex, double &ey) const
bool SetDonor(const unsigned int donorNumber, const double eXsec, const double hxSec, const double concentration)
bool Initialise(const std::string &gridfilename, const std::string &datafilename)
ComponentTcad2d()
Constructor.
void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label) override
void SetRangeZ(const double zmin, const double zmax)
void PrintRegions() const
List all currently defined regions.
bool GetHoleLifetime(const double x, const double y, const double z, double &htau) override
bool HoleAttachment(const double x, const double y, const double z, double &eta) override
Get the hole attachment coefficient.
Medium * GetMedium(const double x, const double y, const double z) override
Get the medium at a given location (x, y, z).
bool GetAcceptorOccupation(const double x, const double y, const double z, const unsigned int acceptorNumber, double &occupationFraction)
void HoleVelocity(const double x, const double y, const double z, double &vx, double &vy, double &vz, Medium *&m, int &status) override
Get the hole drift velocity.
bool GetElement(const unsigned int i, double &vol, double &dmin, double &dmax, int &type) const
void UnsetDriftRegion(const unsigned int ireg)
bool GetElectronLifetime(const double x, const double y, const double z, double &etau) override
bool ElectronAttachment(const double x, const double y, const double z, double &eta) override
Get the electron attachment coefficient.
void SetMedium(const unsigned int ireg, Medium *m)
Set the medium for a given region.
double WeightingPotential(const double x, const double y, const double z, const std::string &label) override
void SetDriftRegion(const unsigned int ireg)
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, double &v, Medium *&m, int &status) override
Calculate the drift field [V/cm] and potential [V] at (x, y, z).
bool GetMobility(const double x, const double y, const double z, double &emob, double &hmob)
void ElectronVelocity(const double x, const double y, const double z, double &vx, double &vy, double &vz, Medium *&m, int &status) override
Get the electron drift velocity.
bool SetAcceptor(const unsigned int acceptorNumber, const double eXsec, const double hxSec, const double concentration)
Abstract base class for media.
void ltrim(std::string &line)