Garfield++ 5.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
12bool ComponentAnsys123::Initialise(const std::string& elist,
13 const std::string& nlist,
14 const std::string& mplist,
15 const std::string& prnsol,
16 const std::string& unit) {
17 Reset();
18 // Keep track of the success.
19 bool ok = true;
20
21 // Buffer for reading
22 constexpr int size = 100;
23 char line[size];
24
25 // Open the material list.
26 std::ifstream fmplist(mplist);
27 if (!fmplist) {
28 PrintCouldNotOpen("Initialise", mplist);
29 return false;
30 }
31
32 // Read the material list.
33 long il = 0;
34 unsigned int icurrmat = 0;
35 bool readerror = false;
36 while (fmplist.getline(line, size, '\n')) {
37 il++;
38 // Skip page feed.
39 if (strcmp(line, "1") == 0) {
40 for (size_t k = 0; k < 5; ++k) fmplist.getline(line, size, '\n');
41 il += 5;
42 continue;
43 }
44 // Split the line in tokens.
45 char* token = strtok(line, " ");
46 // Skip blank lines and headers.
47 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
48 strcmp(token, "TEMPERATURE") == 0 || strcmp(token, "PROPERTY=") == 0 ||
49 int(token[0]) == 10 || int(token[0]) == 13) {
50 continue;
51 }
52 // Read number of materials and initialise the list.
53 if (strcmp(token, "LIST") == 0) {
54 token = strtok(nullptr, " ");
55 token = strtok(nullptr, " ");
56 token = strtok(nullptr, " ");
57 token = strtok(nullptr, " ");
58 const int nMaterials = ReadInteger(token, -1, readerror);
59 if (readerror || nMaterials < 0) {
60 std::cerr << m_className << "::Initialise:\n"
61 << " Error reading file " << mplist << " (line " << il
62 << ").\n";
63 fmplist.close();
64 return false;
65 }
66 m_materials.resize(nMaterials);
67 for (auto& material : m_materials) {
68 material.ohm = -1;
69 material.eps = -1;
70 material.medium = nullptr;
71 }
72 if (m_debug) {
73 std::cout << m_className << "::Initialise: " << nMaterials
74 << " materials.\n";
75 }
76 } else if (strcmp(token, "MATERIAL") == 0) {
77 // Version 12 format: read material number
78 token = strtok(nullptr, " ");
79 token = strtok(nullptr, " ");
80 const int imat = ReadInteger(token, -1, readerror);
81 if (readerror || imat < 0) {
82 std::cerr << m_className << "::Initialise:\n"
83 << " Error reading file " << mplist << " (line " << il
84 << ").\n";
85 fmplist.close();
86 return false;
87 }
88 icurrmat = imat;
89 } else if (strcmp(token, "TEMP") == 0) {
90 // Version 12 format: read property tag and value
91 token = strtok(nullptr, " ");
92 int itype = 0;
93 if (strncmp(token, "PERX", 4) == 0) {
94 itype = 1;
95 } else if (strncmp(token, "RSVX", 4) == 0) {
96 itype = 2;
97 } else {
98 std::cerr << m_className << "::Initialise:\n"
99 << " Unknown material property flag " << token << "\n"
100 << " in material properties file " << mplist << " (line "
101 << il << ").\n";
102 ok = false;
103 }
104 fmplist.getline(line, size, '\n');
105 il++;
106 token = nullptr;
107 token = strtok(line, " ");
108 if (icurrmat < 1 || icurrmat > m_materials.size()) {
109 std::cerr << m_className << "::Initialise:\n"
110 << " Found out-of-range current material index "
111 << icurrmat << "\n"
112 << " in material properties file " << mplist << ".\n";
113 ok = false;
114 readerror = false;
115 } else if (itype == 1) {
116 m_materials[icurrmat - 1].eps = ReadDouble(token, -1, readerror);
117 } else if (itype == 2) {
118 m_materials[icurrmat - 1].ohm = ReadDouble(token, -1, readerror);
119 }
120 if (readerror) {
121 std::cerr << m_className << "::Initialise:\n"
122 << " Error reading file " << mplist << " (line " << il
123 << ").\n";
124 fmplist.close();
125 return false;
126 }
127 } else if (strcmp(token, "PROPERTY") == 0) {
128 // Version 11 format
129 token = strtok(nullptr, " ");
130 token = strtok(nullptr, " ");
131 int itype = 0;
132 if (strcmp(token, "PERX") == 0) {
133 itype = 1;
134 } else if (strcmp(token, "RSVX") == 0) {
135 itype = 2;
136 } else {
137 std::cerr << m_className << "::Initialise:\n"
138 << " Unknown material property flag " << token << "\n"
139 << " in material properties file " << mplist << " (line "
140 << il << ").\n";
141 ok = false;
142 }
143 token = strtok(nullptr, " ");
144 token = strtok(nullptr, " ");
145 int imat = ReadInteger(token, -1, readerror);
146 if (readerror) {
147 std::cerr << m_className << "::Initialise:\n"
148 << " Error reading file " << mplist << " (line " << il
149 << ").\n";
150 fmplist.close();
151 return false;
152 } else if (imat < 1 || imat > (int)m_materials.size()) {
153 std::cerr << m_className << "::Initialise:\n"
154 << " Found out-of-range material index " << imat << "\n"
155 << " in material properties file " << mplist << ".\n";
156 ok = false;
157 } else {
158 fmplist.getline(line, size, '\n');
159 il++;
160 fmplist.getline(line, size, '\n');
161 il++;
162 token = nullptr;
163 token = strtok(line, " ");
164 token = strtok(nullptr, " ");
165 if (itype == 1) {
166 m_materials[imat - 1].eps = ReadDouble(token, -1, readerror);
167 } else if (itype == 2) {
168 m_materials[imat - 1].ohm = ReadDouble(token, -1, readerror);
169 }
170 if (readerror) {
171 std::cerr << m_className << "::Initialise:\n"
172 << " Error reading file " << mplist << " (line " << il
173 << ").\n";
174 fmplist.close();
175 return false;
176 }
177 }
178 }
179 }
180 // Close the file
181 fmplist.close();
182
183 // Find lowest epsilon, check for eps = 0, set default drift medium.
184 if (!SetDefaultDriftMedium()) ok = false;
185
186 // Tell how many lines read
187 std::cout << m_className << "::Initialise:\n"
188 << " Read properties of " << m_materials.size()
189 << " materials from file " << mplist << ".\n";
190 if (m_debug) PrintMaterials();
191
192 // Open the element list
193 std::ifstream felist(elist);
194 if (!felist) {
195 PrintCouldNotOpen("Initialise", elist);
196 return false;
197 }
198
199 // Read the element list.
200 int nbackground = 0;
201 il = 0;
202 int highestnode = 0;
203 while (felist.getline(line, size, '\n')) {
204 il++;
205 // Skip page feed.
206 if (strcmp(line, "1") == 0) {
207 for (size_t k = 0; k < 5; ++k) felist.getline(line, size, '\n');
208 il += 5;
209 continue;
210 }
211 // Skip page feed if Ansys > v15.x
212 if (strstr(line, "***") != nullptr) {
213 for (size_t k = 0; k < 3; ++k) felist.getline(line, size, '\n');
214 il += 3;
215 continue;
216 }
217 // Split the line in tokens.
218 char* token = strtok(line, " ");
219 // Skip blank lines and headers.
220 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
221 int(token[0]) == 10 || int(token[0]) == 13 ||
222 strcmp(token, "LIST") == 0 || strcmp(token, "ELEM") == 0) {
223 continue;
224 }
225 // Read the element.
226 int ielem = ReadInteger(token, -1, readerror);
227 token = strtok(nullptr, " ");
228 int imat = ReadInteger(token, -1, readerror);
229 token = strtok(nullptr, " ");
230 token = strtok(nullptr, " ");
231 token = strtok(nullptr, " ");
232 token = strtok(nullptr, " ");
233 std::vector<int> inode;
234 for (size_t k = 0; k < 8; ++k) {
235 token = strtok(nullptr, " ");
236 const int in = ReadInteger(token, -1, readerror);
237 if (!readerror) inode.push_back(in);
238 }
239 if (!felist.getline(line, size, '\n')) {
240 std::cerr << m_className << "::Initialise:\n"
241 << " Error reading element " << ielem << ".\n";
242 ok = false;
243 break;
244 }
245 ++il;
246 token = strtok(line, " ");
247 const int in8 = ReadInteger(token, -1, readerror);
248 if (!readerror) inode.push_back(in8);
249 token = strtok(nullptr, " ");
250 const int in9 = ReadInteger(token, -1, readerror);
251 if (!readerror) inode.push_back(in9);
252
253 if (inode.size() != 10) {
254 std::cerr << m_className << "::Initialise:\n"
255 << " Error reading file " << elist << " (line "
256 << il << ").\n"
257 << " Read " << inode.size() << " node indices for element "
258 << ielem << " (expected 10).\n";
259 ok = false;
260 break;
261 }
262 // Check synchronisation.
263 if (ielem - 1 != (int)m_elements.size() + nbackground) {
264 std::cerr << m_className << "::Initialise:\n"
265 << " Synchronisation lost on file " << elist << " (line "
266 << il << ").\n"
267 << " Element: " << ielem << " (expected "
268 << m_elements.size() << ").\n";
269 ok = false;
270 break;
271 }
272
273 // Check the material number and ensure that epsilon is non-negative
274 if (imat < 1 || imat > (int)m_materials.size()) {
275 std::cerr << m_className << "::Initialise:\n"
276 << " Out-of-range material number on file " << elist
277 << " (line " << il << ").\n"
278 << " Element: " << ielem << ", material: " << imat << ".\n";
279 ok = false;
280 break;
281 }
282 if (m_materials[imat - 1].eps < 0) {
283 std::cerr << m_className << "::Initialise:\n"
284 << " Element " << ielem << " in " << elist << "\n"
285 << " uses material " << imat << " which does not have\n"
286 << " a positive permittivity in " << mplist << ".\n";
287 ok = false;
288 break;
289 }
290
291 // Check the node numbers.
292 bool degenerate = false;
293 for (size_t k = 0; k < 10; ++k) {
294 if (inode[k] < 1) {
295 std::cerr << m_className << "::Initialise:\n"
296 << " Found a node number < 1 in " << elist << " (line "
297 << il << ").\n"
298 << " Element: " << ielem << ", material: " << imat << ".\n";
299 ok = false;
300 }
301 if (inode[k] > highestnode) highestnode = inode[k];
302 for (size_t kk = k + 1; kk < 10; ++kk) {
303 if (inode[k] == inode[kk]) degenerate = true;
304 }
305 }
306 if (!ok) break;
307
308 // Skip elements in conductors.
309 if (m_deleteBackground && m_materials[imat - 1].ohm == 0) {
310 nbackground++;
311 continue;
312 }
313
314 // These elements must not be degenerate.
315 if (degenerate) {
316 std::cerr << m_className << "::Initialise:\n"
317 << " Element " << ielem << " of file " << elist
318 << " is degenerate,\n"
319 << " no such elements allowed in this type of map.\n";
320 ok = false;
321 break;
322 }
323 Element element;
324 // Store the material reference.
325 element.matmap = imat - 1;
326 // Store the node references.
327 element.emap[0] = inode[0] - 1;
328 element.emap[1] = inode[1] - 1;
329 element.emap[2] = inode[2] - 1;
330 element.emap[3] = inode[3] - 1;
331 element.emap[4] = inode[4] - 1;
332 element.emap[7] = inode[5] - 1;
333 element.emap[5] = inode[6] - 1;
334 element.emap[6] = inode[7] - 1;
335 element.emap[8] = inode[8] - 1;
336 element.emap[9] = inode[9] - 1;
337 m_elements.push_back(std::move(element));
338 }
339 // Close the file
340 felist.close();
341 if (!ok) return false;
342
343 if (m_elements.empty()) {
344 std::cerr << m_className << "::Initialise:\n"
345 << " Found no valid elements in file " << elist << ".\n";
346 return false;
347 }
348 m_degenerate.assign(m_elements.size(), false);
349
350 // Tell how many lines read.
351 std::cout << " Read " << m_elements.size() << " elements from file "
352 << elist << ".\n"
353 << " Highest node number: " << highestnode << "\n"
354 << " Background elements skipped: " << nbackground << "\n";
355 // Check the value of the unit
356 double funit = ScalingFactor(unit);
357 if (funit <= 0.) {
358 std::cerr << m_className << "::Initialise:\n"
359 << " Unknown length unit " << unit << ". Will use cm.\n";
360 funit = 1.0;
361 }
362 if (m_debug) {
363 std::cout << m_className << ":Initialise: Unit scaling factor = "
364 << funit << ".\n";
365 }
366
367 // Open the node list
368 std::ifstream fnlist(nlist);
369 if (!fnlist) {
370 PrintCouldNotOpen("Initialise", nlist);
371 return false;
372 }
373
374 // Read the node list.
375 il = 0;
376 while (fnlist.getline(line, size, '\n')) {
377 il++;
378 // Skip page feed
379 if (strcmp(line, "1") == 0) {
380 for (size_t k = 0; k < 5; ++k) fnlist.getline(line, size, '\n');
381 il += 5;
382 continue;
383 }
384 // Skip page feed if Ansys > v15.x
385 if (strstr(line, "***") != nullptr) {
386 for (size_t k = 0; k < 3; ++k) fnlist.getline(line, size, '\n');
387 il += 3;
388 continue;
389 }
390 // Split the line in tokens-
391 char* token = strtok(line, " ");
392 // Skip blank lines and headers.
393 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
394 int(token[0]) == 10 || int(token[0]) == 13 ||
395 strcmp(token, "LIST") == 0 || strcmp(token, "NODE") == 0 ||
396 strcmp(token, "SORT") == 0) {
397 continue;
398 }
399 // Read the node.
400 int inode = ReadInteger(token, -1, readerror);
401 token = strtok(nullptr, " ");
402 double xnode = ReadDouble(token, -1, readerror);
403 token = strtok(nullptr, " ");
404 double ynode = ReadDouble(token, -1, readerror);
405 token = strtok(nullptr, " ");
406 double znode = ReadDouble(token, -1, readerror);
407 // Check syntax.
408 if (readerror) {
409 std::cerr << m_className << "::Initialise:\n"
410 << " Error reading file " << nlist << " (line " << il
411 << ").\n";
412 fnlist.close();
413 return false;
414 }
415 // Check synchronisation.
416 if (inode - 1 != (int)m_nodes.size()) {
417 std::cerr << m_className << "::Initialise:\n"
418 << " Synchronisation lost on file " << nlist << " (line "
419 << il << ").\n"
420 << " Node: " << inode << " (expected " << m_nodes.size()
421 << "), (x,y,z) = (" << xnode << ", " << ynode << ", " << znode
422 << ")\n";
423 ok = false;
424 break;
425 }
426 // Store the point coordinates
427 Node node;
428 node.x = xnode * funit;
429 node.y = ynode * funit;
430 node.z = znode * funit;
431 m_nodes.push_back(std::move(node));
432 }
433 // Close the file.
434 fnlist.close();
435 if (!ok) return false;
436
437 // Tell how many lines read.
438 std::cout << " Read " << m_nodes.size() << " nodes from file "
439 << nlist << ".\n";
440 // Check number of nodes
441 if ((int)m_nodes.size() != highestnode) {
442 std::cerr << m_className << "::Initialise:\n"
443 << " Number of nodes read (" << m_nodes.size() << ") on " << nlist
444 << "\n"
445 << " does not match element list (" << highestnode << ").\n";
446 return false;
447 }
448
449 if (!LoadPotentials(prnsol, m_pot)) return false;
450
451 m_ready = true;
452 Prepare();
453 return true;
454}
455
456bool ComponentAnsys123::LoadPotentials(const std::string prnsol,
457 std::vector<double>& pot) {
458 // Open the voltage list.
459 std::ifstream fprnsol(prnsol);
460 if (!fprnsol) {
461 PrintCouldNotOpen("LoadPotentials", prnsol);
462 return false;
463 }
464
465 pot.resize(m_nodes.size());
466
467 // Buffer for reading
468 constexpr int size = 100;
469 char line[size];
470
471 // Read the voltage list.
472 bool ok = true;
473 long il = 0;
474 bool readerror = false;
475 unsigned int nread = 0;
476 while (fprnsol.getline(line, size, '\n')) {
477 il++;
478 // Skip page feed.
479 if (strcmp(line, "1") == 0) {
480 for (size_t k = 0; k < 5; ++k) fprnsol.getline(line, size, '\n');
481 il += 5;
482 continue;
483 }
484 // Skip page feed if Ansys > v15.x
485 if (strstr(line, "***") != nullptr) {
486 for (size_t k = 0; k < 3; ++k) fprnsol.getline(line, size, '\n');
487 il += 3;
488 continue;
489 }
490 // Split the line in tokens.
491 char* token = strtok(line, " ");
492 // Skip blank lines and headers.
493 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
494 int(token[0]) == 10 || int(token[0]) == 13 ||
495 strcmp(token, "PRINT") == 0 || strcmp(token, "*****") == 0 ||
496 strcmp(token, "LOAD") == 0 || strcmp(token, "TIME=") == 0 ||
497 strcmp(token, "MAXIMUM") == 0 || strcmp(token, "VALUE") == 0 ||
498 strcmp(token, "NODE") == 0) {
499 continue;
500 }
501 // Read the node number and potential.
502 size_t inode = ReadInteger(token, -1, readerror);
503 token = strtok(nullptr, " ");
504 double volt = ReadDouble(token, -1, readerror);
505 // Check syntax
506 if (readerror) {
507 std::cerr << m_className << "::LoadPotentials:\n"
508 << " Error reading file " << prnsol << " (line << " << il
509 << ").\n";
510 fprnsol.close();
511 return false;
512 }
513 // Check node number and store if OK.
514 if (inode < 1 || inode > m_nodes.size()) {
515 std::cerr << m_className << "::LoadPotentials:\n"
516 << " Node number " << inode << " out of range\n"
517 << " on potential file " << prnsol << " (line " << il
518 << ").\n";
519 ok = false;
520 break;
521 } else {
522 pot[inode - 1] = volt;
523 nread++;
524 }
525 }
526 // Close the file
527 fprnsol.close();
528 if (!ok) return false;
529
530 // Tell how many lines read
531 std::cout << " Read " << nread << " potentials from file "
532 << prnsol << ".\n";
533 // Check number of nodes
534 if (nread != m_nodes.size()) {
535 std::cerr << m_className << "::LoadPotentials:\n"
536 << " Number of nodes read (" << nread << ") on potential file "
537 << prnsol << "\n"
538 << " does not match the node list (" << m_nodes.size() << ").\n";
539 return false;
540 }
541 return true;
542}
543
544bool ComponentAnsys123::SetWeightingField(const std::string& prnsol,
545 const std::string& label) {
546 if (!m_ready) {
547 PrintNotReady("SetWeightingField");
548 std::cerr << " Weighting field cannot be added.\n";
549 return false;
550 }
551
552 std::cout << m_className << "::SetWeightingField:\n"
553 << " Loading field map for electrode " << label << ".\n";
554 // Check if a weighting field with the same label already exists.
555 if (m_wpot.count(label) > 0) {
556 std::cout << " Replacing existing weighting field.\n";
557 m_wpot[label].clear();
558 }
559
560 std::vector<double> pot(m_nodes.size(), 0.);
561 if (!LoadPotentials(prnsol, pot)) return false;
562 m_wpot[label] = std::move(pot);
563 return true;
564}
565
566}
bool Initialise(const std::string &elist="ELIST.lis", const std::string &nlist="NLIST.lis", const std::string &mplist="MPLIST.lis", const std::string &prnsol="PRNSOL.lis", const std::string &unit="cm")
bool SetWeightingField(const std::string &prnsol, const std::string &label)
void PrintMaterials()
List all currently defined materials.
bool SetDefaultDriftMedium()
Find lowest epsilon, check for eps = 0, set default drift media flags.
static double ReadDouble(char *token, double def, bool &error)
static double ScalingFactor(std::string unit)
static int ReadInteger(char *token, int def, bool &error)
std::vector< Material > m_materials
ComponentFieldMap()=delete
Default constructor.
void PrintCouldNotOpen(const std::string &header, const std::string &filename) const
std::map< std::string, std::vector< double > > m_wpot
std::vector< Element > m_elements
void Reset() override
Reset the component.
void PrintNotReady(const std::string &header) const
bool m_debug
Switch on/off debugging messages.
Definition Component.hh:371
std::string m_className
Class name.
Definition Component.hh:359
bool m_ready
Ready for use?
Definition Component.hh:368