17 m_regions.reserve(10);
18 m_vertices.reserve(10000);
19 m_elements.reserve(10000);
23 const double zin,
double& ex,
double& ey,
24 double& ez,
double& p,
Medium*& m,
26 ex = ey = ez = p = 0.;
31 <<
" Field map is not available for interpolation.\n";
36 double x = xin, y = yin, z = zin;
38 bool xmirr =
false, ymirr =
false, zmirr =
false;
39 MapCoordinates(x, y, z, xmirr, ymirr, zmirr);
42 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB ||
43 z < m_zMinBB || z > m_zMaxBB) {
50 std::array<double, nMaxVertices> w;
51 const unsigned int i = FindElement(x, y, z, w);
52 if (i >= m_elements.size()) {
57 const Element& element = m_elements[i];
58 const unsigned int nVertices = element.type == 2 ? 3 : 4;
59 for (
unsigned int j = 0; j < nVertices; ++j) {
60 const Vertex& vj = m_vertices[element.vertex[j]];
69 m = m_regions[element.region].medium;
70 if (!m_regions[element.region].drift || !m) status = -5;
75 const double z,
double& ex,
double& ey,
76 double& ez,
Medium*& m,
int& status) {
82 const double zin,
double& wx,
double& wy,
83 double& wz,
const std::string& ) {
86 std::cerr <<
m_className <<
"::WeightingField: Not available.\n";
89 double x = xin, y = yin, z = zin;
91 bool xmirr =
false, ymirr =
false, zmirr =
false;
92 MapCoordinates(x, y, z, xmirr, ymirr, zmirr);
95 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB ||
96 z < m_zMinBB || z > m_zMaxBB)
return;
98 std::array<double, nMaxVertices> w;
99 const unsigned int i = FindElement(x, y, z, w);
100 if (i >= m_elements.size())
return;
102 const Element& element = m_elements[i];
103 const unsigned int nVertices = element.type == 2 ? 3 : 4;
104 for (
unsigned int j = 0; j < nVertices; ++j) {
105 const auto& f = m_wf[element.vertex[j]];
117 const std::string& ) {
120 std::cerr <<
m_className <<
"::WeightingPotential: Not available.\n";
124 double x = xin, y = yin, z = zin;
125 bool xmirr =
false, ymirr =
false, zmirr =
false;
126 MapCoordinates(x, y, z, xmirr, ymirr, zmirr);
129 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB ||
130 z < m_zMinBB || z > m_zMaxBB)
return 0.;
132 std::array<double, nMaxVertices> w;
133 const unsigned int i = FindElement(x, y, z, w);
134 if (i >= m_elements.size())
return 0.;
137 const Element& element = m_elements[i];
138 const unsigned int nVertices = element.type == 2 ? 3 : 4;
139 for (
unsigned int j = 0; j < nVertices; ++j) {
140 v += w[j] * m_wp[element.vertex[j]];
150 <<
" Field map not available for interpolation.\n";
154 double x = xin, y = yin, z = zin;
155 bool xmirr =
false, ymirr =
false, zmirr =
false;
156 MapCoordinates(x, y, z, xmirr, ymirr, zmirr);
159 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB ||
160 z < m_zMinBB || z > m_zMaxBB) {
164 std::array<double, nMaxVertices> w;
165 const unsigned int i = FindElement(x, y, z, w);
166 if (i >= m_elements.size()) {
171 const Element& element = m_elements[i];
172 return m_regions[element.region].medium;
176 const std::string& datafilename) {
179 if (!LoadGrid(gridfilename)) {
181 <<
" Importing mesh data failed.\n";
186 if (!LoadData(datafilename)) {
188 <<
" Importing electric field and potential failed.\n";
193 m_xMaxBB = m_vertices[m_elements[0].vertex[0]].x;
194 m_yMaxBB = m_vertices[m_elements[0].vertex[0]].y;
195 m_zMaxBB = m_vertices[m_elements[0].vertex[0]].z;
199 m_pMax = m_pMin = m_vertices[m_elements[0].vertex[0]].p;
200 const unsigned int nElements = m_elements.size();
201 for (
unsigned int i = 0; i < nElements; ++i) {
202 Element& element = m_elements[i];
203 double xmin = m_vertices[element.vertex[0]].x;
204 double ymin = m_vertices[element.vertex[0]].y;
205 double zmin = m_vertices[element.vertex[0]].z;
209 const unsigned int nVertices = element.type == 2 ? 3 : 4;
210 for (
unsigned int j = 0; j < nVertices; ++j) {
211 const Vertex& vj = m_vertices[element.vertex[j]];
212 if (vj.x < xmin) xmin = vj.x;
213 if (vj.x > xmax) xmax = vj.x;
214 if (vj.y < ymin) ymin = vj.y;
215 if (vj.y > ymax) ymax = vj.y;
216 if (vj.z < zmin) zmin = vj.z;
217 if (vj.z > zmax) zmax = vj.z;
218 if (vj.p < m_pMin) m_pMin = vj.p;
219 if (vj.p > m_pMax) m_pMax = vj.p;
221 constexpr double tol = 1.e-6;
222 element.xmin = xmin - tol;
223 element.xmax = xmax + tol;
224 element.ymin = ymin - tol;
225 element.ymax = ymax + tol;
226 element.zmin = zmin - tol;
227 element.zmax = zmax + tol;
228 m_xMinBB = std::min(m_xMinBB, xmin);
229 m_xMaxBB = std::max(m_xMaxBB, xmax);
230 m_yMinBB = std::min(m_yMinBB, ymin);
231 m_yMaxBB = std::max(m_yMaxBB, ymax);
232 m_zMinBB = std::min(m_zMinBB, zmin);
233 m_zMaxBB = std::max(m_zMaxBB, zmax);
237 <<
" Bounding box:\n"
238 <<
" " << m_xMinBB <<
" < x [cm] < " << m_xMaxBB <<
"\n"
239 <<
" " << m_yMinBB <<
" < y [cm] < " << m_yMaxBB <<
"\n"
240 <<
" " << m_zMinBB <<
" < z [cm] < " << m_zMaxBB <<
"\n"
241 <<
" Voltage range:\n"
242 <<
" " << m_pMin <<
" < V < " << m_pMax <<
"\n";
247 const int nRegions = m_regions.size();
248 std::vector<unsigned int> nElementsRegion(nRegions, 0);
251 unsigned int nTriangles = 0;
252 unsigned int nTetrahedra = 0;
253 unsigned int nOtherShapes = 0;
256 unsigned int nLoose = 0;
257 std::vector<int> looseElements;
260 unsigned int nDegenerate = 0;
261 std::vector<int> degenerateElements;
263 for (
unsigned int i = 0; i < nElements; ++i) {
264 const Element& element = m_elements[i];
265 if (element.type == 2) {
267 if (element.vertex[0] == element.vertex[1] ||
268 element.vertex[1] == element.vertex[2] ||
269 element.vertex[2] == element.vertex[0]) {
270 degenerateElements.push_back(i);
273 }
else if (element.type == 5) {
274 if (element.vertex[0] == element.vertex[1] ||
275 element.vertex[0] == element.vertex[2] ||
276 element.vertex[0] == element.vertex[3] ||
277 element.vertex[1] == element.vertex[2] ||
278 element.vertex[1] == element.vertex[3] ||
279 element.vertex[2] == element.vertex[3]) {
280 degenerateElements.push_back(i);
288 if (element.region >= 0 && element.region < nRegions) {
289 ++nElementsRegion[element.region];
291 looseElements.push_back(i);
296 if (nDegenerate > 0) {
298 <<
" The following elements are degenerate:\n";
299 for (
unsigned int i = 0; i < nDegenerate; ++i) {
300 std::cerr <<
" " << degenerateElements[i] <<
"\n";
307 <<
" The following elements are not part of any region:\n";
308 for (
unsigned int i = 0; i < nLoose; ++i) {
309 std::cerr <<
" " << looseElements[i] <<
"\n";
315 <<
" Number of regions: " << nRegions <<
"\n";
316 for (
int i = 0; i < nRegions; ++i) {
317 std::cout <<
" " << i <<
": " << m_regions[i].name <<
", "
318 << nElementsRegion[i] <<
" elements\n";
321 std::cout <<
" Number of elements: " << nElements <<
"\n";
322 if (nTriangles > 0) {
323 std::cout <<
" " << nTriangles <<
" triangles\n";
325 if (nTetrahedra > 0) {
326 std::cout <<
" " << nTetrahedra <<
" tetrahedra\n";
328 if (nOtherShapes > 0) {
329 std::cerr <<
" " << nOtherShapes <<
" elements of unknown type\n"
330 <<
" Program bug!\n";
337 for (
unsigned int i = 0; i < nElements; ++i) {
338 const Element& element = m_elements[i];
339 if (element.type == 2) {
340 std::cout <<
" " << i <<
": " << element.vertex[0] <<
" "
341 << element.vertex[1] <<
" " << element.vertex[2]
342 <<
" (triangle, region " << element.region <<
")\n";
343 }
else if (element.type == 5) {
344 std::cout <<
" " << i <<
": " << element.vertex[0] <<
" "
345 << element.vertex[1] <<
" " << element.vertex[2] <<
" "
346 << element.vertex[3] <<
" (tetrahedron, region "
347 << element.region <<
")\n";
352 const unsigned int nVertices = m_vertices.size();
353 std::cout <<
" Number of vertices: " << nVertices <<
"\n";
355 for (
unsigned int i = 0; i < nVertices; ++i) {
356 const Vertex& vi = m_vertices[i];
357 std::cout <<
" " << i <<
": (x, y, z) = (" << vi.x <<
", " << vi.y
358 <<
", " << vi.z <<
"), V = " << vi.p <<
"\n";
364 <<
" Looking for neighbouring elements. Be patient...\n";
375 std::cout <<
m_className <<
"::Initialise: Initialisation finished.\n";
380 const std::string& datfile2,
384 std::cerr <<
m_className <<
"::SetWeightingField:\n"
385 <<
" Mesh is not available. Call Initialise first.\n";
389 std::cerr <<
m_className <<
"::SetWeightingField:\n"
390 <<
" Voltage difference must be > 0.\n";
393 const double s = 1. / dv;
398 std::vector<std::array<double, 3> > wf1;
399 std::vector<double> wp1;
400 if (!LoadWeightingField(datfile1, wf1, wp1)) {
401 std::cerr <<
m_className <<
"::SetWeightingField:\n"
402 <<
" Could not import data from " << datfile1 <<
".\n";
407 std::vector<std::array<double, 3> > wf2;
408 std::vector<double> wp2;
409 if (!LoadWeightingField(datfile2, wf2, wp2)) {
410 std::cerr <<
m_className <<
"::SetWeightingField:\n"
411 <<
" Could not import data from " << datfile2 <<
".\n";
414 const unsigned int nVertices = m_vertices.size();
415 bool foundField =
true;
416 if (wf1.size() != nVertices || wf2.size() != nVertices) {
418 std::cerr <<
m_className <<
"::SetWeightingField:\n"
419 <<
" Could not load electric field values.\n";
421 bool foundPotential =
true;
422 if (wp1.size() != nVertices || wp2.size() != nVertices) {
423 foundPotential =
false;
424 std::cerr <<
m_className <<
"::SetWeightingField:\n"
425 <<
" Could not load electrostatic potentials.\n";
427 if (!foundField && !foundPotential)
return false;
429 m_wf.assign(nVertices, {0., 0., 0.});
430 for (
unsigned int i = 0; i < nVertices; ++i) {
431 for (
unsigned int j = 0; j < 3; ++j) {
432 m_wf[i][j] = (wf2[i][j] - wf1[i][j]) * s;
436 if (foundPotential) {
437 m_wp.assign(nVertices, 0.);
438 for (
unsigned int i = 0; i < nVertices; ++i) {
439 m_wp[i] = (wp2[i] - wp1[i]) * s;
445void ComponentTcad3d::FindNeighbours() {
446 const unsigned int nElements = m_elements.size();
447 std::vector<std::vector<bool> > adjacent(nElements,
448 std::vector<bool>(nElements,
false));
450 constexpr double tol = 5.e-4;
451 for (
unsigned int i = 0; i < nElements; ++i) {
452 const Element& ei = m_elements[i];
453 for (
unsigned int j = 0; j < nElements; ++j) {
454 if (i == j || adjacent[i][j])
continue;
455 const Element& ej = m_elements[j];
456 if (ei.xmin > ej.xmax + tol || ei.xmax < ej.xmin - tol)
continue;
457 if (ei.ymin > ej.ymax + tol || ei.ymax < ej.ymin - tol)
continue;
458 if (ei.zmin > ej.zmax + tol || ei.zmax < ej.zmin - tol)
continue;
459 for (
unsigned int m = 0; m < nMaxVertices; ++m) {
460 if (ei.vertex[m] < 0)
break;
461 for (
unsigned int n = 0; n < nMaxVertices; ++n) {
462 if (ei.vertex[n] < 0)
break;
463 if (ei.vertex[m] == ej.vertex[n]) {
464 adjacent[i][j] = adjacent[j][i] =
true;
468 if (adjacent[i][j])
break;
473 for (
unsigned int i = 0; i < nElements; ++i) {
474 m_elements[i].neighbours.clear();
475 for (
unsigned int j = 0; j < nElements; ++j) {
476 if (adjacent[i][j]) {
477 m_elements[i].neighbours.push_back(j);
484 double& xmax,
double& ymax,
double& zmax) {
518 <<
" Field map not yet initialised.\n";
522 if (m_regions.empty()) {
524 <<
" No regions are currently defined.\n";
528 const unsigned int nRegions = m_regions.size();
530 <<
" Currently " << nRegions <<
" regions are defined.\n"
531 <<
" Index Name Medium\n";
532 for (
unsigned int i = 0; i < nRegions; ++i) {
533 std::cout <<
" " << i <<
" " << m_regions[i].name;
534 if (!m_regions[i].medium) {
535 std::cout <<
" none ";
537 std::cout <<
" " << m_regions[i].medium->GetName();
539 if (m_regions[i].drift) {
540 std::cout <<
" (active region)\n";
548 bool& active)
const {
549 if (i >= m_regions.size()) {
550 std::cerr <<
m_className <<
"::GetRegion: Index out of range.\n";
553 name = m_regions[i].name;
554 active = m_regions[i].drift;
558 if (i >= m_regions.size()) {
559 std::cerr <<
m_className <<
"::SetDriftRegion: Index out of range.\n";
562 m_regions[i].drift =
true;
566 if (i >= m_regions.size()) {
567 std::cerr <<
m_className <<
"::UnsetDriftRegion: Index out of range.\n";
570 m_regions[i].drift =
false;
574 if (i >= m_regions.size()) {
575 std::cerr <<
m_className <<
"::SetMedium: Index out of range.\n";
580 std::cerr <<
m_className <<
"::SetMedium: Null pointer.\n";
583 m_regions[i].medium = medium;
587 if (i >= m_regions.size()) {
588 std::cerr <<
m_className <<
"::GetMedium: Index out of range.\n";
592 m = m_regions[i].medium;
593 if (!m)
return false;
597unsigned int ComponentTcad3d::FindElement(
598 const double x,
const double y,
const double z,
599 std::array<double, nMaxVertices>& w)
const {
602 if (m_lastElement >= 0) {
604 const Element& last = m_elements[m_lastElement];
605 if (x >= last.xmin && x <= last.xmax && y >= last.ymin && y <= last.ymax &&
606 z >= last.zmin && z <= last.zmax) {
607 if (CheckElement(x, y, z, last, w))
return m_lastElement;
611 const unsigned int nNeighbours = last.neighbours.size();
612 for (
unsigned int i = 0; i < nNeighbours; ++i) {
613 const Element& element = m_elements[last.neighbours[i]];
614 if (x < element.xmin || x > element.xmax || y < element.ymin ||
615 y > element.ymax || z < element.zmin || z > element.zmax)
617 if (CheckElement(x, y, z, element, w))
continue;
618 return last.neighbours[i];
624 const unsigned int nElements = m_elements.size();
625 for (
unsigned int i = 0; i < nElements; ++i) {
626 const Element& element = m_elements[i];
627 if (x < element.xmin || x > element.xmax || y < element.ymin ||
628 y > element.ymax || z < element.zmin || z > element.zmax)
630 if (CheckElement(x, y, z, element, w))
return i;
635 <<
" Point (" <<
x <<
", " <<
y <<
", " <<
z
636 <<
") is outside the mesh.\n";
642 double& dmin,
double& dmax,
int& type)
const {
643 if (i >= m_elements.size()) {
644 std::cerr <<
m_className <<
"::GetElement: Index out of range.\n";
648 const Element& element = m_elements[i];
649 if (element.type == 2) {
651 const Vertex& v0 = m_vertices[element.vertex[0]];
652 const Vertex& v1 = m_vertices[element.vertex[1]];
653 const Vertex& v2 = m_vertices[element.vertex[2]];
655 (v1.y - v0.y) * (v2.z - v0.z) - (v1.z - v0.z) * (v2.y - v0.y);
657 (v1.z - v0.z) * (v2.x - v0.x) - (v1.x - v0.x) * (v2.z - v0.z);
659 (v1.x - v0.x) * (v2.y - v0.y) - (v1.y - v0.y) * (v2.x - v0.x);
660 vol = sqrt(vx * vx + vy * vy + vz * vz);
662 sqrt(pow(v1.x - v0.x, 2) + pow(v1.y - v0.y, 2) + pow(v1.z - v0.z, 2));
664 sqrt(pow(v2.x - v0.x, 2) + pow(v2.y - v0.y, 2) + pow(v2.z - v0.z, 2));
666 sqrt(pow(v1.x - v2.x, 2) + pow(v1.y - v2.y, 2) + pow(v1.z - v2.z, 2));
668 if (b < dmin) dmin = b;
669 if (c < dmin) dmin = c;
670 if (b > dmax) dmax = b;
671 if (c > dmax) dmax = c;
672 }
else if (element.type == 5) {
674 const Vertex& v0 = m_vertices[element.vertex[0]];
675 const Vertex& v1 = m_vertices[element.vertex[1]];
676 const Vertex& v2 = m_vertices[element.vertex[2]];
677 const Vertex& v3 = m_vertices[element.vertex[3]];
678 vol = fabs((v3.x - v0.x) * ((v1.y - v0.y) * (v2.z - v0.z) -
679 (v2.y - v0.y) * (v1.z - v0.z)) +
680 (v3.y - v0.y) * ((v1.z - v0.z) * (v2.x - v0.x) -
681 (v2.z - v0.z) * (v1.x - v0.x)) +
682 (v3.z - v0.z) * ((v1.x - v0.x) * (v2.y - v0.y) -
683 (v3.x - v0.x) * (v1.y - v0.y))) /
686 for (
int j = 0; j < nMaxVertices - 1; ++j) {
687 const Vertex& vj = m_vertices[element.vertex[j]];
688 for (
int k = j + 1; k < nMaxVertices; ++k) {
689 const Vertex& vk = m_vertices[element.vertex[k]];
691 const double dist = sqrt(pow(vj.x - vk.x, 2) + pow(vj.y - vk.y, 2) +
692 pow(vj.z - vk.z, 2));
696 if (dist < dmin) dmin = dist;
697 if (dist > dmax) dmax = dist;
703 <<
" Unexpected element type (" << type <<
").\n";
710 double& dmin,
double& dmax,
int& type,
711 int& node1,
int& node2,
int& node3,
int& node4,
712 int& node5,
int& node6,
int& node7,
714 if (!
GetElement(i, vol, dmin, dmax, type))
return false;
715 const Element& element = m_elements[i];
716 node1 = element.vertex[0];
717 node2 = element.vertex[1];
718 node3 = element.vertex[2];
719 node4 = element.vertex[3];
720 node5 = element.vertex[4];
721 node6 = element.vertex[5];
722 node7 = element.vertex[6];
723 reg = element.region;
728 double& z,
double& v,
double& ex,
double& ey,
730 if (i >= m_vertices.size()) {
731 std::cerr <<
m_className <<
"::GetNode: Index out of range.\n";
735 const Vertex& vi = m_vertices[i];
746bool ComponentTcad3d::LoadData(
const std::string& datafilename) {
747 std::ifstream datafile;
748 datafile.open(datafilename.c_str(), std::ios::in);
751 <<
" Could not open file " << datafilename <<
".\n";
755 const unsigned int nVertices = m_vertices.size();
756 for (
unsigned int i = 0; i < nVertices; ++i) {
757 m_vertices[i].p = 0.;
758 m_vertices[i].ex = 0.;
759 m_vertices[i].ey = 0.;
760 m_vertices[i].ez = 0.;
762 while (!datafile.fail()) {
765 std::getline(datafile, line);
769 if (line.substr(0, 8) !=
"function")
continue;
771 const std::string::size_type pEq = line.find(
'=');
772 if (pEq == std::string::npos) {
775 <<
" Error reading file " << datafilename <<
".\n"
776 <<
" Line:\n " << line <<
"\n";
781 line = line.substr(pEq + 1);
783 std::istringstream data;
787 if (dataset ==
"ElectrostaticPotential") {
788 if (!ReadDataset(datafile, dataset))
return false;
789 }
else if (dataset ==
"ElectricField") {
790 if (!ReadDataset(datafile, dataset))
return false;
793 if (datafile.fail() && !datafile.eof()) {
795 <<
" Error reading file " << datafilename <<
"\n";
804bool ComponentTcad3d::ReadDataset(std::ifstream& datafile,
805 const std::string& dataset) {
806 if (!datafile.is_open())
return false;
807 enum DataSet { ElectrostaticPotential, EField, Unknown };
808 DataSet ds = Unknown;
809 if (dataset ==
"ElectrostaticPotential") {
810 ds = ElectrostaticPotential;
811 }
else if (dataset ==
"ElectricField") {
815 <<
" Unexpected dataset " << dataset <<
".\n";
818 bool isVector =
false;
824 std::getline(datafile, line);
825 std::getline(datafile, line);
826 std::getline(datafile, line);
827 std::getline(datafile, line);
829 std::string::size_type bra = line.find(
'[');
830 std::string::size_type ket = line.find(
']');
831 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
833 <<
" Cannot extract region name.\n"
834 <<
" Line:\n " << line <<
"\n";
839 line = line.substr(bra + 1, ket - bra - 1);
841 std::istringstream data;
846 const int index = FindRegion(name);
849 <<
" Unknown region " << name <<
".\n";
855 std::getline(datafile, line);
856 bra = line.find(
'(');
857 ket = line.find(
')');
858 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
860 <<
" Cannot extract number of values to be read.\n"
861 <<
" Line:\n " << line <<
"\n";
866 line = line.substr(bra + 1, ket - bra - 1);
870 if (isVector) nValues /= 3;
872 const unsigned int nVertices = m_vertices.size();
873 std::vector<bool> isInRegion(nVertices,
false);
874 const unsigned int nElements = m_elements.size();
875 for (
unsigned int j = 0; j < nElements; ++j) {
876 if (m_elements[j].region != index)
continue;
877 for (
int k = 0; k <= m_elements[j].type; ++k) {
878 isInRegion[m_elements[j].vertex[k]] =
true;
882 unsigned int ivertex = 0;
883 for (
int j = 0; j < nValues; ++j) {
885 double val1, val2, val3;
887 datafile >> val1 >> val2 >> val3;
892 while (ivertex < nVertices) {
893 if (isInRegion[ivertex])
break;
898 if (ivertex >= nVertices) {
900 <<
" Dataset " << dataset <<
" has more values than "
901 <<
"there are vertices in region " << name <<
"\n";
907 case ElectrostaticPotential:
908 m_vertices[ivertex].p = val1;
911 m_vertices[ivertex].ex = val1;
912 m_vertices[ivertex].ey = val2;
913 m_vertices[ivertex].ez = val3;
917 <<
" Unexpected dataset (" << ds <<
"). Program bug!\n";
927bool ComponentTcad3d::LoadWeightingField(
const std::string& datafilename,
928 std::vector<std::array<double, 3> >& wf, std::vector<double>& wp) {
930 std::ifstream datafile;
931 datafile.open(datafilename.c_str(), std::ios::in);
933 std::cerr <<
m_className <<
"::LoadWeightingField:\n"
934 <<
" Could not open file " << datafilename <<
".\n";
938 const unsigned int nVertices = m_vertices.size();
940 while (!datafile.fail()) {
943 std::getline(datafile, line);
947 if (line.substr(0, 8) !=
"function")
continue;
949 const std::string::size_type pEq = line.find(
'=');
950 if (pEq == std::string::npos) {
952 std::cerr <<
m_className <<
"::LoadWeightingField:\n"
953 <<
" Error reading file " << datafilename <<
".\n"
954 <<
" Line:\n " << line <<
"\n";
958 line = line.substr(pEq + 1);
960 std::istringstream data;
964 if (dataset !=
"ElectrostaticPotential" &&
965 dataset !=
"ElectricField")
continue;
967 if (dataset ==
"ElectricField") {
968 wf.assign(nVertices, {0., 0., 0.});
971 wp.assign(nVertices, 0.);
973 std::getline(datafile, line);
974 std::getline(datafile, line);
975 std::getline(datafile, line);
976 std::getline(datafile, line);
978 auto bra = line.find(
'[');
979 auto ket = line.find(
']');
980 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
981 std::cerr <<
m_className <<
"::LoadWeightingField:\n"
982 <<
" Cannot extract region name.\n"
983 <<
" Line:\n " << line <<
"\n";
987 line = line.substr(bra + 1, ket - bra - 1);
993 const int index = FindRegion(name);
995 std::cerr <<
m_className <<
"::LoadWeightingField:\n"
996 <<
" Unknown region " << name <<
".\n";
1001 std::getline(datafile, line);
1002 bra = line.find(
'(');
1003 ket = line.find(
')');
1004 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1005 std::cerr <<
m_className <<
"::LoadWeightingField:\n"
1006 <<
" Cannot extract number of values to be read.\n"
1007 <<
" Line:\n " << line <<
"\n";
1011 line = line.substr(bra + 1, ket - bra - 1);
1015 if (field) nValues /= 3;
1017 std::vector<bool> isInRegion(nVertices,
false);
1018 const unsigned int nElements = m_elements.size();
1019 for (
unsigned int j = 0; j < nElements; ++j) {
1020 if (m_elements[j].region != index)
continue;
1021 for (
int k = 0; k <= m_elements[j].type; ++k) {
1022 isInRegion[m_elements[j].vertex[k]] =
true;
1025 unsigned int ivertex = 0;
1026 for (
int j = 0; j < nValues; ++j) {
1028 double val1, val2, val3;
1030 datafile >> val1 >> val2 >> val3;
1035 while (ivertex < nVertices) {
1036 if (isInRegion[ivertex])
break;
1041 if (ivertex >= nVertices) {
1042 std::cerr <<
m_className <<
"::LoadWeightingField:\n"
1043 <<
" Dataset " << dataset <<
" has more values than "
1044 <<
"there are vertices in region " << name <<
"\n";
1049 wf[ivertex] = {val1, val2, val3};
1057 if (!ok || (datafile.fail() && !datafile.eof())) {
1058 std::cerr <<
m_className <<
"::LoadWeightingField:\n"
1059 <<
" Error reading file " << datafilename <<
"\n";
1067bool ComponentTcad3d::LoadGrid(
const std::string& gridfilename) {
1069 std::ifstream gridfile;
1070 gridfile.open(gridfilename.c_str(), std::ios::in);
1073 <<
" Could not open file " << gridfilename <<
".\n";
1084 unsigned int nRegions = 0;
1085 while (!gridfile.fail()) {
1088 std::getline(gridfile, line);
1093 if (line.substr(0, 10) !=
"nb_regions")
continue;
1094 const std::string::size_type pEq = line.find(
'=');
1095 if (pEq == std::string::npos) {
1098 <<
" Could not read number of regions.\n";
1103 line = line.substr(pEq + 1);
1104 std::istringstream data;
1109 if (gridfile.eof()) {
1112 <<
" Could not find entry 'nb_regions' in file\n"
1113 <<
" " << gridfilename <<
".\n";
1117 }
else if (gridfile.fail()) {
1120 <<
" Error reading file " << gridfilename <<
" (line " << iLine
1126 m_regions.resize(nRegions);
1127 for (
unsigned int j = 0; j < nRegions; ++j) {
1128 m_regions[j].name =
"";
1129 m_regions[j].drift =
false;
1130 m_regions[j].medium =
nullptr;
1135 <<
" Found " << nRegions <<
" regions.\n";
1139 while (!gridfile.fail()) {
1141 std::getline(gridfile, line);
1145 if (line.substr(0, 7) !=
"regions")
continue;
1147 const std::string::size_type bra = line.find(
'[');
1148 const std::string::size_type ket = line.find(
']');
1149 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1152 <<
" Could not read region names.\n";
1157 line = line.substr(bra + 1, ket - bra - 1);
1158 std::istringstream data;
1160 for (
unsigned int j = 0; j < nRegions; ++j) {
1161 data >> m_regions[j].name;
1164 m_regions[j].drift =
true;
1165 m_regions[j].medium = 0;
1169 if (gridfile.eof()) {
1172 <<
" Could not find entry 'regions' in file\n"
1173 <<
" " << gridfilename <<
".\n";
1177 }
else if (gridfile.fail()) {
1180 <<
" Error reading file " << gridfilename <<
" (line " << iLine
1188 unsigned int nVertices = 0;
1189 while (!gridfile.fail()) {
1191 std::getline(gridfile, line);
1195 if (line.substr(0, 8) !=
"Vertices")
continue;
1197 const std::string::size_type bra = line.find(
'(');
1198 const std::string::size_type ket = line.find(
')');
1199 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1202 <<
" Could not read number of vertices.\n";
1207 line = line.substr(bra + 1, ket - bra - 1);
1208 std::istringstream data;
1211 m_vertices.resize(nVertices);
1213 for (
unsigned int j = 0; j < nVertices; ++j) {
1214 gridfile >> m_vertices[j].x >> m_vertices[j].y >> m_vertices[j].z;
1216 m_vertices[j].x *= 1.e-4;
1217 m_vertices[j].y *= 1.e-4;
1218 m_vertices[j].z *= 1.e-4;
1220 iLine += nVertices - 1;
1223 if (gridfile.eof()) {
1225 <<
" Could not find section 'Vertices' in file\n"
1226 <<
" " << gridfilename <<
".\n";
1230 }
else if (gridfile.fail()) {
1232 <<
" Error reading file " << gridfilename <<
" (line " << iLine
1242 std::vector<int> edgeP1;
1243 std::vector<int> edgeP2;
1244 while (!gridfile.fail()) {
1246 std::getline(gridfile, line);
1250 if (line.substr(0, 5) !=
"Edges")
continue;
1252 const std::string::size_type bra = line.find(
'(');
1253 const std::string::size_type ket = line.find(
')');
1254 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1257 <<
" Could not read number of edges.\n";
1262 line = line.substr(bra + 1, ket - bra - 1);
1263 std::istringstream data;
1266 edgeP1.resize(nEdges);
1267 edgeP2.resize(nEdges);
1269 for (
int j = 0; j < nEdges; ++j) {
1270 gridfile >> edgeP1[j] >> edgeP2[j];
1272 iLine += nEdges - 1;
1275 if (gridfile.eof()) {
1277 <<
" Could not find section 'Edges' in file\n"
1278 <<
" " << gridfilename <<
".\n";
1282 }
else if (gridfile.fail()) {
1284 <<
" Error reading file " << gridfilename <<
" (line " << iLine
1291 for (
int i = nEdges; i--;) {
1293 if (edgeP1[i] < 0 || edgeP1[i] >= (
int)nVertices || edgeP2[i] < 0 ||
1294 edgeP2[i] >= (
int)nVertices) {
1296 <<
" Vertex index of edge " << i <<
" out of range.\n";
1302 if (edgeP1[i] == edgeP2[i]) {
1304 <<
" Edge " << i <<
" is degenerate.\n";
1313 std::vector<Face> faces;
1314 while (!gridfile.fail()) {
1316 std::getline(gridfile, line);
1320 if (line.substr(0, 5) !=
"Faces")
continue;
1322 const std::string::size_type bra = line.find(
'(');
1323 const std::string::size_type ket = line.find(
')');
1324 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1327 <<
" Could not read number of faces.\n";
1332 line = line.substr(bra + 1, ket - bra - 1);
1333 std::istringstream data;
1336 faces.resize(nFaces);
1338 for (
int j = 0; j < nFaces; ++j) {
1339 gridfile >> faces[j].type;
1340 if (faces[j].type != 3 && faces[j].type != 4) {
1342 <<
" Face with index " << j
1343 <<
" has invalid number of edges, " << faces[j].type <<
".\n";
1348 for (
int k = 0; k < faces[j].type; ++k) {
1349 gridfile >> faces[j].edge[k];
1352 iLine += nFaces - 1;
1355 if (gridfile.eof()) {
1357 <<
" Could not find section 'Faces' in file\n"
1358 <<
" " << gridfilename <<
".\n";
1362 }
else if (gridfile.fail()) {
1364 <<
" Error reading file " << gridfilename <<
" (line " << iLine
1373 while (!gridfile.fail()) {
1375 std::getline(gridfile, line);
1379 if (line.substr(0, 8) !=
"Elements")
continue;
1381 const std::string::size_type bra = line.find(
'(');
1382 const std::string::size_type ket = line.find(
')');
1383 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1386 <<
" Could not read number of elements.\n";
1391 line = line.substr(bra + 1, ket - bra - 1);
1392 std::istringstream data;
1397 m_elements.resize(nElements);
1399 for (
int j = 0; j < nElements; ++j) {
1405 int edge0, edge1, edge2;
1406 gridfile >> edge0 >> edge1 >> edge2;
1413 if (edge0 >= nEdges || -edge0 - 1 >= nEdges || edge1 >= nEdges ||
1414 -edge1 - 1 >= nEdges || edge2 >= nEdges || -edge2 - 1 >= nEdges) {
1415 std::cerr <<
m_className <<
"::LoadGrid:\n Error reading file "
1416 << gridfilename <<
" (line " << iLine <<
").\n"
1417 <<
" Edge index out of range.\n";
1422 if (edge0 < 0) edge0 = -edge0 - 1;
1423 if (edge1 < 0) edge1 = -edge1 - 1;
1424 m_elements[j].vertex[0] = edgeP1[edge0];
1425 m_elements[j].vertex[1] = edgeP2[edge0];
1426 if (edgeP1[edge1] != m_elements[j].vertex[0] &&
1427 edgeP1[edge1] != m_elements[j].vertex[1]) {
1428 m_elements[j].vertex[2] = edgeP1[edge1];
1430 m_elements[j].vertex[2] = edgeP2[edge1];
1432 }
else if (type == 5) {
1438 int face0, face1, face2, face3;
1439 gridfile >> face0 >> face1 >> face2 >> face3;
1441 if (face0 >= nFaces || -face0 - 1 >= nFaces || face1 >= nFaces ||
1442 -face1 - 1 >= nFaces || face2 >= nFaces || -face2 - 1 >= nFaces ||
1443 face3 >= nFaces || -face3 - 1 >= nFaces) {
1444 std::cerr <<
m_className <<
"::LoadGrid:\n Error reading file "
1445 << gridfilename <<
" (line " << iLine <<
").\n"
1446 <<
" Face index out of range.\n";
1451 if (face0 < 0) face0 = -face0 - 1;
1452 if (face1 < 0) face1 = -face1 - 1;
1454 int edge0 = faces[face0].edge[0];
1455 int edge1 = faces[face0].edge[1];
1456 int edge2 = faces[face0].edge[2];
1457 if (edge0 < 0) edge0 = -edge0 - 1;
1458 if (edge1 < 0) edge1 = -edge1 - 1;
1459 if (edge2 < 0) edge2 = -edge2 - 1;
1461 if (edge0 >= nEdges || edge1 >= nEdges || edge2 >= nEdges) {
1463 <<
" Error reading file " << gridfilename <<
"\n"
1464 <<
" Edge index in element " << j <<
" out of range.\n";
1470 m_elements[j].vertex[0] = edgeP1[edge0];
1471 m_elements[j].vertex[1] = edgeP2[edge0];
1472 if (edgeP1[edge1] != m_elements[j].vertex[0] &&
1473 edgeP1[edge1] != m_elements[j].vertex[1]) {
1474 m_elements[j].vertex[2] = edgeP1[edge1];
1476 m_elements[j].vertex[2] = edgeP2[edge1];
1479 edge0 = faces[face1].edge[0];
1480 edge1 = faces[face1].edge[1];
1481 edge2 = faces[face1].edge[2];
1482 if (edge0 < 0) edge0 = -edge0 - 1;
1483 if (edge1 < 0) edge1 = -edge1 - 1;
1484 if (edge2 < 0) edge2 = -edge2 - 1;
1485 if (edgeP1[edge0] != m_elements[j].vertex[0] &&
1486 edgeP1[edge0] != m_elements[j].vertex[1] &&
1487 edgeP1[edge0] != m_elements[j].vertex[2]) {
1488 m_elements[j].vertex[3] = edgeP1[edge0];
1489 }
else if (edgeP2[edge0] != m_elements[j].vertex[0] &&
1490 edgeP2[edge0] != m_elements[j].vertex[1] &&
1491 edgeP2[edge0] != m_elements[j].vertex[2]) {
1492 m_elements[j].vertex[3] = edgeP2[edge0];
1493 }
else if (edgeP1[edge1] != m_elements[j].vertex[0] &&
1494 edgeP1[edge1] != m_elements[j].vertex[1] &&
1495 edgeP1[edge1] != m_elements[j].vertex[2]) {
1496 m_elements[j].vertex[3] = edgeP1[edge1];
1497 }
else if (edgeP2[edge1] != m_elements[j].vertex[0] &&
1498 edgeP2[edge1] != m_elements[j].vertex[1] &&
1499 edgeP2[edge1] != m_elements[j].vertex[2]) {
1500 m_elements[j].vertex[3] = edgeP2[edge1];
1503 <<
" Error reading file " << gridfilename <<
"\n"
1504 <<
" Face 1 of element " << j <<
" is degenerate.\n";
1512 <<
" Error reading file " << gridfilename <<
" (line "
1514 if (type == 0 || type == 1) {
1515 std::cerr <<
" Invalid element type (" << type
1516 <<
") for 3d mesh.\n";
1518 std::cerr <<
" Element type " << type <<
" is not supported.\n"
1519 <<
" Remesh with option -t to create only"
1520 <<
" triangles and tetrahedra.\n";
1526 m_elements[j].type = type;
1527 m_elements[j].region = -1;
1531 if (gridfile.eof()) {
1533 <<
" Could not find section 'Elements' in file\n"
1534 <<
" " << gridfilename <<
".\n";
1538 }
else if (gridfile.fail()) {
1539 std::cerr <<
m_className <<
"::LoadGrid:\n Error reading file "
1540 << gridfilename <<
" (line " << iLine <<
").\n";
1548 while (!gridfile.fail()) {
1550 std::getline(gridfile, line);
1553 if (line.substr(0, 6) !=
"Region")
continue;
1555 std::string::size_type bra = line.find(
'(');
1556 std::string::size_type ket = line.find(
')');
1557 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1559 <<
" Could not read region name.\n";
1564 line = line.substr(bra + 1, ket - bra - 1);
1565 std::istringstream data;
1569 const int index = FindRegion(name);
1573 <<
" Error reading file " << gridfilename <<
".\n"
1574 <<
" Unknown region " << name <<
".\n";
1577 std::getline(gridfile, line);
1578 std::getline(gridfile, line);
1579 bra = line.find(
'(');
1580 ket = line.find(
')');
1581 if (ket < bra || bra == std::string::npos || ket == std::string::npos) {
1583 std::cerr <<
m_className <<
"::LoadGrid:\n Error reading file "
1584 << gridfilename <<
".\n Could not read number of elements "
1585 <<
"in region " << name <<
".\n";
1590 line = line.substr(bra + 1, ket - bra - 1);
1591 int nElementsRegion;
1594 data >> nElementsRegion;
1596 for (
int j = 0; j < nElementsRegion; ++j) {
1597 gridfile >> iElement;
1598 m_elements[iElement].region = index;
1603 if (gridfile.fail() && !gridfile.eof()) {
1605 <<
" Error reading file " << gridfilename <<
".\n";
1613void ComponentTcad3d::Cleanup() {
1625bool ComponentTcad3d::CheckTetrahedron(
1626 const double x,
const double y,
const double z,
const Element& element,
1627 std::array<double, nMaxVertices>& w)
const {
1628 const Vertex& v0 = m_vertices[element.vertex[0]];
1629 const Vertex& v1 = m_vertices[element.vertex[1]];
1630 const Vertex& v2 = m_vertices[element.vertex[2]];
1631 const Vertex& v3 = m_vertices[element.vertex[3]];
1632 const double x10 = v1.x - v0.x;
1633 const double y10 = v1.y - v0.y;
1634 const double z10 = v1.z - v0.z;
1636 const double x20 = v2.x - v0.x;
1637 const double y20 = v2.y - v0.y;
1638 const double z20 = v2.z - v0.z;
1640 const double x30 = v3.x - v0.x;
1641 const double y30 = v3.y - v0.y;
1642 const double z30 = v3.z - v0.z;
1644 const double x21 = v2.x - v1.x;
1645 const double y21 = v2.y - v1.y;
1646 const double z21 = v2.z - v1.z;
1648 const double x31 = v3.x - v1.x;
1649 const double y31 = v3.y - v1.y;
1650 const double z31 = v3.z - v1.z;
1652 const double x32 = v3.x - v2.x;
1653 const double y32 = v3.y - v2.y;
1654 const double z32 = v3.z - v2.z;
1656 w[0] = (
x - v1.x) * (y21 * z31 - y31 * z21) +
1657 (
y - v1.y) * (z21 * x31 - z31 * x21) +
1658 (
z - v1.z) * (x21 * y31 - x31 * y21);
1660 w[0] /= x10 * (y31 * z21 - y21 * z31) + y10 * (z31 * x21 - z21 * x31) +
1661 z10 * (x31 * y21 - x21 * y31);
1662 if (w[0] < 0.)
return false;
1664 w[1] = (
x - v2.x) * (-y20 * z32 + y32 * z20) +
1665 (
y - v2.y) * (-z20 * x32 + z32 * x20) +
1666 (
z - v2.z) * (-x20 * y32 + x32 * y20);
1668 w[1] /= x21 * (y20 * z32 - y32 * z20) + y21 * (z20 * x32 - z32 * x20) +
1669 z21 * (x20 * y32 - x32 * y20);
1670 if (w[1] < 0.)
return false;
1672 w[2] = (
x - v3.x) * (y30 * z31 - y31 * z30) +
1673 (
y - v3.y) * (z30 * x31 - z31 * x30) +
1674 (
z - v3.z) * (x30 * y31 - x31 * y30);
1676 w[2] /= x32 * (y31 * z30 - y30 * z31) + y32 * (z31 * x30 - z30 * x31) +
1677 z32 * (x31 * y30 - x30 * y31);
1678 if (w[2] < 0.)
return false;
1680 w[3] = (
x - v0.x) * (y20 * z10 - y10 * z20) +
1681 (
y - v0.y) * (z20 * x10 - z10 * x20) +
1682 (
z - v0.z) * (x20 * y10 - x10 * y20);
1684 w[3] /= x30 * (y20 * z10 - y10 * z20) + y30 * (z20 * x10 - z10 * x20) +
1685 z30 * (x20 * y10 - x10 * y20);
1686 if (w[3] < 0.)
return false;
1690 const double xr = w[0] * v0.x + w[1] * v1.x + w[2] * v2.x + w[3] * v3.x;
1691 const double yr = w[0] * v0.y + w[1] * v1.y + w[2] * v2.y + w[3] * v3.y;
1692 const double zr = w[0] * v0.z + w[1] * v1.z + w[2] * v2.z + w[3] * v3.z;
1693 std::cout <<
m_className <<
"::CheckTetrahedron:\n"
1694 <<
" Original coordinates: (" <<
x <<
", " <<
y <<
", "
1696 <<
" Local coordinates: (" << w[0] <<
", " << w[1]
1697 <<
", " << w[2] <<
", " << w[3] <<
")\n"
1698 <<
" Reconstructed coordinates: (" << xr <<
", " << yr <<
", "
1700 <<
" Checksum: " << w[0] + w[1] + w[2] + w[3] - 1. <<
"\n";
1706bool ComponentTcad3d::CheckTriangle(
1707 const double x,
const double y,
const double z,
const Element& element,
1708 std::array<double, nMaxVertices>& w)
const {
1709 const Vertex& v0 = m_vertices[element.vertex[0]];
1710 const Vertex& v1 = m_vertices[element.vertex[1]];
1711 const Vertex& v2 = m_vertices[element.vertex[2]];
1713 const double v1x = v1.x - v0.x;
1714 const double v2x = v2.x - v0.x;
1715 const double v1y = v1.y - v0.y;
1716 const double v2y = v2.y - v0.y;
1717 const double v1z = v1.z - v0.z;
1718 const double v2z = v2.z - v0.z;
1722 const double a = v1y * v2z - v2y * v1z;
1723 const double b = v1z * v2x - v2z * v1x;
1724 const double c = v1x * v2y - v2x * v1y;
1725 const double d = a * v0.x + b * v0.y + c * v0.z;
1727 if (a * x + b * y + c * z != d)
return false;
1733 w[1] = ((
x - v0.x) * v2y - (y - v0.y) * v2x) / (v1x * v2y - v1y * v2x);
1734 if (w[1] < 0. || w[1] > 1.)
return false;
1735 w[2] = ((v0.x -
x) * v1y - (v0.y - y) * v1x) / (v1x * v2y - v1y * v2x);
1736 if (w[2] < 0. || w[1] + w[2] > 1.)
return false;
1739 w[0] = 1. - w[1] - w[2];
1744void ComponentTcad3d::Reset() {
1749void ComponentTcad3d::UpdatePeriodicity() {
1751 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1752 <<
" Field map not available.\n";
1756 for (
unsigned int i = 0; i < 3; ++i) {
1759 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1760 <<
" Both simple and mirror periodicity requested. Reset.\n";
1766 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1767 <<
" Axial symmetry is not supported. Reset.\n";
1773 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1774 <<
" Rotation symmetry is not supported. Reset.\n";
1779void ComponentTcad3d::MapCoordinates(
double& x,
double& y,
double& z,
1780 bool& xmirr,
bool& ymirr,
1781 bool& zmirr)
const {
1783 const double cellsx = m_xMaxBB - m_xMinBB;
1785 x = m_xMinBB + fmod(x - m_xMinBB, cellsx);
1786 if (x < m_xMinBB)
x += cellsx;
1788 double xNew = m_xMinBB + fmod(x - m_xMinBB, cellsx);
1789 if (xNew < m_xMinBB) xNew += cellsx;
1790 const int nx = int(floor(0.5 + (xNew - x) / cellsx));
1791 if (nx != 2 * (nx / 2)) {
1792 xNew = m_xMinBB + m_xMaxBB - xNew;
1798 const double cellsy = m_yMaxBB - m_yMinBB;
1800 y = m_yMinBB + fmod(y - m_yMinBB, cellsy);
1801 if (y < m_yMinBB)
y += cellsy;
1803 double yNew = m_yMinBB + fmod(y - m_yMinBB, cellsy);
1804 if (yNew < m_yMinBB) yNew += cellsy;
1805 const int ny = int(floor(0.5 + (yNew - y) / cellsy));
1806 if (ny != 2 * (ny / 2)) {
1807 yNew = m_yMinBB + m_yMaxBB - yNew;
1813 const double cellsz = m_zMaxBB - m_zMinBB;
1815 z = m_zMinBB + fmod(z - m_zMinBB, cellsz);
1816 if (z < m_zMinBB)
z += cellsz;
1818 double zNew = m_zMinBB + fmod(z - m_zMinBB, cellsz);
1819 if (zNew < m_zMinBB) zNew += cellsz;
1820 const int nz = int(floor(0.5 + (zNew - z) / cellsz));
1821 if (nz != 2 * (nz / 2)) {
1822 zNew = m_zMinBB + m_zMaxBB - zNew;
1829int ComponentTcad3d::FindRegion(
const std::string& name)
const {
1830 const unsigned int nRegions = m_regions.size();
1831 for (
unsigned int j = 0; j < nRegions; ++j) {
1832 if (name == m_regions[j].name)
return j;
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 Initialise(const std::string &gridfilename, const std::string &datafilename)
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, double &v, Medium *&m, int &status) override
Calculate the drift field [V/cm] and potential [V] at (x, y, z).
void UnsetDriftRegion(const unsigned int ireg)
void GetRegion(const unsigned int ireg, std::string &name, bool &active) const
double WeightingPotential(const double x, const double y, const double z, const std::string &label) override
bool GetNode(const unsigned int i, double &x, double &y, double &z, double &v, double &ex, double &ey, double &ez) const
void SetDriftRegion(const unsigned int ireg)
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the bounding box coordinates.
void PrintRegions()
List all currently defined regions.
Medium * GetMedium(const double x, const double y, const double z) override
Get the medium at a given location (x, y, z).
bool GetVoltageRange(double &vmin, double &vmax) override
Calculate the voltage range [V].
void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label) override
bool SetWeightingField(const std::string &datfile1, const std::string &datfile2, const double dv)
bool GetElement(const unsigned int i, double &vol, double &dmin, double &dmax, int &type) const
void SetMedium(const unsigned int ireg, Medium *m)
Set the medium for a given region.
ComponentTcad3d()
Constructor.
Abstract base class for media.
void ltrim(std::string &line)