Garfield++ 3.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
ComponentAnsys123.cc
Go to the documentation of this file.
1#include <math.h>
2#include <stdlib.h>
3#include <fstream>
4#include <iostream>
5
7
8namespace Garfield {
9
11 m_className = "ComponentAnsys123";
12}
13
14bool ComponentAnsys123::Initialise(std::string elist, std::string nlist,
15 std::string mplist, std::string prnsol,
16 std::string unit) {
17 m_ready = false;
18 m_warning = false;
19 m_nWarnings = 10;
20 // Keep track of the success.
21 bool ok = true;
22
23 // Buffer for reading
24 const int size = 100;
25 char line[size];
26
27 // Open the material list.
28 std::ifstream fmplist;
29 fmplist.open(mplist.c_str(), std::ios::in);
30 if (fmplist.fail()) {
31 std::cerr << m_className << "::Initialise:\n";
32 std::cerr << " Could not open material file " << mplist
33 << " for reading.\n",
34 std::cerr << " The file perhaps does not exist.\n";
35 return false;
36 }
37
38 // Read the material list.
39 m_nMaterials = 0;
40 long il = 0;
41 unsigned int icurrmat = 0;
42 bool readerror = false;
43 while (fmplist.getline(line, size, '\n')) {
44 il++;
45 // Skip page feed
46 if (strcmp(line, "1") == 0) {
47 fmplist.getline(line, size, '\n');
48 il++;
49 fmplist.getline(line, size, '\n');
50 il++;
51 fmplist.getline(line, size, '\n');
52 il++;
53 fmplist.getline(line, size, '\n');
54 il++;
55 fmplist.getline(line, size, '\n');
56 il++;
57 continue;
58 }
59 // Split the line in tokens
60 char* token = NULL;
61 token = strtok(line, " ");
62 // Skip blank lines and headers
63 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
64 strcmp(token, "TEMPERATURE") == 0 || strcmp(token, "PROPERTY=") == 0 ||
65 int(token[0]) == 10 || int(token[0]) == 13)
66 continue;
67 // Read number of materials,
68 // ensure it does not exceed the maximum and initialise the list
69 if (strcmp(token, "LIST") == 0) {
70 token = strtok(NULL, " ");
71 token = strtok(NULL, " ");
72 token = strtok(NULL, " ");
73 token = strtok(NULL, " ");
74 m_nMaterials = ReadInteger(token, -1, readerror);
75 if (readerror) {
76 std::cerr << m_className << "::Initialise:\n";
77 std::cerr << " Error reading file " << mplist << " (line " << il
78 << ").\n";
79 fmplist.close();
80 ok = false;
81 return false;
82 }
83 materials.resize(m_nMaterials);
84 for (unsigned int i = 0; i < m_nMaterials; ++i) {
85 materials[i].ohm = -1;
86 materials[i].eps = -1;
87 materials[i].medium = nullptr;
88 }
89 if (m_debug) {
90 std::cout << m_className << "::Initialise:\n";
91 std::cout << " Number of materials: " << m_nMaterials << "\n";
92 }
93 } else if (strcmp(token, "MATERIAL") == 0) {
94 // Version 12 format: read material number
95 token = strtok(NULL, " ");
96 token = strtok(NULL, " ");
97 const int imat = ReadInteger(token, -1, readerror);
98 if (readerror || imat < 0) {
99 std::cerr << m_className << "::Initialise:\n";
100 std::cerr << " Error reading file " << mplist << " (line " << il
101 << ").\n";
102 fmplist.close();
103 ok = false;
104 return false;
105 }
106 icurrmat = imat;
107 } else if (strcmp(token, "TEMP") == 0) {
108 // Version 12 format: read property tag and value
109 token = strtok(NULL, " ");
110 int itype = 0;
111 if (strncmp(token, "PERX", 4) == 0) {
112 itype = 1;
113 } else if (strncmp(token, "RSVX", 4) == 0) {
114 itype = 2;
115 } else {
116 std::cerr << m_className << "::Initialise:\n";
117 std::cerr << " Found unknown material property flag " << token
118 << "\n";
119 std::cerr << " on material properties file " << mplist << " (line "
120 << il << ").\n";
121 ok = false;
122 }
123 fmplist.getline(line, size, '\n');
124 il++;
125 token = NULL;
126 token = strtok(line, " ");
127 if (icurrmat < 1 || icurrmat > m_nMaterials) {
128 std::cerr << m_className << "::Initialise:\n";
129 std::cerr << " Found out-of-range current material index "
130 << icurrmat << "\n";
131 std::cerr << " in material properties file " << mplist << ".\n";
132 ok = false;
133 readerror = false;
134 } else if (itype == 1) {
135 materials[icurrmat - 1].eps = ReadDouble(token, -1, readerror);
136 } else if (itype == 2) {
137 materials[icurrmat - 1].ohm = ReadDouble(token, -1, readerror);
138 }
139 if (readerror) {
140 std::cerr << m_className << "::Initialise:\n";
141 std::cerr << " Error reading file " << mplist << " line " << il
142 << ").\n";
143 fmplist.close();
144 ok = false;
145 return false;
146 }
147 } else if (strcmp(token, "PROPERTY") == 0) {
148 // Version 11 format
149 token = strtok(NULL, " ");
150 token = strtok(NULL, " ");
151 int itype = 0;
152 if (strcmp(token, "PERX") == 0) {
153 itype = 1;
154 } else if (strcmp(token, "RSVX") == 0) {
155 itype = 2;
156 } else {
157 std::cerr << m_className << "::Initialise:\n";
158 std::cerr << " Found unknown material property flag " << token
159 << "\n";
160 std::cerr << " on material properties file " << mplist << " (line "
161 << il << ").\n";
162 ok = false;
163 }
164 token = strtok(NULL, " ");
165 token = strtok(NULL, " ");
166 int imat = ReadInteger(token, -1, readerror);
167 if (readerror) {
168 std::cerr << m_className << "::Initialise:\n";
169 std::cerr << " Error reading file " << mplist << " (line " << il
170 << ").\n";
171 fmplist.close();
172 ok = false;
173 return false;
174 } else if (imat < 1 || imat > (int)m_nMaterials) {
175 std::cerr << m_className << "::Initialise:\n";
176 std::cerr << " Found out-of-range material index " << imat << "\n";
177 std::cerr << " in material properties file " << mplist << ".\n";
178 ok = false;
179 } else {
180 fmplist.getline(line, size, '\n');
181 il++;
182 fmplist.getline(line, size, '\n');
183 il++;
184 token = NULL;
185 token = strtok(line, " ");
186 token = strtok(NULL, " ");
187 if (itype == 1) {
188 materials[imat - 1].eps = ReadDouble(token, -1, readerror);
189 } else if (itype == 2) {
190 materials[imat - 1].ohm = ReadDouble(token, -1, readerror);
191 }
192 if (readerror) {
193 std::cerr << m_className << "::Initialise:\n";
194 std::cerr << " Error reading file " << mplist << " (line " << il
195 << ").\n";
196 fmplist.close();
197 ok = false;
198 return false;
199 }
200 }
201 }
202 }
203
204 // Close the file
205 fmplist.close();
206
207 // Find the lowest epsilon, check for eps = 0, set default drift media
208 double epsmin = -1;
209 unsigned int iepsmin = 0;
210 for (unsigned int imat = 0; imat < m_nMaterials; ++imat) {
211 if (materials[imat].eps < 0) continue;
212 if (materials[imat].eps == 0) {
213 std::cerr << m_className << "::Initialise:\n";
214 std::cerr << " Material " << imat
215 << " has been assigned a permittivity\n";
216 std::cerr << " equal to zero in " << mplist << ".\n";
217 ok = false;
218 } else if (epsmin < 0. || epsmin > materials[imat].eps) {
219 epsmin = materials[imat].eps;
220 iepsmin = imat;
221 }
222 }
223
224 if (epsmin < 0.) {
225 std::cerr << m_className << "::Initialise:\n";
226 std::cerr << " No material with positive permittivity found \n";
227 std::cerr << " in material list " << mplist << ".\n";
228 ok = false;
229 } else {
230 for (unsigned int imat = 0; imat < m_nMaterials; ++imat) {
231 if (imat == iepsmin) {
232 materials[imat].driftmedium = true;
233 } else {
234 materials[imat].driftmedium = false;
235 }
236 }
237 }
238
239 // Tell how many lines read
240 std::cout << m_className << "::Initialise:\n";
241 std::cout << " Read properties of " << m_nMaterials
242 << " materials from file " << mplist << ".\n";
243 if (m_debug) PrintMaterials();
244
245 // Open the element list
246 std::ifstream felist;
247 felist.open(elist.c_str(), std::ios::in);
248 if (felist.fail()) {
249 std::cerr << m_className << "::Initialise:\n";
250 std::cerr << " Could not open element file " << elist
251 << " for reading.\n";
252 std::cerr << " The file perhaps does not exist.\n";
253 return false;
254 }
255
256 // Read the element list
257 elements.clear();
258 nElements = 0;
259 Element newElement;
260 int nbackground = 0;
261 il = 0;
262 int highestnode = 0;
263 while (felist.getline(line, size, '\n')) {
264 il++;
265 // Skip page feed
266 if (strcmp(line, "1") == 0) {
267 felist.getline(line, size, '\n');
268 il++;
269 felist.getline(line, size, '\n');
270 il++;
271 felist.getline(line, size, '\n');
272 il++;
273 felist.getline(line, size, '\n');
274 il++;
275 felist.getline(line, size, '\n');
276 il++;
277 continue;
278 }
279 // Skip page feed if ansys > v15.x
280 if (strstr(line,"***") != NULL) {
281 felist.getline(line, size, '\n');
282 il++;
283 felist.getline(line, size, '\n');
284 il++;
285 felist.getline(line, size, '\n');
286 il++;
287 continue;
288 }
289 // Split the line in tokens
290 char* token = NULL;
291 // Split into tokens
292 token = strtok(line, " ");
293 // Skip blank lines and headers
294 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
295 int(token[0]) == 10 || int(token[0]) == 13 ||
296 strcmp(token, "LIST") == 0 || strcmp(token, "ELEM") == 0) {
297 continue;
298 }
299 // Read the element
300 int ielem = ReadInteger(token, -1, readerror);
301 token = strtok(NULL, " ");
302 int imat = ReadInteger(token, -1, readerror);
303 token = strtok(NULL, " ");
304 token = strtok(NULL, " ");
305 token = strtok(NULL, " ");
306 token = strtok(NULL, " ");
307 token = strtok(NULL, " ");
308 int in0 = ReadInteger(token, -1, readerror);
309 token = strtok(NULL, " ");
310 int in1 = ReadInteger(token, -1, readerror);
311 token = strtok(NULL, " ");
312 int in2 = ReadInteger(token, -1, readerror);
313 token = strtok(NULL, " ");
314 int in3 = ReadInteger(token, -1, readerror);
315 token = strtok(NULL, " ");
316 int in4 = ReadInteger(token, -1, readerror);
317 token = strtok(NULL, " ");
318 int in5 = ReadInteger(token, -1, readerror);
319 token = strtok(NULL, " ");
320 int in6 = ReadInteger(token, -1, readerror);
321 token = strtok(NULL, " ");
322 int in7 = ReadInteger(token, -1, readerror);
323 if (!felist.getline(line, size, '\n')) {
324 std::cerr << m_className << "::Initialise:\n";
325 std::cerr << " Error reading element " << ielem << ".\n";
326 ok = false;
327 break;
328 }
329 ++il;
330 token = NULL;
331 token = strtok(line, " ");
332 int in8 = ReadInteger(token, -1, readerror);
333 token = strtok(NULL, " ");
334 int in9 = ReadInteger(token, -1, readerror);
335
336 // Check synchronisation
337 if (readerror) {
338 std::cerr << m_className << "::Initialise:\n";
339 std::cerr << " Error reading file " << elist << " (line " << il
340 << ").\n";
341 felist.close();
342 ok = false;
343 return false;
344 } else if (ielem - 1 != nElements + nbackground) {
345 std::cerr << m_className << "::Initialise:\n";
346 std::cerr << " Synchronisation lost on file " << elist << " (line "
347 << il << ").\n";
348 std::cerr << " Element: " << ielem << " (expected " << nElements
349 << "), material: " << imat << ",\n";
350 std::cerr << " nodes: (" << in0 << ", " << in1 << ", " << in2 << ", "
351 << in3 << ", " << in4 << ", " << in5 << ", " << in6 << ", "
352 << in7 << ", " << in8 << ", " << in9 << ")\n";
353 ok = false;
354 }
355
356 // Check the material number and ensure that epsilon is non-negative
357 if (imat < 1 || imat > (int)m_nMaterials) {
358 std::cerr << m_className << "::Initialise:\n";
359 std::cerr << " Out-of-range material number on file " << elist
360 << " (line " << il << ").\n";
361 std::cerr << " Element: " << ielem << ", material: " << imat << ",\n";
362 std::cerr << " nodes: (" << in0 << ", " << in1 << ", " << in2 << ", "
363 << in3 << ", " << in4 << ", " << in5 << ", " << in6 << ", "
364 << in7 << ", " << in8 << ", " << in9 << ")\n";
365 ok = false;
366 }
367 if (materials[imat - 1].eps < 0) {
368 std::cerr << m_className << "::Initialise:\n";
369 std::cerr << " Element " << ielem << " in element list " << elist
370 << "\n";
371 std::cerr << " uses material " << imat
372 << " which has not been assigned\n";
373 std::cerr << " a positive permittivity in material list " << mplist
374 << ".\n";
375 ok = false;
376 }
377
378 // Check the node numbers
379 if (in0 < 1 || in1 < 1 || in2 < 1 || in3 < 1 || in4 < 1 || in5 < 1 ||
380 in6 < 1 || in7 < 1 || in8 < 1 || in9 < 1) {
381 std::cerr << m_className << "::Initialise:\n";
382 std::cerr << " Found a node number < 1 on file " << elist << " (line "
383 << il << ").\n";
384 std::cerr << " Element: " << ielem << ", material: " << imat << ",\n";
385 std::cerr << " nodes: (" << in0 << ", " << in1 << ", " << in2 << ", "
386 << in3 << ", " << in4 << ", " << in5 << ", " << in6 << ", "
387 << in7 << ", " << in8 << ", " << in9 << ")\n";
388 ok = false;
389 }
390 if (in0 > highestnode) highestnode = in0;
391 if (in1 > highestnode) highestnode = in1;
392 if (in2 > highestnode) highestnode = in2;
393 if (in3 > highestnode) highestnode = in3;
394 if (in4 > highestnode) highestnode = in4;
395 if (in5 > highestnode) highestnode = in5;
396 if (in6 > highestnode) highestnode = in6;
397 if (in7 > highestnode) highestnode = in7;
398 if (in8 > highestnode) highestnode = in8;
399 if (in9 > highestnode) highestnode = in9;
400
401 // Skip elements in conductors.
402 if (m_deleteBackground && materials[imat - 1].ohm == 0) {
403 nbackground++;
404 continue;
405 }
406
407 // These elements must not be degenerate.
408 if (in0 == in1 || in0 == in2 || in0 == in3 || in0 == in4 || in0 == in5 ||
409 in0 == in6 || in0 == in7 || in0 == in8 || in0 == in9 || in1 == in2 ||
410 in1 == in3 || in1 == in4 || in1 == in5 || in1 == in6 || in1 == in7 ||
411 in1 == in8 || in1 == in9 || in2 == in3 || in2 == in4 || in2 == in5 ||
412 in2 == in6 || in2 == in7 || in2 == in8 || in2 == in9 || in3 == in4 ||
413 in3 == in5 || in3 == in6 || in3 == in7 || in3 == in8 || in3 == in9 ||
414 in4 == in5 || in4 == in6 || in4 == in7 || in4 == in8 || in4 == in9 ||
415 in5 == in6 || in5 == in7 || in5 == in8 || in5 == in9 || in6 == in7 ||
416 in6 == in8 || in6 == in9 || in7 == in8 || in7 == in9 || in8 == in9) {
417 std::cerr << m_className << "::Initialise:\n";
418 std::cerr << " Element " << ielem << " of file " << elist
419 << " is degenerate,\n";
420 std::cerr << " no such elements allowed in this type of map.\n";
421 ok = false;
422 }
423
424 newElement.degenerate = false;
425
426 // Store the material reference
427 newElement.matmap = imat - 1;
428
429 // Node references
430 newElement.emap[0] = in0 - 1;
431 newElement.emap[1] = in1 - 1;
432 newElement.emap[2] = in2 - 1;
433 newElement.emap[3] = in3 - 1;
434 newElement.emap[4] = in4 - 1;
435 newElement.emap[7] = in5 - 1;
436 newElement.emap[5] = in6 - 1;
437 newElement.emap[6] = in7 - 1;
438 newElement.emap[8] = in8 - 1;
439 newElement.emap[9] = in9 - 1;
440 elements.push_back(newElement);
441 nElements++;
442 }
443 // Close the file
444 felist.close();
445
446 // Tell how many lines read.
447 std::cout << m_className << "::Initialise:\n";
448 std::cout << " Read " << nElements << " elements from file " << elist
449 << ",\n";
450 std::cout << " highest node number: " << highestnode << ",\n";
451 std::cout << " background elements skipped: " << nbackground << "\n";
452 // Check the value of the unit
453 double funit;
454 if (strcmp(unit.c_str(), "mum") == 0 || strcmp(unit.c_str(), "micron") == 0 ||
455 strcmp(unit.c_str(), "micrometer") == 0) {
456 funit = 0.0001;
457 } else if (strcmp(unit.c_str(), "mm") == 0 ||
458 strcmp(unit.c_str(), "millimeter") == 0) {
459 funit = 0.1;
460 } else if (strcmp(unit.c_str(), "cm") == 0 ||
461 strcmp(unit.c_str(), "centimeter") == 0) {
462 funit = 1.0;
463 } else if (strcmp(unit.c_str(), "m") == 0 ||
464 strcmp(unit.c_str(), "meter") == 0) {
465 funit = 100.0;
466 } else {
467 std::cerr << m_className << "::Initialise:\n";
468 std::cerr << " Unknown length unit " << unit << ".\n";
469 ok = false;
470 funit = 1.0;
471 }
472 if (m_debug) {
473 std::cout << m_className << ":Initialise:\n";
474 std::cout << " Unit scaling factor = " << funit << ".\n";
475 }
476
477 // Open the node list
478 std::ifstream fnlist;
479 fnlist.open(nlist.c_str(), std::ios::in);
480 if (fnlist.fail()) {
481 std::cerr << m_className << "::Initialise:\n";
482 std::cerr << " Could not open nodes file " << nlist << " for reading.\n";
483 std::cerr << " The file perhaps does not exist.\n";
484 return false;
485 }
486
487 // Read the node list
488 nodes.clear();
489 nNodes = 0;
490 Node newNode;
491 newNode.w.clear();
492 il = 0;
493 while (fnlist.getline(line, size, '\n')) {
494 il++;
495 // Skip page feed
496 if (strcmp(line, "1") == 0) {
497 fnlist.getline(line, size, '\n');
498 il++;
499 fnlist.getline(line, size, '\n');
500 il++;
501 fnlist.getline(line, size, '\n');
502 il++;
503 fnlist.getline(line, size, '\n');
504 il++;
505 fnlist.getline(line, size, '\n');
506 il++;
507 continue;
508 }
509 // Skip page feed if ansys > v15.x
510 if (strstr(line,"***") != NULL) {
511 fnlist.getline(line, size, '\n');
512 il++;
513 fnlist.getline(line, size, '\n');
514 il++;
515 fnlist.getline(line, size, '\n');
516 il++;
517 continue;
518 }
519 // Split the line in tokens
520 char* token = NULL;
521 token = strtok(line, " ");
522 // Skip blank lines and headers
523 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
524 int(token[0]) == 10 || int(token[0]) == 13 ||
525 strcmp(token, "LIST") == 0 || strcmp(token, "NODE") == 0)
526 continue;
527 // Read the element
528 int inode = ReadInteger(token, -1, readerror);
529 token = strtok(NULL, " ");
530 double xnode = ReadDouble(token, -1, readerror);
531 token = strtok(NULL, " ");
532 double ynode = ReadDouble(token, -1, readerror);
533 token = strtok(NULL, " ");
534 double znode = ReadDouble(token, -1, readerror);
535 // Check syntax
536 if (readerror) {
537 std::cerr << m_className << "::Initialise:\n";
538 std::cerr << " Error reading file " << nlist << " (line " << il
539 << ").\n";
540 fnlist.close();
541 ok = false;
542 return false;
543 }
544 // Check synchronisation
545 if (inode - 1 != nNodes) {
546 std::cerr << m_className << "::Initialise:\n";
547 std::cerr << " Synchronisation lost on file " << nlist << " (line "
548 << il << ").\n";
549 std::cerr << " Node: " << inode << " (expected " << nNodes
550 << "), (x,y,z) = (" << xnode << ", " << ynode << ", " << znode
551 << ")\n";
552 ok = false;
553 }
554 // Store the point coordinates
555 newNode.x = xnode * funit;
556 newNode.y = ynode * funit;
557 newNode.z = znode * funit;
558 nodes.push_back(newNode);
559 nNodes++;
560 }
561 // Close the file
562 fnlist.close();
563 // Tell how many lines read
564 std::cout << m_className << "::Initialise:\n";
565 std::cout << " Read " << nNodes << " nodes from file " << nlist << ".\n";
566 // Check number of nodes
567 if (nNodes != highestnode) {
568 std::cerr << m_className << "::Initialise:\n";
569 std::cerr << " Number of nodes read (" << nNodes << ") on " << nlist
570 << "\n";
571 std::cerr << " does not match element list (" << highestnode << ").\n";
572 ok = false;
573 }
574
575 // Open the voltage list
576 std::ifstream fprnsol;
577 fprnsol.open(prnsol.c_str(), std::ios::in);
578 if (fprnsol.fail()) {
579 std::cerr << m_className << "::Initialise:\n";
580 std::cerr << " Could not open potential file " << prnsol
581 << " for reading.\n";
582 std::cerr << " The file perhaps does not exist.\n";
583 return false;
584 }
585
586 // Read the voltage list
587 il = 0;
588 int nread = 0;
589 while (fprnsol.getline(line, size, '\n')) {
590 il++;
591 // Skip page feed
592 if (strcmp(line, "1") == 0) {
593 fprnsol.getline(line, size, '\n');
594 il++;
595 fprnsol.getline(line, size, '\n');
596 il++;
597 fprnsol.getline(line, size, '\n');
598 il++;
599 fprnsol.getline(line, size, '\n');
600 il++;
601 fprnsol.getline(line, size, '\n');
602 il++;
603 continue;
604 }
605// Skip page feed if ansys > v15.x
606 if (strstr(line,"***") != NULL) {
607 fprnsol.getline(line, size, '\n');
608 il++;
609 fprnsol.getline(line, size, '\n');
610 il++;
611 fprnsol.getline(line, size, '\n');
612 il++;
613 continue;
614 }
615 // Split the line in tokens
616 char* token = NULL;
617 token = strtok(line, " ");
618 // Skip blank lines and headers
619 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
620 int(token[0]) == 10 || int(token[0]) == 13 ||
621 strcmp(token, "PRINT") == 0 || strcmp(token, "*****") == 0 ||
622 strcmp(token, "LOAD") == 0 || strcmp(token, "TIME=") == 0 ||
623 strcmp(token, "MAXIMUM") == 0 || strcmp(token, "VALUE") == 0 ||
624 strcmp(token, "NODE") == 0)
625 continue;
626 // Read the element
627 int inode = ReadInteger(token, -1, readerror);
628 token = strtok(NULL, " ");
629 double volt = ReadDouble(token, -1, readerror);
630 // Check syntax
631 if (readerror) {
632 std::cerr << m_className << "::Initialise:\n";
633 std::cerr << " Error reading file " << prnsol << " (line << " << il
634 << ").\n";
635 fprnsol.close();
636 ok = false;
637 return false;
638 }
639 // Check node number and store if OK
640 if (inode < 1 || inode > highestnode) {
641 std::cerr << m_className << "::Initialise:\n";
642 std::cerr << " Node number " << inode << " out of range\n";
643 std::cerr << " on potential file " << prnsol << " (line " << il
644 << ").\n";
645 ok = false;
646 } else {
647 nodes[inode - 1].v = volt;
648 nread++;
649 }
650 }
651 // Close the file
652 fprnsol.close();
653 // Tell how many lines read
654 std::cout << m_className << "::Initialise:\n";
655 std::cout << " Read " << nread << " potentials from file " << prnsol
656 << ".\n";
657 // Check number of nodes
658 if (nread != nNodes) {
659 std::cerr << m_className << "::Initialise:\n";
660 std::cerr << " Number of nodes read (" << nread << ") on potential file "
661 << prnsol << "\n";
662 std::cerr << " does not match the node list (" << nNodes << ").\n";
663 ok = false;
664 }
665
666 // Set the ready flag
667 if (ok) {
668 m_ready = true;
669 } else {
670 std::cerr << m_className << "::Initialise:\n";
671 std::cerr
672 << " Field map could not be read and can not be interpolated.\n";
673 return false;
674 }
675
676 // Remove weighting fields (if any).
677 wfields.clear();
678 wfieldsOk.clear();
680
681 // Establish the ranges
682 SetRange();
684 return true;
685}
686
688 std::string label) {
689 if (!m_ready) {
690 PrintNotReady("SetWeightingField");
691 std::cerr << " Weighting field cannot be added.\n";
692 return false;
693 }
694
695 // Open the voltage list.
696 std::ifstream fprnsol;
697 fprnsol.open(prnsol.c_str(), std::ios::in);
698 if (fprnsol.fail()) {
699 std::cerr << m_className << "::SetWeightingField:\n";
700 std::cerr << " Could not open potential file " << prnsol
701 << " for reading.\n";
702 std::cerr << " The file perhaps does not exist.\n";
703 return false;
704 }
705
706 // Check if a weighting field with the same label already exists.
707 int iw = nWeightingFields;
708 for (int i = nWeightingFields; i--;) {
709 if (wfields[i] == label) {
710 iw = i;
711 break;
712 }
713 }
714 if (iw == nWeightingFields) {
718 for (int j = nNodes; j--;) {
719 nodes[j].w.resize(nWeightingFields);
720 }
721 } else {
722 std::cout << m_className << "::SetWeightingField:\n";
723 std::cout << " Replacing existing weighting field " << label << ".\n";
724 }
725 wfields[iw] = label;
726 wfieldsOk[iw] = false;
727
728 // Buffer for reading
729 const int size = 100;
730 char line[size];
731
732 bool ok = true;
733 // Read the voltage list.
734 int il = 0;
735 int nread = 0;
736 bool readerror = false;
737
738 while (fprnsol.getline(line, size, '\n')) {
739 il++;
740 // Skip page feed
741 if (strcmp(line, "1") == 0) {
742 fprnsol.getline(line, size, '\n');
743 il++;
744 fprnsol.getline(line, size, '\n');
745 il++;
746 fprnsol.getline(line, size, '\n');
747 il++;
748 fprnsol.getline(line, size, '\n');
749 il++;
750 fprnsol.getline(line, size, '\n');
751 il++;
752 continue;
753 }
754 // Split the line in tokens.
755 char* token = NULL;
756 token = strtok(line, " ");
757 // Skip blank lines and headers.
758 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
759 int(token[0]) == 10 || int(token[0]) == 13 ||
760 strcmp(token, "PRINT") == 0 || strcmp(token, "*****") == 0 ||
761 strcmp(token, "LOAD") == 0 || strcmp(token, "TIME=") == 0 ||
762 strcmp(token, "MAXIMUM") == 0 || strcmp(token, "VALUE") == 0 ||
763 strcmp(token, "NODE") == 0)
764 continue;
765 // Read the element.
766 int inode = ReadInteger(token, -1, readerror);
767 token = strtok(NULL, " ");
768 double volt = ReadDouble(token, -1, readerror);
769 // Check the syntax.
770 if (readerror) {
771 std::cerr << m_className << "::SetWeightingField:\n";
772 std::cerr << " Error reading file " << prnsol.c_str() << " (line "
773 << il << ").\n";
774 fprnsol.close();
775 return false;
776 }
777 // Check node number and store if OK.
778 if (inode < 1 || inode > nNodes) {
779 std::cerr << m_className << "::SetWeightingField:\n";
780 std::cerr << " Node number " << inode << " out of range\n";
781 std::cerr << " on potential file " << prnsol.c_str() << " (line " << il
782 << ").\n";
783 ok = false;
784 } else {
785 nodes[inode - 1].w[iw] = volt;
786 nread++;
787 }
788 }
789 // Close the file.
790 fprnsol.close();
791
792 std::cout << m_className << "::SetWeightingField:\n";
793 std::cout << " Read " << nread << " potentials from file "
794 << prnsol.c_str() << ".\n";
795 // Check the number of nodes.
796 if (nread != nNodes) {
797 std::cerr << m_className << "::SetWeightingField:\n";
798 std::cerr << " Number of nodes read (" << nread << ") "
799 << " on potential file " << prnsol.c_str() << "\n";
800 std::cerr << " does not match the node list (" << nNodes << ").\n";
801 ok = false;
802 }
803
804 // Set the ready flag.
805 wfieldsOk[iw] = ok;
806 if (!ok) {
807 std::cerr << m_className << "::SetWeightingField:\n";
808 std::cerr << " Field map could not be read "
809 << "and cannot be interpolated.\n";
810 return false;
811 }
812 return true;
813}
814
815void ComponentAnsys123::ElectricField(const double x, const double y,
816 const double z, double& ex, double& ey,
817 double& ez, Medium*& m, int& status) {
818 double v = 0.;
819 ElectricField(x, y, z, ex, ey, ez, v, m, status);
820}
821
822void ComponentAnsys123::ElectricField(const double xin, const double yin,
823 const double zin, double& ex, double& ey,
824 double& ez, double& volt, Medium*& m,
825 int& status) {
826 // Copy the coordinates
827 double x = xin, y = yin, z = zin;
828
829 // Map the coordinates onto field map coordinates
830 bool xmirr, ymirr, zmirr;
831 double rcoordinate, rotation;
832 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
833
834 // Initial values
835 ex = ey = ez = volt = 0.;
836 status = 0;
837 m = nullptr;
838
839 // Do not proceed if not properly initialised.
840 if (!m_ready) {
841 status = -10;
842 PrintNotReady("ElectricField");
843 return;
844 }
845
846 if (m_warning) PrintWarning("ElectricField");
847
848 // Find the element that contains this point
849 double t1, t2, t3, t4, jac[4][4], det;
850 const int imap = FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
851 if (imap < 0) {
852 if (m_debug) {
853 std::cerr << m_className << "::ElectricField: Point (" << x << ", " << y
854 << ", " << z << ") not in the mesh.\n";
855 }
856 status = -6;
857 return;
858 }
859
860 const Element& element = elements[imap];
861 if (m_debug) {
862 PrintElement("ElectricField", x, y, z, t1, t2, t3, t4, element, 10);
863 }
864 const Node& n0 = nodes[element.emap[0]];
865 const Node& n1 = nodes[element.emap[1]];
866 const Node& n2 = nodes[element.emap[2]];
867 const Node& n3 = nodes[element.emap[3]];
868 const Node& n4 = nodes[element.emap[4]];
869 const Node& n5 = nodes[element.emap[5]];
870 const Node& n6 = nodes[element.emap[6]];
871 const Node& n7 = nodes[element.emap[7]];
872 const Node& n8 = nodes[element.emap[8]];
873 const Node& n9 = nodes[element.emap[9]];
874 // Shorthands.
875 const double fourt1 = 4 * t1;
876 const double fourt2 = 4 * t2;
877 const double fourt3 = 4 * t3;
878 const double fourt4 = 4 * t4;
879 const double invdet = 1. / det;
880 // Tetrahedral field
881 volt = n0.v * t1 * (2 * t1 - 1) + n1.v * t2 * (2 * t2 - 1) +
882 n2.v * t3 * (2 * t3 - 1) + n3.v * t4 * (2 * t4 - 1) +
883 n4.v * fourt1 * t2 + n5.v * fourt1 * t3 + n6.v * fourt1 * t4 +
884 n7.v * fourt2 * t3 + n8.v * fourt2 * t4 + n9.v * fourt3 * t4;
885 ex = -(n0.v * (fourt1 - 1) * jac[0][1] + n1.v * (fourt2 - 1) * jac[1][1] +
886 n2.v * (fourt3 - 1) * jac[2][1] + n3.v * (fourt4 - 1) * jac[3][1] +
887 n4.v * (fourt2 * jac[0][1] + fourt1 * jac[1][1]) +
888 n5.v * (fourt3 * jac[0][1] + fourt1 * jac[2][1]) +
889 n6.v * (fourt4 * jac[0][1] + fourt1 * jac[3][1]) +
890 n7.v * (fourt3 * jac[1][1] + fourt2 * jac[2][1]) +
891 n8.v * (fourt4 * jac[1][1] + fourt2 * jac[3][1]) +
892 n9.v * (fourt4 * jac[2][1] + fourt3 * jac[3][1])) *
893 invdet;
894
895 ey = -(n0.v * (fourt1 - 1) * jac[0][2] + n1.v * (fourt2 - 1) * jac[1][2] +
896 n2.v * (fourt3 - 1) * jac[2][2] + n3.v * (fourt4 - 1) * jac[3][2] +
897 n4.v * (fourt2 * jac[0][2] + fourt1 * jac[1][2]) +
898 n5.v * (fourt3 * jac[0][2] + fourt1 * jac[2][2]) +
899 n6.v * (fourt4 * jac[0][2] + fourt1 * jac[3][2]) +
900 n7.v * (fourt3 * jac[1][2] + fourt2 * jac[2][2]) +
901 n8.v * (fourt4 * jac[1][2] + fourt2 * jac[3][2]) +
902 n9.v * (fourt4 * jac[2][2] + fourt3 * jac[3][2])) *
903 invdet;
904
905 ez = -(n0.v * (fourt1 - 1) * jac[0][3] + n1.v * (fourt2 - 1) * jac[1][3] +
906 n2.v * (fourt3 - 1) * jac[2][3] + n3.v * (fourt4 - 1) * jac[3][3] +
907 n4.v * (fourt2 * jac[0][3] + fourt1 * jac[1][3]) +
908 n5.v * (fourt3 * jac[0][3] + fourt1 * jac[2][3]) +
909 n6.v * (fourt4 * jac[0][3] + fourt1 * jac[3][3]) +
910 n7.v * (fourt3 * jac[1][3] + fourt2 * jac[2][3]) +
911 n8.v * (fourt4 * jac[1][3] + fourt2 * jac[3][3]) +
912 n9.v * (fourt4 * jac[2][3] + fourt3 * jac[3][3])) *
913 invdet;
914
915 // Transform field to global coordinates
916 UnmapFields(ex, ey, ez, x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
917
918 // Drift medium?
919 if (m_debug) {
920 std::cout << m_className << "::ElectricField:\n";
921 std::cout << " Material " << element.matmap << ", drift flag "
922 << materials[element.matmap].driftmedium << ".\n";
923 }
924 m = materials[element.matmap].medium;
925 status = -5;
926 if (materials[element.matmap].driftmedium) {
927 if (m && m->IsDriftable()) status = 0;
928 }
929}
930
931void ComponentAnsys123::WeightingField(const double xin, const double yin,
932 const double zin, double& wx, double& wy,
933 double& wz, const std::string& label) {
934 // Initial values
935 wx = wy = wz = 0;
936
937 // Do not proceed if not properly initialised.
938 if (!m_ready) return;
939
940 // Look for the label.
941 int iw = 0;
942 bool found = false;
943 for (int i = nWeightingFields; i--;) {
944 if (wfields[i] == label) {
945 iw = i;
946 found = true;
947 break;
948 }
949 }
950
951 // Do not proceed if the requested weighting field does not exist.
952 if (!found) return;
953 // Check if the weighting field is properly initialised.
954 if (!wfieldsOk[iw]) return;
955
956 // Copy the coordinates.
957 double x = xin, y = yin, z = zin;
958
959 // Map the coordinates onto field map coordinates
960 bool xmirr, ymirr, zmirr;
961 double rcoordinate, rotation;
962 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
963
964 if (m_warning) PrintWarning("WeightingField");
965
966 // Find the element that contains this point.
967 double t1, t2, t3, t4, jac[4][4], det;
968 const int imap = FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
969 // Check if the point is in the mesh.
970 if (imap < 0) return;
971
972 const Element& element = elements[imap];
973 if (m_debug) {
974 PrintElement("WeightingField", x, y, z, t1, t2, t3, t4, element, 10, iw);
975 }
976 const Node& n0 = nodes[element.emap[0]];
977 const Node& n1 = nodes[element.emap[1]];
978 const Node& n2 = nodes[element.emap[2]];
979 const Node& n3 = nodes[element.emap[3]];
980 const Node& n4 = nodes[element.emap[4]];
981 const Node& n5 = nodes[element.emap[5]];
982 const Node& n6 = nodes[element.emap[6]];
983 const Node& n7 = nodes[element.emap[7]];
984 const Node& n8 = nodes[element.emap[8]];
985 const Node& n9 = nodes[element.emap[9]];
986 // Tetrahedral field
987 const double invdet = 1. / det;
988 const double fourt1 = 4 * t1;
989 const double fourt2 = 4 * t2;
990 const double fourt3 = 4 * t3;
991 const double fourt4 = 4 * t4;
992 wx = -(n0.w[iw] * (fourt1 - 1) * jac[0][1] +
993 n1.w[iw] * (fourt2 - 1) * jac[1][1] +
994 n2.w[iw] * (fourt3 - 1) * jac[2][1] +
995 n3.w[iw] * (fourt4 - 1) * jac[3][1] +
996 n4.w[iw] * (fourt2 * jac[0][1] + fourt1 * jac[1][1]) +
997 n5.w[iw] * (fourt3 * jac[0][1] + fourt1 * jac[2][1]) +
998 n6.w[iw] * (fourt4 * jac[0][1] + fourt1 * jac[3][1]) +
999 n7.w[iw] * (fourt3 * jac[1][1] + fourt2 * jac[2][1]) +
1000 n8.w[iw] * (fourt4 * jac[1][1] + fourt2 * jac[3][1]) +
1001 n9.w[iw] * (fourt4 * jac[2][1] + fourt3 * jac[3][1])) *
1002 invdet;
1003
1004 wy = -(n0.w[iw] * (fourt1 - 1) * jac[0][2] +
1005 n1.w[iw] * (fourt2 - 1) * jac[1][2] +
1006 n2.w[iw] * (fourt3 - 1) * jac[2][2] +
1007 n3.w[iw] * (fourt4 - 1) * jac[3][2] +
1008 n4.w[iw] * (fourt2 * jac[0][2] + fourt1 * jac[1][2]) +
1009 n5.w[iw] * (fourt3 * jac[0][2] + fourt1 * jac[2][2]) +
1010 n6.w[iw] * (fourt4 * jac[0][2] + fourt1 * jac[3][2]) +
1011 n7.w[iw] * (fourt3 * jac[1][2] + fourt2 * jac[2][2]) +
1012 n8.w[iw] * (fourt4 * jac[1][2] + fourt2 * jac[3][2]) +
1013 n9.w[iw] * (fourt4 * jac[2][2] + fourt3 * jac[3][2])) *
1014 invdet;
1015
1016 wz = -(n0.w[iw] * (fourt1 - 1) * jac[0][3] +
1017 n1.w[iw] * (fourt2 - 1) * jac[1][3] +
1018 n2.w[iw] * (fourt3 - 1) * jac[2][3] +
1019 n3.w[iw] * (fourt4 - 1) * jac[3][3] +
1020 n4.w[iw] * (fourt2 * jac[0][3] + fourt1 * jac[1][3]) +
1021 n5.w[iw] * (fourt3 * jac[0][3] + fourt1 * jac[2][3]) +
1022 n6.w[iw] * (fourt4 * jac[0][3] + fourt1 * jac[3][3]) +
1023 n7.w[iw] * (fourt3 * jac[1][3] + fourt2 * jac[2][3]) +
1024 n8.w[iw] * (fourt4 * jac[1][3] + fourt2 * jac[3][3]) +
1025 n9.w[iw] * (fourt4 * jac[2][3] + fourt3 * jac[3][3])) *
1026 invdet;
1027
1028 // Transform field to global coordinates
1029 UnmapFields(wx, wy, wz, x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
1030}
1031
1032double ComponentAnsys123::WeightingPotential(const double xin, const double yin,
1033 const double zin,
1034 const std::string& label) {
1035 // Do not proceed if not properly initialised.
1036 if (!m_ready) return 0.;
1037
1038 // Look for the label.
1039 int iw = 0;
1040 bool found = false;
1041 for (int i = nWeightingFields; i--;) {
1042 if (wfields[i] == label) {
1043 iw = i;
1044 found = true;
1045 break;
1046 }
1047 }
1048
1049 // Do not proceed if the requested weighting field does not exist.
1050 if (!found) return 0.;
1051 // Check if the weighting field is properly initialised.
1052 if (!wfieldsOk[iw]) return 0.;
1053
1054 // Copy the coordinates.
1055 double x = xin, y = yin, z = zin;
1056
1057 // Map the coordinates onto field map coordinates.
1058 bool xmirr, ymirr, zmirr;
1059 double rcoordinate, rotation;
1060 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
1061
1062 if (m_warning) PrintWarning("WeightingPotential");
1063
1064 // Find the element that contains this point.
1065 double t1, t2, t3, t4, jac[4][4], det;
1066 const int imap = FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
1067 if (imap < 0) return 0.;
1068
1069 const Element& element = elements[imap];
1070 if (m_debug) {
1071 PrintElement("WeightingPotential", x, y, z, t1, t2, t3, t4, element, 10,
1072 iw);
1073 }
1074 const Node& n0 = nodes[element.emap[0]];
1075 const Node& n1 = nodes[element.emap[1]];
1076 const Node& n2 = nodes[element.emap[2]];
1077 const Node& n3 = nodes[element.emap[3]];
1078 const Node& n4 = nodes[element.emap[4]];
1079 const Node& n5 = nodes[element.emap[5]];
1080 const Node& n6 = nodes[element.emap[6]];
1081 const Node& n7 = nodes[element.emap[7]];
1082 const Node& n8 = nodes[element.emap[8]];
1083 const Node& n9 = nodes[element.emap[9]];
1084 return n0.w[iw] * t1 * (2 * t1 - 1) + n1.w[iw] * t2 * (2 * t2 - 1) +
1085 n2.w[iw] * t3 * (2 * t3 - 1) + n3.w[iw] * t4 * (2 * t4 - 1) +
1086 4 * n4.w[iw] * t1 * t2 + 4 * n5.w[iw] * t1 * t3 +
1087 4 * n6.w[iw] * t1 * t4 + 4 * n7.w[iw] * t2 * t3 +
1088 4 * n8.w[iw] * t2 * t4 + 4 * n9.w[iw] * t3 * t4;
1089}
1090
1091Medium* ComponentAnsys123::GetMedium(const double xin, const double yin,
1092 const double zin) {
1093 // Copy the coordinates.
1094 double x = xin, y = yin, z = zin;
1095
1096 // Map the coordinates onto field map coordinates.
1097 bool xmirr, ymirr, zmirr;
1098 double rcoordinate, rotation;
1099 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
1100
1101 // Do not proceed if not properly initialised.
1102 if (!m_ready) {
1103 std::cerr << m_className << "::GetMedium:\n";
1104 std::cerr << " Field map not available for interpolation.\n";
1105 return NULL;
1106 }
1107 if (m_warning) PrintWarning("GetMedium");
1108
1109 // Find the element that contains this point.
1110 double t1, t2, t3, t4, jac[4][4], det;
1111 const int imap = FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
1112 if (imap < 0) {
1113 if (m_debug) {
1114 std::cerr << m_className << "::GetMedium:\n";
1115 std::cerr << " Point (" << x << ", " << y << ", " << z
1116 << ") not in the mesh.\n";
1117 }
1118 return NULL;
1119 }
1120 const Element& element = elements[imap];
1121 if (element.matmap >= m_nMaterials) {
1122 if (m_debug) {
1123 std::cerr << m_className << "::GetMedium:\n";
1124 std::cerr << " Point (" << x << ", " << y << ", " << z << ")"
1125 << " has out of range material number " << imap << ".\n";
1126 }
1127 return NULL;
1128 }
1129
1130 if (m_debug) {
1131 PrintElement("GetMedium", x, y, z, t1, t2, t3, t4, element, 10);
1132 }
1133
1134 // Assign a medium.
1135 return materials[element.matmap].medium;
1136}
1137
1138double ComponentAnsys123::GetElementVolume(const unsigned int i) {
1139 if (i >= elements.size()) return 0.;
1140 const Element& element = elements[i];
1141 const Node& n0 = nodes[element.emap[0]];
1142 const Node& n1 = nodes[element.emap[1]];
1143 const Node& n2 = nodes[element.emap[2]];
1144 const Node& n3 = nodes[element.emap[3]];
1145 const double vol =
1146 fabs((n3.x - n0.x) *
1147 ((n1.y - n0.y) * (n2.z - n0.z) - (n2.y - n0.y) * (n1.z - n0.z)) +
1148 (n3.y - n0.y) *
1149 ((n1.z - n0.z) * (n2.x - n0.x) - (n2.z - n0.z) * (n1.x - n0.x)) +
1150 (n3.z - n0.z) * ((n1.x - n0.x) * (n2.y - n0.y) -
1151 (n3.x - n0.x) * (n1.y - n0.y))) /
1152 6.;
1153 return vol;
1154}
1155
1156void ComponentAnsys123::GetAspectRatio(const unsigned int i, double& dmin,
1157 double& dmax) {
1158 if (i >= elements.size()) {
1159 dmin = dmax = 0.;
1160 return;
1161 }
1162
1163 const Element& element = elements[i];
1164 const int np = 4;
1165 // Loop over all pairs of vertices.
1166 for (int j = 0; j < np - 1; ++j) {
1167 const Node& nj = nodes[element.emap[j]];
1168 for (int k = j + 1; k < np; ++k) {
1169 const Node& nk = nodes[element.emap[k]];
1170 // Compute distance.
1171 const double dx = nj.x - nk.x;
1172 const double dy = nj.y - nk.y;
1173 const double dz = nj.z - nk.z;
1174 const double dist = sqrt(dx * dx + dy * dy + dz * dz);
1175 if (k == 1) {
1176 dmin = dmax = dist;
1177 } else {
1178 if (dist < dmin) dmin = dist;
1179 if (dist > dmax) dmax = dist;
1180 }
1181 }
1182 }
1183}
1184}
bool Initialise(std::string elist="ELIST.lis", std::string nlist="NLIST.lis", std::string mplist="MPLIST.lis", std::string prnsol="PRNSOL.lis", std::string unit="cm")
double GetElementVolume(const unsigned int i) override
void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label) override
double WeightingPotential(const double x, const double y, const double z, const std::string &label) override
void UpdatePeriodicity() override
Verify periodicities.
void GetAspectRatio(const unsigned int i, double &dmin, double &dmax) override
bool SetWeightingField(std::string prnsol, std::string label)
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status) override
Medium * GetMedium(const double x, const double y, const double z) override
Get the medium at a given location (x, y, z).
bool m_ready
Ready for use?
std::string m_className
Class name.
bool m_debug
Switch on/off debugging messages.
Base class for components based on finite-element field maps.
void PrintMaterials()
List all currently defined materials.
double ReadDouble(char *token, double def, bool &error)
void MapCoordinates(double &xpos, double &ypos, double &zpos, bool &xmirrored, bool &ymirrored, bool &zmirrored, double &rcoordinate, double &rotation) const
Move (xpos, ypos, zpos) to field map coordinates.
void PrintWarning(const std::string &header)
int ReadInteger(char *token, int def, bool &error)
std::vector< Material > materials
int FindElement13(const double x, const double y, const double z, double &t1, double &t2, double &t3, double &t4, double jac[4][4], double &det)
Find the element for a point in curved quadratic tetrahedra.
void PrintElement(const std::string &header, const double x, const double y, const double z, const double t1, const double t2, const double t3, const double t4, const Element &element, const unsigned int n, const int iw=-1) const
virtual void SetRange()
Calculate x, y, z, V and angular ranges.
std::vector< Element > elements
std::vector< std::string > wfields
void UnmapFields(double &ex, double &ey, double &ez, double &xpos, double &ypos, double &zpos, bool &xmirrored, bool &ymirrored, bool &zmirrored, double &rcoordinate, double &rotation) const
Move (ex, ey, ez) to global coordinates.
void PrintNotReady(const std::string &header) const
Abstract base class for media.
Definition: Medium.hh:13
bool IsDriftable() const
Is charge carrier transport enabled in this medium?
Definition: Medium.hh:74