Garfield++ v1r0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
ComponentTcad2d.cc
Go to the documentation of this file.
1#include <iostream>
2#include <fstream>
3#include <sstream>
4#include <string>
5#include <algorithm>
6#include <cmath>
7
8#include "ComponentTcad2d.hh"
9
10namespace Garfield {
11
13 : ComponentBase(),
14 nRegions(0),
15 nVertices(0),
16 nElements(0),
17 hasPotential(false),
18 hasField(false),
19 hasElectronMobility(false),
20 hasHoleMobility(false),
21 pMin(0.),
22 pMax(0.),
23 hasRangeZ(false),
24 lastElement(0) {
25
26 m_className = "ComponentTcad2d";
27
28 regions.reserve(10);
29 regions.clear();
30 vertices.reserve(1000);
31 vertices.clear();
32 elements.reserve(1000);
33 elements.clear();
34 for (int i = nMaxVertices; i--;) w[i] = 0.;
35}
36
37void ComponentTcad2d::ElectricField(const double xin, const double yin,
38 const double zin, double& ex, double& ey,
39 double& ez, double& p, Medium*& m,
40 int& status) {
41
42 m = 0;
43 // Make sure the field map has been loaded.
44 if (!ready) {
45 std::cerr << m_className << "::ElectricField:\n";
46 std::cerr << " Field map is not available for interpolation.\n";
47 status = -10;
48 return;
49 }
50
51 double x = xin, y = yin, z = zin;
52 // In case of periodicity, reduce to the cell volume.
53 bool xMirrored = false;
54 const double cellsx = xMaxBoundingBox - xMinBoundingBox;
55 if (xPeriodic) {
56 x = xMinBoundingBox + fmod(x - xMinBoundingBox, cellsx);
57 if (x < xMinBoundingBox) x += cellsx;
58 } else if (xMirrorPeriodic) {
59 double xNew = xMinBoundingBox + fmod(x - xMinBoundingBox, cellsx);
60 if (xNew < xMinBoundingBox) xNew += cellsx;
61 int nx = int(floor(0.5 + (xNew - x) / cellsx));
62 if (nx != 2 * (nx / 2)) {
63 xNew = xMinBoundingBox + xMaxBoundingBox - xNew;
64 xMirrored = true;
65 }
66 x = xNew;
67 }
68 bool yMirrored = false;
69 const double cellsy = yMaxBoundingBox - yMinBoundingBox;
70 if (yPeriodic) {
71 y = yMinBoundingBox + fmod(y - yMinBoundingBox, cellsy);
72 if (y < yMinBoundingBox) y += cellsy;
73 } else if (yMirrorPeriodic) {
74 double yNew = yMinBoundingBox + fmod(y - yMinBoundingBox, cellsy);
75 if (yNew < yMinBoundingBox) yNew += cellsy;
76 int ny = int(floor(0.5 + (yNew - y) / cellsy));
77 if (ny != 2 * (ny / 2)) {
78 yNew = yMinBoundingBox + yMaxBoundingBox - yNew;
79 yMirrored = true;
80 }
81 y = yNew;
82 }
83
84 // Check if the point is inside the bounding box.
85 if (x < xMinBoundingBox || x > xMaxBoundingBox || y < yMinBoundingBox ||
86 y > yMaxBoundingBox) {
87 status = -11;
88 return;
89 }
90 if (hasRangeZ) {
91 if (z < zMinBoundingBox || z > zMaxBoundingBox) {
92 status = -11;
93 return;
94 }
95 }
96
97 // Initialise the electric field and potential.
98 ex = ey = ez = p = 0.;
99 // Assume this will work.
100 status = 0;
101 // Check if the point is still located in the previously found element.
102 int i = lastElement;
103 switch (elements[i].type) {
104 case 1:
105 if (CheckLine(x, y, i)) {
106 ex = w[0] * vertices[elements[i].vertex[0]].ex +
107 w[1] * vertices[elements[i].vertex[1]].ex;
108 ey = w[0] * vertices[elements[i].vertex[0]].ey +
109 w[1] * vertices[elements[i].vertex[1]].ey;
110 p = w[0] * vertices[elements[i].vertex[0]].p +
111 w[1] * vertices[elements[i].vertex[1]].p;
112 if (xMirrored) ex = -ex;
113 if (yMirrored) ey = -ey;
114 m = regions[elements[i].region].medium;
115 if (!regions[elements[i].region].drift || m == 0) status = -5;
116 return;
117 }
118 break;
119 case 2:
120 if (CheckTriangle(x, y, i)) {
121 ex = w[0] * vertices[elements[i].vertex[0]].ex +
122 w[1] * vertices[elements[i].vertex[1]].ex +
123 w[2] * vertices[elements[i].vertex[2]].ex;
124 ey = w[0] * vertices[elements[i].vertex[0]].ey +
125 w[1] * vertices[elements[i].vertex[1]].ey +
126 w[2] * vertices[elements[i].vertex[2]].ey;
127 p = w[0] * vertices[elements[i].vertex[0]].p +
128 w[1] * vertices[elements[i].vertex[1]].p +
129 w[2] * vertices[elements[i].vertex[2]].p;
130 if (xMirrored) ex = -ex;
131 if (yMirrored) ey = -ey;
132 m = regions[elements[i].region].medium;
133 if (!regions[elements[i].region].drift || m == 0) status = -5;
134 return;
135 }
136 break;
137 case 3:
138 if (CheckRectangle(x, y, i)) {
139 ex = w[0] * vertices[elements[i].vertex[0]].ex +
140 w[1] * vertices[elements[i].vertex[1]].ex +
141 w[2] * vertices[elements[i].vertex[2]].ex +
142 w[3] * vertices[elements[i].vertex[3]].ex;
143 ey = w[0] * vertices[elements[i].vertex[0]].ey +
144 w[1] * vertices[elements[i].vertex[1]].ey +
145 w[2] * vertices[elements[i].vertex[2]].ey +
146 w[3] * vertices[elements[i].vertex[3]].ey;
147 p = w[0] * vertices[elements[i].vertex[0]].p +
148 w[1] * vertices[elements[i].vertex[1]].p +
149 w[2] * vertices[elements[i].vertex[2]].p +
150 w[3] * vertices[elements[i].vertex[3]].p;
151 if (xMirrored) ex = -ex;
152 if (yMirrored) ey = -ey;
153 m = regions[elements[i].region].medium;
154 if (!regions[elements[i].region].drift || m == 0) status = -5;
155 return;
156 }
157 break;
158 default:
159 std::cerr << m_className << "::ElectricField:\n";
160 std::cerr << " Unknown element type (" << elements[i].type << ").\n";
161 status = -11;
162 return;
163 break;
164 }
165
166 // The point is not in the previous element.
167 // Check the adjacent elements.
168 for (int j = elements[lastElement].nNeighbours; j--;) {
169 i = elements[lastElement].neighbours[j];
170 if (x < vertices[elements[i].vertex[0]].x) continue;
171 switch (elements[i].type) {
172 case 1:
173 if (CheckLine(x, y, i)) {
174 ex = w[0] * vertices[elements[i].vertex[0]].ex +
175 w[1] * vertices[elements[i].vertex[1]].ex;
176 ey = w[0] * vertices[elements[i].vertex[0]].ey +
177 w[1] * vertices[elements[i].vertex[1]].ey;
178 p = w[0] * vertices[elements[i].vertex[0]].p +
179 w[1] * vertices[elements[i].vertex[1]].p;
180 if (xMirrored) ex = -ex;
181 if (yMirrored) ey = -ey;
182 lastElement = i;
183 m = regions[elements[i].region].medium;
184 if (!regions[elements[i].region].drift || m == 0) status = -5;
185 return;
186 }
187 break;
188 case 2:
189 if (CheckTriangle(x, y, i)) {
190 ex = w[0] * vertices[elements[i].vertex[0]].ex +
191 w[1] * vertices[elements[i].vertex[1]].ex +
192 w[2] * vertices[elements[i].vertex[2]].ex;
193 ey = w[0] * vertices[elements[i].vertex[0]].ey +
194 w[1] * vertices[elements[i].vertex[1]].ey +
195 w[2] * vertices[elements[i].vertex[2]].ey;
196 p = w[0] * vertices[elements[i].vertex[0]].p +
197 w[1] * vertices[elements[i].vertex[1]].p +
198 w[2] * vertices[elements[i].vertex[2]].p;
199 if (xMirrored) ex = -ex;
200 if (yMirrored) ey = -ey;
201 lastElement = i;
202 m = regions[elements[i].region].medium;
203 if (!regions[elements[i].region].drift || m == 0) status = -5;
204 return;
205 }
206 break;
207 case 3:
208 if (CheckRectangle(x, y, i)) {
209 ex = w[0] * vertices[elements[i].vertex[0]].ex +
210 w[1] * vertices[elements[i].vertex[1]].ex +
211 w[2] * vertices[elements[i].vertex[2]].ex +
212 w[3] * vertices[elements[i].vertex[3]].ex;
213 ey = w[0] * vertices[elements[i].vertex[0]].ey +
214 w[1] * vertices[elements[i].vertex[1]].ey +
215 w[2] * vertices[elements[i].vertex[2]].ey +
216 w[3] * vertices[elements[i].vertex[3]].ey;
217 p = w[0] * vertices[elements[i].vertex[0]].p +
218 w[1] * vertices[elements[i].vertex[1]].p +
219 w[2] * vertices[elements[i].vertex[2]].p +
220 w[3] * vertices[elements[i].vertex[3]].p;
221 if (xMirrored) ex = -ex;
222 if (yMirrored) ey = -ey;
223 lastElement = i;
224 m = regions[elements[i].region].medium;
225 if (!regions[elements[i].region].drift || m == 0) status = -5;
226 return;
227 }
228 break;
229 default:
230 std::cerr << m_className << "::ElectricField:\n";
231 std::cerr << " Invalid element type (" << elements[i].type << ").\n";
232 status = -11;
233 return;
234 break;
235 }
236 }
237
238 // The point is not in the previous element nor in the adjacent ones.
239 // We have to loop over all elements.
240 for (i = nElements; i--;) {
241 if (x < vertices[elements[i].vertex[0]].x) continue;
242 switch (elements[i].type) {
243 case 1:
244 if (CheckLine(x, y, i)) {
245 ex = w[0] * vertices[elements[i].vertex[0]].ex +
246 w[1] * vertices[elements[i].vertex[1]].ex;
247 ey = w[0] * vertices[elements[i].vertex[0]].ey +
248 w[1] * vertices[elements[i].vertex[1]].ey;
249 p = w[0] * vertices[elements[i].vertex[0]].p +
250 w[1] * vertices[elements[i].vertex[1]].p;
251 if (xMirrored) ex = -ex;
252 if (yMirrored) ey = -ey;
253 lastElement = i;
254 m = regions[elements[i].region].medium;
255 if (!regions[elements[i].region].drift || m == 0) status = -5;
256 return;
257 }
258 break;
259 case 2:
260 if (CheckTriangle(x, y, i)) {
261 ex = w[0] * vertices[elements[i].vertex[0]].ex +
262 w[1] * vertices[elements[i].vertex[1]].ex +
263 w[2] * vertices[elements[i].vertex[2]].ex;
264 ey = w[0] * vertices[elements[i].vertex[0]].ey +
265 w[1] * vertices[elements[i].vertex[1]].ey +
266 w[2] * vertices[elements[i].vertex[2]].ey;
267 p = w[0] * vertices[elements[i].vertex[0]].p +
268 w[1] * vertices[elements[i].vertex[1]].p +
269 w[2] * vertices[elements[i].vertex[2]].p;
270 if (xMirrored) ex = -ex;
271 if (yMirrored) ey = -ey;
272 lastElement = i;
273 m = regions[elements[i].region].medium;
274 if (!regions[elements[i].region].drift || m == 0) status = -5;
275 return;
276 }
277 break;
278 case 3:
279 if (CheckRectangle(x, y, i)) {
280 ex = w[0] * vertices[elements[i].vertex[0]].ex +
281 w[1] * vertices[elements[i].vertex[1]].ex +
282 w[2] * vertices[elements[i].vertex[2]].ex +
283 w[3] * vertices[elements[i].vertex[3]].ex;
284 ey = w[0] * vertices[elements[i].vertex[0]].ey +
285 w[1] * vertices[elements[i].vertex[1]].ey +
286 w[2] * vertices[elements[i].vertex[2]].ey +
287 w[3] * vertices[elements[i].vertex[3]].ey;
288 p = w[0] * vertices[elements[i].vertex[0]].p +
289 w[1] * vertices[elements[i].vertex[1]].p +
290 w[2] * vertices[elements[i].vertex[2]].p +
291 w[3] * vertices[elements[i].vertex[3]].p;
292 if (xMirrored) ex = -ex;
293 if (yMirrored) ey = -ey;
294 lastElement = i;
295 m = regions[elements[i].region].medium;
296 if (!regions[elements[i].region].drift || m == 0) status = -5;
297 return;
298 }
299 break;
300 default:
301 std::cerr << m_className << "::ElectricField:\n";
302 std::cerr << " Invalid element type (" << elements[i].type << ").\n";
303 status = -11;
304 return;
305 break;
306 }
307 }
308 // Point is outside the mesh.
309 if (debug) {
310 std::cerr << m_className << "::ElectricField:\n";
311 std::cerr << " Point (" << x << ", " << y << ") is outside the mesh.\n";
312 }
313 status = -6;
314 return;
315}
316
317void ComponentTcad2d::ElectricField(const double x, const double y,
318 const double z, double& ex, double& ey,
319 double& ez, Medium*& m, int& status) {
320
321 double v = 0.;
322 ElectricField(x, y, z, ex, ey, ez, v, m, status);
323}
324
325Medium* ComponentTcad2d::GetMedium(const double& xin, const double& yin,
326 const double& zin) {
327
328 // Make sure the field map has been loaded.
329 if (!ready) {
330 std::cerr << m_className << "::GetMedium:\n";
331 std::cerr << " Field map not available for interpolation.\n";
332 return NULL;
333 }
334
335 double x = xin, y = yin, z = zin;
336 // In case of periodicity, reduce to the cell volume.
337 const double cellsx = xMaxBoundingBox - xMinBoundingBox;
338 if (xPeriodic) {
339 x = xMinBoundingBox + fmod(x - xMinBoundingBox, cellsx);
340 if (x < xMinBoundingBox) x += cellsx;
341 } else if (xMirrorPeriodic) {
342 double xNew = xMinBoundingBox + fmod(x - xMinBoundingBox, cellsx);
343 if (xNew < xMinBoundingBox) xNew += cellsx;
344 int nx = int(floor(0.5 + (xNew - x) / cellsx));
345 if (nx != 2 * (nx / 2)) {
346 xNew = xMinBoundingBox + xMaxBoundingBox - xNew;
347 }
348 x = xNew;
349 }
350 const double cellsy = yMaxBoundingBox - yMinBoundingBox;
351 if (yPeriodic) {
352 y = yMinBoundingBox + fmod(y - yMinBoundingBox, cellsy);
353 if (y < yMinBoundingBox) y += cellsy;
354 } else if (yMirrorPeriodic) {
355 double yNew = yMinBoundingBox + fmod(y - yMinBoundingBox, cellsy);
356 if (yNew < yMinBoundingBox) yNew += cellsy;
357 int ny = int(floor(0.5 + (yNew - y) / cellsy));
358 if (ny != 2 * (ny / 2)) {
359 yNew = yMinBoundingBox + yMaxBoundingBox - yNew;
360 }
361 y = yNew;
362 }
363
364 // Check if the point is inside the bounding box.
365 if (x < xMinBoundingBox || x > xMaxBoundingBox || y < yMinBoundingBox ||
366 y > yMaxBoundingBox) {
367 return NULL;
368 }
369 if (hasRangeZ) {
370 if (z < zMinBoundingBox || z > zMaxBoundingBox) {
371 return NULL;
372 }
373 }
374
375 // Check if the point is still located in the previous element.
376 int i = lastElement;
377 switch (elements[i].type) {
378 case 1:
379 if (CheckLine(x, y, i)) {
380 return regions[elements[i].region].medium;
381 }
382 break;
383 case 2:
384 if (CheckTriangle(x, y, i)) {
385 return regions[elements[i].region].medium;
386 }
387 break;
388 case 3:
389 if (CheckRectangle(x, y, i)) {
390 return regions[elements[i].region].medium;
391 }
392 break;
393 default:
394 std::cerr << m_className << "::GetMedium:\n";
395 std::cerr << " Invalid element type (" << elements[i].type << ").\n";
396 return NULL;
397 break;
398 }
399
400 // The point is not in the previous element.
401 // Check the adjacent elements.
402 for (int j = elements[lastElement].nNeighbours; j--;) {
403 i = elements[lastElement].neighbours[j];
404 if (x < vertices[elements[i].vertex[0]].x) continue;
405 switch (elements[i].type) {
406 case 1:
407 if (CheckLine(x, y, i)) {
408 lastElement = i;
409 return regions[elements[i].region].medium;
410 }
411 break;
412 case 2:
413 if (CheckTriangle(x, y, i)) {
414 lastElement = i;
415 return regions[elements[i].region].medium;
416 }
417 break;
418 case 3:
419 if (CheckRectangle(x, y, i)) {
420 lastElement = i;
421 return regions[elements[i].region].medium;
422 }
423 break;
424 default:
425 std::cerr << m_className << "::GetMedium:\n";
426 std::cerr << " Invalid element type (" << elements[i].type << ").\n";
427 return NULL;
428 break;
429 }
430 }
431
432 // The point is not in the previous element nor in the adjacent ones.
433 // We have to loop over all elements.
434 for (i = nElements; i--;) {
435 if (x < vertices[elements[i].vertex[0]].x) continue;
436 switch (elements[i].type) {
437 case 1:
438 if (CheckLine(x, y, i)) {
439 lastElement = i;
440 return regions[elements[i].region].medium;
441 }
442 break;
443 case 2:
444 if (CheckTriangle(x, y, i)) {
445 lastElement = i;
446 return regions[elements[i].region].medium;
447 }
448 break;
449 case 3:
450 if (CheckRectangle(x, y, i)) {
451 lastElement = i;
452 return regions[elements[i].region].medium;
453 }
454 break;
455 default:
456 std::cerr << m_className << "::GetMedium:\n";
457 std::cerr << " Invalid element type (" << elements[i].type << ").\n";
458 return NULL;
459 break;
460 }
461 }
462 // The point is outside the mesh.
463 return NULL;
464}
465
466bool ComponentTcad2d::GetMobility(const double xin, const double yin,
467 const double zin, double& emob,
468 double& hmob) {
469
470 emob = hmob = 0.;
471 // Make sure the field map has been loaded.
472 if (!ready) {
473 std::cerr << m_className << "::GetMobility:\n";
474 std::cerr << " Field map is not available for interpolation.\n";
475 return false;
476 }
477
478 double x = xin, y = yin, z = zin;
479 // In case of periodicity, reduce to the cell volume.
480 const double cellsx = xMaxBoundingBox - xMinBoundingBox;
481 if (xPeriodic) {
482 x = xMinBoundingBox + fmod(x - xMinBoundingBox, cellsx);
483 if (x < xMinBoundingBox) x += cellsx;
484 } else if (xMirrorPeriodic) {
485 double xNew = xMinBoundingBox + fmod(x - xMinBoundingBox, cellsx);
486 if (xNew < xMinBoundingBox) xNew += cellsx;
487 int nx = int(floor(0.5 + (xNew - x) / cellsx));
488 if (nx != 2 * (nx / 2)) {
489 xNew = xMinBoundingBox + xMaxBoundingBox - xNew;
490 }
491 x = xNew;
492 }
493 const double cellsy = xMaxBoundingBox - xMinBoundingBox;
494 if (yPeriodic) {
495 y = yMinBoundingBox + fmod(y - yMinBoundingBox, cellsy);
496 if (y < yMinBoundingBox) y += cellsy;
497 } else if (yMirrorPeriodic) {
498 double yNew = yMinBoundingBox + fmod(y - yMinBoundingBox, cellsy);
499 if (yNew < yMinBoundingBox) yNew += cellsy;
500 int ny = int(floor(0.5 + (yNew - y) / cellsy));
501 if (ny != 2 * (ny / 2)) {
502 yNew = yMinBoundingBox + yMaxBoundingBox - yNew;
503 }
504 y = yNew;
505 }
506
507 // Check if the point is inside the bounding box.
508 if (x < xMinBoundingBox || x > xMaxBoundingBox || y < yMinBoundingBox ||
509 y > yMaxBoundingBox) {
510 return false;
511 }
512 if (hasRangeZ) {
513 if (z < zMinBoundingBox || z > zMaxBoundingBox) {
514 return false;
515 }
516 }
517
518 // Check if the point is still located in the previously found element.
519 int i = lastElement;
520 switch (elements[i].type) {
521 case 1:
522 if (CheckLine(x, y, i)) {
523 emob = w[0] * vertices[elements[i].vertex[0]].emob +
524 w[1] * vertices[elements[i].vertex[1]].emob;
525 hmob = w[0] * vertices[elements[i].vertex[0]].hmob +
526 w[1] * vertices[elements[i].vertex[1]].hmob;
527 return true;
528 }
529 break;
530 case 2:
531 if (CheckTriangle(x, y, i)) {
532 emob = w[0] * vertices[elements[i].vertex[0]].emob +
533 w[1] * vertices[elements[i].vertex[1]].emob +
534 w[2] * vertices[elements[i].vertex[2]].emob;
535 hmob = w[0] * vertices[elements[i].vertex[0]].hmob +
536 w[1] * vertices[elements[i].vertex[1]].hmob +
537 w[2] * vertices[elements[i].vertex[2]].hmob;
538 return true;
539 }
540 break;
541 case 3:
542 if (CheckRectangle(x, y, i)) {
543 emob = w[0] * vertices[elements[i].vertex[0]].emob +
544 w[1] * vertices[elements[i].vertex[1]].emob +
545 w[2] * vertices[elements[i].vertex[2]].emob +
546 w[3] * vertices[elements[i].vertex[3]].emob;
547 hmob = w[0] * vertices[elements[i].vertex[0]].hmob +
548 w[1] * vertices[elements[i].vertex[1]].hmob +
549 w[2] * vertices[elements[i].vertex[2]].hmob +
550 w[3] * vertices[elements[i].vertex[3]].hmob;
551 return true;
552 }
553 break;
554 default:
555 std::cerr << m_className << "::GetMobility:\n";
556 std::cerr << " Unknown element type (" << elements[i].type << ").\n";
557 return false;
558 break;
559 }
560
561 // The point is not in the previous element.
562 // Check the adjacent elements.
563 for (int j = elements[lastElement].nNeighbours; j--;) {
564 i = elements[lastElement].neighbours[j];
565 if (x < vertices[elements[i].vertex[0]].x) continue;
566 switch (elements[i].type) {
567 case 1:
568 if (CheckLine(x, y, i)) {
569 emob = w[0] * vertices[elements[i].vertex[0]].emob +
570 w[1] * vertices[elements[i].vertex[1]].emob;
571 hmob = w[0] * vertices[elements[i].vertex[0]].hmob +
572 w[1] * vertices[elements[i].vertex[1]].hmob;
573 lastElement = i;
574 return true;
575 }
576 break;
577 case 2:
578 if (CheckTriangle(x, y, i)) {
579 emob = w[0] * vertices[elements[i].vertex[0]].emob +
580 w[1] * vertices[elements[i].vertex[1]].emob +
581 w[2] * vertices[elements[i].vertex[2]].emob;
582 hmob = w[0] * vertices[elements[i].vertex[0]].hmob +
583 w[1] * vertices[elements[i].vertex[1]].hmob +
584 w[2] * vertices[elements[i].vertex[2]].hmob;
585 lastElement = i;
586 return true;
587 }
588 break;
589 case 3:
590 if (CheckRectangle(x, y, i)) {
591 emob = w[0] * vertices[elements[i].vertex[0]].emob +
592 w[1] * vertices[elements[i].vertex[1]].emob +
593 w[2] * vertices[elements[i].vertex[2]].emob +
594 w[3] * vertices[elements[i].vertex[3]].emob;
595 hmob = w[0] * vertices[elements[i].vertex[0]].hmob +
596 w[1] * vertices[elements[i].vertex[1]].hmob +
597 w[2] * vertices[elements[i].vertex[2]].hmob +
598 w[3] * vertices[elements[i].vertex[3]].hmob;
599 lastElement = i;
600 return true;
601 }
602 break;
603 default:
604 std::cerr << m_className << "::GetMobility:\n";
605 std::cerr << " Invalid element type (" << elements[i].type << ").\n";
606 return false;
607 break;
608 }
609 }
610
611 // The point is not in the previous element nor in the adjacent ones.
612 // We have to loop over all elements.
613 for (i = nElements; i--;) {
614 if (x < vertices[elements[i].vertex[0]].x) continue;
615 switch (elements[i].type) {
616 case 1:
617 if (CheckLine(x, y, i)) {
618 emob = w[0] * vertices[elements[i].vertex[0]].emob +
619 w[1] * vertices[elements[i].vertex[1]].emob;
620 hmob = w[0] * vertices[elements[i].vertex[0]].hmob +
621 w[1] * vertices[elements[i].vertex[1]].hmob;
622 lastElement = i;
623 return true;
624 }
625 break;
626 case 2:
627 if (CheckTriangle(x, y, i)) {
628 emob = w[0] * vertices[elements[i].vertex[0]].emob +
629 w[1] * vertices[elements[i].vertex[1]].emob +
630 w[2] * vertices[elements[i].vertex[2]].emob;
631 hmob = w[0] * vertices[elements[i].vertex[0]].hmob +
632 w[1] * vertices[elements[i].vertex[1]].hmob +
633 w[2] * vertices[elements[i].vertex[2]].hmob;
634 lastElement = i;
635 return true;
636 }
637 break;
638 case 3:
639 if (CheckRectangle(x, y, i)) {
640 emob = w[0] * vertices[elements[i].vertex[0]].emob +
641 w[1] * vertices[elements[i].vertex[1]].emob +
642 w[2] * vertices[elements[i].vertex[2]].emob +
643 w[3] * vertices[elements[i].vertex[3]].emob;
644 hmob = w[0] * vertices[elements[i].vertex[0]].hmob +
645 w[1] * vertices[elements[i].vertex[1]].hmob +
646 w[2] * vertices[elements[i].vertex[2]].hmob +
647 w[3] * vertices[elements[i].vertex[3]].hmob;
648 lastElement = i;
649 return true;
650 }
651 break;
652 default:
653 std::cerr << m_className << "::GetMobility:\n";
654 std::cerr << " Invalid element type (" << elements[i].type << ").\n";
655 return false;
656 break;
657 }
658 }
659 // Point is outside the mesh.
660 if (debug) {
661 std::cerr << m_className << "::GetMobility:\n";
662 std::cerr << " Point (" << x << ", " << y << ") is outside the mesh.\n";
663 }
664 return false;
665}
666
667bool ComponentTcad2d::Initialise(const std::string gridfilename,
668 const std::string datafilename) {
669
670 ready = false;
671 // Import mesh data from .grd file.
672 if (!LoadGrid(gridfilename)) {
673 std::cerr << m_className << "::Initialise:\n";
674 std::cerr << " Importing mesh data failed.\n";
675 return false;
676 }
677
678 hasPotential = hasField = false;
679 hasElectronMobility = hasHoleMobility = false;
680
681 // Import electric field and potential from .dat file.
682 if (!LoadData(datafilename)) {
683 std::cerr << m_className << "::Initialise:\n";
684 std::cerr << " Importing electric field and potential failed.\n";
685 return false;
686 }
687
688 // Find min./max. coordinates and potentials.
689 xMaxBoundingBox = xMinBoundingBox = vertices[elements[0].vertex[0]].x;
690 yMaxBoundingBox = yMinBoundingBox = vertices[elements[0].vertex[0]].y;
691 pMax = pMin = vertices[elements[0].vertex[0]].p;
692 for (int i = nElements; i--;) {
693 for (int j = 0; j <= elements[i].type; ++j) {
694 if (vertices[elements[i].vertex[j]].x < xMinBoundingBox) {
695 xMinBoundingBox = vertices[elements[i].vertex[j]].x;
696 } else if (vertices[elements[i].vertex[j]].x > xMaxBoundingBox) {
697 xMaxBoundingBox = vertices[elements[i].vertex[j]].x;
698 }
699 if (vertices[elements[i].vertex[j]].y < yMinBoundingBox) {
700 yMinBoundingBox = vertices[elements[i].vertex[j]].y;
701 } else if (vertices[elements[i].vertex[j]].y > yMaxBoundingBox) {
702 yMaxBoundingBox = vertices[elements[i].vertex[j]].y;
703 }
704 if (vertices[elements[i].vertex[j]].p < pMin) {
705 pMin = vertices[elements[i].vertex[j]].p;
706 } else if (vertices[elements[i].vertex[j]].p > pMax) {
707 pMax = vertices[elements[i].vertex[j]].p;
708 }
709 }
710 }
711
712 std::cout << m_className << "::Initialise:\n";
713 std::cout << " Available data:\n";
714 if (hasPotential) {
715 std::cout << " Electrostatic potential\n";
716 }
717 if (hasField) {
718 std::cout << " Electric field\n";
719 }
720 if (hasElectronMobility) {
721 std::cout << " Electron mobility\n";
722 }
723 if (hasHoleMobility) {
724 std::cout << " Hole mobility\n";
725 }
726 std::cout << " Bounding box:\n";
727 std::cout << " " << xMinBoundingBox << " < x [cm] < " << xMaxBoundingBox
728 << "\n";
729 std::cout << " " << yMinBoundingBox << " < y [cm] < " << yMaxBoundingBox
730 << "\n";
731 std::cout << " Voltage range:\n";
732 std::cout << " " << pMin << " < V < " << pMax << "\n";
733
734 bool ok = true;
735
736 // Count the number of elements belonging to a region.
737 std::vector<int> nElementsRegion;
738 nElementsRegion.resize(nRegions);
739 for (int i = nRegions; i--;) nElementsRegion[i] = 0;
740
741 // Count the different element shapes.
742 int nLines = 0;
743 int nTriangles = 0;
744 int nRectangles = 0;
745 int nOtherShapes = 0;
746
747 // Check if there are elements which are not part of any region.
748 int nLoose = 0;
749 std::vector<int> looseElements;
750 looseElements.clear();
751
752 // Check if there are degenerate elements.
753 int nDegenerate = 0;
754 std::vector<int> degenerateElements;
755 degenerateElements.clear();
756
757 for (int i = nElements; i--;) {
758 if (elements[i].type == 1) {
759 ++nLines;
760 if (elements[i].vertex[0] == elements[i].vertex[1]) {
761 degenerateElements.push_back(i);
762 ++nDegenerate;
763 }
764 } else if (elements[i].type == 2) {
765 ++nTriangles;
766 if (elements[i].vertex[0] == elements[i].vertex[1] ||
767 elements[i].vertex[1] == elements[i].vertex[2] ||
768 elements[i].vertex[2] == elements[i].vertex[0]) {
769 degenerateElements.push_back(i);
770 ++nDegenerate;
771 }
772 } else if (elements[i].type == 3) {
773 ++nRectangles;
774 if (elements[i].vertex[0] == elements[i].vertex[1] ||
775 elements[i].vertex[0] == elements[i].vertex[2] ||
776 elements[i].vertex[0] == elements[i].vertex[3] ||
777 elements[i].vertex[1] == elements[i].vertex[2] ||
778 elements[i].vertex[1] == elements[i].vertex[3] ||
779 elements[i].vertex[2] == elements[i].vertex[3]) {
780 degenerateElements.push_back(i);
781 ++nDegenerate;
782 }
783 } else {
784 // Other shapes should not occur, since they were excluded in LoadGrid.
785 ++nOtherShapes;
786 }
787 if (elements[i].region >= 0 && elements[i].region < nRegions) {
788 ++nElementsRegion[elements[i].region];
789 } else {
790 looseElements.push_back(i);
791 ++nLoose;
792 }
793 }
794
795 if (nDegenerate > 0) {
796 std::cerr << m_className << "::Initialise:\n";
797 std::cerr << " The following elements are degenerate:\n";
798 for (int i = nDegenerate; i--;) {
799 std::cerr << " " << degenerateElements[i] << "\n";
800 }
801 ok = false;
802 }
803
804 if (nLoose > 0) {
805 std::cerr << m_className << "::Initialise:\n";
806 std::cerr << " The following elements are not part of any region:\n";
807 for (int i = nLoose; i--;) {
808 std::cerr << " " << looseElements[i] << "\n";
809 }
810 ok = false;
811 }
812
813 std::cout << m_className << "::Initialise:\n";
814 std::cout << " Number of regions: " << nRegions << "\n";
815 for (int i = 0; i < nRegions; ++i) {
816 std::cout << " " << i << ": " << regions[i].name << ", "
817 << nElementsRegion[i] << " elements\n";
818 }
819
820 std::cout << " Number of elements: " << nElements << "\n";
821 if (nLines > 0) {
822 std::cout << " " << nLines << " lines\n";
823 }
824 if (nTriangles > 0) {
825 std::cout << " " << nTriangles << " triangles\n";
826 }
827 if (nRectangles > 0) {
828 std::cout << " " << nRectangles << " rectangles\n";
829 }
830 if (nOtherShapes > 0) {
831 std::cout << " " << nOtherShapes << " elements of unknown type\n";
832 std::cout << " Program bug!\n";
833 ready = false;
834 Cleanup();
835 return false;
836 }
837
838 std::cout << " Number of vertices: " << nVertices << "\n";
839
840 // Find adjacent elements.
841 FindNeighbours();
842
843 if (!ok) {
844 ready = false;
845 Cleanup();
846 return false;
847 }
848
849 ready = true;
850 UpdatePeriodicity();
851 return true;
852}
853
854bool ComponentTcad2d::GetBoundingBox(double& xmin, double& ymin, double& zmin,
855 double& xmax, double& ymax, double& zmax) {
856
857 if (!ready) return false;
858 if (xPeriodic || xMirrorPeriodic) {
859 xmin = -INFINITY;
860 xmax = +INFINITY;
861 } else {
862 xmin = xMinBoundingBox;
863 xmax = xMaxBoundingBox;
864 }
865
866 if (yPeriodic || yMirrorPeriodic) {
867 ymin = -INFINITY;
868 ymax = +INFINITY;
869 } else {
870 ymin = yMinBoundingBox;
871 ymax = yMaxBoundingBox;
872 }
873
874 if (hasRangeZ) {
875 zmin = zMinBoundingBox;
876 zmax = zMaxBoundingBox;
877 }
878 return true;
879}
880
881void ComponentTcad2d::SetRangeZ(const double zmin, const double zmax) {
882
883 if (fabs(zmax - zmin) <= 0.) {
884 std::cerr << m_className << "::SetRangeZ:\n";
885 std::cerr << " Zero range is not permitted.\n";
886 return;
887 }
888 zMinBoundingBox = std::min(zmin, zmax);
889 zMaxBoundingBox = std::max(zmin, zmax);
890 hasRangeZ = true;
891}
892
893bool ComponentTcad2d::GetVoltageRange(double& vmin, double& vmax) {
894
895 if (!ready) return false;
896 vmin = pMin;
897 vmax = pMax;
898 return true;
899}
900
902
903 // Do not proceed if not properly initialised.
904 if (!ready) {
905 std::cerr << m_className << "::PrintRegions:\n";
906 std::cerr << " Field map not yet initialised.\n";
907 return;
908 }
909
910 if (nRegions < 0) {
911 std::cerr << m_className << "::PrintRegions:\n";
912 std::cerr << " No regions are currently defined.\n";
913 return;
914 }
915
916 std::cout << m_className << "::PrintRegions:\n";
917 std::cout << " Currently " << nRegions << " regions are defined.\n";
918 std::cout << " Index Name Medium\n";
919 for (int i = 0; i < nRegions; ++i) {
920 std::cout << " " << i << " " << regions[i].name;
921 if (regions[i].medium == 0) {
922 std::cout << " none ";
923 } else {
924 std::cout << " " << regions[i].medium->GetName();
925 }
926 if (regions[i].drift) {
927 std::cout << " (active region)\n";
928 } else {
929 std::cout << "\n";
930 }
931 }
932}
933
934void ComponentTcad2d::GetRegion(const int i, std::string& name, bool& active) {
935
936 if (i < 0 || i >= nRegions) {
937 std::cerr << m_className << "::GetRegion:\n";
938 std::cerr << " Region " << i << " does not exist.\n";
939 return;
940 }
941 name = regions[i].name;
942 active = regions[i].drift;
943}
944
946
947 if (i < 0 || i >= nRegions) {
948 std::cerr << m_className << "::SetDriftRegion:\n";
949 std::cerr << " Region " << i << " does not exist.\n";
950 return;
951 }
952 regions[i].drift = true;
953}
954
956
957 if (i < 0 || i >= nRegions) {
958 std::cerr << m_className << "::UnsetDriftRegion:\n";
959 std::cerr << " Region " << i << " does not exist.\n";
960 return;
961 }
962 regions[i].drift = false;
963}
964
965void ComponentTcad2d::SetMedium(const int i, Medium* medium) {
966
967 if (i < 0 || i >= nRegions) {
968 std::cerr << m_className << "::SetMedium:\n";
969 std::cerr << " Region " << i << " does not exist.\n";
970 return;
971 }
972
973 if (medium == 0) {
974 std::cerr << m_className << "::SetMedium:\n";
975 std::cerr << " Medium pointer is null.\n";
976 return;
977 }
978
979 regions[i].medium = medium;
980}
981
982Medium* ComponentTcad2d::GetMedium(const unsigned int& i) const {
983
984 if (i >= (unsigned int)nRegions) {
985 std::cerr << m_className << "::GetMedium:\n";
986 std::cerr << " Region " << i << " does not exist.\n";
987 return NULL;
988 }
989
990 return regions[i].medium;
991}
992
993bool ComponentTcad2d::GetElement(const int i, double& vol, double& dmin,
994 double& dmax, int& type) {
995
996 if (i < 0 || i >= nElements) {
997 std::cerr << m_className << "::GetElement:\n";
998 std::cerr << " Element index (" << i << ") out of range.\n";
999 return false;
1000 }
1001
1002 type = elements[i].type;
1003 if (elements[i].type == 1) {
1004 const double d = sqrt(pow(vertices[elements[i].vertex[1]].x -
1005 vertices[elements[i].vertex[0]].x,
1006 2) +
1007 pow(vertices[elements[i].vertex[1]].y -
1008 vertices[elements[i].vertex[0]].y,
1009 2));
1010 dmin = dmax = vol = d;
1011 } else if (elements[i].type == 2) {
1012 vol = fabs((vertices[elements[i].vertex[2]].x -
1013 vertices[elements[i].vertex[0]].x) *
1014 (vertices[elements[i].vertex[1]].y -
1015 vertices[elements[i].vertex[0]].y) -
1016 (vertices[elements[i].vertex[2]].y -
1017 vertices[elements[i].vertex[0]].y) *
1018 (vertices[elements[i].vertex[1]].x -
1019 vertices[elements[i].vertex[0]].x)) /
1020 2.;
1021 const double a = sqrt(pow(vertices[elements[i].vertex[1]].x -
1022 vertices[elements[i].vertex[0]].x,
1023 2) +
1024 pow(vertices[elements[i].vertex[1]].y -
1025 vertices[elements[i].vertex[0]].y,
1026 2));
1027 const double b = sqrt(pow(vertices[elements[i].vertex[2]].x -
1028 vertices[elements[i].vertex[0]].x,
1029 2) +
1030 pow(vertices[elements[i].vertex[2]].y -
1031 vertices[elements[i].vertex[0]].y,
1032 2));
1033 const double c = sqrt(pow(vertices[elements[i].vertex[1]].x -
1034 vertices[elements[i].vertex[2]].x,
1035 2) +
1036 pow(vertices[elements[i].vertex[1]].y -
1037 vertices[elements[i].vertex[2]].y,
1038 2));
1039 dmin = dmax = a;
1040 if (b > dmax) dmax = b;
1041 if (c > dmax) dmax = c;
1042 if (b < dmin) dmin = b;
1043 if (c < dmin) dmin = c;
1044 } else if (elements[i].type == 3) {
1045 const double a = sqrt(pow(vertices[elements[i].vertex[1]].x -
1046 vertices[elements[i].vertex[0]].x,
1047 2) +
1048 pow(vertices[elements[i].vertex[1]].y -
1049 vertices[elements[i].vertex[0]].y,
1050 2));
1051 const double b = sqrt(pow(vertices[elements[i].vertex[3]].x -
1052 vertices[elements[i].vertex[0]].x,
1053 2) +
1054 pow(vertices[elements[i].vertex[3]].y -
1055 vertices[elements[i].vertex[0]].y,
1056 2));
1057 vol = a * b;
1058 dmin = std::min(a, b);
1059 dmax = sqrt(a * a + b * b);
1060 } else {
1061 std::cerr << m_className << "::GetElement:\n";
1062 std::cerr << " Unexpected element type (" << type << ")\n";
1063 return false;
1064 }
1065 return true;
1066}
1067
1068bool ComponentTcad2d::GetElement(const int i, double& vol, double& dmin,
1069 double& dmax, int& type, int& node1,
1070 int& node2, int& node3, int& node4, int& reg) {
1071
1072 if (!GetElement(i, vol, dmin, dmax, type)) return false;
1073 node1 = elements[i].vertex[0];
1074 node2 = elements[i].vertex[1];
1075 node3 = elements[i].vertex[2];
1076 node4 = elements[i].vertex[3];
1077 reg = elements[i].region;
1078 return true;
1079}
1080
1081bool ComponentTcad2d::GetNode(const int i, double& x, double& y, double& v,
1082 double& ex, double& ey) {
1083
1084 if (i < 0 || i >= nVertices) {
1085 std::cerr << m_className << "::GetNode:\n";
1086 std::cerr << " Node index (" << i << ") out of range.\n";
1087 return false;
1088 }
1089
1090 x = vertices[i].x;
1091 y = vertices[i].y;
1092 v = vertices[i].p;
1093 ex = vertices[i].ex;
1094 ey = vertices[i].ey;
1095 return true;
1096}
1097
1098bool ComponentTcad2d::LoadData(const std::string datafilename) {
1099
1100 std::ifstream datafile;
1101 datafile.open(datafilename.c_str(), std::ios::in);
1102 if (!datafile) {
1103 std::cerr << m_className << "::LoadData:\n";
1104 std::cerr << " Could not open file " << datafilename << ".\n";
1105 return false;
1106 }
1107
1108 std::string line;
1109 std::istringstream data;
1110
1111 std::vector<bool> isInRegion(nVertices);
1112 std::vector<int> fillCount(nVertices);
1113
1114 for (int i = nVertices; i--;) {
1115 fillCount[i] = 0;
1116 vertices[i].p = 0.;
1117 vertices[i].ex = 0.;
1118 vertices[i].ey = 0.;
1119 vertices[i].emob = 0.;
1120 vertices[i].hmob = 0.;
1121 vertices[i].isShared = false;
1122 }
1123
1124 std::string::size_type pBra, pKet, pEq;
1125
1126 while (!datafile.fail()) {
1127 // Read one line.
1128 std::getline(datafile, line);
1129 // Strip white space from beginning of line.
1130 line.erase(line.begin(),
1131 std::find_if(line.begin(), line.end(),
1132 not1(std::ptr_fun<int, int>(isspace))));
1133 // Find data section.
1134 if (line.substr(0, 8) == "function") {
1135 // Read type of data set.
1136 pEq = line.find('=');
1137 if (pEq == std::string::npos) {
1138 // No "=" found.
1139 std::cerr << m_className << "::LoadData:\n";
1140 std::cerr << " Error reading file " << datafilename << ".\n";
1141 std::cerr << " Line:\n";
1142 std::cerr << " " << line << "\n";
1143 datafile.close();
1144 Cleanup();
1145 return false;
1146 }
1147 line = line.substr(pEq + 1);
1148 std::string dataset;
1149 data.str(line);
1150 data >> dataset;
1151 data.clear();
1152 if (dataset == "ElectrostaticPotential") {
1153 std::getline(datafile, line);
1154 std::getline(datafile, line);
1155 std::getline(datafile, line);
1156 std::getline(datafile, line);
1157 // Get the region name (given in brackets).
1158 pBra = line.find('[');
1159 pKet = line.find(']');
1160 if (pKet < pBra || pBra == std::string::npos ||
1161 pKet == std::string::npos) {
1162 std::cerr << m_className << "::LoadData:\n";
1163 std::cerr << " Error reading file " << datafilename << "\n";
1164 std::cerr << " Line:\n";
1165 std::cerr << " " << line << "\n";
1166 datafile.close();
1167 Cleanup();
1168 return false;
1169 }
1170 line = line.substr(pBra + 1, pKet - pBra - 1);
1171 std::string name;
1172 data.str(line);
1173 data >> name;
1174 data.clear();
1175 // Check if the region name matches one from the mesh file.
1176 int index = -1;
1177 for (int j = 0; j < nRegions; ++j) {
1178 if (name == regions[j].name) {
1179 index = j;
1180 break;
1181 }
1182 }
1183 if (index == -1) {
1184 std::cerr << m_className << "::LoadData:\n";
1185 std::cerr << " Error reading file " << datafilename << "\n";
1186 std::cerr << " Unknown region " << name << ".\n";
1187 continue;
1188 }
1189 // Get the number of values.
1190 std::getline(datafile, line);
1191 pBra = line.find('(');
1192 pKet = line.find(')');
1193 if (pKet < pBra || pBra == std::string::npos ||
1194 pKet == std::string::npos) {
1195 std::cerr << m_className << "::LoadData:\n";
1196 std::cerr << " Error reading file " << datafilename << "\n";
1197 std::cerr << " Line:\n";
1198 std::cerr << " " << line << "\n";
1199 datafile.close();
1200 Cleanup();
1201 return false;
1202 }
1203 line = line.substr(pBra + 1, pKet - pBra - 1);
1204 int nValues;
1205 data.str(line);
1206 data >> nValues;
1207 data.clear();
1208 // Mark the vertices belonging to this region.
1209 for (int j = nVertices; j--;) isInRegion[j] = false;
1210 for (int j = 0; j < nElements; ++j) {
1211 if (elements[j].region != index) continue;
1212 for (int k = 0; k <= elements[j].type; ++k) {
1213 isInRegion[elements[j].vertex[k]] = true;
1214 }
1215 }
1216 int ivertex = 0;
1217 double val;
1218 for (int j = 0; j < nValues; ++j) {
1219 // Read the next value.
1220 datafile >> val;
1221 // Find the next vertex belonging to the region.
1222 while (ivertex < nVertices) {
1223 if (isInRegion[ivertex]) break;
1224 ++ivertex;
1225 }
1226 // Check if there is a mismatch between the number of vertices
1227 // and the number of potential values.
1228 if (ivertex >= nVertices) {
1229 std::cerr << m_className << "::LoadData:\n";
1230 std::cerr << " Error reading file " << datafilename << "\n";
1231 std::cerr << " Dataset ElectrostaticPotential:\n";
1232 std::cerr << " More values than vertices in region " << name
1233 << "\n";
1234 datafile.close();
1235 Cleanup();
1236 return false;
1237 }
1238 vertices[ivertex].p = val;
1239 ++fillCount[ivertex];
1240 ++ivertex;
1241 }
1242 hasPotential = true;
1243 } else if (dataset == "ElectricField") {
1244 // Same procedure as for the potential.
1245 std::getline(datafile, line);
1246 std::getline(datafile, line);
1247 std::getline(datafile, line);
1248 std::getline(datafile, line);
1249 pBra = line.find('[');
1250 pKet = line.find(']');
1251 if (pKet < pBra || pBra == std::string::npos ||
1252 pKet == std::string::npos) {
1253 std::cerr << m_className << "::LoadData:\n";
1254 std::cerr << " Error reading file " << datafilename << ".\n";
1255 std::cerr << " Line:\n";
1256 std::cerr << " " << line << "\n";
1257 datafile.close();
1258 Cleanup();
1259 return false;
1260 }
1261 line = line.substr(pBra + 1, pKet - pBra - 1);
1262 std::string name;
1263 data.str(line);
1264 data >> name;
1265 data.clear();
1266 int index = -1;
1267 for (int j = 0; j < nRegions; ++j) {
1268 if (name == regions[j].name) {
1269 index = j;
1270 break;
1271 }
1272 }
1273 if (index == -1) {
1274 std::cerr << m_className << "::LoadData:\n";
1275 std::cerr << " Error reading file " << datafilename << "\n";
1276 std::cerr << " Unknown region " << name << ".\n";
1277 continue;
1278 }
1279 std::getline(datafile, line);
1280 pBra = line.find('(');
1281 pKet = line.find(')');
1282 if (pKet < pBra || pBra == std::string::npos ||
1283 pKet == std::string::npos) {
1284 std::cerr << m_className << "::LoadData\n";
1285 std::cerr << " Error reading file " << datafilename << "\n";
1286 std::cerr << " Line:\n";
1287 std::cerr << " " << line << "\n";
1288 datafile.close();
1289 Cleanup();
1290 return false;
1291 }
1292 line = line.substr(pBra + 1, pKet - pBra - 1);
1293 int nValues;
1294 data.str(line);
1295 data >> nValues;
1296 data.clear();
1297 // In case of the electric field, there are two values per vertex.
1298 nValues = nValues / 2;
1299 for (int j = nVertices; j--;) isInRegion[j] = false;
1300 for (int j = 0; j < nElements; ++j) {
1301 if (elements[j].region != index) continue;
1302 for (int k = 0; k <= elements[j].type; ++k) {
1303 isInRegion[elements[j].vertex[k]] = true;
1304 }
1305 }
1306 int ivertex = 0;
1307 double val1, val2;
1308 for (int j = 0; j < nValues; ++j) {
1309 datafile >> val1 >> val2;
1310 while (ivertex < nVertices) {
1311 if (isInRegion[ivertex]) break;
1312 ++ivertex;
1313 }
1314 if (ivertex >= nVertices) {
1315 std::cerr << m_className << "::LoadData\n"
1316 << " Error reading file " << datafilename << "\n";
1317 std::cerr << " Dataset ElectricField:\n";
1318 std::cerr << " More values than vertices in region " << name
1319 << "\n";
1320 datafile.close();
1321 Cleanup();
1322 return false;
1323 }
1324 vertices[ivertex].ex = val1;
1325 vertices[ivertex].ey = val2;
1326 ++ivertex;
1327 }
1328 hasField = true;
1329 } else if (dataset == "eMobility") {
1330 std::getline(datafile, line);
1331 std::getline(datafile, line);
1332 std::getline(datafile, line);
1333 std::getline(datafile, line);
1334 // Get the region name (given in brackets).
1335 pBra = line.find('[');
1336 pKet = line.find(']');
1337 if (pKet < pBra || pBra == std::string::npos ||
1338 pKet == std::string::npos) {
1339 std::cerr << m_className << "::LoadData:\n";
1340 std::cerr << " Error reading file " << datafilename << "\n";
1341 std::cerr << " Line:\n";
1342 std::cerr << " " << line << "\n";
1343 datafile.close();
1344 Cleanup();
1345 return false;
1346 }
1347 line = line.substr(pBra + 1, pKet - pBra - 1);
1348 std::string name;
1349 data.str(line);
1350 data >> name;
1351 data.clear();
1352 // Check if the region name matches one from the mesh file.
1353 int index = -1;
1354 for (int j = 0; j < nRegions; ++j) {
1355 if (name == regions[j].name) {
1356 index = j;
1357 break;
1358 }
1359 }
1360 if (index == -1) {
1361 std::cerr << m_className << "::LoadData:\n";
1362 std::cerr << " Error reading file " << datafilename << "\n";
1363 std::cerr << " Unknown region " << name << ".\n";
1364 continue;
1365 }
1366 // Get the number of values.
1367 std::getline(datafile, line);
1368 pBra = line.find('(');
1369 pKet = line.find(')');
1370 if (pKet < pBra || pBra == std::string::npos ||
1371 pKet == std::string::npos) {
1372 std::cerr << m_className << "::LoadData:\n";
1373 std::cerr << " Error reading file " << datafilename << "\n";
1374 std::cerr << " Line:\n";
1375 std::cerr << " " << line << "\n";
1376 datafile.close();
1377 Cleanup();
1378 return false;
1379 }
1380 line = line.substr(pBra + 1, pKet - pBra - 1);
1381 int nValues;
1382 data.str(line);
1383 data >> nValues;
1384 data.clear();
1385 // Mark the vertices belonging to this region.
1386 for (int j = nVertices; j--;) isInRegion[j] = false;
1387 for (int j = 0; j < nElements; ++j) {
1388 if (elements[j].region != index) continue;
1389 for (int k = 0; k <= elements[j].type; ++k) {
1390 isInRegion[elements[j].vertex[k]] = true;
1391 }
1392 }
1393 int ivertex = 0;
1394 double val;
1395 for (int j = 0; j < nValues; ++j) {
1396 // Read the next value.
1397 datafile >> val;
1398 // Find the next vertex belonging to the region.
1399 while (ivertex < nVertices) {
1400 if (isInRegion[ivertex]) break;
1401 ++ivertex;
1402 }
1403 // Check if there is a mismatch between the number of vertices
1404 // and the number of mobility values.
1405 if (ivertex >= nVertices) {
1406 std::cerr << m_className << "::LoadData:\n";
1407 std::cerr << " Dataset eMobility:\n";
1408 std::cerr << " More values than vertices in region " << name
1409 << "\n";
1410 datafile.close();
1411 Cleanup();
1412 return false;
1413 }
1414 // Convert from cm2 / (V s) to cm2 / (V ns).
1415 vertices[ivertex].emob = val * 1.e-9;
1416 ++fillCount[ivertex];
1417 ++ivertex;
1418 }
1419 hasElectronMobility = true;
1420 } else if (dataset == "hMobility") {
1421 std::getline(datafile, line);
1422 std::getline(datafile, line);
1423 std::getline(datafile, line);
1424 std::getline(datafile, line);
1425 // Get the region name (given in brackets).
1426 pBra = line.find('[');
1427 pKet = line.find(']');
1428 if (pKet < pBra || pBra == std::string::npos ||
1429 pKet == std::string::npos) {
1430 std::cerr << m_className << "::LoadData:\n";
1431 std::cerr << " Error reading file " << datafilename << "\n";
1432 std::cerr << " Line:\n";
1433 std::cerr << " " << line << "\n";
1434 datafile.close();
1435 Cleanup();
1436 return false;
1437 }
1438 line = line.substr(pBra + 1, pKet - pBra - 1);
1439 std::string name;
1440 data.str(line);
1441 data >> name;
1442 data.clear();
1443 // Check if the region name matches one from the mesh file.
1444 int index = -1;
1445 for (int j = 0; j < nRegions; ++j) {
1446 if (name == regions[j].name) {
1447 index = j;
1448 break;
1449 }
1450 }
1451 if (index == -1) {
1452 std::cerr << m_className << "::LoadData:\n";
1453 std::cerr << " Error reading file " << datafilename << "\n";
1454 std::cerr << " Unknown region " << name << ".\n";
1455 continue;
1456 }
1457 // Get the number of values.
1458 std::getline(datafile, line);
1459 pBra = line.find('(');
1460 pKet = line.find(')');
1461 if (pKet < pBra || pBra == std::string::npos ||
1462 pKet == std::string::npos) {
1463 std::cerr << m_className << "::LoadData:\n";
1464 std::cerr << " Error reading file " << datafilename << "\n";
1465 std::cerr << " Line:\n";
1466 std::cerr << " " << line << "\n";
1467 datafile.close();
1468 Cleanup();
1469 return false;
1470 }
1471 line = line.substr(pBra + 1, pKet - pBra - 1);
1472 int nValues;
1473 data.str(line);
1474 data >> nValues;
1475 data.clear();
1476 // Mark the vertices belonging to this region.
1477 for (int j = nVertices; j--;) isInRegion[j] = false;
1478 for (int j = 0; j < nElements; ++j) {
1479 if (elements[j].region != index) continue;
1480 for (int k = 0; k <= elements[j].type; ++k) {
1481 isInRegion[elements[j].vertex[k]] = true;
1482 }
1483 }
1484 int ivertex = 0;
1485 double val;
1486 for (int j = 0; j < nValues; ++j) {
1487 // Read the next value.
1488 datafile >> val;
1489 // Find the next vertex belonging to the region.
1490 while (ivertex < nVertices) {
1491 if (isInRegion[ivertex]) break;
1492 ++ivertex;
1493 }
1494 // Check if there is a mismatch between the number of vertices
1495 // and the number of mobility values.
1496 if (ivertex >= nVertices) {
1497 std::cerr << m_className << "::LoadData:\n";
1498 std::cerr << " Dataset hMobility:\n";
1499 std::cerr << " More values than vertices in region " << name
1500 << "\n";
1501 datafile.close();
1502 Cleanup();
1503 return false;
1504 }
1505 // Convert from cm2 / (V s) to cm2 / (V ns).
1506 vertices[ivertex].hmob = val * 1.e-9;
1507 ++fillCount[ivertex];
1508 ++ivertex;
1509 }
1510 hasHoleMobility = true;
1511 }
1512 }
1513 }
1514 if (datafile.fail() && !datafile.eof()) {
1515 std::cerr << m_className << "::LoadData\n";
1516 std::cerr << " Error reading file " << datafilename << "\n";
1517 datafile.close();
1518 Cleanup();
1519 return false;
1520 }
1521
1522 for (int i = nVertices; i--;) {
1523 if (fillCount[i] > 1) vertices[i].isShared = true;
1524 }
1525
1526 datafile.close();
1527
1528 return true;
1529}
1530
1531bool ComponentTcad2d::LoadGrid(const std::string gridfilename) {
1532
1533 // Open the file containing the mesh description.
1534 std::ifstream gridfile;
1535 gridfile.open(gridfilename.c_str(), std::ios::in);
1536 if (!gridfile) {
1537 std::cerr << m_className << "::LoadGrid:\n";
1538 std::cerr << " Could not open file " << gridfilename << ".\n";
1539 return false;
1540 }
1541
1542 std::string line;
1543 std::istringstream data;
1544
1545 // Delete existing mesh information.
1546 Cleanup();
1547 std::string::size_type pBra, pKet, pEq;
1548 // Count line numbers.
1549 int iLine = 0;
1550
1551 // Get the number of regions.
1552 while (!gridfile.fail()) {
1553 // Read one line.
1554 std::getline(gridfile, line);
1555 ++iLine;
1556 // Strip white space from the beginning of the line.
1557 line.erase(line.begin(), find_if(line.begin(), line.end(),
1558 not1(std::ptr_fun<int, int>(isspace))));
1559 // Find entry 'nb_regions'.
1560 if (line.substr(0, 10) == "nb_regions") {
1561 pEq = line.find('=');
1562 if (pEq == std::string::npos) {
1563 // No "=" sign found.
1564 std::cerr << m_className << "::LoadGrid:\n";
1565 std::cerr << " Could not read number of regions.\n";
1566 Cleanup();
1567 gridfile.close();
1568 return false;
1569 }
1570 line = line.substr(pEq + 1);
1571 data.str(line);
1572 data >> nRegions;
1573 data.clear();
1574 break;
1575 }
1576 if (gridfile.fail()) break;
1577 }
1578 if (gridfile.eof()) {
1579 // Reached end of file.
1580 std::cerr << m_className << "::LoadGrid:\n";
1581 std::cerr << " Could not find entry 'nb_regions' in file\n";
1582 std::cerr << " " << gridfilename << ".\n";
1583 Cleanup();
1584 gridfile.close();
1585 return false;
1586 } else if (gridfile.fail()) {
1587 // Error reading from the file.
1588 std::cerr << m_className << "::LoadGrid:\n";
1589 std::cerr << " Error reading file " << gridfilename << " (line " << iLine
1590 << ").\n";
1591 Cleanup();
1592 gridfile.close();
1593 return false;
1594 }
1595 regions.resize(nRegions);
1596 for (int j = nRegions; j--;) {
1597 regions[j].name = "";
1598 regions[j].drift = false;
1599 regions[j].medium = 0;
1600 }
1601
1602 if (debug) {
1603 std::cout << m_className << "::LoadGrid:\n";
1604 std::cout << " Found " << nRegions << " regions.\n";
1605 }
1606
1607 // Get the region names.
1608 while (!gridfile.fail()) {
1609 std::getline(gridfile, line);
1610 ++iLine;
1611 line.erase(line.begin(), find_if(line.begin(), line.end(),
1612 not1(std::ptr_fun<int, int>(isspace))));
1613 // Find entry 'regions'.
1614 if (line.substr(0, 7) == "regions") {
1615 // Get region names (given in brackets).
1616 pBra = line.find('[');
1617 pKet = line.find(']');
1618 if (pKet < pBra || pBra == std::string::npos ||
1619 pKet == std::string::npos) {
1620 // No closed brackets [].
1621 std::cerr << m_className << "::LoadGrid:\n";
1622 std::cerr << " Could not read region names.\n";
1623 Cleanup();
1624 gridfile.close();
1625 return false;
1626 }
1627 line = line.substr(pBra + 1, pKet - pBra - 1);
1628 data.str(line);
1629 for (int j = 0; j < nRegions; ++j) {
1630 data >> regions[j].name;
1631 data.clear();
1632 // Assume by default that all regions are active.
1633 regions[j].drift = true;
1634 regions[j].medium = 0;
1635 }
1636 break;
1637 }
1638 }
1639 if (gridfile.eof()) {
1640 // Reached end of file.
1641 std::cerr << m_className << "::LoadGrid:\n";
1642 std::cerr << " Could not find entry 'regions' in file\n";
1643 std::cerr << " " << gridfilename << ".\n";
1644 Cleanup();
1645 gridfile.close();
1646 return false;
1647 } else if (gridfile.fail()) {
1648 // Error reading from the file.
1649 std::cerr << m_className << "::LoadGrid:\n";
1650 std::cerr << " Error reading file " << gridfilename << " (line " << iLine
1651 << ").\n";
1652 Cleanup();
1653 gridfile.close();
1654 return false;
1655 }
1656
1657 // Get the vertices.
1658 while (!gridfile.fail()) {
1659 std::getline(gridfile, line);
1660 ++iLine;
1661 line.erase(line.begin(), find_if(line.begin(), line.end(),
1662 not1(std::ptr_fun<int, int>(isspace))));
1663 // Find section 'Vertices'.
1664 if (line.substr(0, 8) == "Vertices") {
1665 // Get number of vertices (given in brackets).
1666 pBra = line.find('(');
1667 pKet = line.find(')');
1668 if (pKet < pBra || pBra == std::string::npos ||
1669 pKet == std::string::npos) {
1670 // No closed brackets [].
1671 std::cerr << m_className << "::LoadGrid:\n";
1672 std::cerr << " Could not read number of vertices.\n";
1673 Cleanup();
1674 gridfile.close();
1675 return false;
1676 }
1677 line = line.substr(pBra + 1, pKet - pBra - 1);
1678 data.str(line);
1679 data >> nVertices;
1680 data.clear();
1681 vertices.resize(nVertices);
1682 // Get the coordinates of this vertex.
1683 for (int j = 0; j < nVertices; ++j) {
1684 gridfile >> vertices[j].x >> vertices[j].y;
1685 // Change units from micron to cm.
1686 vertices[j].x *= 1.e-4;
1687 vertices[j].y *= 1.e-4;
1688 ++iLine;
1689 }
1690 break;
1691 }
1692 }
1693 if (gridfile.eof()) {
1694 std::cerr << m_className << "::LoadGrid:\n";
1695 std::cerr << " Could not find section 'Vertices' in file\n";
1696 std::cerr << " " << gridfilename << ".\n";
1697 Cleanup();
1698 gridfile.close();
1699 return false;
1700 } else if (gridfile.fail()) {
1701 std::cerr << m_className << "::LoadGrid:\n";
1702 std::cerr << " Error reading file " << gridfilename << " (line " << iLine
1703 << ").\n";
1704 Cleanup();
1705 gridfile.close();
1706 return false;
1707 }
1708
1709 // Get the "edges" (lines connecting two vertices).
1710 int nEdges = 0;
1711 // Temporary arrays for storing edge points.
1712 std::vector<int> edgeP1;
1713 edgeP1.clear();
1714 std::vector<int> edgeP2;
1715 edgeP2.clear();
1716 while (!gridfile.fail()) {
1717 std::getline(gridfile, line);
1718 ++iLine;
1719 line.erase(line.begin(), find_if(line.begin(), line.end(),
1720 not1(std::ptr_fun<int, int>(isspace))));
1721 // Find section 'Edges'.
1722 if (line.substr(0, 5) == "Edges") {
1723 // Get the number of edges (given in brackets).
1724 pBra = line.find('(');
1725 pKet = line.find(')');
1726 if (pKet < pBra || pBra == std::string::npos ||
1727 pKet == std::string::npos) {
1728 // No closed brackets ()
1729 std::cerr << m_className << "::LoadGrid:\n";
1730 std::cerr << " Could not read number of edges.\n";
1731 Cleanup();
1732 gridfile.close();
1733 return false;
1734 }
1735 line = line.substr(pBra + 1, pKet - pBra - 1);
1736 data.str(line);
1737 data >> nEdges;
1738 data.clear();
1739 edgeP1.resize(nEdges);
1740 edgeP2.resize(nEdges);
1741 // Get the indices of the two endpoints.
1742 for (int j = 0; j < nEdges; ++j) {
1743 gridfile >> edgeP1[j] >> edgeP2[j];
1744 ++iLine;
1745 }
1746 break;
1747 }
1748 }
1749 if (gridfile.eof()) {
1750 std::cerr << m_className << "::LoadGrid:\n";
1751 std::cerr << " Could not find section 'Edges' in file\n";
1752 std::cerr << " " << gridfilename << ".\n";
1753 Cleanup();
1754 gridfile.close();
1755 return false;
1756 } else if (gridfile.fail()) {
1757 std::cerr << m_className << "::LoadGrid:\n";
1758 std::cerr << " Error reading file " << gridfilename << " (line " << iLine
1759 << ").\n";
1760 Cleanup();
1761 gridfile.close();
1762 return false;
1763 }
1764
1765 for (int i = nEdges; i--;) {
1766 // Make sure the indices of the edge endpoints are not out of range.
1767 if (edgeP1[i] < 0 || edgeP1[i] >= nVertices || edgeP2[i] < 0 ||
1768 edgeP2[i] >= nVertices) {
1769 std::cerr << m_className << "::LoadGrid:\n";
1770 std::cerr << " Vertex index of edge " << i << " out of range.\n";
1771 Cleanup();
1772 gridfile.close();
1773 return false;
1774 }
1775 // Make sure the edge is non-degenerate.
1776 if (edgeP1[i] == edgeP2[i]) {
1777 std::cerr << m_className << "::LoadGrid:\n";
1778 std::cerr << " Edge " << i << " is degenerate.\n";
1779 Cleanup();
1780 gridfile.close();
1781 return false;
1782 }
1783 }
1784
1785 // Get the elements.
1786 int edge0, edge1, edge2, edge3;
1787 int type;
1788 while (!gridfile.fail()) {
1789 std::getline(gridfile, line);
1790 ++iLine;
1791 line.erase(line.begin(), find_if(line.begin(), line.end(),
1792 not1(std::ptr_fun<int, int>(isspace))));
1793 // Find section 'Elements'.
1794 if (line.substr(0, 8) == "Elements") {
1795 // Get number of elements (given in brackets).
1796 pBra = line.find('(');
1797 pKet = line.find(')');
1798 if (pKet < pBra || pBra == std::string::npos ||
1799 pKet == std::string::npos) {
1800 // No closed brackets ().
1801 std::cerr << m_className << "::LoadGrid:\n";
1802 std::cerr << " Could not read number of elements.\n";
1803 Cleanup();
1804 gridfile.close();
1805 return false;
1806 }
1807 line = line.substr(pBra + 1, pKet - pBra - 1);
1808 data.str(line);
1809 data >> nElements;
1810 data.clear();
1811 // Resize array of elements.
1812 elements.resize(nElements);
1813 // Get type and constituting edges of each element.
1814 for (int j = 0; j < nElements; ++j) {
1815 for (int k = nMaxVertices; k--;) elements[j].vertex[k] = -1;
1816 elements[j].nNeighbours = 0;
1817 elements[j].neighbours.clear();
1818 ++iLine;
1819 gridfile >> type;
1820 switch (type) {
1821 case 1:
1822 // Line
1823 gridfile >> edge0 >> edge1;
1824 if (edge0 < 0) edge0 = -edge0 - 1;
1825 if (edge1 < 0) edge1 = -edge1 - 1;
1826 // Make sure the indices are not out of range.
1827 if (edge0 >= nEdges || edge1 >= nEdges) {
1828 std::cerr << m_className << "::LoadGrid:\n";
1829 std::cerr << " Error reading file " << gridfilename
1830 << " (line " << iLine << ").\n";
1831 std::cerr << " Edge index out of range.\n";
1832 Cleanup();
1833 gridfile.close();
1834 return false;
1835 }
1836 // Get the vertices of this element.
1837 // Negative edge index means that the sequence of the two points
1838 // is supposed to be inverted.
1839 // The actual index is then given by "-index - 1".
1840 // Orientt the line such that the first point is on the left.
1841 if (vertices[edgeP1[edge0]].x > vertices[edgeP2[edge0]].x) {
1842 elements[j].vertex[0] = edgeP2[edge0];
1843 elements[j].vertex[1] = edgeP1[edge0];
1844 } else {
1845 elements[j].vertex[0] = edgeP1[edge0];
1846 elements[j].vertex[1] = edgeP2[edge0];
1847 }
1848 break;
1849 case 2:
1850 // Triangle
1851 gridfile >> edge0 >> edge1 >> edge2;
1852 // Make sure the indices are not out of range.
1853 if (edge0 < 0) edge0 = -edge0 - 1;
1854 if (edge1 < 0) edge1 = -edge1 - 1;
1855 if (edge2 < 0) edge2 = -edge2 - 1;
1856 if (edge0 >= nEdges || edge1 >= nEdges || edge2 >= nEdges) {
1857 std::cerr << m_className << "::LoadGrid:\n";
1858 std::cerr << " Error reading file " << gridfilename
1859 << " (line " << iLine << ").\n";
1860 std::cerr << " Edge index out of range.\n";
1861 Cleanup();
1862 gridfile.close();
1863 return false;
1864 }
1865 elements[j].vertex[0] = edgeP1[edge0];
1866 elements[j].vertex[1] = edgeP2[edge0];
1867 if (edgeP1[edge1] != elements[j].vertex[0] &&
1868 edgeP1[edge1] != elements[j].vertex[1]) {
1869 elements[j].vertex[2] = edgeP1[edge1];
1870 } else {
1871 elements[j].vertex[2] = edgeP2[edge1];
1872 }
1873 // Rearrange vertices such that point 0 is on the left.
1874 while (vertices[elements[j].vertex[0]].x >
1875 vertices[elements[j].vertex[1]].x ||
1876 vertices[elements[j].vertex[0]].x >
1877 vertices[elements[j].vertex[2]].x) {
1878 const int tmp = elements[j].vertex[0];
1879 elements[j].vertex[0] = elements[j].vertex[1];
1880 elements[j].vertex[1] = elements[j].vertex[2];
1881 elements[j].vertex[2] = tmp;
1882 }
1883 break;
1884 case 3:
1885 // Rectangle
1886 gridfile >> edge0 >> edge1 >> edge2 >> edge3;
1887 // Make sure the indices are not out of range.
1888 if (edge0 >= nEdges || -edge0 - 1 >= nEdges || edge1 >= nEdges ||
1889 -edge1 - 1 >= nEdges || edge2 >= nEdges ||
1890 -edge2 - 1 >= nEdges || edge3 >= nEdges ||
1891 -edge3 - 1 >= nEdges) {
1892 std::cerr << m_className << "::LoadGrid:\n";
1893 std::cerr << " Error reading file " << gridfilename
1894 << " (line " << iLine << ").\n";
1895 std::cerr << " Edge index out of range.\n";
1896 Cleanup();
1897 gridfile.close();
1898 return false;
1899 }
1900 if (edge0 >= 0)
1901 elements[j].vertex[0] = edgeP1[edge0];
1902 else
1903 elements[j].vertex[0] = edgeP2[-edge0 - 1];
1904 if (edge1 >= 0)
1905 elements[j].vertex[1] = edgeP1[edge1];
1906 else
1907 elements[j].vertex[1] = edgeP2[-edge1 - 1];
1908 if (edge2 >= 0)
1909 elements[j].vertex[2] = edgeP1[edge2];
1910 else
1911 elements[j].vertex[2] = edgeP2[-edge2 - 1];
1912 if (edge3 >= 0)
1913 elements[j].vertex[3] = edgeP1[edge3];
1914 else
1915 elements[j].vertex[3] = edgeP2[-edge3 - 1];
1916
1917 // Rearrange vertices such that point 0 is on the left.
1918 while (vertices[elements[j].vertex[0]].x >
1919 vertices[elements[j].vertex[1]].x ||
1920 vertices[elements[j].vertex[0]].x >
1921 vertices[elements[j].vertex[2]].x ||
1922 vertices[elements[j].vertex[0]].x >
1923 vertices[elements[j].vertex[3]].x) {
1924 const int tmp = elements[j].vertex[0];
1925 elements[j].vertex[0] = elements[j].vertex[1];
1926 elements[j].vertex[1] = elements[j].vertex[2];
1927 elements[j].vertex[2] = elements[j].vertex[3];
1928 elements[j].vertex[3] = tmp;
1929 }
1930 break;
1931 default:
1932 // Other element types are not permitted for 2d grids.
1933 std::cerr << m_className << "::LoadGrid:\n"
1934 << " Error reading file " << gridfilename << " (line "
1935 << iLine << ").\n";
1936 std::cerr << " Invalid element type (" << type
1937 << ") for 2d mesh.\n";
1938 Cleanup();
1939 gridfile.close();
1940 return false;
1941 break;
1942 }
1943 elements[j].type = type;
1944 elements[j].region = -1;
1945 }
1946 break;
1947 }
1948 }
1949 if (gridfile.eof()) {
1950 std::cerr << m_className << "::LoadGrid:\n";
1951 std::cerr << " Could not find section 'Elements' in file\n";
1952 std::cerr << " " << gridfilename << ".\n";
1953 Cleanup();
1954 gridfile.close();
1955 return false;
1956 } else if (gridfile.fail()) {
1957 std::cerr << m_className << "::LoadGrid:\n";
1958 std::cerr << " Error reading file " << gridfilename << " (line " << iLine
1959 << ").\n";
1960 Cleanup();
1961 gridfile.close();
1962 return false;
1963 }
1964
1965 // Assign regions to elements.
1966 std::string name;
1967 while (!gridfile.fail()) {
1968 std::getline(gridfile, line);
1969 line.erase(line.begin(), find_if(line.begin(), line.end(),
1970 not1(std::ptr_fun<int, int>(isspace))));
1971 // Find section 'Region'.
1972 if (line.substr(0, 6) == "Region") {
1973 // Get region name (given in brackets).
1974 pBra = line.find('(');
1975 pKet = line.find(')');
1976 if (pKet < pBra || pBra == std::string::npos ||
1977 pKet == std::string::npos) {
1978 std::cerr << m_className << "::LoadGrid:\n";
1979 std::cerr << " Could not read region name.\n";
1980 Cleanup();
1981 gridfile.close();
1982 return false;
1983 }
1984 line = line.substr(pBra + 1, pKet - pBra - 1);
1985 data.str(line);
1986 data >> name;
1987 data.clear();
1988 int index = -1;
1989 for (int j = 0; j < nRegions; ++j) {
1990 if (name == regions[j].name) {
1991 index = j;
1992 break;
1993 }
1994 }
1995 if (index == -1) {
1996 // Specified region name is not in the list.
1997 std::cerr << m_className << "::LoadGrid:\n";
1998 std::cerr << " Error reading file " << gridfilename << ".\n";
1999 std::cerr << " Unknown region " << name << ".\n";
2000 continue;
2001 }
2002 std::getline(gridfile, line);
2003 std::getline(gridfile, line);
2004 pBra = line.find('(');
2005 pKet = line.find(')');
2006 if (pKet < pBra || pBra == std::string::npos ||
2007 pKet == std::string::npos) {
2008 // No closed brackets ().
2009 std::cerr << m_className << "::LoadGrid:\n";
2010 std::cerr << " Error reading file " << gridfilename << ".\n";
2011 std::cerr << " Could not read number of elements in region " << name
2012 << ".\n";
2013 Cleanup();
2014 gridfile.close();
2015 return false;
2016 }
2017 line = line.substr(pBra + 1, pKet - pBra - 1);
2018 int nElementsRegion;
2019 int iElement;
2020 data.str(line);
2021 data >> nElementsRegion;
2022 data.clear();
2023 for (int j = 0; j < nElementsRegion; ++j) {
2024 gridfile >> iElement;
2025 elements[iElement].region = index;
2026 }
2027 }
2028 }
2029
2030 gridfile.close();
2031 if (gridfile.fail() && !gridfile.eof()) {
2032 std::cerr << m_className << "::LoadGrid:\n";
2033 std::cerr << " Error reading file " << gridfilename << ".\n";
2034 Cleanup();
2035 return false;
2036 }
2037
2038 return true;
2039}
2040
2041void ComponentTcad2d::FindNeighbours() {
2042
2043 std::vector<std::vector<bool> > adjacent;
2044 adjacent.resize(nElements);
2045 for (int i = nElements; i--;) {
2046 adjacent[i].resize(nElements);
2047 for (int j = nElements; j--;) {
2048 adjacent[i][j] = false;
2049 }
2050 }
2051
2052 for (int i = nElements; i--;) {
2053 for (int m = nMaxVertices; m--;) {
2054 if (elements[i].vertex[m] < 0) continue;
2055 for (int j = nElements; j--;) {
2056 if (i == j || adjacent[i][j]) continue;
2057 for (int n = nMaxVertices; n--;) {
2058 if (elements[i].vertex[m] == elements[j].vertex[n]) {
2059 adjacent[i][j] = true;
2060 break;
2061 }
2062 }
2063 }
2064 }
2065 }
2066
2067 for (int i = nElements; i--;) {
2068 elements[i].nNeighbours = 0;
2069 elements[i].neighbours.clear();
2070 for (int j = nElements; j--;) {
2071 if (adjacent[i][j]) {
2072 elements[i].neighbours.push_back(j);
2073 elements[i].nNeighbours += 1;
2074 }
2075 }
2076 }
2077}
2078
2079void ComponentTcad2d::Cleanup() {
2080
2081 // Vertices
2082 vertices.clear();
2083 nVertices = 0;
2084
2085 // Elements
2086 elements.clear();
2087 nElements = 0;
2088
2089 // Regions
2090 regions.clear();
2091 nRegions = 0;
2092}
2093
2094bool ComponentTcad2d::CheckRectangle(const double x, const double y,
2095 const int i) {
2096
2097 if (y < vertices[elements[i].vertex[0]].y ||
2098 x > vertices[elements[i].vertex[3]].x ||
2099 y > vertices[elements[i].vertex[1]].y) {
2100 return false;
2101 }
2102
2103 // Map (x, y) to local variables (u, v) in [-1, 1].
2104 const double u =
2105 (x - 0.5 * (vertices[elements[i].vertex[0]].x +
2106 vertices[elements[i].vertex[3]].x)) /
2107 (vertices[elements[i].vertex[3]].x - vertices[elements[i].vertex[0]].x);
2108 const double v =
2109 (y - 0.5 * (vertices[elements[i].vertex[0]].y +
2110 vertices[elements[i].vertex[1]].y)) /
2111 (vertices[elements[i].vertex[1]].y - vertices[elements[i].vertex[0]].y);
2112 // Compute weighting factors for each corner.
2113 w[0] = (0.5 - u) * (0.5 - v);
2114 w[1] = (0.5 - u) * (0.5 + v);
2115 w[2] = (0.5 + u) * (0.5 + v);
2116 w[3] = (0.5 + u) * (0.5 - v);
2117
2118 return true;
2119}
2120
2121bool ComponentTcad2d::CheckTriangle(const double x, const double y,
2122 const int i) {
2123
2124 if (x > vertices[elements[i].vertex[1]].x &&
2125 x > vertices[elements[i].vertex[2]].x)
2126 return false;
2127 if (y < vertices[elements[i].vertex[0]].y &&
2128 y < vertices[elements[i].vertex[1]].y &&
2129 y < vertices[elements[i].vertex[2]].y)
2130 return false;
2131 if (y > vertices[elements[i].vertex[0]].y &&
2132 y > vertices[elements[i].vertex[1]].y &&
2133 y > vertices[elements[i].vertex[2]].y)
2134 return false;
2135
2136 // Map (x, y) onto local variables (b, c) such that
2137 // P = A + b * (B - A) + c * (C - A)
2138 // A point P is inside the triangle ABC if b, c > 0 and b + c < 1;
2139 // b, c are also weighting factors for points B, C
2140 const double v1x =
2141 vertices[elements[i].vertex[1]].x - vertices[elements[i].vertex[0]].x;
2142 const double v1y =
2143 vertices[elements[i].vertex[1]].y - vertices[elements[i].vertex[0]].y;
2144 const double v2x =
2145 vertices[elements[i].vertex[2]].x - vertices[elements[i].vertex[0]].x;
2146 const double v2y =
2147 vertices[elements[i].vertex[2]].y - vertices[elements[i].vertex[0]].y;
2148
2149 w[1] = ((x - vertices[elements[i].vertex[0]].x) * v2y -
2150 (y - vertices[elements[i].vertex[0]].y) * v2x) /
2151 (v1x * v2y - v1y * v2x);
2152 if (w[1] < 0. || w[1] > 1.) return false;
2153
2154 w[2] = ((vertices[elements[i].vertex[0]].x - x) * v1y -
2155 (vertices[elements[i].vertex[0]].y - y) * v1x) /
2156 (v1x * v2y - v1y * v2x);
2157 if (w[2] < 0. || w[1] + w[2] > 1.) return false;
2158
2159 // Weighting factor for point A
2160 w[0] = 1. - w[1] - w[2];
2161
2162 return true;
2163}
2164
2165bool ComponentTcad2d::CheckLine(const double x, const double y, const int i) {
2166
2167 if (x > vertices[elements[i].vertex[1]].x) return false;
2168 if (y < vertices[elements[i].vertex[0]].y &&
2169 y < vertices[elements[i].vertex[1]].y)
2170 return false;
2171 if (y > vertices[elements[i].vertex[0]].y &&
2172 y > vertices[elements[i].vertex[1]].y)
2173 return false;
2174 const double v1x =
2175 vertices[elements[i].vertex[1]].x - vertices[elements[i].vertex[0]].x;
2176 const double v1y =
2177 vertices[elements[i].vertex[1]].y - vertices[elements[i].vertex[0]].y;
2178 const double tx = (x - vertices[elements[i].vertex[0]].x) / v1x;
2179 if (tx < 0. || tx > 1.) return false;
2180 const double ty = (y - vertices[elements[i].vertex[0]].y) / v1y;
2181 if (ty < 0. || ty > 1.) return false;
2182 if (tx == ty) {
2183 // Compute weighting factors for endpoints A, B
2184 w[0] = tx;
2185 w[1] = 1. - w[0];
2186 return true;
2187 }
2188 return false;
2189}
2190
2191void ComponentTcad2d::Reset() {
2192
2193 Cleanup();
2194 hasRangeZ = false;
2195 ready = false;
2196}
2197
2198void ComponentTcad2d::UpdatePeriodicity() {
2199
2200 if (!ready) {
2201 std::cerr << m_className << "::UpdatePeriodicity:\n";
2202 std::cerr << " Field map not available.\n";
2203 return;
2204 }
2205
2206 // Check for conflicts.
2207 if (xPeriodic && xMirrorPeriodic) {
2208 std::cerr << m_className << "::UpdatePeriodicity:\n";
2209 std::cerr << " Both simple and mirror periodicity\n";
2210 std::cerr << " along x requested; reset.\n";
2211 xPeriodic = xMirrorPeriodic = false;
2212 }
2213
2214 if (yPeriodic && yMirrorPeriodic) {
2215 std::cerr << m_className << "::UpdatePeriodicity:\n";
2216 std::cerr << " Both simple and mirror periodicity\n";
2217 std::cerr << " along y requested; reset.\n";
2218 yPeriodic = yMirrorPeriodic = false;
2219 }
2220
2221 if (zPeriodic || zMirrorPeriodic) {
2222 std::cerr << m_className << "::UpdatePeriodicity:\n";
2223 std::cerr << " Periodicity along z requested; reset.\n";
2224 zPeriodic = zMirrorPeriodic = false;
2225 }
2226
2228 std::cerr << m_className << "::UpdatePeriodicity:\n";
2229 std::cerr << " Axial symmetry is not supported; reset.\n";
2231 }
2232
2234 std::cerr << m_className << "::UpdatePeriodicity:\n";
2235 std::cerr << " Rotation symmetry is not supported; reset.\n";
2237 }
2238}
2239}
DoubleAc pow(const DoubleAc &f, double p)
Definition: DoubleAc.cpp:336
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:313
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:616
bool GetNode(const int i, double &x, double &y, double &v, double &ex, double &ey)
void SetDriftRegion(const int ireg)
void UnsetDriftRegion(const int ireg)
void SetMedium(const int ireg, Medium *m)
bool GetElement(const int i, double &vol, double &dmin, double &dmax, int &type)
bool GetVoltageRange(double &vmin, double &vmax)
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
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)
void SetRangeZ(const double zmin, const double zmax)
Medium * GetMedium(const double &x, const double &y, const double &z)
void GetRegion(const int i, std::string &name, bool &active)
bool GetMobility(const double x, const double y, const double z, double &emob, double &hmob)