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