12void ltrim(std::string& line) {
13 line.erase(line.begin(), find_if(line.begin(), line.end(),
14 not1(std::ptr_fun<int, int>(isspace))));
22 m_hasPotential(false),
24 m_hasElectronMobility(false),
25 m_hasHoleMobility(false),
26 m_hasElectronVelocity(false),
27 m_hasHoleVelocity(false),
28 m_hasElectronLifetime(false),
29 m_hasHoleLifetime(false),
38 m_regions.reserve(10);
39 m_vertices.reserve(10000);
40 m_elements.reserve(10000);
45 const double eXsec,
const double hXsec,
49 if (donorNumber >= m_donors.size()) {
51 <<
" Index (" << donorNumber <<
") out of range.\n";
54 m_donors[donorNumber].xsece = eXsec;
55 m_donors[donorNumber].xsech = hXsec;
56 m_donors[donorNumber].conc = conc;
58 m_validTraps = CheckTraps();
63 const double eXsec,
const double hXsec,
66 if (acceptorNumber >= m_acceptors.size()) {
68 <<
" Index (" << acceptorNumber <<
") out of range.\n";
71 m_acceptors[acceptorNumber].xsece = eXsec;
72 m_acceptors[acceptorNumber].xsech = hXsec;
73 m_acceptors[acceptorNumber].conc = conc;
75 m_validTraps = CheckTraps();
80 const double z,
double& eta) {
83 std::cerr <<
m_className <<
"::ElectronAttachment:\n"
84 <<
" Trap cross-sections or concentrations are invalid.\n";
88 if (m_donors.empty() && m_acceptors.empty()) {
90 std::cerr <<
m_className <<
"::ElectronAttachment:\n"
91 <<
" There are no traps defined.\n";
96 const unsigned int nAcceptors = m_acceptors.size();
97 for (
unsigned int i = 0; i < nAcceptors; ++i) {
98 const Defect& acceptor = m_acceptors[i];
101 eta += acceptor.conc * acceptor.xsece * (1. - f);
103 const unsigned int nDonors = m_donors.size();
104 for (
unsigned int i = 0; i < nDonors; ++i) {
105 const Defect& donor = m_donors[i];
108 eta += donor.conc * donor.xsece * f;
114 const double z,
double& eta) {
119 <<
" Trap cross-sections or concentrations are invalid.\n";
123 if (m_donors.empty() && m_acceptors.empty()) {
126 <<
" There are no traps defined.\n";
131 const unsigned int nAcceptors = m_acceptors.size();
132 for (
unsigned int i = 0; i < nAcceptors; ++i) {
133 const Defect& acceptor = m_acceptors[i];
136 eta += acceptor.conc * acceptor.xsech * f;
138 const unsigned int nDonors = m_donors.size();
139 for (
unsigned int i = 0; i < nDonors; ++i) {
140 const Defect& donor = m_donors[i];
143 eta += donor.conc * donor.xsech * (1. - f);
149 double& wx,
double& wy,
double& wz,
150 const std::string& ) {
158 const double zin,
double& ex,
double& ey,
159 double& ez,
double& p,
Medium*& m,
163 ex = ey = ez = p = 0.;
169 <<
" Field map is not available for interpolation.\n";
175 double x = xin, y = yin, z = zin;
176 bool xmirr =
false, ymirr =
false;
177 MapCoordinates(x, y, xmirr, ymirr);
179 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB) {
183 if (m_hasRangeZ && (z < m_zMinBB || z > m_zMaxBB)) {
190 double w[nMaxVertices] = {0};
191 if (m_lastElement >= 0) {
193 const Element& last = m_elements[m_lastElement];
194 if (x >= last.xmin && x <= last.xmax && y >= last.ymin && y <= last.ymax) {
195 if (CheckElement(x, y, last, w)) {
196 const unsigned int nVertices = last.type + 1;
197 for (
unsigned int j = 0; j < nVertices; ++j) {
198 const Vertex& vj = m_vertices[last.vertex[j]];
205 m = m_regions[last.region].medium;
206 if (!m_regions[last.region].drift || !m) status = -5;
212 const unsigned int nNeighbours = last.neighbours.size();
213 for (
unsigned int i = 0; i < nNeighbours; ++i) {
214 const Element& element = m_elements[last.neighbours[i]];
215 if (x < element.xmin || x > element.xmax ||
216 y < element.ymin || y > element.ymax)
continue;
217 if (!CheckElement(x, y, element, w))
continue;
218 const unsigned int nVertices = element.type + 1;
219 for (
unsigned int j = 0; j < nVertices; ++j) {
220 const Vertex& vj = m_vertices[element.vertex[j]];
227 m = m_regions[element.region].medium;
228 if (!m_regions[element.region].drift || !m) status = -5;
229 m_lastElement = last.neighbours[i];
236 const unsigned int nElements = m_elements.size();
237 for (
unsigned int i = 0; i < nElements; ++i) {
238 const Element& element = m_elements[i];
239 if (x < element.xmin || x > element.xmax ||
240 y < element.ymin || y > element.ymax)
continue;
241 if (!CheckElement(x, y, element, w))
continue;
242 const unsigned int nVertices = element.type + 1;
243 for (
unsigned int j = 0; j < nVertices; ++j) {
244 const Vertex& vj = m_vertices[element.vertex[j]];
251 m = m_regions[element.region].medium;
252 if (!m_regions[element.region].drift || !m) status = -5;
259 <<
" Point (" << x <<
", " << y <<
") is outside the mesh.\n";
266 double& vx,
double& vy,
double& vz,
267 Medium*& m,
int& status) {
274 std::cerr <<
m_className <<
"::ElectronVelocity:\n";
275 std::cerr <<
" Field map is not available for interpolation.\n";
280 double x = xin, y = yin, z = zin;
282 bool xmirr =
false, ymirr =
false;
283 MapCoordinates(x, y, xmirr, ymirr);
284 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB) {
288 if (m_hasRangeZ && (z < m_zMinBB || z > m_zMaxBB)) {
295 double w[nMaxVertices] = {0};
296 if (m_lastElement >= 0) {
298 const Element& last = m_elements[m_lastElement];
299 if (x >= last.xmin && x <= last.xmax && y >= last.ymin && y <= last.ymax) {
300 if (CheckElement(x, y, last, w)) {
301 const unsigned int nVertices = last.type + 1;
302 for (
unsigned int j = 0; j < nVertices; ++j) {
303 const Vertex& vj = m_vertices[last.vertex[j]];
309 m = m_regions[last.region].medium;
310 if (!m_regions[last.region].drift || !m) status = -5;
316 const unsigned int nNeighbours = last.neighbours.size();
317 for (
unsigned int i = 0; i < nNeighbours; ++i) {
318 const Element& element = m_elements[last.neighbours[i]];
319 if (x < element.xmin || x > element.xmax ||
320 y < element.ymin || y > element.ymax)
continue;
321 if (!CheckElement(x, y, element, w))
continue;
322 const unsigned int nVertices = element.type + 1;
323 for (
unsigned int j = 0; j < nVertices; ++j) {
324 const Vertex& vj = m_vertices[element.vertex[j]];
330 m = m_regions[element.region].medium;
331 if (!m_regions[element.region].drift || !m) status = -5;
332 m_lastElement = last.neighbours[i];
339 const unsigned int nElements = m_elements.size();
340 for (
unsigned int i = 0; i < nElements; ++i) {
341 const Element& element = m_elements[i];
342 if (x < element.xmin || x > element.xmax ||
343 y < element.ymin || y > element.ymax)
continue;
344 if (!CheckElement(x, y, element, w))
continue;
345 const unsigned int nVertices = element.type + 1;
346 for (
unsigned int j = 0; j < nVertices; ++j) {
347 const Vertex& vj = m_vertices[element.vertex[j]];
353 m = m_regions[element.region].medium;
354 if (!m_regions[element.region].drift || !m) status = -5;
360 std::cerr <<
m_className <<
"::ElectronVelocity:\n"
361 <<
" Point (" << x <<
", " << y <<
") is outside the mesh.\n";
368 double& vx,
double& vy,
double& vz,
369 Medium*& m,
int& status) {
378 <<
" Field map is not available for interpolation.\n";
383 double x = xin, y = yin, z = zin;
385 bool xmirr =
false, ymirr =
false;
386 MapCoordinates(x, y, xmirr, ymirr);
387 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB) {
391 if (m_hasRangeZ && (z < m_zMinBB || z > m_zMaxBB)) {
399 double w[nMaxVertices] = {0};
400 if (m_lastElement >= 0) {
402 const Element& last = m_elements[m_lastElement];
403 if (x >= last.xmin && x <= last.xmax && y >= last.ymin && y <= last.ymax) {
404 if (CheckElement(x, y, last, w)) {
405 const unsigned int nVertices = last.type + 1;
406 for (
unsigned int j = 0; j < nVertices; ++j) {
407 const Vertex& vj = m_vertices[last.vertex[j]];
413 m = m_regions[last.region].medium;
414 if (!m_regions[last.region].drift || !m) status = -5;
420 const unsigned int nNeighbours = last.neighbours.size();
421 for (
unsigned int i = 0; i < nNeighbours; ++i) {
422 const Element& element = m_elements[last.neighbours[i]];
423 if (x < element.xmin || x > element.xmax ||
424 y < element.ymin || y > element.ymax)
continue;
425 if (!CheckElement(x, y, element, w))
continue;
426 const unsigned int nVertices = element.type + 1;
427 for (
unsigned int j = 0; j < nVertices; ++j) {
428 const Vertex& vj = m_vertices[element.vertex[j]];
434 m = m_regions[element.region].medium;
435 if (!m_regions[element.region].drift || !m) status = -5;
436 m_lastElement = last.neighbours[i];
443 const unsigned int nElements = m_elements.size();
444 for (
unsigned int i = 0; i < nElements; ++i) {
445 const Element& element = m_elements[i];
446 if (x < element.xmin || x > element.xmax ||
447 y < element.ymin || y > element.ymax)
continue;
448 if (!CheckElement(x, y, element, w))
continue;
449 const unsigned int nVertices = element.type + 1;
450 for (
unsigned int j = 0; j < nVertices; ++j) {
451 const Vertex& vj = m_vertices[element.vertex[j]];
457 m = m_regions[element.region].medium;
458 if (!m_regions[element.region].drift || !m) status = -5;
466 <<
" Point (" << x <<
", " << y <<
") is outside the mesh.\n";
477 <<
" Field map not available for interpolation.\n";
481 double x = xin, y = yin, z = zin;
483 bool xmirr =
false, ymirr =
false;
484 MapCoordinates(x, y, xmirr, ymirr);
486 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB) {
489 if (m_hasRangeZ && (z < m_zMinBB || z > m_zMaxBB))
return NULL;
492 double w[nMaxVertices] = {0};
493 if (m_lastElement >= 0) {
495 const Element& last = m_elements[m_lastElement];
496 if (x >= last.xmin && x <= last.xmax && y >= last.ymin && y <= last.ymax &&
497 CheckElement(x, y, last, w)) {
498 return m_regions[last.region].medium;
503 const unsigned int nNeighbours = last.neighbours.size();
504 for (
unsigned int i = 0; i < nNeighbours; ++i) {
505 const Element& element = m_elements[last.neighbours[i]];
506 if (x < element.xmin || x > element.xmax ||
507 y < element.ymin || y > element.ymax)
continue;
508 if (!CheckElement(x, y, element, w))
continue;
509 m_lastElement = last.neighbours[i];
510 return m_regions[element.region].medium;
516 const unsigned int nElements = m_elements.size();
517 for (
unsigned int i = 0; i < nElements; ++i) {
518 const Element& element = m_elements[i];
519 if (x < element.xmin || x > element.xmax ||
520 y < element.ymin || y > element.ymax)
continue;
521 if (!CheckElement(x, y, element, w))
continue;
523 return m_regions[element.region].medium;
531 const double zin,
double& tau) {
536 std::cerr <<
m_className <<
"::GetElectronLifetime:\n"
537 <<
" Field map is not available for interpolation.\n";
541 double x = xin, y = yin, z = zin;
543 bool xmirr =
false, ymirr =
false;
544 MapCoordinates(x, y, xmirr, ymirr);
546 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB) {
549 if (m_hasRangeZ && (z < m_zMinBB || z > m_zMaxBB))
return false;
551 double w[nMaxVertices] = {0};
552 if (m_lastElement >= 0) {
554 const Element& last = m_elements[m_lastElement];
555 if (x >= last.xmin && x <= last.xmax && y >= last.ymin && y <= last.ymax) {
556 if (CheckElement(x, y, last, w)) {
557 const unsigned int nVertices = last.type + 1;
558 for (
unsigned int j = 0; j < nVertices; ++j) {
559 const Vertex& vj = m_vertices[last.vertex[j]];
560 tau += w[j] * vj.eTau;
567 const unsigned int nNeighbours = last.neighbours.size();
568 for (
unsigned int i = 0; i < nNeighbours; ++i) {
569 const Element& element = m_elements[last.neighbours[i]];
570 if (x < element.xmin || x > element.xmax ||
571 y < element.ymin || y > element.ymax)
continue;
572 if (!CheckElement(x, y, element, w))
continue;
573 const unsigned int nVertices = element.type + 1;
574 for (
unsigned int j = 0; j < nVertices; ++j) {
575 const Vertex& vj = m_vertices[element.vertex[j]];
576 tau += w[j] * vj.eTau;
578 m_lastElement = last.neighbours[i];
585 const unsigned int nElements = m_elements.size();
586 for (
unsigned int i = 0; i < nElements; ++i) {
587 const Element& element = m_elements[i];
588 if (x < element.xmin || x > element.xmax ||
589 y < element.ymin || y > element.ymax)
continue;
590 if (!CheckElement(x, y, element, w))
continue;
591 const unsigned int nVertices = element.type + 1;
592 for (
unsigned int j = 0; j < nVertices; ++j) {
593 const Vertex& vj = m_vertices[element.vertex[j]];
594 tau += w[j] * vj.eTau;
602 std::cerr <<
m_className <<
"::GetElectronLifetime:\n"
603 <<
" Point (" << x <<
", " << y <<
") is outside the mesh.\n";
609 const double zin,
double& tau) {
615 <<
" Field map is not available for interpolation.\n";
619 double x = xin, y = yin, z = zin;
621 bool xmirr =
false, ymirr =
false;
622 MapCoordinates(x, y, xmirr, ymirr);
624 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB) {
627 if (m_hasRangeZ && (z < m_zMinBB || z > m_zMaxBB))
return false;
629 double w[nMaxVertices] = {0};
630 if (m_lastElement >= 0) {
632 const Element& last = m_elements[m_lastElement];
633 if (x >= last.xmin && x <= last.xmax && y >= last.ymin && y <= last.ymax) {
634 if (CheckElement(x, y, last, w)) {
635 const unsigned int nVertices = last.type + 1;
636 for (
unsigned int j = 0; j < nVertices; ++j) {
637 const Vertex& vj = m_vertices[last.vertex[j]];
638 tau += w[j] * vj.hTau;
645 const unsigned int nNeighbours = last.neighbours.size();
646 for (
unsigned int i = 0; i < nNeighbours; ++i) {
647 const Element& element = m_elements[last.neighbours[i]];
648 if (x < element.xmin || x > element.xmax ||
649 y < element.ymin || y > element.ymax)
continue;
650 if (!CheckElement(x, y, element, w))
continue;
651 const unsigned int nVertices = element.type + 1;
652 for (
unsigned int j = 0; j < nVertices; ++j) {
653 const Vertex& vj = m_vertices[element.vertex[j]];
654 tau += w[j] * vj.hTau;
656 m_lastElement = last.neighbours[i];
663 const unsigned int nElements = m_elements.size();
664 for (
unsigned int i = 0; i < nElements; ++i) {
665 const Element& element = m_elements[i];
666 if (x < element.xmin || x > element.xmax ||
667 y < element.ymin || y > element.ymax)
continue;
668 if (!CheckElement(x, y, element, w))
continue;
669 const unsigned int nVertices = element.type + 1;
670 for (
unsigned int j = 0; j < nVertices; ++j) {
671 const Vertex& vj = m_vertices[element.vertex[j]];
672 tau += w[j] * vj.hTau;
681 <<
" Point (" << x <<
", " << y <<
") is outside the mesh.\n";
689 double& emob,
double& hmob) {
696 <<
" Field map is not available for interpolation.\n";
700 double x = xin, y = yin, z = zin;
702 bool xmirr =
false, ymirr =
false;
703 MapCoordinates(x, y, xmirr, ymirr);
705 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB) {
708 if (m_hasRangeZ && (z < m_zMinBB || z > m_zMaxBB)) {
712 double w[nMaxVertices] = {0};
713 if (m_lastElement >= 0) {
715 const Element& last = m_elements[m_lastElement];
716 if (x >= last.xmin && x <= last.xmax && y >= last.ymin && y <= last.ymax) {
717 if (CheckElement(x, y, last, w)) {
718 const unsigned int nVertices = last.type + 1;
719 for (
unsigned int j = 0; j < nVertices; ++j) {
720 const Vertex& vj = m_vertices[last.vertex[j]];
721 emob += w[j] * vj.emob;
722 hmob += w[j] * vj.hmob;
729 const unsigned int nNeighbours = last.neighbours.size();
730 for (
unsigned int i = 0; i < nNeighbours; ++i) {
731 const Element& element = m_elements[last.neighbours[i]];
732 if (x < element.xmin || x > element.xmax ||
733 y < element.ymin || y > element.ymax)
continue;
734 if (!CheckElement(x, y, element, w))
continue;
735 const unsigned int nVertices = element.type + 1;
736 for (
unsigned int j = 0; j < nVertices; ++j) {
737 const Vertex& vj = m_vertices[element.vertex[j]];
738 emob += w[j] * vj.emob;
739 hmob += w[j] * vj.hmob;
741 m_lastElement = last.neighbours[i];
748 const unsigned int nElements = m_elements.size();
749 for (
unsigned int i = 0; i < nElements; ++i) {
750 const Element& element = m_elements[i];
751 if (x < element.xmin || x > element.xmax ||
752 y < element.ymin || y > element.ymax)
continue;
753 if (!CheckElement(x, y, element, w))
continue;
754 const unsigned int nVertices = element.type + 1;
755 for (
unsigned int j = 0; j < nVertices; ++j) {
756 const Vertex& vj = m_vertices[element.vertex[j]];
757 emob += w[j] * vj.emob;
758 hmob += w[j] * vj.hmob;
767 <<
" Point (" << x <<
", " << y <<
") is outside the mesh.\n";
774 const unsigned int donorNumber,
777 if (donorNumber >= m_donors.size()) {
778 std::cerr <<
m_className <<
"::GetDonorOccupation:\n"
779 <<
" Donor " << donorNumber <<
" does not exist.\n";
785 std::cerr <<
m_className <<
"::GetDonorOccupation:\n"
786 <<
" Field map is not available for interpolation.\n";
790 double x = xin, y = yin, z = zin;
792 bool xmirr =
false, ymirr =
false;
793 MapCoordinates(x, y, xmirr, ymirr);
795 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB) {
798 if (m_hasRangeZ && (z < m_zMinBB || z > m_zMaxBB)) {
802 double w[nMaxVertices] = {0};
803 if (m_lastElement >= 0) {
805 const Element& last = m_elements[m_lastElement];
806 if (x >= last.xmin && x <= last.xmax && y >= last.ymin && y <= last.ymax) {
807 if (CheckElement(x, y, last, w)) {
808 const unsigned int nVertices = last.type + 1;
809 for (
unsigned int j = 0; j < nVertices; ++j) {
810 const Vertex& vj = m_vertices[last.vertex[j]];
811 f += w[j] * vj.donorOcc[donorNumber];
818 const unsigned int nNeighbours = last.neighbours.size();
819 for (
unsigned int i = 0; i < nNeighbours; ++i) {
820 const Element& element = m_elements[last.neighbours[i]];
821 if (x < element.xmin || x > element.xmax ||
822 y < element.ymin || y > element.ymax)
continue;
823 if (!CheckElement(x, y, element, w))
continue;
824 const unsigned int nVertices = element.type + 1;
825 for (
unsigned int j = 0; j < nVertices; ++j) {
826 const Vertex& vj = m_vertices[element.vertex[j]];
827 f += w[j] * vj.donorOcc[donorNumber];
829 m_lastElement = last.neighbours[i];
836 const unsigned int nElements = m_elements.size();
837 for (
unsigned int i = 0; i < nElements; ++i) {
838 const Element& element = m_elements[i];
839 if (x < element.xmin || x > element.xmax ||
840 y < element.ymin || y > element.ymax)
continue;
841 if (!CheckElement(x, y, element, w))
continue;
842 const unsigned int nVertices = element.type + 1;
843 for (
unsigned int j = 0; j < nVertices; ++j) {
844 const Vertex& vj = m_vertices[element.vertex[j]];
845 f += w[j] * vj.donorOcc[donorNumber];
853 std::cerr <<
m_className <<
"::GetDonorOccupation:\n"
854 <<
" Point (" << x <<
", " << y <<
") is outside the mesh.\n";
861 const unsigned int acceptorNumber,
864 if (acceptorNumber >= m_acceptors.size()) {
865 std::cerr <<
m_className <<
"::GetAcceptorOccupation:\n"
866 <<
" Acceptor " << acceptorNumber <<
" does not exist.\n";
872 std::cerr <<
m_className <<
"::GetAcceptorOccupation:\n"
873 <<
" Field map is not available for interpolation.\n";
877 double x = xin, y = yin, z = zin;
879 bool xmirr =
false, ymirr =
false;
880 MapCoordinates(x, y, xmirr, ymirr);
882 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB) {
885 if (m_hasRangeZ && (z < m_zMinBB || z > m_zMaxBB)) {
890 double w[nMaxVertices] = {0};
891 if (m_lastElement >= 0) {
893 const Element& last = m_elements[m_lastElement];
894 if (x >= last.xmin && x <= last.xmax && y >= last.ymin && y <= last.ymax) {
895 if (CheckElement(x, y, last, w)) {
896 const unsigned int nVertices = last.type + 1;
897 for (
unsigned int j = 0; j < nVertices; ++j) {
898 const Vertex& vj = m_vertices[last.vertex[j]];
899 f += w[j] * vj.acceptorOcc[acceptorNumber];
906 const unsigned int nNeighbours = last.neighbours.size();
907 for (
unsigned int i = 0; i < nNeighbours; ++i) {
908 const Element& element = m_elements[last.neighbours[i]];
909 if (x < element.xmin || x > element.xmax ||
910 y < element.ymin || y > element.ymax)
continue;
911 if (!CheckElement(x, y, element, w))
continue;
912 const unsigned int nVertices = element.type + 1;
913 for (
unsigned int j = 0; j < nVertices; ++j) {
914 const Vertex& vj = m_vertices[element.vertex[j]];
915 f += w[j] * vj.acceptorOcc[acceptorNumber];
917 m_lastElement = last.neighbours[i];
924 const unsigned int nElements = m_elements.size();
925 for (
unsigned int i = 0; i < nElements; ++i) {
926 const Element& element = m_elements[i];
927 if (x < element.xmin || x > element.xmax ||
928 y < element.ymin || y > element.ymax)
continue;
929 if (!CheckElement(x, y, element, w))
continue;
930 const unsigned int nVertices = element.type + 1;
931 for (
unsigned int j = 0; j < nVertices; ++j) {
932 const Vertex& vj = m_vertices[element.vertex[j]];
933 f += w[j] * vj.acceptorOcc[acceptorNumber];
941 std::cerr <<
m_className <<
"::GetAcceptorOccupation:\n"
942 <<
" Point (" << x <<
", " << y <<
") is outside the mesh.\n";
948 const std::string& datafilename) {
952 m_hasPotential = m_hasField =
false;
953 m_hasElectronMobility = m_hasHoleMobility =
false;
954 m_validTraps =
false;
959 if (!LoadGrid(gridfilename)) {
961 <<
" Importing mesh data failed.\n";
967 if (!LoadData(datafilename)) {
969 <<
" Importing electric field and potential failed.\n";
974 m_xMaxBB = m_xMinBB = m_vertices[m_elements[0].vertex[0]].x;
975 m_yMaxBB = m_yMinBB = m_vertices[m_elements[0].vertex[0]].y;
976 m_pMax = m_pMin = m_vertices[m_elements[0].vertex[0]].p;
977 const unsigned int nElements = m_elements.size();
978 for (
unsigned int i = 0; i < nElements; ++i) {
979 const Vertex& v0 = m_vertices[m_elements[i].vertex[0]];
980 const Vertex& v1 = m_vertices[m_elements[i].vertex[1]];
981 double xmin = std::min(v0.x, v1.x);
982 double xmax = std::max(v0.x, v1.x);
983 double ymin = std::min(v0.y, v1.y);
984 double ymax = std::max(v0.y, v1.y);
985 m_pMin = std::min(m_pMin, std::min(v0.p, v1.p));
986 m_pMax = std::max(m_pMax, std::max(v0.p, v1.p));
987 if (m_elements[i].type > 1) {
988 const Vertex& v2 = m_vertices[m_elements[i].vertex[2]];
989 xmin = std::min(xmin, v2.x);
990 xmax = std::max(xmax, v2.x);
991 ymin = std::min(ymin, v2.y);
992 ymax = std::max(ymax, v2.y);
993 m_pMin = std::min(m_pMin, v2.p);
994 m_pMax = std::max(m_pMax, v2.p);
996 if (m_elements[i].type > 2) {
997 const Vertex& v3 = m_vertices[m_elements[i].vertex[3]];
998 xmin = std::min(xmin, v3.x);
999 xmax = std::max(xmax, v3.x);
1000 ymin = std::min(ymin, v3.y);
1001 ymax = std::max(ymax, v3.y);
1002 m_pMin = std::min(m_pMin, v3.p);
1003 m_pMax = std::max(m_pMax, v3.p);
1005 const double tol = 1.e-6;
1006 m_elements[i].xmin = xmin - tol;
1007 m_elements[i].xmax = xmax + tol;
1008 m_elements[i].ymin = ymin - tol;
1009 m_elements[i].ymax = ymax + tol;
1010 m_xMinBB = std::min(m_xMinBB, xmin);
1011 m_xMaxBB = std::max(m_xMaxBB, xmax);
1012 m_yMinBB = std::min(m_yMinBB, ymin);
1013 m_yMaxBB = std::max(m_yMaxBB, ymax);
1017 <<
" Available data:\n";
1018 if (m_hasPotential) {
1019 std::cout <<
" Electrostatic potential\n";
1022 std::cout <<
" Electric field\n";
1024 if (m_hasElectronMobility) {
1025 std::cout <<
" Electron mobility\n";
1027 if (m_hasHoleMobility) {
1028 std::cout <<
" Hole mobility\n";
1030 if (m_hasElectronVelocity) {
1031 std::cout <<
" Electron velocity\n";
1033 if (m_hasHoleVelocity) {
1034 std::cout <<
" Hole velocity\n";
1036 if (m_hasElectronLifetime) {
1037 std::cout <<
" Electron lifetimes\n";
1039 if (m_hasHoleLifetime) {
1040 std::cout <<
" Hole lifetimes\n";
1042 if (!m_donors.empty()) {
1043 std::cout <<
" " << m_donors.size() <<
" donor-type traps\n";
1045 if (!m_acceptors.empty()) {
1046 std::cout <<
" " << m_acceptors.size() <<
" acceptor-type traps\n";
1048 std::cout <<
" Bounding box:\n"
1049 <<
" " << m_xMinBB <<
" < x [cm] < " << m_xMaxBB <<
"\n"
1050 <<
" " << m_yMinBB <<
" < y [cm] < " << m_yMaxBB <<
"\n"
1051 <<
" Voltage range:\n"
1052 <<
" " << m_pMin <<
" < V < " << m_pMax <<
"\n";
1057 const int nRegions = m_regions.size();
1058 std::vector<int> nElementsRegion(nRegions, 0);
1061 unsigned int nLines = 0;
1062 unsigned int nTriangles = 0;
1063 unsigned int nRectangles = 0;
1064 unsigned int nOtherShapes = 0;
1067 unsigned int nLoose = 0;
1068 std::vector<int> looseElements;
1071 unsigned int nDegenerate = 0;
1072 std::vector<int> degenerateElements;
1074 for (
unsigned int i = 0; i < nElements; ++i) {
1075 const Element& element = m_elements[i];
1076 if (element.type == 1) {
1078 if (element.vertex[0] == element.vertex[1]) {
1079 degenerateElements.push_back(i);
1082 }
else if (element.type == 2) {
1084 if (element.vertex[0] == element.vertex[1] ||
1085 element.vertex[1] == element.vertex[2] ||
1086 element.vertex[2] == element.vertex[0]) {
1087 degenerateElements.push_back(i);
1090 }
else if (element.type == 3) {
1092 if (element.vertex[0] == element.vertex[1] ||
1093 element.vertex[0] == element.vertex[2] ||
1094 element.vertex[0] == element.vertex[3] ||
1095 element.vertex[1] == element.vertex[2] ||
1096 element.vertex[1] == element.vertex[3] ||
1097 element.vertex[2] == element.vertex[3]) {
1098 degenerateElements.push_back(i);
1105 if (element.region >= 0 && element.region < nRegions) {
1106 ++nElementsRegion[element.region];
1108 looseElements.push_back(i);
1113 if (nDegenerate > 0) {
1115 <<
" The following elements are degenerate:\n";
1116 for (
unsigned int i = 0; i < nDegenerate; ++i) {
1117 std::cerr <<
" " << degenerateElements[i] <<
"\n";
1124 <<
" The following elements are not part of any region:\n";
1125 for (
unsigned int i = 0; i < nLoose; ++i) {
1126 std::cerr <<
" " << looseElements[i] <<
"\n";
1132 <<
" Number of regions: " << nRegions <<
"\n";
1133 for (
int i = 0; i < nRegions; ++i) {
1134 std::cout <<
" " << i <<
": " << m_regions[i].name <<
", "
1135 << nElementsRegion[i] <<
" elements\n";
1138 std::cout <<
" Number of elements: " << nElements <<
"\n";
1140 std::cout <<
" " << nLines <<
" lines\n";
1142 if (nTriangles > 0) {
1143 std::cout <<
" " << nTriangles <<
" triangles\n";
1145 if (nRectangles > 0) {
1146 std::cout <<
" " << nRectangles <<
" rectangles\n";
1148 if (nOtherShapes > 0) {
1149 std::cerr <<
" " << nOtherShapes <<
" elements of unknown type.\n"
1150 <<
" Program bug!\n";
1156 std::cout <<
" Number of vertices: " << m_vertices.size() <<
"\n";
1160 <<
" Looking for neighbouring elements. Be patient...\n";
1170 UpdatePeriodicity();
1172 <<
" Initialisation finished.\n";
1177 double& xmax,
double& ymax,
double& zmax) {
1205 if (fabs(zmax - zmin) <= 0.) {
1207 <<
" Zero range is not permitted.\n";
1210 m_zMinBB = std::min(zmin, zmax);
1211 m_zMaxBB = std::max(zmin, zmax);
1228 <<
" Field map not yet initialised.\n";
1232 if (m_regions.empty()) {
1234 <<
" No regions are currently defined.\n";
1238 const unsigned int nRegions = m_regions.size();
1240 <<
" Currently " << nRegions <<
" regions are defined.\n"
1241 <<
" Index Name Medium\n";
1242 for (
unsigned int i = 0; i < nRegions; ++i) {
1243 std::cout <<
" " << i <<
" " << m_regions[i].name;
1244 if (!m_regions[i].medium) {
1245 std::cout <<
" none ";
1247 std::cout <<
" " << m_regions[i].medium->GetName();
1249 if (m_regions[i].drift) {
1250 std::cout <<
" (active region)\n";
1258 std::string& name,
bool& active)
const {
1260 if (i >= m_regions.size()) {
1262 <<
" Region " << i <<
" does not exist.\n";
1265 name = m_regions[i].name;
1266 active = m_regions[i].drift;
1271 if (i >= m_regions.size()) {
1273 <<
" Region " << i <<
" does not exist.\n";
1276 m_regions[i].drift =
true;
1281 if (i >= m_regions.size()) {
1282 std::cerr <<
m_className <<
"::UnsetDriftRegion:\n"
1283 <<
" Region " << i <<
" does not exist.\n";
1286 m_regions[i].drift =
false;
1291 if (i >= m_regions.size()) {
1293 <<
" Region " << i <<
" does not exist.\n";
1298 std::cerr <<
m_className <<
"::SetMedium:\n Null pointer.\n";
1302 m_regions[i].medium = medium;
1307 if (i >= m_regions.size()) {
1309 <<
" Region " << i <<
" does not exist.\n";
1313 return m_regions[i].medium;
1317 double& dmax,
int& type)
const {
1319 if (i >= m_elements.size()) {
1321 <<
" Element index (" << i <<
") out of range.\n";
1325 const Element& element = m_elements[i];
1326 if (element.type == 1) {
1327 const Vertex& v0 = m_vertices[element.vertex[0]];
1328 const Vertex& v1 = m_vertices[element.vertex[1]];
1329 const double dx = v1.x - v0.x;
1330 const double dy = v1.y - v0.y;
1331 const double d = sqrt(dx * dx + dy * dy);
1332 dmin = dmax = vol = d;
1333 }
else if (m_elements[i].type == 2) {
1334 const Vertex& v0 = m_vertices[element.vertex[0]];
1335 const Vertex& v1 = m_vertices[element.vertex[1]];
1336 const Vertex& v2 = m_vertices[element.vertex[2]];
1337 vol = 0.5 * fabs((v2.x - v0.x) * (v1.y - v0.y) -
1338 (v2.y - v0.y) * (v1.x - v0.x));
1339 const double a = sqrt(pow(v1.x - v0.x, 2) + pow(v1.y - v0.y, 2));
1340 const double b = sqrt(pow(v2.x - v0.x, 2) + pow(v2.y - v0.y, 2));
1341 const double c = sqrt(pow(v1.x - v2.x, 2) + pow(v1.y - v2.y, 2));
1342 dmin = std::min(std::min(a, b), c);
1343 dmax = std::max(std::max(a, b), c);
1344 }
else if (m_elements[i].type == 3) {
1345 const Vertex& v0 = m_vertices[element.vertex[0]];
1346 const Vertex& v1 = m_vertices[element.vertex[1]];
1347 const Vertex& v3 = m_vertices[element.vertex[3]];
1348 const double a = sqrt(pow(v1.x - v0.x, 2) + pow(v1.y - v0.y, 2));
1349 const double b = sqrt(pow(v3.x - v0.x, 2) + pow(v3.y - v0.y, 2));
1351 dmin = std::min(a, b);
1352 dmax = sqrt(a * a + b * b);
1355 <<
" Unexpected element type (" << type <<
")\n";
1362 double& dmin,
double& dmax,
int& type,
1363 int& node1,
int& node2,
1364 int& node3,
int& node4,
int& reg)
const {
1366 if (!
GetElement(i, vol, dmin, dmax, type))
return false;
1367 const Element& element = m_elements[i];
1368 node1 = element.vertex[0];
1369 node2 = element.vertex[1];
1370 node3 = element.vertex[2];
1371 node4 = element.vertex[3];
1372 reg = element.region;
1377 double& x,
double& y,
double& v,
1378 double& ex,
double& ey)
const {
1380 if (i >= m_vertices.size()) {
1382 <<
" Node index (" << i <<
") out of range.\n";
1386 x = m_vertices[i].x;
1387 y = m_vertices[i].y;
1388 v = m_vertices[i].p;
1389 ex = m_vertices[i].ex;
1390 ey = m_vertices[i].ey;
1394bool ComponentTcad2d::LoadData(
const std::string& datafilename) {
1396 std::ifstream datafile;
1397 datafile.open(datafilename.c_str(), std::ios::in);
1400 <<
" Could not open file " << datafilename <<
".\n";
1404 const unsigned int nVertices = m_vertices.size();
1405 std::vector<unsigned int> fillCount(nVertices, 0);
1406 for (
unsigned int i = 0; i < nVertices; ++i) {
1407 m_vertices[i].p = 0.;
1408 m_vertices[i].ex = 0.;
1409 m_vertices[i].ey = 0.;
1410 m_vertices[i].emob = 0.;
1411 m_vertices[i].hmob = 0.;
1412 m_vertices[i].donorOcc.clear();
1413 m_vertices[i].acceptorOcc.clear();
1416 m_acceptors.clear();
1418 while (!datafile.fail()) {
1421 std::getline(datafile, line);
1424 if (line.substr(0, 8) !=
"function")
continue;
1426 const std::string::size_type pEq = line.find(
'=');
1427 if (pEq == std::string::npos) {
1430 <<
" Error reading file " << datafilename <<
".\n"
1431 <<
" Line:\n " << line <<
"\n";
1436 line = line.substr(pEq + 1);
1437 std::string dataset;
1438 std::istringstream data;
1441 if (dataset ==
"ElectrostaticPotential") {
1442 if (!ReadDataset(datafile, dataset))
return false;
1443 m_hasPotential =
true;
1444 }
else if (dataset ==
"ElectricField") {
1445 if (!ReadDataset(datafile, dataset))
return false;
1447 }
else if (dataset ==
"eDriftVelocity") {
1448 if (!ReadDataset(datafile, dataset))
return false;
1449 m_hasElectronVelocity=
true;
1450 }
else if (dataset ==
"hDriftVelocity") {
1451 if (!ReadDataset(datafile, dataset))
return false;
1452 m_hasHoleVelocity=
true;
1453 }
else if (dataset ==
"eMobility") {
1454 if (!ReadDataset(datafile, dataset))
return false;
1455 m_hasElectronMobility =
true;
1456 }
else if (dataset ==
"hMobility") {
1457 if (!ReadDataset(datafile, dataset))
return false;
1458 m_hasHoleMobility =
true;
1459 }
else if (dataset ==
"eLifetime") {
1460 if (!ReadDataset(datafile, dataset))
return false;
1461 m_hasElectronLifetime =
true;
1462 }
else if (dataset ==
"hLifetime") {
1463 if (!ReadDataset(datafile, dataset))
return false;
1464 m_hasHoleLifetime =
true;
1465 }
else if (dataset.substr(0,14) ==
"TrapOccupation" &&
1466 dataset.substr(17,2) ==
"Do") {
1467 if (!ReadDataset(datafile, dataset))
return false;
1472 m_donors.push_back(donor);
1473 }
else if (dataset.substr(0,14) ==
"TrapOccupation" &&
1474 dataset.substr(17, 2) ==
"Ac") {
1475 if (!ReadDataset(datafile, dataset))
return false;
1477 acceptor.xsece = -1.;
1478 acceptor.xsech = -1.;
1479 acceptor.conc = -1.;
1480 m_acceptors.push_back(acceptor);
1483 if (datafile.fail() && !datafile.eof()) {
1485 <<
" Error reading file " << datafilename <<
"\n";
1496bool ComponentTcad2d::ReadDataset(std::ifstream& datafile,
1497 const std::string& dataset) {
1500 ElectrostaticPotential,
1508 DonorTrapOccupation,
1509 AcceptorTrapOccupation,
1512 DataSet ds = Unknown;
1513 if (dataset ==
"ElectrostaticPotential") {
1514 ds = ElectrostaticPotential;
1515 }
else if (dataset ==
"ElectricField") {
1517 }
else if (dataset ==
"eDriftVelocity") {
1518 ds = eDriftVelocity;
1519 }
else if (dataset ==
"hDriftVelocity") {
1520 ds = hDriftVelocity;
1521 }
else if (dataset ==
"eMobility") {
1523 }
else if (dataset ==
"hMobility") {
1525 }
else if (dataset ==
"eLifetime") {
1527 }
else if (dataset ==
"hLifetime") {
1529 }
else if (dataset.substr(0,14) ==
"TrapOccupation") {
1530 if (dataset.substr(17,2) ==
"Do") {
1531 ds = DonorTrapOccupation;
1532 }
else if (dataset.substr(17,2) ==
"Ac") {
1533 ds = AcceptorTrapOccupation;
1537 <<
" Unexpected dataset " << dataset <<
".\n";
1541 bool isVector =
false;
1543 ds == eDriftVelocity || ds == hDriftVelocity) {
1547 if (!datafile.is_open())
return false;
1549 std::getline(datafile, line);
1550 std::getline(datafile, line);
1551 std::getline(datafile, line);
1552 std::getline(datafile, line);
1554 std::string::size_type bra = line.find(
'[');
1555 std::string::size_type ket = line.find(
']');
1556 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1558 <<
" Cannot extract region name.\n"
1559 <<
" Line:\n " << line <<
"\n";
1564 line = line.substr(bra + 1, ket - bra - 1);
1566 std::istringstream data;
1571 const int index = FindRegion(name);
1574 <<
" Unknown region " << name <<
".\n";
1580 std::getline(datafile, line);
1581 bra = line.find(
'(');
1582 ket = line.find(
')');
1583 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1585 <<
" Cannot extract number of values to be read.\n"
1586 <<
" Line:\n " << line <<
"\n";
1591 line = line.substr(bra + 1, ket - bra - 1);
1596 if (isVector) nValues = nValues / 2;
1598 const unsigned int nVertices = m_vertices.size();
1599 std::vector<bool> isInRegion(nVertices,
false);
1600 const unsigned int nElements = m_elements.size();
1601 for (
unsigned int j = 0; j < nElements; ++j) {
1602 if (m_elements[j].region != index)
continue;
1603 for (
int k = 0; k <= m_elements[j].type; ++k) {
1604 isInRegion[m_elements[j].vertex[k]] =
true;
1608 unsigned int ivertex = 0;
1609 for (
int j = 0; j < nValues; ++j) {
1613 datafile >> val1 >> val2;
1618 while (ivertex < nVertices) {
1619 if (isInRegion[ivertex])
break;
1624 if (ivertex >= nVertices) {
1626 <<
" Dataset " << dataset
1627 <<
" has more values than vertices in region " << name <<
"\n";
1633 case ElectrostaticPotential:
1634 m_vertices[ivertex].p = val1;
1637 m_vertices[ivertex].ex = val1;
1638 m_vertices[ivertex].ey = val2;
1640 case eDriftVelocity:
1642 m_vertices[ivertex].eVx = val1 * 1.e-9;
1643 m_vertices[ivertex].eVy = val2 * 1.e-9;
1645 case hDriftVelocity:
1647 m_vertices[ivertex].hVx = val1 * 1.e-9;
1648 m_vertices[ivertex].hVy = val2 * 1.e-9;
1652 m_vertices[ivertex].emob = val1 * 1.e-9;
1656 m_vertices[ivertex].hmob = val1 * 1.e-9;
1660 m_vertices[ivertex].eTau = val1 * 1.e9;
1664 m_vertices[ivertex].hTau = val1 * 1.e9;
1666 case DonorTrapOccupation:
1667 m_vertices[ivertex].donorOcc.push_back(val1);
1669 case AcceptorTrapOccupation:
1670 m_vertices[ivertex].acceptorOcc.push_back(val1);
1674 <<
" Unexpected dataset (" << ds <<
"). Program bug!\n";
1685bool ComponentTcad2d::LoadGrid(
const std::string& gridfilename) {
1688 std::ifstream gridfile;
1689 gridfile.open(gridfilename.c_str(), std::ios::in);
1692 <<
" Could not open file " << gridfilename <<
".\n";
1699 unsigned int iLine = 0;
1701 unsigned int nRegions = 0;
1702 while (!gridfile.fail()) {
1705 std::getline(gridfile, line);
1709 if (line.substr(0, 10) !=
"nb_regions")
continue;
1710 const std::string::size_type pEq = line.find(
'=');
1711 if (pEq == std::string::npos) {
1714 <<
" Could not read number of regions.\n";
1719 line = line.substr(pEq + 1);
1720 std::istringstream data;
1725 if (gridfile.eof()) {
1728 <<
" Could not find entry 'nb_regions' in file\n"
1729 <<
" " << gridfilename <<
".\n";
1733 }
else if (gridfile.fail()) {
1736 <<
" Error reading file " << gridfilename <<
" (line "
1742 m_regions.resize(nRegions);
1743 for (
unsigned int j = 0; j < nRegions; ++j) {
1744 m_regions[j].name =
"";
1745 m_regions[j].drift =
false;
1746 m_regions[j].medium = NULL;
1751 <<
" Found " << nRegions <<
" regions.\n";
1755 while (!gridfile.fail()) {
1757 std::getline(gridfile, line);
1761 if (line.substr(0, 7) !=
"regions")
continue;
1763 const std::string::size_type bra = line.find(
'[');
1764 const std::string::size_type ket = line.find(
']');
1765 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1768 <<
" Could not read region names.\n";
1773 line = line.substr(bra + 1, ket - bra - 1);
1774 std::istringstream data;
1776 for (
unsigned int j = 0; j < nRegions; ++j) {
1777 data >> m_regions[j].name;
1780 m_regions[j].drift =
true;
1781 m_regions[j].medium = NULL;
1785 if (gridfile.eof()) {
1788 <<
" Could not find entry 'regions' in file\n"
1789 <<
" " << gridfilename <<
".\n";
1793 }
else if (gridfile.fail()) {
1796 <<
" Error reading file " << gridfilename <<
" (line "
1804 unsigned int nVertices = 0;
1805 while (!gridfile.fail()) {
1807 std::getline(gridfile, line);
1811 if (line.substr(0, 8) !=
"Vertices")
continue;
1813 const std::string::size_type bra = line.find(
'(');
1814 const std::string::size_type ket = line.find(
')');
1815 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1818 <<
" Could not read number of vertices.\n";
1823 line = line.substr(bra + 1, ket - bra - 1);
1824 std::istringstream data;
1827 m_vertices.resize(nVertices);
1829 for (
unsigned int j = 0; j < nVertices; ++j) {
1830 gridfile >> m_vertices[j].x >> m_vertices[j].y;
1832 m_vertices[j].x *= 1.e-4;
1833 m_vertices[j].y *= 1.e-4;
1838 if (gridfile.eof()) {
1840 <<
" Could not find section 'Vertices' in file\n"
1841 <<
" " << gridfilename <<
".\n";
1845 }
else if (gridfile.fail()) {
1847 <<
" Error reading file " << gridfilename <<
" (line " << iLine
1857 std::vector<int> edgeP1;
1858 std::vector<int> edgeP2;
1859 while (!gridfile.fail()) {
1861 std::getline(gridfile, line);
1865 if (line.substr(0, 5) !=
"Edges")
continue;
1867 const std::string::size_type bra = line.find(
'(');
1868 const std::string::size_type ket = line.find(
')');
1869 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1872 <<
" Could not read number of edges.\n";
1877 line = line.substr(bra + 1, ket - bra - 1);
1878 std::istringstream data;
1881 edgeP1.resize(nEdges);
1882 edgeP2.resize(nEdges);
1884 for (
int j = 0; j < nEdges; ++j) {
1885 gridfile >> edgeP1[j] >> edgeP2[j];
1890 if (gridfile.eof()) {
1892 <<
" Could not find section 'Edges' in file\n"
1893 <<
" " << gridfilename <<
".\n";
1897 }
else if (gridfile.fail()) {
1899 <<
" Error reading file " << gridfilename <<
" (line "
1906 for (
int i = 0; i < nEdges; ++i) {
1908 if (edgeP1[i] < 0 || edgeP1[i] >= (
int)nVertices ||
1909 edgeP2[i] < 0 || edgeP2[i] >= (
int)nVertices) {
1911 <<
" Vertex index of edge " << i <<
" out of range.\n";
1917 if (edgeP1[i] == edgeP2[i]) {
1919 <<
" Edge " << i <<
" is degenerate.\n";
1927 int edge0, edge1, edge2, edge3;
1929 unsigned int nElements = 0;
1930 while (!gridfile.fail()) {
1932 std::getline(gridfile, line);
1936 if (line.substr(0, 8) !=
"Elements")
continue;
1938 const std::string::size_type bra = line.find(
'(');
1939 const std::string::size_type ket = line.find(
')');
1940 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1943 <<
" Could not read number of elements.\n";
1948 line = line.substr(bra + 1, ket - bra - 1);
1949 std::istringstream data;
1953 m_elements.resize(nElements);
1955 for (
unsigned int j = 0; j < nElements; ++j) {
1956 for (
int k = nMaxVertices; k--;) m_elements[j].vertex[k] = -1;
1957 m_elements[j].neighbours.clear();
1963 gridfile >> edge0 >> edge1;
1964 if (edge0 < 0) edge0 = -edge0 - 1;
1965 if (edge1 < 0) edge1 = -edge1 - 1;
1967 if (edge0 >= nEdges || edge1 >= nEdges) {
1969 <<
" Error reading file " << gridfilename
1970 <<
" (line " << iLine <<
").\n"
1971 <<
" Edge index out of range.\n";
1981 if (m_vertices[edgeP1[edge0]].x > m_vertices[edgeP2[edge0]].x) {
1982 m_elements[j].vertex[0] = edgeP2[edge0];
1983 m_elements[j].vertex[1] = edgeP1[edge0];
1985 m_elements[j].vertex[0] = edgeP1[edge0];
1986 m_elements[j].vertex[1] = edgeP2[edge0];
1991 gridfile >> edge0 >> edge1 >> edge2;
1993 if (edge0 < 0) edge0 = -edge0 - 1;
1994 if (edge1 < 0) edge1 = -edge1 - 1;
1995 if (edge2 < 0) edge2 = -edge2 - 1;
1996 if (edge0 >= nEdges || edge1 >= nEdges || edge2 >= nEdges) {
1998 <<
" Error reading file " << gridfilename
1999 <<
" (line " << iLine <<
").\n"
2000 <<
" Edge index out of range.\n";
2005 m_elements[j].vertex[0] = edgeP1[edge0];
2006 m_elements[j].vertex[1] = edgeP2[edge0];
2007 if (edgeP1[edge1] != m_elements[j].vertex[0] &&
2008 edgeP1[edge1] != m_elements[j].vertex[1]) {
2009 m_elements[j].vertex[2] = edgeP1[edge1];
2011 m_elements[j].vertex[2] = edgeP2[edge1];
2014 while (m_vertices[m_elements[j].vertex[0]].x >
2015 m_vertices[m_elements[j].vertex[1]].x ||
2016 m_vertices[m_elements[j].vertex[0]].x >
2017 m_vertices[m_elements[j].vertex[2]].x) {
2018 const int tmp = m_elements[j].vertex[0];
2019 m_elements[j].vertex[0] = m_elements[j].vertex[1];
2020 m_elements[j].vertex[1] = m_elements[j].vertex[2];
2021 m_elements[j].vertex[2] = tmp;
2026 gridfile >> edge0 >> edge1 >> edge2 >> edge3;
2028 if (edge0 >= nEdges || -edge0 - 1 >= nEdges ||
2029 edge1 >= nEdges || -edge1 - 1 >= nEdges ||
2030 edge2 >= nEdges || -edge2 - 1 >= nEdges ||
2031 edge3 >= nEdges || -edge3 - 1 >= nEdges) {
2033 <<
" Error reading file " << gridfilename
2034 <<
" (line " << iLine <<
").\n"
2035 <<
" Edge index out of range.\n";
2041 m_elements[j].vertex[0] = edgeP1[edge0];
2043 m_elements[j].vertex[0] = edgeP2[-edge0 - 1];
2045 m_elements[j].vertex[1] = edgeP1[edge1];
2047 m_elements[j].vertex[1] = edgeP2[-edge1 - 1];
2049 m_elements[j].vertex[2] = edgeP1[edge2];
2051 m_elements[j].vertex[2] = edgeP2[-edge2 - 1];
2053 m_elements[j].vertex[3] = edgeP1[edge3];
2055 m_elements[j].vertex[3] = edgeP2[-edge3 - 1];
2058 while (m_vertices[m_elements[j].vertex[0]].x >
2059 m_vertices[m_elements[j].vertex[1]].x ||
2060 m_vertices[m_elements[j].vertex[0]].x >
2061 m_vertices[m_elements[j].vertex[2]].x ||
2062 m_vertices[m_elements[j].vertex[0]].x >
2063 m_vertices[m_elements[j].vertex[3]].x) {
2064 const int tmp = m_elements[j].vertex[0];
2065 m_elements[j].vertex[0] = m_elements[j].vertex[1];
2066 m_elements[j].vertex[1] = m_elements[j].vertex[2];
2067 m_elements[j].vertex[2] = m_elements[j].vertex[3];
2068 m_elements[j].vertex[3] = tmp;
2074 <<
" Error reading file " << gridfilename <<
" (line "
2076 std::cerr <<
" Invalid element type (" << type
2077 <<
") for 2d mesh.\n";
2083 m_elements[j].type = type;
2084 m_elements[j].region = -1;
2088 if (gridfile.eof()) {
2090 std::cerr <<
" Could not find section 'Elements' in file\n";
2091 std::cerr <<
" " << gridfilename <<
".\n";
2095 }
else if (gridfile.fail()) {
2097 std::cerr <<
" Error reading file " << gridfilename <<
" (line " << iLine
2106 while (!gridfile.fail()) {
2108 std::getline(gridfile, line);
2111 if (line.substr(0, 6) !=
"Region")
continue;
2113 std::string::size_type bra = line.find(
'(');
2114 std::string::size_type ket = line.find(
')');
2115 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
2117 <<
" Could not read region name.\n";
2122 line = line.substr(bra + 1, ket - bra - 1);
2123 std::istringstream data;
2127 const int index = FindRegion(name);
2131 std::cerr <<
" Error reading file " << gridfilename <<
".\n";
2132 std::cerr <<
" Unknown region " << name <<
".\n";
2135 std::getline(gridfile, line);
2136 std::getline(gridfile, line);
2137 bra = line.find(
'(');
2138 ket = line.find(
')');
2139 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
2142 std::cerr <<
" Error reading file " << gridfilename <<
".\n";
2143 std::cerr <<
" Could not read number of elements in region " << name
2149 line = line.substr(bra + 1, ket - bra - 1);
2150 int nElementsRegion;
2153 data >> nElementsRegion;
2155 for (
int j = 0; j < nElementsRegion; ++j) {
2156 gridfile >> iElement;
2157 m_elements[iElement].region = index;
2162 if (gridfile.fail() && !gridfile.eof()) {
2164 std::cerr <<
" Error reading file " << gridfilename <<
".\n";
2172void ComponentTcad2d::FindNeighbours() {
2174 const unsigned int nElements = m_elements.size();
2175 std::vector<std::vector<bool> > adjacent(nElements, std::vector<bool>(nElements,
false));
2177 const double tol = 5.e-4;
2178 for (
unsigned int i = 0; i < nElements; ++i) {
2179 const Element& ei = m_elements[i];
2180 for (
unsigned int j = 0; j < nElements; ++j) {
2181 if (i == j || adjacent[i][j])
continue;
2182 const Element& ej = m_elements[j];
2183 if (ei.xmin > ej.xmax + tol || ei.xmax < ej.xmin - tol)
continue;
2184 if (ei.ymin > ej.ymax + tol || ei.ymax < ej.ymin - tol)
continue;
2185 for (
unsigned int m = 0; m < nMaxVertices; ++m) {
2186 if (ei.vertex[m] < 0)
break;
2187 for (
unsigned int n = 0; n < nMaxVertices; ++n) {
2188 if (ei.vertex[n] < 0)
break;
2189 if (ei.vertex[m] == ej.vertex[n]) {
2190 adjacent[i][j] = adjacent[j][i] =
true;
2194 if (adjacent[i][j])
break;
2199 for (
unsigned int i = 0; i < nElements; ++i) {
2200 m_elements[i].neighbours.clear();
2201 for (
unsigned int j = 0; j < nElements; ++j) {
2202 if (adjacent[i][j]) {
2203 m_elements[i].neighbours.push_back(j);
2209void ComponentTcad2d::Cleanup() {
2221bool ComponentTcad2d::CheckElement(
const double x,
const double y,
2222 const Element& element,
2223 double w[nMaxVertices])
const {
2225 switch (element.type) {
2227 return CheckLine(x, y, element, w);
2230 return CheckTriangle(x, y, element, w);
2233 return CheckRectangle(x, y, element, w);
2237 <<
" Unknown element type. Program bug!\n";
2243bool ComponentTcad2d::CheckRectangle(
const double x,
const double y,
2244 const Element& element,
2245 double w[nMaxVertices])
const {
2247 const Vertex& v0 = m_vertices[element.vertex[0]];
2248 const Vertex& v1 = m_vertices[element.vertex[1]];
2249 const Vertex& v3 = m_vertices[element.vertex[3]];
2250 if (y < v0.y || x > v3.x || y > v1.y)
return false;
2253 const double u = (x - 0.5 * (v0.x + v3.x)) / (v3.x - v0.x);
2254 const double v = (y - 0.5 * (v0.y + v1.y)) / (v1.y - v0.y);
2256 w[0] = (0.5 - u) * (0.5 - v);
2257 w[1] = (0.5 - u) * (0.5 + v);
2258 w[2] = (0.5 + u) * (0.5 + v);
2259 w[3] = (0.5 + u) * (0.5 - v);
2263bool ComponentTcad2d::CheckTriangle(
const double x,
const double y,
2264 const Element& element,
2265 double w[nMaxVertices])
const {
2267 const Vertex& v0 = m_vertices[element.vertex[0]];
2268 const Vertex& v1 = m_vertices[element.vertex[1]];
2269 const Vertex& v2 = m_vertices[element.vertex[2]];
2270 if (x > v1.x && x > v2.x)
return false;
2271 if (y < v0.y && y < v1.y && y < v2.y)
return false;
2272 if (y > v0.y && y > v1.y && y > v2.y)
return false;
2278 const double v1x = v1.x - v0.x;
2279 const double v1y = v1.y - v0.y;
2280 const double v2x = v2.x - v0.x;
2281 const double v2y = v2.y - v0.y;
2283 w[1] = ((x - v0.x) * v2y - (y - v0.y) * v2x) / (v1x * v2y - v1y * v2x);
2284 if (w[1] < 0. || w[1] > 1.)
return false;
2285 w[2] = ((v0.x - x) * v1y - (v0.y - y) * v1x) / (v1x * v2y - v1y * v2x);
2286 if (w[2] < 0. || w[1] + w[2] > 1.)
return false;
2289 w[0] = 1. - w[1] - w[2];
2294bool ComponentTcad2d::CheckLine(
const double x,
const double y,
2295 const Element& element,
2296 double w[nMaxVertices])
const {
2298 const Vertex& v0 = m_vertices[element.vertex[0]];
2299 const Vertex& v1 = m_vertices[element.vertex[1]];
2300 if (x > v1.x)
return false;
2301 if (y < v0.y && y < v1.y)
return false;
2302 if (y > v0.y && y > v1.y)
return false;
2303 const double tx = (x - v0.x) / (v1.x - v0.x);
2304 if (tx < 0. || tx > 1.)
return false;
2305 const double ty = (y - v0.y) / (v1.y - v0.y);
2306 if (ty < 0. || ty > 1.)
return false;
2316void ComponentTcad2d::Reset() {
2319 m_hasRangeZ =
false;
2323void ComponentTcad2d::UpdatePeriodicity() {
2326 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
2327 <<
" Field map not available.\n";
2333 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
2334 <<
" Both simple and mirror periodicity\n"
2335 <<
" along x requested; reset.\n";
2340 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
2341 <<
" Both simple and mirror periodicity\n"
2342 <<
" along y requested; reset.\n";
2347 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
2348 <<
" Periodicity along z requested; reset.\n";
2353 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
2354 <<
" Axial symmetry is not supported; reset.\n";
2359 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
2360 <<
" Rotation symmetry is not supported; reset.\n";
2365int ComponentTcad2d::FindRegion(
const std::string& name)
const {
2367 const unsigned int nRegions = m_regions.size();
2368 for (
unsigned int j = 0; j < nRegions; ++j) {
2369 if (name == m_regions[j].name)
return j;
2374void ComponentTcad2d::MapCoordinates(
double& x,
double& y,
2375 bool& xmirr,
bool& ymirr)
const {
2379 const double cellsx = m_xMaxBB - m_xMinBB;
2381 x = m_xMinBB + fmod(x - m_xMinBB, cellsx);
2382 if (x < m_xMinBB) x += cellsx;
2384 double xNew = m_xMinBB + fmod(x - m_xMinBB, cellsx);
2385 if (xNew < m_xMinBB) xNew += cellsx;
2386 const int nx = int(floor(0.5 + (xNew - x) / cellsx));
2387 if (nx != 2 * (nx / 2)) {
2388 xNew = m_xMinBB + m_xMaxBB - xNew;
2394 const double cellsy = m_yMaxBB - m_yMinBB;
2396 y = m_yMinBB + fmod(y - m_yMinBB, cellsy);
2397 if (y < m_yMinBB) y += cellsy;
2399 double yNew = m_yMinBB + fmod(y - m_yMinBB, cellsy);
2400 if (yNew < m_yMinBB) yNew += cellsy;
2401 const int ny = int(floor(0.5 + (yNew - y) / cellsy));
2402 if (ny != 2 * (ny / 2)) {
2403 yNew = m_yMinBB + m_yMaxBB - yNew;
2410bool ComponentTcad2d::CheckTraps()
const {
2412 const unsigned int nDonors = m_donors.size();
2413 for (
unsigned int i = 0; i < nDonors; ++i) {
2414 if (m_donors[i].xsece < 0. || m_donors[i].xsech < 0.)
return false;
2415 if (m_donors[i].conc < 0.)
return false;
2418 const unsigned int nAcceptors = m_acceptors.size();
2419 for (
unsigned int i = 0; i < nAcceptors; ++i) {
2420 if (m_acceptors[i].xsece < 0. || m_acceptors[i].xsech < 0.)
return false;
2421 if (m_acceptors[i].conc < 0.)
return false;
Abstract base class for components.
bool m_zMirrorPeriodic
Mirror periodicity in z.
bool m_yAxiallyPeriodic
Axial periodicity in y.
bool m_zRotationSymmetry
Rotation symmetry around z-axis.
bool m_yRotationSymmetry
Rotation symmetry around y-axis.
bool m_ready
Ready for use?
bool m_zAxiallyPeriodic
Axial periodicity in z.
bool m_xRotationSymmetry
Rotation symmetry around x-axis.
bool m_yPeriodic
Simple periodicity in y.
bool m_yMirrorPeriodic
Mirror periodicity in y.
bool m_xPeriodic
Simple periodicity in x.
bool m_zPeriodic
Simple periodicity in z.
std::string m_className
Class name.
bool m_xAxiallyPeriodic
Axial periodicity in x.
bool m_debug
Switch on/off debugging messages.
bool m_xMirrorPeriodic
Mirror periodicity in x.
bool GetVoltageRange(double &vmin, double &vmax)
Calculate the voltage range [V].
bool GetDonorOccupation(const double x, const double y, const double z, const unsigned int donorNumber, double &occupationFraction)
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)
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Get the bounding box coordinates.
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, double &v, Medium *&m, int &status)
void SetRangeZ(const double zmin, const double zmax)
void PrintRegions() const
bool GetHoleLifetime(const double x, const double y, const double z, double &htau)
void ElectronVelocity(const double x, const double y, const double z, double &vx, double &vy, double &vz, Medium *&m, int &status)
Get the electron drift velocity.
bool ElectronAttachment(const double x, const double y, const double z, double &eta)
Get the electron attachment coefficient.
bool GetElectronLifetime(const double x, const double y, const double z, double &etau)
bool GetAcceptorOccupation(const double x, const double y, const double z, const unsigned int acceptorNumber, double &occupationFraction)
bool GetElement(const unsigned int i, double &vol, double &dmin, double &dmax, int &type) const
void UnsetDriftRegion(const unsigned int ireg)
void SetMedium(const unsigned int ireg, Medium *m)
void HoleVelocity(const double x, const double y, const double z, double &vx, double &vy, double &vz, Medium *&m, int &status)
Get the hole drift velocity.
bool HoleAttachment(const double x, const double y, const double z, double &eta)
Get the hole attachment coefficient.
void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label)
void SetDriftRegion(const unsigned int ireg)
Medium * GetMedium(const double x, const double y, const double z)
Get the medium at a given location (x, y, z).
bool GetMobility(const double x, const double y, const double z, double &emob, double &hmob)
bool SetAcceptor(const unsigned int acceptorNumber, const double eXsec, const double hxSec, const double concentration)
Abstract base class for media.