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