Garfield++ v2r0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
ComponentTcad3d.cc
Go to the documentation of this file.
1#include <iostream>
2#include <fstream>
3#include <sstream>
4#include <cmath>
5#include <string>
6#include <algorithm>
7
8#include "ComponentTcad3d.hh"
10
11namespace {
12
13void ltrim(std::string& line) {
14 line.erase(line.begin(), find_if(line.begin(), line.end(),
15 not1(std::ptr_fun<int, int>(isspace))));
16}
17
18}
19
20namespace Garfield {
21
23 m_pMin(0.),
24 m_pMax(0.),
25 m_lastElement(0) {
26
27 m_className = "ComponentTcad3d";
28
29 m_regions.reserve(10);
30 m_vertices.reserve(10000);
31 m_elements.reserve(10000);
32}
33
34void ComponentTcad3d::ElectricField(const double xin, const double yin,
35 const double zin, double& ex, double& ey,
36 double& ez, double& p, Medium*& m,
37 int& status) {
38
39 ex = ey = ez = p = 0.;
40 m = NULL;
41 // Make sure the field map has been loaded.
42 if (!m_ready) {
43 std::cerr << m_className << "::ElectricField:\n"
44 << " Field map is not available for interpolation.\n";
45 status = -10;
46 return;
47 }
48
49 double x = xin, y = yin, z = zin;
50 // In case of periodicity, reduce to the cell volume.
51 bool xmirr = false, ymirr = false, zmirr = false;
52 MapCoordinates(x, y, z, xmirr, ymirr, zmirr);
53
54 // Check if the point is inside the bounding box.
55 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB ||
56 z < m_zMinBB || z > m_zMaxBB) {
57 status = -11;
58 return;
59 }
60
61 // Assume this will work.
62 status = 0;
63 double w[nMaxVertices] = {0};
64 if (m_lastElement >= 0) {
65 // Check if the point is still located in the previously found element.
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]];
74 ex += w[j] * vj.ex;
75 ey += w[j] * vj.ey;
76 ez += w[j] * vj.ez;
77 p += w[j] * vj.p;
78 }
79 if (xmirr) ex = -ex;
80 if (ymirr) ey = -ey;
81 if (zmirr) ez = -ez;
82 m = m_regions[last.region].medium;
83 if (!m_regions[last.region].drift || !m) status = -5;
84 return;
85 }
86 }
87 // The point is not in the previous element.
88 // Check the adjacent elements.
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]];
99 ex += w[j] * vj.ex;
100 ey += w[j] * vj.ey;
101 ez += w[j] * vj.ez;
102 p += w[j] * vj.p;
103 }
104 if (xmirr) ex = -ex;
105 if (ymirr) ey = -ey;
106 if (zmirr) ez = -ez;
107 m = m_regions[element.region].medium;
108 if (!m_regions[element.region].drift || !m) status = -5;
109 m_lastElement = last.neighbours[i];
110 return;
111 }
112 }
113
114 // The point is not in the previous element.
115 // We have to loop over all elements.
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]];
126 ex += w[j] * vj.ex;
127 ey += w[j] * vj.ey;
128 ez += w[j] * vj.ez;
129 p += w[j] * vj.p;
130 }
131 if (xmirr) ex = -ex;
132 if (ymirr) ey = -ey;
133 if (zmirr) ez = -ez;
134 m = m_regions[element.region].medium;
135 if (!m_regions[element.region].drift || !m) status = -5;
136 m_lastElement = i;
137 return;
138 }
139
140 // Point is outside the mesh.
141 if (m_debug) {
142 std::cerr << m_className << "::ElectricField:\n"
143 << " Point (" << x << ", " << y << ", " << z
144 << ") is outside the mesh.\n";
145 }
146 status = -6;
147 return;
148}
149
150void ComponentTcad3d::ElectricField(const double x, const double y,
151 const double z, double& ex, double& ey,
152 double& ez, Medium*& m, int& status) {
153
154 double v = 0.;
155 ElectricField(x, y, z, ex, ey, ez, v, m, status);
156}
157
158Medium* ComponentTcad3d::GetMedium(const double xin, const double yin,
159 const double zin) {
160
161 // Make sure the field map has been loaded.
162 if (!m_ready) {
163 std::cerr << m_className << "::GetMedium:\n"
164 << " Field map not available for interpolation.\n";
165 return NULL;
166 }
167
168 double x = xin, y = yin, z = zin;
169 bool xmirr = false, ymirr = false, zmirr = false;
170 MapCoordinates(x, y, z, xmirr, ymirr, zmirr);
171
172 // Check if the point is inside the bounding box.
173 if (x < m_xMinBB || x > m_xMaxBB || y < m_yMinBB || y > m_yMaxBB ||
174 z < m_zMinBB || z > m_zMaxBB) {
175 return NULL;
176 }
177
178 double w[nMaxVertices] = {0};
179 if (m_lastElement >= 0) {
180 // Check if the point is still located in the previously found element.
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;
187 }
188 }
189
190 // The point is not in the previous element.
191 // Check the adjacent elements.
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;
201 }
202 }
203
204 // The point is not in the previous element nor in the adjacent ones.
205 // We have to loop over all elements.
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;
213 m_lastElement = i;
214 return m_regions[element.region].medium;
215 }
216
217 // The point is outside the mesh.
218 return NULL;
219}
220
221bool ComponentTcad3d::Initialise(const std::string& gridfilename,
222 const std::string& datafilename) {
223
224 m_ready = false;
225 // Import mesh data from .grd file.
226 if (!LoadGrid(gridfilename)) {
227 std::cerr << m_className << "::Initialise:\n"
228 << " Importing mesh data failed.\n";
229 return false;
230 }
231
232 // Import electric field and potential from .dat file.
233 if (!LoadData(datafilename)) {
234 std::cerr << m_className << "::Initialise:\n"
235 << " Importing electric field and potential failed.\n";
236 return false;
237 }
238
239 // Find min./max. coordinates and potentials.
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;
243 m_xMinBB = m_xMaxBB;
244 m_yMinBB = m_yMaxBB;
245 m_zMinBB = m_zMaxBB;
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;
253 double xmax = xmin;
254 double ymax = ymin;
255 double zmax = zmin;
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;
267 }
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);
281 }
282
283 std::cout << m_className << "::Initialise:\n"
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";
290
291 bool ok = true;
292
293 // Count the number of elements belonging to a region.
294 const int nRegions = m_regions.size();
295 std::vector<unsigned int> nElementsRegion(nRegions, 0);
296
297 // Count the different element shapes.
298 unsigned int nTriangles = 0;
299 unsigned int nTetrahedra = 0;
300 unsigned int nOtherShapes = 0;
301
302 // Check if there are elements which are not part of any region.
303 unsigned int nLoose = 0;
304 std::vector<int> looseElements;
305
306 // Check if there are degenerate elements.
307 unsigned int nDegenerate = 0;
308 std::vector<int> degenerateElements;
309
310 for (unsigned int i = 0; i < nElements; ++i) {
311 const Element& element = m_elements[i];
312 if (element.type == 2) {
313 ++nTriangles;
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);
318 ++nDegenerate;
319 }
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);
328 ++nDegenerate;
329 }
330 ++nTetrahedra;
331 } else {
332 // Other shapes should not occur, since they were excluded in LoadGrid.
333 ++nOtherShapes;
334 }
335 if (element.region >= 0 && element.region < nRegions) {
336 ++nElementsRegion[element.region];
337 } else {
338 looseElements.push_back(i);
339 ++nLoose;
340 }
341 }
342
343 if (nDegenerate > 0) {
344 std::cerr << m_className << "::Initialise:\n"
345 << " The following elements are degenerate:\n";
346 for (unsigned int i = 0; i < nDegenerate; ++i) {
347 std::cerr << " " << degenerateElements[i] << "\n";
348 }
349 ok = false;
350 }
351
352 if (nLoose > 0) {
353 std::cerr << m_className << "::Initialise:\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";
357 }
358 ok = false;
359 }
360
361 std::cout << m_className << "::Initialise:\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";
366 }
367
368 std::cout << " Number of elements: " << nElements << "\n";
369 if (nTriangles > 0) {
370 std::cout << " " << nTriangles << " triangles\n";
371 }
372 if (nTetrahedra > 0) {
373 std::cout << " " << nTetrahedra << " tetrahedra\n";
374 }
375 if (nOtherShapes > 0) {
376 std::cerr << " " << nOtherShapes << " elements of unknown type\n"
377 << " Program bug!\n";
378 m_ready = false;
379 Cleanup();
380 return false;
381 }
382 if (m_debug) {
383 // For each element, print the indices of the constituting vertices.
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";
395 }
396 }
397 }
398
399 const unsigned int nVertices = m_vertices.size();
400 std::cout << " Number of vertices: " << nVertices << "\n";
401 if (m_debug) {
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";
406 }
407 }
408
409 // Find adjacent elements.
410 std::cout << m_className << "::Initialise:\n"
411 << " Looking for neighbouring elements. Be patient...\n";
412 FindNeighbours();
413
414 if (!ok) {
415 m_ready = false;
416 Cleanup();
417 return false;
418 }
419
420 m_ready = true;
421 UpdatePeriodicity();
422 std::cout << m_className << "::Initialise:\n"
423 << " Initialisation finished.\n";
424 return true;
425}
426
427void ComponentTcad3d::FindNeighbours() {
428
429 const unsigned int nElements = m_elements.size();
430 std::vector<std::vector<bool> > adjacent(nElements, std::vector<bool>(nElements, false));
431
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;
447 break;
448 }
449 }
450 if (adjacent[i][j]) break;
451 }
452 }
453 }
454
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);
460 }
461 }
462 }
463}
464
465bool ComponentTcad3d::GetBoundingBox(double& xmin, double& ymin, double& zmin,
466 double& xmax, double& ymax, double& zmax) {
467
468 if (!m_ready) return false;
469 xmin = m_xMinBB;
470 ymin = m_yMinBB;
471 zmin = m_zMinBB;
472 xmax = m_xMaxBB;
473 ymax = m_yMaxBB;
474 zmax = m_zMaxBB;
476 xmin = -INFINITY;
477 xmax = +INFINITY;
478 }
480 ymin = -INFINITY;
481 ymax = +INFINITY;
482 }
484 zmin = -INFINITY;
485 zmax = +INFINITY;
486 }
487 return true;
488}
489
490bool ComponentTcad3d::GetVoltageRange(double& vmin, double& vmax) {
491
492 if (!m_ready) return false;
493 vmin = m_pMin;
494 vmax = m_pMax;
495 return true;
496}
497
499
500 // Do not proceed if not properly initialised.
501 if (!m_ready) {
502 std::cerr << m_className << "::PrintRegions:\n"
503 << " Field map not yet initialised.\n";
504 return;
505 }
506
507 if (m_regions.empty()) {
508 std::cerr << m_className << "::PrintRegions:\n"
509 << " No regions are currently defined.\n";
510 return;
511 }
512
513 const unsigned int nRegions = m_regions.size();
514 std::cout << m_className << "::PrintRegions:\n"
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 ";
521 } else {
522 std::cout << " " << m_regions[i].medium->GetName();
523 }
524 if (m_regions[i].drift) {
525 std::cout << " (active region)\n";
526 } else {
527 std::cout << "\n";
528 }
529 }
530}
531
532void ComponentTcad3d::GetRegion(const unsigned int i, std::string& name,
533 bool& active) const {
534
535 if (i >= m_regions.size()) {
536 std::cerr << m_className << "::GetRegion:\n"
537 << " Region " << i << " does not exist.\n";
538 return;
539 }
540 name = m_regions[i].name;
541 active = m_regions[i].drift;
542}
543
544void ComponentTcad3d::SetDriftRegion(const unsigned int i) {
545
546 if (i >= m_regions.size()) {
547 std::cerr << m_className << "::SetDriftRegion:\n"
548 << " Region " << i << " does not exist.\n";
549 return;
550 }
551 m_regions[i].drift = true;
552}
553
554void ComponentTcad3d::UnsetDriftRegion(const unsigned int i) {
555
556 if (i >= m_regions.size()) {
557 std::cerr << m_className << "::UnsetDriftRegion:\n"
558 << " Region " << i << " does not exist.\n";
559 return;
560 }
561 m_regions[i].drift = false;
562}
563
564void ComponentTcad3d::SetMedium(const unsigned int i, Medium* medium) {
565
566 if (i >= m_regions.size()) {
567 std::cerr << m_className << "::SetMedium:\n"
568 << " Region " << i << " does not exist.\n";
569 return;
570 }
571
572 if (!medium) {
573 std::cerr << m_className << "::SetMedium:\n Null pointer.\n";
574 return;
575 }
576 m_regions[i].medium = medium;
577}
578
579bool ComponentTcad3d::GetMedium(const unsigned int i, Medium*& m) const {
580
581 if (i >= m_regions.size()) {
582 std::cerr << m_className << "::GetMedium:\n"
583 << " Region " << i << " does not exist.\n";
584 return false;
585 }
586
587 m = m_regions[i].medium;
588 if (!m) return false;
589 return true;
590}
591
592bool ComponentTcad3d::GetElement(const unsigned int i, double& vol,
593 double& dmin, double& dmax,
594 int& type) const {
595
596 if (i >= m_elements.size()) {
597 std::cerr << m_className << "::GetElement:\n"
598 << " Element index (" << i << ") out of range.\n";
599 return false;
600 }
601
602 const Element& element = m_elements[i];
603 if (element.type == 2) {
604 // Triangle
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));
621 dmin = dmax = a;
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) {
627 // Tetrahedron
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.;
635 // Loop over all pairs of m_vertices.
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]];
640 // Compute distance.
641 const double dist = sqrt(pow(vj.x - vk.x, 2) + pow(vj.y - vk.y, 2) +
642 pow(vj.z - vk.z, 2));
643 if (k == 1) {
644 dmin = dmax = dist;
645 } else {
646 if (dist < dmin) dmin = dist;
647 if (dist > dmax) dmax = dist;
648 }
649 }
650 }
651 } else {
652 std::cerr << m_className << "::GetElement:\n"
653 << " Unexpected element type (" << type << ").\n";
654 return false;
655 }
656 return true;
657}
658
659bool ComponentTcad3d::GetElement(const unsigned int i, double& vol,
660 double& dmin, double& dmax, int& type,
661 int& node1, int& node2, int& node3, int& node4,
662 int& node5, int& node6, int& node7,
663 int& reg) const {
664
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;
675 return true;
676}
677
678bool ComponentTcad3d::GetNode(const unsigned int i,
679 double& x, double& y, double& z, double& v,
680 double& ex, double& ey, double& ez) const {
681
682 if (i >= m_vertices.size()) {
683 std::cerr << m_className << "::GetNode:\n"
684 << " Node index (" << i << ") out of range.\n";
685 return false;
686 }
687
688 const Vertex& vi = m_vertices[i];
689 x = vi.x;
690 y = vi.y;
691 z = vi.z;
692 v = vi.p;
693 ex = vi.ex;
694 ey = vi.ey;
695 ez = vi.ez;
696 return true;
697}
698
699bool ComponentTcad3d::LoadData(const std::string& datafilename) {
700
701 std::ifstream datafile;
702 datafile.open(datafilename.c_str(), std::ios::in);
703 if (!datafile) {
704 std::cerr << m_className << "::LoadData:\n"
705 << " Could not open file " << datafilename << ".\n";
706 return false;
707 }
708
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.;
715 }
716 while (!datafile.fail()) {
717 // Read one line.
718 std::string line;
719 std::getline(datafile, line);
720 // Strip white space from beginning of line.
721 ltrim(line);
722 // Find data section.
723 if (line.substr(0, 8) != "function") continue;
724 // Read type of data set.
725 const std::string::size_type pEq = line.find('=');
726 if (pEq == std::string::npos) {
727 // No "=" found.
728 std::cerr << m_className << "::LoadData:\n"
729 << " Error reading file " << datafilename << ".\n"
730 << " Line:\n " << line << "\n";
731 datafile.close();
732 Cleanup();
733 return false;
734 }
735 line = line.substr(pEq + 1);
736 std::string dataset;
737 std::istringstream data;
738 data.str(line);
739 data >> dataset;
740 data.clear();
741 if (dataset == "ElectrostaticPotential") {
742 if (!ReadDataset(datafile, dataset)) return false;
743 } else if (dataset == "ElectricField") {
744 if (!ReadDataset(datafile, dataset)) return false;
745 }
746 }
747 if (datafile.fail() && !datafile.eof()) {
748 std::cerr << m_className << "::LoadData\n"
749 << " Error reading file " << datafilename << "\n";
750 datafile.close();
751 Cleanup();
752 return false;
753 }
754 datafile.close();
755 return true;
756}
757
758bool ComponentTcad3d::ReadDataset(std::ifstream& datafile,
759 const std::string& dataset) {
760
761 if (!datafile.is_open()) return false;
762 enum DataSet {
763 ElectrostaticPotential,
764 EField,
765 Unknown
766 };
767 DataSet ds = Unknown;
768 if (dataset == "ElectrostaticPotential") {
769 ds = ElectrostaticPotential;
770 } else if (dataset == "ElectricField") {
771 ds = EField;
772 } else {
773 std::cerr << m_className << "::ReadDataset:\n"
774 << " Unexpected dataset " << dataset << ".\n";
775 return false;
776 }
777 bool isVector = false;
778 if (ds == EField) {
779 isVector = true;
780 }
781
782 std::string line;
783 std::getline(datafile, line);
784 std::getline(datafile, line);
785 std::getline(datafile, line);
786 std::getline(datafile, line);
787 // Get the region name (given in brackets).
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) {
791 std::cerr << m_className << "::ReadDataset:\n"
792 << " Cannot extract region name.\n"
793 << " Line:\n " << line << "\n";
794 datafile.close();
795 Cleanup();
796 return false;
797 }
798 line = line.substr(bra + 1, ket - bra - 1);
799 std::string name;
800 std::istringstream data;
801 data.str(line);
802 data >> name;
803 data.clear();
804 // Check if the region name matches one from the mesh file.
805 const int index = FindRegion(name);
806 if (index < 0) {
807 std::cerr << m_className << "::ReadDataset:\n"
808 << " Unknown region " << name << ".\n";
809 return false;
810 }
811 // Get the number of values.
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) {
816 std::cerr << m_className << "::ReadDataset:\n"
817 << " Cannot extract number of values to be read.\n"
818 << " Line:\n " << line << "\n";
819 datafile.close();
820 Cleanup();
821 return false;
822 }
823 line = line.substr(bra + 1, ket - bra - 1);
824 int nValues;
825 data.str(line);
826 data >> nValues;
827 if (isVector) nValues /= 3;
828 // Mark the vertices belonging to this region.
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;
836 }
837 }
838
839 unsigned int ivertex = 0;
840 for (int j = 0; j < nValues; ++j) {
841 // Read the next value.
842 double val1, val2, val3;
843 if (isVector) {
844 datafile >> val1 >> val2 >> val3;
845 } else {
846 datafile >> val1;
847 }
848 // Find the next vertex belonging to the region.
849 while (ivertex < nVertices) {
850 if (isInRegion[ivertex]) break;
851 ++ivertex;
852 }
853 // Check if there is a mismatch between the number of m_vertices
854 // and the number of potential values.
855 if (ivertex >= nVertices) {
856 std::cerr << m_className << "::ReadDataset:\n"
857 << " Dataset " << dataset << " has more values than "
858 << "there are vertices in region " << name << "\n";
859 datafile.close();
860 Cleanup();
861 return false;
862 }
863 switch (ds) {
864 case ElectrostaticPotential:
865 m_vertices[ivertex].p = val1;
866 break;
867 case EField:
868 m_vertices[ivertex].ex = val1;
869 m_vertices[ivertex].ey = val2;
870 m_vertices[ivertex].ez = val3;
871 break;
872 default:
873 std::cerr << m_className << "::ReadDataset:\n"
874 << " Unexpected dataset (" << ds << "). Program bug!\n";
875 datafile.close();
876 Cleanup();
877 return false;
878 }
879 ++ivertex;
880 }
881 return true;
882}
883
884bool ComponentTcad3d::LoadGrid(const std::string& gridfilename) {
885
886 // Open the file containing the mesh description.
887 std::ifstream gridfile;
888 gridfile.open(gridfilename.c_str(), std::ios::in);
889 if (!gridfile) {
890 std::cerr << m_className << "::LoadGrid:\n"
891 << " Could not open file " << gridfilename << ".\n";
892 return false;
893 }
894
895 // Delete existing mesh information.
896 Cleanup();
897
898 // Count line numbers.
899 int iLine = 0;
900
901 // Get the number of regions.
902 unsigned int nRegions = 0;
903 while (!gridfile.fail()) {
904 // Read one line.
905 std::string line;
906 std::getline(gridfile, line);
907 ++iLine;
908 // Strip white space from the beginning of the line.
909 ltrim(line);
910 // Find entry 'nb_regions'.
911 if (line.substr(0, 10) != "nb_regions") continue;
912 const std::string::size_type pEq = line.find('=');
913 if (pEq == std::string::npos) {
914 // No "=" sign found.
915 std::cerr << m_className << "::LoadGrid:\n"
916 << " Could not read number of regions.\n";
917 Cleanup();
918 gridfile.close();
919 return false;
920 }
921 line = line.substr(pEq + 1);
922 std::istringstream data;
923 data.str(line);
924 data >> nRegions;
925 break;
926 }
927 if (gridfile.eof()) {
928 // Reached end of file.
929 std::cerr << m_className << "::LoadGrid:\n"
930 << " Could not find entry 'nb_regions' in file\n"
931 << " " << gridfilename << ".\n";
932 Cleanup();
933 gridfile.close();
934 return false;
935 } else if (gridfile.fail()) {
936 // Error reading from the file.
937 std::cerr << m_className << "::LoadGrid:\n"
938 << " Error reading file " << gridfilename << " (line " << iLine
939 << ").\n";
940 Cleanup();
941 gridfile.close();
942 return false;
943 }
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;
949 }
950
951 if (m_debug) {
952 std::cout << m_className << "::LoadGrid:\n"
953 << " Found " << nRegions << " regions.\n";
954 }
955
956 // Get the region names.
957 while (!gridfile.fail()) {
958 std::string line;
959 std::getline(gridfile, line);
960 ++iLine;
961 ltrim(line);
962 // Find entry 'regions'.
963 if (line.substr(0, 7) != "regions") continue;
964 // Get region names (given in brackets).
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) {
968 // No closed brackets [].
969 std::cerr << m_className << "::LoadGrid:\n"
970 << " Could not read region names.\n";
971 Cleanup();
972 gridfile.close();
973 return false;
974 }
975 line = line.substr(bra + 1, ket - bra - 1);
976 std::istringstream data;
977 data.str(line);
978 for (unsigned int j = 0; j < nRegions; ++j) {
979 data >> m_regions[j].name;
980 data.clear();
981 // Assume by default that all regions are active.
982 m_regions[j].drift = true;
983 m_regions[j].medium = 0;
984 }
985 break;
986 }
987 if (gridfile.eof()) {
988 // Reached end of file.
989 std::cerr << m_className << "::LoadGrid:\n"
990 << " Could not find entry 'regions' in file\n"
991 << " " << gridfilename << ".\n";
992 Cleanup();
993 gridfile.close();
994 return false;
995 } else if (gridfile.fail()) {
996 // Error reading from the file.
997 std::cerr << m_className << "::LoadGrid:\n"
998 << " Error reading file " << gridfilename << " (line " << iLine
999 << ").\n";
1000 Cleanup();
1001 gridfile.close();
1002 return false;
1003 }
1004
1005 // Get the vertices.
1006 unsigned int nVertices = 0;
1007 while (!gridfile.fail()) {
1008 std::string line;
1009 std::getline(gridfile, line);
1010 ++iLine;
1011 ltrim(line);
1012 // Find section 'Vertices'.
1013 if (line.substr(0, 8) != "Vertices") continue;
1014 // Get number of vertices (given in brackets).
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) {
1018 // No closed brackets [].
1019 std::cerr << m_className << "::LoadGrid:\n";
1020 std::cerr << " Could not read number of vertices.\n";
1021 Cleanup();
1022 gridfile.close();
1023 return false;
1024 }
1025 line = line.substr(bra + 1, ket - bra - 1);
1026 std::istringstream data;
1027 data.str(line);
1028 data >> nVertices;
1029 m_vertices.resize(nVertices);
1030 // Get the coordinates of this vertex.
1031 for (unsigned int j = 0; j < nVertices; ++j) {
1032 gridfile >> m_vertices[j].x >> m_vertices[j].y >> m_vertices[j].z;
1033 // Change units from micron to cm.
1034 m_vertices[j].x *= 1.e-4;
1035 m_vertices[j].y *= 1.e-4;
1036 m_vertices[j].z *= 1.e-4;
1037 }
1038 iLine += nVertices - 1;
1039 break;
1040 }
1041 if (gridfile.eof()) {
1042 std::cerr << m_className << "::LoadGrid:\n"
1043 << " Could not find section 'Vertices' in file\n"
1044 << " " << gridfilename << ".\n";
1045 Cleanup();
1046 gridfile.close();
1047 return false;
1048 } else if (gridfile.fail()) {
1049 std::cerr << m_className << "::LoadGrid:\n"
1050 << " Error reading file " << gridfilename << " (line " << iLine
1051 << ").\n";
1052 Cleanup();
1053 gridfile.close();
1054 return false;
1055 }
1056
1057 // Get the "edges" (lines connecting two vertices).
1058 int nEdges = 0;
1059 // Temporary arrays for storing edge points.
1060 std::vector<int> edgeP1;
1061 std::vector<int> edgeP2;
1062 while (!gridfile.fail()) {
1063 std::string line;
1064 std::getline(gridfile, line);
1065 ++iLine;
1066 ltrim(line);
1067 // Find section 'Edges'.
1068 if (line.substr(0, 5) != "Edges") continue;
1069 // Get the number of edges (given in brackets).
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) {
1073 // No closed brackets ()
1074 std::cerr << m_className << "::LoadGrid:\n"
1075 << " Could not read number of edges.\n";
1076 Cleanup();
1077 gridfile.close();
1078 return false;
1079 }
1080 line = line.substr(bra + 1, ket - bra - 1);
1081 std::istringstream data;
1082 data.str(line);
1083 data >> nEdges;
1084 edgeP1.resize(nEdges);
1085 edgeP2.resize(nEdges);
1086 // Get the indices of the two endpoints.
1087 for (int j = 0; j < nEdges; ++j) {
1088 gridfile >> edgeP1[j] >> edgeP2[j];
1089 }
1090 iLine += nEdges - 1;
1091 break;
1092 }
1093 if (gridfile.eof()) {
1094 std::cerr << m_className << "::LoadGrid:\n"
1095 << " Could not find section 'Edges' in file\n"
1096 << " " << gridfilename << ".\n";
1097 Cleanup();
1098 gridfile.close();
1099 return false;
1100 } else if (gridfile.fail()) {
1101 std::cerr << m_className << "::LoadGrid:\n"
1102 << " Error reading file " << gridfilename << " (line " << iLine
1103 << ").\n";
1104 Cleanup();
1105 gridfile.close();
1106 return false;
1107 }
1108
1109 for (int i = nEdges; i--;) {
1110 // Make sure the indices of the edge endpoints are not out of range.
1111 if (edgeP1[i] < 0 || edgeP1[i] >= (int)nVertices ||
1112 edgeP2[i] < 0 || edgeP2[i] >= (int)nVertices) {
1113 std::cerr << m_className << "::LoadGrid:\n"
1114 << " Vertex index of edge " << i << " out of range.\n";
1115 Cleanup();
1116 gridfile.close();
1117 return false;
1118 }
1119 // Make sure the edge is non-degenerate.
1120 if (edgeP1[i] == edgeP2[i]) {
1121 std::cerr << m_className << "::LoadGrid:\n"
1122 << " Edge " << i << " is degenerate.\n";
1123 Cleanup();
1124 gridfile.close();
1125 return false;
1126 }
1127 }
1128
1129 // Get the "faces".
1130 int nFaces = 0;
1131 std::vector<Face> faces;
1132 while (!gridfile.fail()) {
1133 std::string line;
1134 std::getline(gridfile, line);
1135 ++iLine;
1136 ltrim(line);
1137 // Find section 'Faces'.
1138 if (line.substr(0, 5) != "Faces") continue;
1139 // Get the number of faces (given in brackets).
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) {
1144 // No closed brackets ()
1145 std::cerr << m_className << "::LoadGrid:\n";
1146 std::cerr << " Could not read number of faces.\n";
1147 Cleanup();
1148 gridfile.close();
1149 return false;
1150 }
1151 line = line.substr(bra + 1, ket - bra - 1);
1152 std::istringstream data;
1153 data.str(line);
1154 data >> nFaces;
1155 faces.resize(nFaces);
1156 // Get the indices of the edges constituting this face.
1157 for (int j = 0; j < nFaces; ++j) {
1158 gridfile >> faces[j].type;
1159 if (faces[j].type != 3 && faces[j].type != 4) {
1160 std::cerr << m_className << "::LoadGrid:\n";
1161 std::cerr << " Face with index " << j
1162 << " has invalid number of edges, " << faces[j].type << ".\n";
1163 Cleanup();
1164 gridfile.close();
1165 return false;
1166 }
1167 for (int k = 0; k < faces[j].type; ++k) {
1168 gridfile >> faces[j].edge[k];
1169 }
1170 }
1171 iLine += nFaces - 1;
1172 break;
1173 }
1174 if (gridfile.eof()) {
1175 std::cerr << m_className << "::LoadGrid:\n"
1176 << " Could not find section 'Faces' in file\n"
1177 << " " << gridfilename << ".\n";
1178 Cleanup();
1179 gridfile.close();
1180 return false;
1181 } else if (gridfile.fail()) {
1182 std::cerr << m_className << "::LoadGrid:\n"
1183 << " Error reading file " << gridfilename << " (line " << iLine
1184 << ").\n";
1185 Cleanup();
1186 gridfile.close();
1187 return false;
1188 }
1189
1190 // Get the elements.
1191 int nElements = 0;
1192 while (!gridfile.fail()) {
1193 std::string line;
1194 std::getline(gridfile, line);
1195 ++iLine;
1196 ltrim(line);
1197 // Find section 'Elements'.
1198 if (line.substr(0, 8) != "Elements") continue;
1199 // Get number of elements (given in brackets).
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) {
1204 // No closed brackets ().
1205 std::cerr << m_className << "::LoadGrid:\n";
1206 std::cerr << " Could not read number of elements.\n";
1207 Cleanup();
1208 gridfile.close();
1209 return false;
1210 }
1211 line = line.substr(bra + 1, ket - bra - 1);
1212 std::istringstream data;
1213 data.str(line);
1214 data >> nElements;
1215 data.clear();
1216 // Resize array of elements.
1217 m_elements.resize(nElements);
1218 // Get type and constituting edges of each element.
1219 for (int j = 0; j < nElements; ++j) {
1220 ++iLine;
1221 int type = 0;
1222 gridfile >> type;
1223 if (type == 2) {
1224 // Triangle
1225 int edge0, edge1, edge2;
1226 gridfile >> edge0 >> edge1 >> edge2;
1227 // Get the vertices.
1228 // Negative edge index means that the sequence of the two points
1229 // is supposed to be inverted.
1230 // The actual index is then given by "-index - 1".
1231 // For our purposes, the orientation does not matter.
1232 // Make sure the indices are not out of range.
1233 if (edge0 >= nEdges || -edge0 - 1 >= nEdges || edge1 >= nEdges ||
1234 -edge1 - 1 >= nEdges || edge2 >= nEdges || -edge2 - 1 >= nEdges) {
1235 std::cerr << m_className << "::LoadGrid:\n";
1236 std::cerr << " Error reading file " << gridfilename << " (line "
1237 << iLine << ").\n";
1238 std::cerr << " Edge index out of range.\n";
1239 Cleanup();
1240 gridfile.close();
1241 return false;
1242 }
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];
1250 } else {
1251 m_elements[j].vertex[2] = edgeP2[edge1];
1252 }
1253 } else if (type == 5) {
1254 // Tetrahedron
1255 // Get the faces.
1256 // Negative face index means that the sequence of the edges
1257 // is supposed to be inverted.
1258 // For our purposes, the orientation does not matter.
1259 int face0, face1, face2, face3;
1260 gridfile >> face0 >> face1 >> face2 >> face3;
1261 // Make sure the face indices are not out of range.
1262 if (face0 >= nFaces || -face0 - 1 >= nFaces || face1 >= nFaces ||
1263 -face1 - 1 >= nFaces || face2 >= nFaces || -face2 - 1 >= nFaces ||
1264 face3 >= nFaces || -face3 - 1 >= nFaces) {
1265 std::cerr << m_className << "::LoadGrid:\n";
1266 std::cerr << " Error reading file " << gridfilename << " (line "
1267 << iLine << ").\n";
1268 std::cerr << " Face index out of range.\n";
1269 Cleanup();
1270 gridfile.close();
1271 return false;
1272 }
1273 if (face0 < 0) face0 = -face0 - 1;
1274 if (face1 < 0) face1 = -face1 - 1;
1275 // Get the edges of the first face.
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;
1282 // Make sure the edge indices are not out of range.
1283 if (edge0 >= nEdges || edge1 >= nEdges || edge2 >= nEdges) {
1284 std::cerr << m_className << "::LoadGrid:\n";
1285 std::cerr << " Error reading file " << gridfilename << "\n";
1286 std::cerr << " Edge index in element " << j
1287 << " out of range.\n";
1288 Cleanup();
1289 gridfile.close();
1290 return false;
1291 }
1292 // Get the first three vertices.
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];
1298 } else {
1299 m_elements[j].vertex[2] = edgeP2[edge1];
1300 }
1301 // Get the fourth vertex from face 1.
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];
1324 } else {
1325 std::cerr << m_className << "::LoadGrid:\n";
1326 std::cerr << " Error reading file " << gridfilename << "\n";
1327 std::cerr << " Face 1 of element " << j << " is degenerate.\n";
1328 Cleanup();
1329 gridfile.close();
1330 return false;
1331 }
1332 } else {
1333 // Other element types are not allowed.
1334 std::cerr << m_className << "::LoadGrid:\n"
1335 << " Error reading file " << gridfilename << " (line "
1336 << iLine << ").\n";
1337 if (type == 0 || type == 1) {
1338 std::cerr << " Invalid element type (" << type
1339 << ") for 3d mesh.\n";
1340 } else {
1341 std::cerr << " Element type " << type << " is not supported.\n"
1342 << " Remesh with option -t to create only"
1343 << " triangles and tetrahedra.\n";
1344 }
1345 Cleanup();
1346 gridfile.close();
1347 return false;
1348 }
1349 m_elements[j].type = type;
1350 m_elements[j].region = -1;
1351 }
1352 break;
1353 }
1354 if (gridfile.eof()) {
1355 std::cerr << m_className << "::LoadGrid:\n";
1356 std::cerr << " Could not find section 'Elements' in file\n";
1357 std::cerr << " " << gridfilename << ".\n";
1358 Cleanup();
1359 gridfile.close();
1360 return false;
1361 } else if (gridfile.fail()) {
1362 std::cerr << m_className << "::LoadGrid:\n";
1363 std::cerr << " Error reading file " << gridfilename << " (line " << iLine
1364 << ").\n";
1365 Cleanup();
1366 gridfile.close();
1367 return false;
1368 }
1369
1370 // Assign regions to elements.
1371 std::string name;
1372 while (!gridfile.fail()) {
1373 std::string line;
1374 std::getline(gridfile, line);
1375 ltrim(line);
1376 // Find section 'Region'.
1377 if (line.substr(0, 6) != "Region") continue;
1378 // Get region name (given in brackets).
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) {
1382 std::cerr << m_className << "::LoadGrid:\n";
1383 std::cerr << " Could not read region name.\n";
1384 Cleanup();
1385 gridfile.close();
1386 return false;
1387 }
1388 line = line.substr(bra + 1, ket - bra - 1);
1389 std::istringstream data;
1390 data.str(line);
1391 data >> name;
1392 data.clear();
1393 const int index = FindRegion(name);
1394 if (index == -1) {
1395 // Specified region name is not in the list.
1396 std::cerr << m_className << "::LoadGrid:\n"
1397 << " Error reading file " << gridfilename << ".\n"
1398 << " Unknown region " << name << ".\n";
1399 continue;
1400 }
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) {
1406 // No closed brackets ().
1407 std::cerr << m_className << "::LoadGrid:\n";
1408 std::cerr << " Error reading file " << gridfilename << ".\n";
1409 std::cerr << " Could not read number of elements in region " << name
1410 << ".\n";
1411 Cleanup();
1412 gridfile.close();
1413 return false;
1414 }
1415 line = line.substr(bra + 1, ket - bra - 1);
1416 int nElementsRegion;
1417 int iElement;
1418 data.str(line);
1419 data >> nElementsRegion;
1420 data.clear();
1421 for (int j = 0; j < nElementsRegion; ++j) {
1422 gridfile >> iElement;
1423 m_elements[iElement].region = index;
1424 }
1425 }
1426
1427 gridfile.close();
1428 if (gridfile.fail() && !gridfile.eof()) {
1429 std::cerr << m_className << "::LoadGrid:\n"
1430 << " Error reading file " << gridfilename << ".\n";
1431 Cleanup();
1432 return false;
1433 }
1434
1435 return true;
1436}
1437
1438void ComponentTcad3d::Cleanup() {
1439
1440 // Vertices
1441 m_vertices.clear();
1442 // Elements
1443 m_elements.clear();
1444 // Regions
1445 m_regions.clear();
1446}
1447
1448bool ComponentTcad3d::CheckTetrahedron(const double x, const double y,
1449 const double z,
1450 const Element& element,
1451 double w[nMaxVertices]) const {
1452
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;
1460
1461 const double x20 = v2.x - v0.x;
1462 const double y20 = v2.y - v0.y;
1463 const double z20 = v2.z - v0.z;
1464
1465 const double x30 = v3.x - v0.x;
1466 const double y30 = v3.y - v0.y;
1467 const double z30 = v3.z - v0.z;
1468
1469 const double x21 = v2.x - v1.x;
1470 const double y21 = v2.y - v1.y;
1471 const double z21 = v2.z - v1.z;
1472
1473 const double x31 = v3.x - v1.x;
1474 const double y31 = v3.y - v1.y;
1475 const double z31 = v3.z - v1.z;
1476
1477 const double x32 = v3.x - v2.x;
1478 const double y32 = v3.y - v2.y;
1479 const double z32 = v3.z - v2.z;
1480
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);
1484
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;
1488
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);
1492
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;
1496
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);
1500
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;
1504
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);
1508
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;
1512
1513 if (m_debug) {
1514 // Reconstruct the point from the local coordinates.
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";
1526 }
1527
1528 return true;
1529}
1530
1531bool ComponentTcad3d::CheckTriangle(const double x, const double y,
1532 const double z,
1533 const Element& element,
1534 double w[nMaxVertices]) const {
1535
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]];
1539
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;
1546
1547 // Check whether the point lies in the plane of the triangle.
1548 // Compute the coefficients of the plane equation.
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;
1553 // Check if the point satisfies the plane equation.
1554 if (a * x + b * y + c * z != d) return false;
1555
1556 // Map (x, y) onto local variables (b, c) such that
1557 // P = A + b * (B - A) + c * (C - A)
1558 // A point P is inside the triangle ABC if b, c > 0 and b + c < 1;
1559 // b, c are also weighting factors for points B, C
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;
1564
1565 // Weighting factor for point A
1566 w[0] = 1. - w[1] - w[2];
1567
1568 return true;
1569}
1570
1571void ComponentTcad3d::Reset() {
1572
1573 Cleanup();
1574 m_ready = false;
1575}
1576
1577void ComponentTcad3d::UpdatePeriodicity() {
1578
1579 if (!m_ready) {
1580 std::cerr << m_className << "::UpdatePeriodicity:\n"
1581 << " Field map not available.\n";
1582 return;
1583 }
1584
1585 // Check for conflicts.
1587 std::cerr << m_className << "::UpdatePeriodicity:\n"
1588 << " Both simple and mirror periodicity\n"
1589 << " along x requested; reset.\n";
1591 }
1592
1594 std::cerr << m_className << "::UpdatePeriodicity:\n"
1595 << " Both simple and mirror periodicity\n"
1596 << " along y requested; reset.\n";
1598 }
1599
1601 std::cerr << m_className << "::UpdatePeriodicity:\n"
1602 << " Both simple and mirror periodicity\n"
1603 << " along z requested; reset.\n";
1605 }
1606
1608 std::cerr << m_className << "::UpdatePeriodicity:\n"
1609 << " Axial symmetry is not supported; reset.\n";
1611 }
1612
1614 std::cerr << m_className << "::UpdatePeriodicity:\n"
1615 << " Rotation symmetry is not supported; reset.\n";
1617 }
1618}
1619
1620void ComponentTcad3d::MapCoordinates(double& x, double& y, double& z,
1621 bool& xmirr, bool& ymirr, bool& zmirr) const {
1622
1623 xmirr = false;
1624 const double cellsx = m_xMaxBB - m_xMinBB;
1625 if (m_xPeriodic) {
1626 x = m_xMinBB + fmod(x - m_xMinBB, cellsx);
1627 if (x < m_xMinBB) x += cellsx;
1628 } else if (m_xMirrorPeriodic) {
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;
1634 xmirr = true;
1635 }
1636 x = xNew;
1637 }
1638 ymirr = false;
1639 const double cellsy = m_yMaxBB - m_yMinBB;
1640 if (m_yPeriodic) {
1641 y = m_yMinBB + fmod(y - m_yMinBB, cellsy);
1642 if (y < m_yMinBB) y += cellsy;
1643 } else if (m_yMirrorPeriodic) {
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;
1649 ymirr = true;
1650 }
1651 y = yNew;
1652 }
1653 zmirr = false;
1654 const double cellsz = m_zMaxBB - m_zMinBB;
1655 if (m_zPeriodic) {
1656 z = m_zMinBB + fmod(z - m_zMinBB, cellsz);
1657 if (z < m_zMinBB) z += cellsz;
1658 } else if (m_zMirrorPeriodic) {
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;
1664 zmirr = true;
1665 }
1666 z = zNew;
1667 }
1668}
1669
1670int ComponentTcad3d::FindRegion(const std::string& name) const {
1671
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;
1675 }
1676 return -1;
1677}
1678
1679}
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.
Definition: Medium.hh:11