13void ltrim(std::string& line) {
14 line.erase(line.begin(), find_if(line.begin(), line.end(),
15 not1(std::ptr_fun<int, int>(isspace))));
29 m_regions.reserve(10);
30 m_vertices.reserve(10000);
31 m_elements.reserve(10000);
35 const double zin,
double& ex,
double& ey,
36 double& ez,
double& p,
Medium*& m,
39 ex = ey = ez = p = 0.;
44 <<
" Field map is not available for interpolation.\n";
49 double x = xin, y = yin, z = zin;
51 bool xmirr =
false, ymirr =
false, zmirr =
false;
52 MapCoordinates(x, y, z, xmirr, ymirr, zmirr);
55 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB ||
56 z < m_zMinBB || z > m_zMaxBB) {
63 double w[nMaxVertices] = {0};
64 if (m_lastElement >= 0) {
66 const Element& last = m_elements[m_lastElement];
67 if (x >= last.xmin && x <= last.xmax &&
68 y >= last.ymin && y <= last.ymax &&
69 z >= last.zmin && z <= last.zmax) {
70 if (CheckElement(x, y, z, last, w)) {
71 const unsigned int nVertices = last.type == 2 ? 3 : 4;
72 for (
unsigned int j = 0; j < nVertices; ++j) {
73 const Vertex& vj = m_vertices[last.vertex[j]];
82 m = m_regions[last.region].medium;
83 if (!m_regions[last.region].drift || !m) status = -5;
89 const unsigned int nNeighbours = last.neighbours.size();
90 for (
unsigned int i = 0; i < nNeighbours; ++i) {
91 const Element& element = m_elements[last.neighbours[i]];
92 if (x < element.xmin || x > element.xmax ||
93 y < element.ymin || y > element.ymax ||
94 z < element.zmin || z > element.zmax)
continue;
95 if (!CheckElement(x, y, z, element, w))
continue;
96 const unsigned int nVertices = element.type == 2 ? 3 : 4;
97 for (
unsigned int j = 0; j < nVertices; ++j) {
98 const Vertex& vj = m_vertices[element.vertex[j]];
107 m = m_regions[element.region].medium;
108 if (!m_regions[element.region].drift || !m) status = -5;
109 m_lastElement = last.neighbours[i];
116 const unsigned int nElements = m_elements.size();
117 for (
unsigned int i = 0; i < nElements; ++i) {
118 const Element& element = m_elements[i];
119 if (x < element.xmin || x > element.xmax ||
120 y < element.ymin || y > element.ymax ||
121 z < element.zmin || z > element.zmax)
continue;
122 if (!CheckElement(x, y, z, element, w))
continue;
123 const unsigned int nVertices = element.type == 2 ? 3 : 4;
124 for (
unsigned int j = 0; j < nVertices; ++j) {
125 const Vertex& vj = m_vertices[element.vertex[j]];
134 m = m_regions[element.region].medium;
135 if (!m_regions[element.region].drift || !m) status = -5;
143 <<
" Point (" << x <<
", " << y <<
", " << z
144 <<
") is outside the mesh.\n";
151 const double z,
double& ex,
double& ey,
152 double& ez,
Medium*& m,
int& status) {
164 <<
" Field map not available for interpolation.\n";
168 double x = xin, y = yin, z = zin;
169 bool xmirr =
false, ymirr =
false, zmirr =
false;
170 MapCoordinates(x, y, z, xmirr, ymirr, zmirr);
173 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB ||
174 z < m_zMinBB || z > m_zMaxBB) {
178 double w[nMaxVertices] = {0};
179 if (m_lastElement >= 0) {
181 const Element& last = m_elements[m_lastElement];
182 if (x >= last.xmin && x <= last.xmax &&
183 y >= last.ymin && y <= last.ymax &&
184 z >= last.zmin && z <= last.zmax) {
185 if (CheckElement(x, y, z, last, w)) {
186 return m_regions[last.region].medium;
192 const unsigned int nNeighbours = last.neighbours.size();
193 for (
unsigned int i = 0; i < nNeighbours; ++i) {
194 const Element& element = m_elements[last.neighbours[i]];
195 if (x < element.xmin || x > element.xmax ||
196 y < element.ymin || y > element.ymax ||
197 z < element.zmin || z > element.zmax)
continue;
198 if (!CheckElement(x, y, z, element, w))
continue;
199 m_lastElement = last.neighbours[i];
200 return m_regions[element.region].medium;
206 const unsigned int nElements = m_elements.size();
207 for (
unsigned int i = 0; i < nElements; ++i) {
208 const Element& element = m_elements[i];
209 if (x < element.xmin || x > element.xmax ||
210 y < element.ymin || y > element.ymax ||
211 z < element.zmin || z > element.zmax)
continue;
212 if (!CheckElement(x, y, z, element, w))
continue;
214 return m_regions[element.region].medium;
222 const std::string& datafilename) {
226 if (!LoadGrid(gridfilename)) {
228 <<
" Importing mesh data failed.\n";
233 if (!LoadData(datafilename)) {
235 <<
" Importing electric field and potential failed.\n";
240 m_xMaxBB = m_vertices[m_elements[0].vertex[0]].x;
241 m_yMaxBB = m_vertices[m_elements[0].vertex[0]].y;
242 m_zMaxBB = m_vertices[m_elements[0].vertex[0]].z;
246 m_pMax = m_pMin = m_vertices[m_elements[0].vertex[0]].p;
247 const unsigned int nElements = m_elements.size();
248 for (
unsigned int i = 0; i < nElements; ++i) {
249 Element& element = m_elements[i];
250 double xmin = m_vertices[element.vertex[0]].x;
251 double ymin = m_vertices[element.vertex[0]].y;
252 double zmin = m_vertices[element.vertex[0]].z;
256 const unsigned int nVertices = element.type == 2 ? 3 : 4;
257 for (
unsigned int j = 0; j < nVertices; ++j) {
258 const Vertex& vj = m_vertices[element.vertex[j]];
259 if (vj.x < xmin) xmin = vj.x;
260 if (vj.x > xmax) xmax = vj.x;
261 if (vj.y < ymin) ymin = vj.y;
262 if (vj.y > ymax) ymax = vj.y;
263 if (vj.z < zmin) zmin = vj.z;
264 if (vj.z > zmax) zmax = vj.z;
265 if (vj.p < m_pMin) m_pMin = vj.p;
266 if (vj.p > m_pMax) m_pMax = vj.p;
268 const double tol = 1.e-6;
269 element.xmin = xmin - tol;
270 element.xmax = xmax + tol;
271 element.ymin = ymin - tol;
272 element.ymax = ymax + tol;
273 element.zmin = zmin - tol;
274 element.zmax = zmax + tol;
275 m_xMinBB = std::min(m_xMinBB, xmin);
276 m_xMaxBB = std::max(m_xMaxBB, xmax);
277 m_yMinBB = std::min(m_yMinBB, ymin);
278 m_yMaxBB = std::max(m_yMaxBB, ymax);
279 m_zMinBB = std::min(m_zMinBB, zmin);
280 m_zMaxBB = std::max(m_zMaxBB, zmax);
284 <<
" Bounding box:\n"
285 <<
" " << m_xMinBB <<
" < x [cm] < " << m_xMaxBB <<
"\n"
286 <<
" " << m_yMinBB <<
" < y [cm] < " << m_yMaxBB <<
"\n"
287 <<
" " << m_zMinBB <<
" < z [cm] < " << m_zMaxBB <<
"\n"
288 <<
" Voltage range:\n"
289 <<
" " << m_pMin <<
" < V < " << m_pMax <<
"\n";
294 const int nRegions = m_regions.size();
295 std::vector<unsigned int> nElementsRegion(nRegions, 0);
298 unsigned int nTriangles = 0;
299 unsigned int nTetrahedra = 0;
300 unsigned int nOtherShapes = 0;
303 unsigned int nLoose = 0;
304 std::vector<int> looseElements;
307 unsigned int nDegenerate = 0;
308 std::vector<int> degenerateElements;
310 for (
unsigned int i = 0; i < nElements; ++i) {
311 const Element& element = m_elements[i];
312 if (element.type == 2) {
314 if (element.vertex[0] == element.vertex[1] ||
315 element.vertex[1] == element.vertex[2] ||
316 element.vertex[2] == element.vertex[0]) {
317 degenerateElements.push_back(i);
320 }
else if (element.type == 5) {
321 if (element.vertex[0] == element.vertex[1] ||
322 element.vertex[0] == element.vertex[2] ||
323 element.vertex[0] == element.vertex[3] ||
324 element.vertex[1] == element.vertex[2] ||
325 element.vertex[1] == element.vertex[3] ||
326 element.vertex[2] == element.vertex[3]) {
327 degenerateElements.push_back(i);
335 if (element.region >= 0 && element.region < nRegions) {
336 ++nElementsRegion[element.region];
338 looseElements.push_back(i);
343 if (nDegenerate > 0) {
345 <<
" The following elements are degenerate:\n";
346 for (
unsigned int i = 0; i < nDegenerate; ++i) {
347 std::cerr <<
" " << degenerateElements[i] <<
"\n";
354 <<
" The following elements are not part of any region:\n";
355 for (
unsigned int i = 0; i < nLoose; ++i) {
356 std::cerr <<
" " << looseElements[i] <<
"\n";
362 <<
" Number of regions: " << nRegions <<
"\n";
363 for (
int i = 0; i < nRegions; ++i) {
364 std::cout <<
" " << i <<
": " << m_regions[i].name <<
", "
365 << nElementsRegion[i] <<
" elements\n";
368 std::cout <<
" Number of elements: " << nElements <<
"\n";
369 if (nTriangles > 0) {
370 std::cout <<
" " << nTriangles <<
" triangles\n";
372 if (nTetrahedra > 0) {
373 std::cout <<
" " << nTetrahedra <<
" tetrahedra\n";
375 if (nOtherShapes > 0) {
376 std::cerr <<
" " << nOtherShapes <<
" elements of unknown type\n"
377 <<
" Program bug!\n";
384 for (
unsigned int i = 0; i < nElements; ++i) {
385 const Element& element = m_elements[i];
386 if (element.type == 2) {
387 std::cout <<
" " << i <<
": " << element.vertex[0] <<
" "
388 << element.vertex[1] <<
" " << element.vertex[2]
389 <<
" (triangle, region " << element.region <<
")\n";
390 }
else if (element.type == 5) {
391 std::cout <<
" " << i <<
": " << element.vertex[0] <<
" "
392 << element.vertex[1] <<
" " << element.vertex[2]
393 <<
" " << element.vertex[3] <<
" (tetrahedron, region "
394 << element.region <<
")\n";
399 const unsigned int nVertices = m_vertices.size();
400 std::cout <<
" Number of vertices: " << nVertices <<
"\n";
402 for (
unsigned int i = 0; i < nVertices; ++i) {
403 const Vertex& vi = m_vertices[i];
404 std::cout <<
" " << i <<
": (x, y, z) = (" << vi.x <<
", "
405 << vi.y <<
", " << vi.z <<
"), V = " << vi.p <<
"\n";
411 <<
" Looking for neighbouring elements. Be patient...\n";
423 <<
" Initialisation finished.\n";
427void ComponentTcad3d::FindNeighbours() {
429 const unsigned int nElements = m_elements.size();
430 std::vector<std::vector<bool> > adjacent(nElements, std::vector<bool>(nElements,
false));
432 const double tol = 5.e-4;
433 for (
unsigned int i = 0; i < nElements; ++i) {
434 const Element& ei = m_elements[i];
435 for (
unsigned int j = 0; j < nElements; ++j) {
436 if (i == j || adjacent[i][j])
continue;
437 const Element& ej = m_elements[j];
438 if (ei.xmin > ej.xmax + tol || ei.xmax < ej.xmin - tol)
continue;
439 if (ei.ymin > ej.ymax + tol || ei.ymax < ej.ymin - tol)
continue;
440 if (ei.zmin > ej.zmax + tol || ei.zmax < ej.zmin - tol)
continue;
441 for (
unsigned int m = 0; m < nMaxVertices; ++m) {
442 if (ei.vertex[m] < 0)
break;
443 for (
unsigned int n = 0; n < nMaxVertices; ++n) {
444 if (ei.vertex[n] < 0)
break;
445 if (ei.vertex[m] == ej.vertex[n]) {
446 adjacent[i][j] = adjacent[j][i] =
true;
450 if (adjacent[i][j])
break;
455 for (
unsigned int i = 0; i < nElements; ++i) {
456 m_elements[i].neighbours.clear();
457 for (
unsigned int j = 0; j < nElements; ++j) {
458 if (adjacent[i][j]) {
459 m_elements[i].neighbours.push_back(j);
466 double& xmax,
double& ymax,
double& zmax) {
503 <<
" Field map not yet initialised.\n";
507 if (m_regions.empty()) {
509 <<
" No regions are currently defined.\n";
513 const unsigned int nRegions = m_regions.size();
515 <<
" Currently " << nRegions <<
" regions are defined.\n"
516 <<
" Index Name Medium\n";
517 for (
unsigned int i = 0; i < nRegions; ++i) {
518 std::cout <<
" " << i <<
" " << m_regions[i].name;
519 if (!m_regions[i].medium) {
520 std::cout <<
" none ";
522 std::cout <<
" " << m_regions[i].medium->GetName();
524 if (m_regions[i].drift) {
525 std::cout <<
" (active region)\n";
533 bool& active)
const {
535 if (i >= m_regions.size()) {
537 <<
" Region " << i <<
" does not exist.\n";
540 name = m_regions[i].name;
541 active = m_regions[i].drift;
546 if (i >= m_regions.size()) {
548 <<
" Region " << i <<
" does not exist.\n";
551 m_regions[i].drift =
true;
556 if (i >= m_regions.size()) {
557 std::cerr <<
m_className <<
"::UnsetDriftRegion:\n"
558 <<
" Region " << i <<
" does not exist.\n";
561 m_regions[i].drift =
false;
566 if (i >= m_regions.size()) {
568 <<
" Region " << i <<
" does not exist.\n";
573 std::cerr <<
m_className <<
"::SetMedium:\n Null pointer.\n";
576 m_regions[i].medium = medium;
581 if (i >= m_regions.size()) {
583 <<
" Region " << i <<
" does not exist.\n";
587 m = m_regions[i].medium;
588 if (!m)
return false;
593 double& dmin,
double& dmax,
596 if (i >= m_elements.size()) {
598 <<
" Element index (" << i <<
") out of range.\n";
602 const Element& element = m_elements[i];
603 if (element.type == 2) {
605 const Vertex& v0 = m_vertices[element.vertex[0]];
606 const Vertex& v1 = m_vertices[element.vertex[1]];
607 const Vertex& v2 = m_vertices[element.vertex[2]];
608 const double vx = (v1.y - v0.y) * (v2.z - v0.z) -
609 (v1.z - v0.z) * (v2.y - v0.y);
610 const double vy = (v1.z - v0.z) * (v2.x - v0.x) -
611 (v1.x - v0.x) * (v2.z - v0.z);
612 const double vz = (v1.x - v0.x) * (v2.y - v0.y) -
613 (v1.y - v0.y) * (v2.x - v0.x);
614 vol = sqrt(vx * vx + vy * vy + vz * vz);
615 const double a = sqrt(pow(v1.x - v0.x, 2) + pow(v1.y - v0.y, 2) +
616 pow(v1.z - v0.z, 2));
617 const double b = sqrt(pow(v2.x - v0.x, 2) + pow(v2.y - v0.y, 2) +
618 pow(v2.z - v0.z, 2));
619 const double c = sqrt(pow(v1.x - v2.x, 2) + pow(v1.y - v2.y, 2) +
620 pow(v1.z - v2.z, 2));
622 if (b < dmin) dmin = b;
623 if (c < dmin) dmin = c;
624 if (b > dmax) dmax = b;
625 if (c > dmax) dmax = c;
626 }
else if (element.type == 5) {
628 const Vertex& v0 = m_vertices[element.vertex[0]];
629 const Vertex& v1 = m_vertices[element.vertex[1]];
630 const Vertex& v2 = m_vertices[element.vertex[2]];
631 const Vertex& v3 = m_vertices[element.vertex[3]];
632 vol = fabs((v3.x - v0.x) * ((v1.y - v0.y) * (v2.z - v0.z) - (v2.y - v0.y) * (v1.z - v0.z)) +
633 (v3.y - v0.y) * ((v1.z - v0.z) * (v2.x - v0.x) - (v2.z - v0.z) * (v1.x - v0.x)) +
634 (v3.z - v0.z) * ((v1.x - v0.x) * (v2.y - v0.y) - (v3.x - v0.x) * (v1.y - v0.y))) / 6.;
636 for (
int j = 0; j < nMaxVertices - 1; ++j) {
637 const Vertex& vj = m_vertices[element.vertex[j]];
638 for (
int k = j + 1; k < nMaxVertices; ++k) {
639 const Vertex& vk = m_vertices[element.vertex[k]];
641 const double dist = sqrt(pow(vj.x - vk.x, 2) + pow(vj.y - vk.y, 2) +
642 pow(vj.z - vk.z, 2));
646 if (dist < dmin) dmin = dist;
647 if (dist > dmax) dmax = dist;
653 <<
" Unexpected element type (" << type <<
").\n";
660 double& dmin,
double& dmax,
int& type,
661 int& node1,
int& node2,
int& node3,
int& node4,
662 int& node5,
int& node6,
int& node7,
665 if (!
GetElement(i, vol, dmin, dmax, type))
return false;
666 const Element& element = m_elements[i];
667 node1 = element.vertex[0];
668 node2 = element.vertex[1];
669 node3 = element.vertex[2];
670 node4 = element.vertex[3];
671 node5 = element.vertex[4];
672 node6 = element.vertex[5];
673 node7 = element.vertex[6];
674 reg = element.region;
679 double& x,
double& y,
double& z,
double& v,
680 double& ex,
double& ey,
double& ez)
const {
682 if (i >= m_vertices.size()) {
684 <<
" Node index (" << i <<
") out of range.\n";
688 const Vertex& vi = m_vertices[i];
699bool ComponentTcad3d::LoadData(
const std::string& datafilename) {
701 std::ifstream datafile;
702 datafile.open(datafilename.c_str(), std::ios::in);
705 <<
" Could not open file " << datafilename <<
".\n";
709 const unsigned int nVertices = m_vertices.size();
710 for (
unsigned int i = 0; i < nVertices; ++i) {
711 m_vertices[i].p = 0.;
712 m_vertices[i].ex = 0.;
713 m_vertices[i].ey = 0.;
714 m_vertices[i].ez = 0.;
716 while (!datafile.fail()) {
719 std::getline(datafile, line);
723 if (line.substr(0, 8) !=
"function")
continue;
725 const std::string::size_type pEq = line.find(
'=');
726 if (pEq == std::string::npos) {
729 <<
" Error reading file " << datafilename <<
".\n"
730 <<
" Line:\n " << line <<
"\n";
735 line = line.substr(pEq + 1);
737 std::istringstream data;
741 if (dataset ==
"ElectrostaticPotential") {
742 if (!ReadDataset(datafile, dataset))
return false;
743 }
else if (dataset ==
"ElectricField") {
744 if (!ReadDataset(datafile, dataset))
return false;
747 if (datafile.fail() && !datafile.eof()) {
749 <<
" Error reading file " << datafilename <<
"\n";
758bool ComponentTcad3d::ReadDataset(std::ifstream& datafile,
759 const std::string& dataset) {
761 if (!datafile.is_open())
return false;
763 ElectrostaticPotential,
767 DataSet ds = Unknown;
768 if (dataset ==
"ElectrostaticPotential") {
769 ds = ElectrostaticPotential;
770 }
else if (dataset ==
"ElectricField") {
774 <<
" Unexpected dataset " << dataset <<
".\n";
777 bool isVector =
false;
783 std::getline(datafile, line);
784 std::getline(datafile, line);
785 std::getline(datafile, line);
786 std::getline(datafile, line);
788 std::string::size_type bra = line.find(
'[');
789 std::string::size_type ket = line.find(
']');
790 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
792 <<
" Cannot extract region name.\n"
793 <<
" Line:\n " << line <<
"\n";
798 line = line.substr(bra + 1, ket - bra - 1);
800 std::istringstream data;
805 const int index = FindRegion(name);
808 <<
" Unknown region " << name <<
".\n";
812 std::getline(datafile, line);
813 bra = line.find(
'(');
814 ket = line.find(
')');
815 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
817 <<
" Cannot extract number of values to be read.\n"
818 <<
" Line:\n " << line <<
"\n";
823 line = line.substr(bra + 1, ket - bra - 1);
827 if (isVector) nValues /= 3;
829 const unsigned int nVertices = m_vertices.size();
830 std::vector<bool> isInRegion(nVertices,
false);
831 const unsigned int nElements = m_elements.size();
832 for (
unsigned int j = 0; j < nElements; ++j) {
833 if (m_elements[j].region != index)
continue;
834 for (
int k = 0; k <= m_elements[j].type; ++k) {
835 isInRegion[m_elements[j].vertex[k]] =
true;
839 unsigned int ivertex = 0;
840 for (
int j = 0; j < nValues; ++j) {
842 double val1, val2, val3;
844 datafile >> val1 >> val2 >> val3;
849 while (ivertex < nVertices) {
850 if (isInRegion[ivertex])
break;
855 if (ivertex >= nVertices) {
857 <<
" Dataset " << dataset <<
" has more values than "
858 <<
"there are vertices in region " << name <<
"\n";
864 case ElectrostaticPotential:
865 m_vertices[ivertex].p = val1;
868 m_vertices[ivertex].ex = val1;
869 m_vertices[ivertex].ey = val2;
870 m_vertices[ivertex].ez = val3;
874 <<
" Unexpected dataset (" << ds <<
"). Program bug!\n";
884bool ComponentTcad3d::LoadGrid(
const std::string& gridfilename) {
887 std::ifstream gridfile;
888 gridfile.open(gridfilename.c_str(), std::ios::in);
891 <<
" Could not open file " << gridfilename <<
".\n";
902 unsigned int nRegions = 0;
903 while (!gridfile.fail()) {
906 std::getline(gridfile, line);
911 if (line.substr(0, 10) !=
"nb_regions")
continue;
912 const std::string::size_type pEq = line.find(
'=');
913 if (pEq == std::string::npos) {
916 <<
" Could not read number of regions.\n";
921 line = line.substr(pEq + 1);
922 std::istringstream data;
927 if (gridfile.eof()) {
930 <<
" Could not find entry 'nb_regions' in file\n"
931 <<
" " << gridfilename <<
".\n";
935 }
else if (gridfile.fail()) {
938 <<
" Error reading file " << gridfilename <<
" (line " << iLine
944 m_regions.resize(nRegions);
945 for (
unsigned int j = 0; j < nRegions; ++j) {
946 m_regions[j].name =
"";
947 m_regions[j].drift =
false;
948 m_regions[j].medium = NULL;
953 <<
" Found " << nRegions <<
" regions.\n";
957 while (!gridfile.fail()) {
959 std::getline(gridfile, line);
963 if (line.substr(0, 7) !=
"regions")
continue;
965 const std::string::size_type bra = line.find(
'[');
966 const std::string::size_type ket = line.find(
']');
967 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
970 <<
" Could not read region names.\n";
975 line = line.substr(bra + 1, ket - bra - 1);
976 std::istringstream data;
978 for (
unsigned int j = 0; j < nRegions; ++j) {
979 data >> m_regions[j].name;
982 m_regions[j].drift =
true;
983 m_regions[j].medium = 0;
987 if (gridfile.eof()) {
990 <<
" Could not find entry 'regions' in file\n"
991 <<
" " << gridfilename <<
".\n";
995 }
else if (gridfile.fail()) {
998 <<
" Error reading file " << gridfilename <<
" (line " << iLine
1006 unsigned int nVertices = 0;
1007 while (!gridfile.fail()) {
1009 std::getline(gridfile, line);
1013 if (line.substr(0, 8) !=
"Vertices")
continue;
1015 const std::string::size_type bra = line.find(
'(');
1016 const std::string::size_type ket = line.find(
')');
1017 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1020 std::cerr <<
" Could not read number of vertices.\n";
1025 line = line.substr(bra + 1, ket - bra - 1);
1026 std::istringstream data;
1029 m_vertices.resize(nVertices);
1031 for (
unsigned int j = 0; j < nVertices; ++j) {
1032 gridfile >> m_vertices[j].x >> m_vertices[j].y >> m_vertices[j].z;
1034 m_vertices[j].x *= 1.e-4;
1035 m_vertices[j].y *= 1.e-4;
1036 m_vertices[j].z *= 1.e-4;
1038 iLine += nVertices - 1;
1041 if (gridfile.eof()) {
1043 <<
" Could not find section 'Vertices' in file\n"
1044 <<
" " << gridfilename <<
".\n";
1048 }
else if (gridfile.fail()) {
1050 <<
" Error reading file " << gridfilename <<
" (line " << iLine
1060 std::vector<int> edgeP1;
1061 std::vector<int> edgeP2;
1062 while (!gridfile.fail()) {
1064 std::getline(gridfile, line);
1068 if (line.substr(0, 5) !=
"Edges")
continue;
1070 const std::string::size_type bra = line.find(
'(');
1071 const std::string::size_type ket = line.find(
')');
1072 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1075 <<
" Could not read number of edges.\n";
1080 line = line.substr(bra + 1, ket - bra - 1);
1081 std::istringstream data;
1084 edgeP1.resize(nEdges);
1085 edgeP2.resize(nEdges);
1087 for (
int j = 0; j < nEdges; ++j) {
1088 gridfile >> edgeP1[j] >> edgeP2[j];
1090 iLine += nEdges - 1;
1093 if (gridfile.eof()) {
1095 <<
" Could not find section 'Edges' in file\n"
1096 <<
" " << gridfilename <<
".\n";
1100 }
else if (gridfile.fail()) {
1102 <<
" Error reading file " << gridfilename <<
" (line " << iLine
1109 for (
int i = nEdges; i--;) {
1111 if (edgeP1[i] < 0 || edgeP1[i] >= (
int)nVertices ||
1112 edgeP2[i] < 0 || edgeP2[i] >= (
int)nVertices) {
1114 <<
" Vertex index of edge " << i <<
" out of range.\n";
1120 if (edgeP1[i] == edgeP2[i]) {
1122 <<
" Edge " << i <<
" is degenerate.\n";
1131 std::vector<Face> faces;
1132 while (!gridfile.fail()) {
1134 std::getline(gridfile, line);
1138 if (line.substr(0, 5) !=
"Faces")
continue;
1140 const std::string::size_type bra = line.find(
'(');
1141 const std::string::size_type ket = line.find(
')');
1142 if (ket < bra || bra == std::string::npos ||
1143 ket == std::string::npos) {
1146 std::cerr <<
" Could not read number of faces.\n";
1151 line = line.substr(bra + 1, ket - bra - 1);
1152 std::istringstream data;
1155 faces.resize(nFaces);
1157 for (
int j = 0; j < nFaces; ++j) {
1158 gridfile >> faces[j].type;
1159 if (faces[j].type != 3 && faces[j].type != 4) {
1161 std::cerr <<
" Face with index " << j
1162 <<
" has invalid number of edges, " << faces[j].type <<
".\n";
1167 for (
int k = 0; k < faces[j].type; ++k) {
1168 gridfile >> faces[j].edge[k];
1171 iLine += nFaces - 1;
1174 if (gridfile.eof()) {
1176 <<
" Could not find section 'Faces' in file\n"
1177 <<
" " << gridfilename <<
".\n";
1181 }
else if (gridfile.fail()) {
1183 <<
" Error reading file " << gridfilename <<
" (line " << iLine
1192 while (!gridfile.fail()) {
1194 std::getline(gridfile, line);
1198 if (line.substr(0, 8) !=
"Elements")
continue;
1200 const std::string::size_type bra = line.find(
'(');
1201 const std::string::size_type ket = line.find(
')');
1202 if (ket < bra || bra == std::string::npos ||
1203 ket == std::string::npos) {
1206 std::cerr <<
" Could not read number of elements.\n";
1211 line = line.substr(bra + 1, ket - bra - 1);
1212 std::istringstream data;
1217 m_elements.resize(nElements);
1219 for (
int j = 0; j < nElements; ++j) {
1225 int edge0, edge1, edge2;
1226 gridfile >> edge0 >> edge1 >> edge2;
1233 if (edge0 >= nEdges || -edge0 - 1 >= nEdges || edge1 >= nEdges ||
1234 -edge1 - 1 >= nEdges || edge2 >= nEdges || -edge2 - 1 >= nEdges) {
1236 std::cerr <<
" Error reading file " << gridfilename <<
" (line "
1238 std::cerr <<
" Edge index out of range.\n";
1243 if (edge0 < 0) edge0 = -edge0 - 1;
1244 if (edge1 < 0) edge1 = -edge1 - 1;
1245 m_elements[j].vertex[0] = edgeP1[edge0];
1246 m_elements[j].vertex[1] = edgeP2[edge0];
1247 if (edgeP1[edge1] != m_elements[j].vertex[0] &&
1248 edgeP1[edge1] != m_elements[j].vertex[1]) {
1249 m_elements[j].vertex[2] = edgeP1[edge1];
1251 m_elements[j].vertex[2] = edgeP2[edge1];
1253 }
else if (type == 5) {
1259 int face0, face1, face2, face3;
1260 gridfile >> face0 >> face1 >> face2 >> face3;
1262 if (face0 >= nFaces || -face0 - 1 >= nFaces || face1 >= nFaces ||
1263 -face1 - 1 >= nFaces || face2 >= nFaces || -face2 - 1 >= nFaces ||
1264 face3 >= nFaces || -face3 - 1 >= nFaces) {
1266 std::cerr <<
" Error reading file " << gridfilename <<
" (line "
1268 std::cerr <<
" Face index out of range.\n";
1273 if (face0 < 0) face0 = -face0 - 1;
1274 if (face1 < 0) face1 = -face1 - 1;
1276 int edge0 = faces[face0].edge[0];
1277 int edge1 = faces[face0].edge[1];
1278 int edge2 = faces[face0].edge[2];
1279 if (edge0 < 0) edge0 = -edge0 - 1;
1280 if (edge1 < 0) edge1 = -edge1 - 1;
1281 if (edge2 < 0) edge2 = -edge2 - 1;
1283 if (edge0 >= nEdges || edge1 >= nEdges || edge2 >= nEdges) {
1285 std::cerr <<
" Error reading file " << gridfilename <<
"\n";
1286 std::cerr <<
" Edge index in element " << j
1287 <<
" out of range.\n";
1293 m_elements[j].vertex[0] = edgeP1[edge0];
1294 m_elements[j].vertex[1] = edgeP2[edge0];
1295 if (edgeP1[edge1] != m_elements[j].vertex[0] &&
1296 edgeP1[edge1] != m_elements[j].vertex[1]) {
1297 m_elements[j].vertex[2] = edgeP1[edge1];
1299 m_elements[j].vertex[2] = edgeP2[edge1];
1302 edge0 = faces[face1].edge[0];
1303 edge1 = faces[face1].edge[1];
1304 edge2 = faces[face1].edge[2];
1305 if (edge0 < 0) edge0 = -edge0 - 1;
1306 if (edge1 < 0) edge1 = -edge1 - 1;
1307 if (edge2 < 0) edge2 = -edge2 - 1;
1308 if (edgeP1[edge0] != m_elements[j].vertex[0] &&
1309 edgeP1[edge0] != m_elements[j].vertex[1] &&
1310 edgeP1[edge0] != m_elements[j].vertex[2]) {
1311 m_elements[j].vertex[3] = edgeP1[edge0];
1312 }
else if (edgeP2[edge0] != m_elements[j].vertex[0] &&
1313 edgeP2[edge0] != m_elements[j].vertex[1] &&
1314 edgeP2[edge0] != m_elements[j].vertex[2]) {
1315 m_elements[j].vertex[3] = edgeP2[edge0];
1316 }
else if (edgeP1[edge1] != m_elements[j].vertex[0] &&
1317 edgeP1[edge1] != m_elements[j].vertex[1] &&
1318 edgeP1[edge1] != m_elements[j].vertex[2]) {
1319 m_elements[j].vertex[3] = edgeP1[edge1];
1320 }
else if (edgeP2[edge1] != m_elements[j].vertex[0] &&
1321 edgeP2[edge1] != m_elements[j].vertex[1] &&
1322 edgeP2[edge1] != m_elements[j].vertex[2]) {
1323 m_elements[j].vertex[3] = edgeP2[edge1];
1326 std::cerr <<
" Error reading file " << gridfilename <<
"\n";
1327 std::cerr <<
" Face 1 of element " << j <<
" is degenerate.\n";
1335 <<
" Error reading file " << gridfilename <<
" (line "
1337 if (type == 0 || type == 1) {
1338 std::cerr <<
" Invalid element type (" << type
1339 <<
") for 3d mesh.\n";
1341 std::cerr <<
" Element type " << type <<
" is not supported.\n"
1342 <<
" Remesh with option -t to create only"
1343 <<
" triangles and tetrahedra.\n";
1349 m_elements[j].type = type;
1350 m_elements[j].region = -1;
1354 if (gridfile.eof()) {
1356 std::cerr <<
" Could not find section 'Elements' in file\n";
1357 std::cerr <<
" " << gridfilename <<
".\n";
1361 }
else if (gridfile.fail()) {
1363 std::cerr <<
" Error reading file " << gridfilename <<
" (line " << iLine
1372 while (!gridfile.fail()) {
1374 std::getline(gridfile, line);
1377 if (line.substr(0, 6) !=
"Region")
continue;
1379 std::string::size_type bra = line.find(
'(');
1380 std::string::size_type ket = line.find(
')');
1381 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1383 std::cerr <<
" Could not read region name.\n";
1388 line = line.substr(bra + 1, ket - bra - 1);
1389 std::istringstream data;
1393 const int index = FindRegion(name);
1397 <<
" Error reading file " << gridfilename <<
".\n"
1398 <<
" Unknown region " << name <<
".\n";
1401 std::getline(gridfile, line);
1402 std::getline(gridfile, line);
1403 bra = line.find(
'(');
1404 ket = line.find(
')');
1405 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1408 std::cerr <<
" Error reading file " << gridfilename <<
".\n";
1409 std::cerr <<
" Could not read number of elements in region " << name
1415 line = line.substr(bra + 1, ket - bra - 1);
1416 int nElementsRegion;
1419 data >> nElementsRegion;
1421 for (
int j = 0; j < nElementsRegion; ++j) {
1422 gridfile >> iElement;
1423 m_elements[iElement].region = index;
1428 if (gridfile.fail() && !gridfile.eof()) {
1430 <<
" Error reading file " << gridfilename <<
".\n";
1438void ComponentTcad3d::Cleanup() {
1448bool ComponentTcad3d::CheckTetrahedron(
const double x,
const double y,
1450 const Element& element,
1451 double w[nMaxVertices])
const {
1453 const Vertex& v0 = m_vertices[element.vertex[0]];
1454 const Vertex& v1 = m_vertices[element.vertex[1]];
1455 const Vertex& v2 = m_vertices[element.vertex[2]];
1456 const Vertex& v3 = m_vertices[element.vertex[3]];
1457 const double x10 = v1.x - v0.x;
1458 const double y10 = v1.y - v0.y;
1459 const double z10 = v1.z - v0.z;
1461 const double x20 = v2.x - v0.x;
1462 const double y20 = v2.y - v0.y;
1463 const double z20 = v2.z - v0.z;
1465 const double x30 = v3.x - v0.x;
1466 const double y30 = v3.y - v0.y;
1467 const double z30 = v3.z - v0.z;
1469 const double x21 = v2.x - v1.x;
1470 const double y21 = v2.y - v1.y;
1471 const double z21 = v2.z - v1.z;
1473 const double x31 = v3.x - v1.x;
1474 const double y31 = v3.y - v1.y;
1475 const double z31 = v3.z - v1.z;
1477 const double x32 = v3.x - v2.x;
1478 const double y32 = v3.y - v2.y;
1479 const double z32 = v3.z - v2.z;
1481 w[0] = (x - v1.x) * (y21 * z31 - y31 * z21) +
1482 (y - v1.y) * (z21 * x31 - z31 * x21) +
1483 (z - v1.z) * (x21 * y31 - x31 * y21);
1485 w[0] /= x10 * (y31 * z21 - y21 * z31) + y10 * (z31 * x21 - z21 * x31) +
1486 z10 * (x31 * y21 - x21 * y31);
1487 if (w[0] < 0.)
return false;
1489 w[1] = (x - v2.x) * (-y20 * z32 + y32 * z20) +
1490 (y - v2.y) * (-z20 * x32 + z32 * x20) +
1491 (z - v2.z) * (-x20 * y32 + x32 * y20);
1493 w[1] /= x21 * (y20 * z32 - y32 * z20) + y21 * (z20 * x32 - z32 * x20) +
1494 z21 * (x20 * y32 - x32 * y20);
1495 if (w[1] < 0.)
return false;
1497 w[2] = (x - v3.x) * (y30 * z31 - y31 * z30) +
1498 (y - v3.y) * (z30 * x31 - z31 * x30) +
1499 (z - v3.z) * (x30 * y31 - x31 * y30);
1501 w[2] /= x32 * (y31 * z30 - y30 * z31) + y32 * (z31 * x30 - z30 * x31) +
1502 z32 * (x31 * y30 - x30 * y31);
1503 if (w[2] < 0.)
return false;
1505 w[3] = (x - v0.x) * (y20 * z10 - y10 * z20) +
1506 (y - v0.y) * (z20 * x10 - z10 * x20) +
1507 (z - v0.z) * (x20 * y10 - x10 * y20);
1509 w[3] /= x30 * (y20 * z10 - y10 * z20) + y30 * (z20 * x10 - z10 * x20) +
1510 z30 * (x20 * y10 - x10 * y20);
1511 if (w[3] < 0.)
return false;
1515 const double xr = w[0] * v0.x + w[1] * v1.x + w[2] * v2.x + w[3] * v3.x;
1516 const double yr = w[0] * v0.y + w[1] * v1.y + w[2] * v2.y + w[3] * v3.y;
1517 const double zr = w[0] * v0.z + w[1] * v1.z + w[2] * v2.z + w[3] * v3.z;
1518 std::cout <<
m_className <<
"::CheckTetrahedron:\n"
1519 <<
" Original coordinates: ("
1520 << x <<
", " << y <<
", " << z <<
")\n"
1521 <<
" Local coordinates: ("
1522 << w[0] <<
", " << w[1] <<
", " << w[2] <<
", " << w[3] <<
")\n"
1523 <<
" Reconstructed coordinates: ("
1524 << xr <<
", " << yr <<
", " << zr <<
")\n"
1525 <<
" Checksum: " << w[0] + w[1] + w[2] + w[3] - 1. <<
"\n";
1531bool ComponentTcad3d::CheckTriangle(
const double x,
const double y,
1533 const Element& element,
1534 double w[nMaxVertices])
const {
1536 const Vertex& v0 = m_vertices[element.vertex[0]];
1537 const Vertex& v1 = m_vertices[element.vertex[1]];
1538 const Vertex& v2 = m_vertices[element.vertex[2]];
1540 const double v1x = v1.x - v0.x;
1541 const double v2x = v2.x - v0.x;
1542 const double v1y = v1.y - v0.y;
1543 const double v2y = v2.y - v0.y;
1544 const double v1z = v1.z - v0.z;
1545 const double v2z = v2.z - v0.z;
1549 const double a = v1y * v2z - v2y * v1z;
1550 const double b = v1z * v2x - v2z * v1x;
1551 const double c = v1x * v2y - v2x * v1y;
1552 const double d = a * v0.x + b * v0.y + c * v0.z;
1554 if (a * x + b * y + c * z != d)
return false;
1560 w[1] = ((x - v0.x) * v2y - (y - v0.y) * v2x) / (v1x * v2y - v1y * v2x);
1561 if (w[1] < 0. || w[1] > 1.)
return false;
1562 w[2] = ((v0.x - x) * v1y - (v0.y - y) * v1x) / (v1x * v2y - v1y * v2x);
1563 if (w[2] < 0. || w[1] + w[2] > 1.)
return false;
1566 w[0] = 1. - w[1] - w[2];
1571void ComponentTcad3d::Reset() {
1577void ComponentTcad3d::UpdatePeriodicity() {
1580 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1581 <<
" Field map not available.\n";
1587 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1588 <<
" Both simple and mirror periodicity\n"
1589 <<
" along x requested; reset.\n";
1594 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1595 <<
" Both simple and mirror periodicity\n"
1596 <<
" along y requested; reset.\n";
1601 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1602 <<
" Both simple and mirror periodicity\n"
1603 <<
" along z requested; reset.\n";
1608 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1609 <<
" Axial symmetry is not supported; reset.\n";
1614 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1615 <<
" Rotation symmetry is not supported; reset.\n";
1620void ComponentTcad3d::MapCoordinates(
double& x,
double& y,
double& z,
1621 bool& xmirr,
bool& ymirr,
bool& zmirr)
const {
1624 const double cellsx = m_xMaxBB - m_xMinBB;
1626 x = m_xMinBB + fmod(x - m_xMinBB, cellsx);
1627 if (x < m_xMinBB) x += cellsx;
1629 double xNew = m_xMinBB + fmod(x - m_xMinBB, cellsx);
1630 if (xNew < m_xMinBB) xNew += cellsx;
1631 const int nx = int(floor(0.5 + (xNew - x) / cellsx));
1632 if (nx != 2 * (nx / 2)) {
1633 xNew = m_xMinBB + m_xMaxBB - xNew;
1639 const double cellsy = m_yMaxBB - m_yMinBB;
1641 y = m_yMinBB + fmod(y - m_yMinBB, cellsy);
1642 if (y < m_yMinBB) y += cellsy;
1644 double yNew = m_yMinBB + fmod(y - m_yMinBB, cellsy);
1645 if (yNew < m_yMinBB) yNew += cellsy;
1646 const int ny = int(floor(0.5 + (yNew - y) / cellsy));
1647 if (ny != 2 * (ny / 2)) {
1648 yNew = m_yMinBB + m_yMaxBB - yNew;
1654 const double cellsz = m_zMaxBB - m_zMinBB;
1656 z = m_zMinBB + fmod(z - m_zMinBB, cellsz);
1657 if (z < m_zMinBB) z += cellsz;
1659 double zNew = m_zMinBB + fmod(z - m_zMinBB, cellsz);
1660 if (zNew < m_zMinBB) zNew += cellsz;
1661 const int nz = int(floor(0.5 + (zNew - z) / cellsz));
1662 if (nz != 2 * (nz / 2)) {
1663 zNew = m_zMinBB + m_zMaxBB - zNew;
1670int ComponentTcad3d::FindRegion(
const std::string& name)
const {
1672 const unsigned int nRegions = m_regions.size();
1673 for (
unsigned int j = 0; j < nRegions; ++j) {
1674 if (name == m_regions[j].name)
return j;
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 Initialise(const std::string &gridfilename, const std::string &datafilename)
void UnsetDriftRegion(const unsigned int ireg)
void GetRegion(const unsigned int ireg, std::string &name, bool &active) const
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Get the bounding box coordinates.
bool GetNode(const unsigned int i, double &x, double &y, double &z, double &v, double &ex, double &ey, double &ez) const
Medium * GetMedium(const double x, const double y, const double z)
Get the medium at a given location (x, y, z).
void SetDriftRegion(const unsigned int ireg)
bool GetVoltageRange(double &vmin, double &vmax)
Calculate the voltage range [V].
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, double &v, Medium *&m, int &status)
bool GetElement(const unsigned int i, double &vol, double &dmin, double &dmax, int &type) const
void SetMedium(const unsigned int ireg, Medium *m)
Abstract base class for media.