Garfield++ 5.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
ComponentCST.cc
Go to the documentation of this file.
1#include <math.h>
2#include <stdlib.h>
3#include <sys/stat.h>
4#include <algorithm>
5#include <fstream>
6#include <functional>
7#include <iomanip>
8#include <iostream>
9#include <sstream>
10#include <vector>
11
13
14namespace {
15
16bool ReadHeader(FILE* f, const int fileSize, const bool debug,
17 int& nX, int& nY, int& nZ, int& nNS,
18 int& nES, int& nEM, int& nMaterials) {
19
20 if (!f) return false;
21 // Size of the header in binary files used in the CST export
22 static constexpr int headerSize = 1000;
23 if (fileSize < headerSize) {
24 std::cerr << "ComponentCST::ReadHeader:\n"
25 << " Error. The file is extremely short and does not seem to "
26 << "contain a header or data." << std::endl;
27 return false;
28 }
29 char header[headerSize];
30 size_t result = fread(header, sizeof(char), headerSize, f);
31 if (result != headerSize) {
32 std::cerr << "ComponentCST::ReadHeader: Could not read the header.\n";
33 return false;
34 }
35
36 int nMeshX = 0, nMeshY = 0, nMeshZ = 0;
37 int nNx = 0, nNy = 0, nNz = 0;
38 int nEx = 0, nEy = 0, nEz = 0;
39
40 std::string fmt = "mesh_nx=%d mesh_ny=%d mesh_nz=%d\n";
41 fmt += "mesh_xlines=%d mesh_ylines=%d mesh_zlines=%d\n";
42 fmt += "nodes_scalar=%d ";
43 fmt += "nodes_vector_x=%d nodes_vector_y=%d nodes_vector_z=%d\n";
44 fmt += "elements_scalar=%d elements_vector_x=%d ";
45 fmt += "elements_vector_y=%d elements_vector_z=%d\n";
46 fmt += "elements_material=%d\n";
47 fmt += "n_materials=%d\n";
48 int filled = std::sscanf(header, fmt.c_str(),
49 &nMeshX, &nMeshY, &nMeshZ, &nX, &nY, &nZ,
50 &nNS, &nNx, &nNy, &nNz, &nES, &nEx, &nEy, &nEz, &nEM, &nMaterials);
51 if (filled != 16) {
52 std::cerr << "ComponentCST::ReadHeader: File header is broken.\n";
53 return false;
54 }
55 if (fileSize < 1000 + (nX + nY + nZ) * 8 +
56 (nNS + nNx + nNy + nNz + nES + nEx + nEy + nEz) * 4 +
57 nEM * 1 + nMaterials * 20) {
58 std::cerr << "ComponentCST::ReadHeader: Unexpected file size.\n";
59 return false;
60 }
61 if (debug) {
62 std::cout << "ComponentCST::ReadHeader:\n"
63 << " Mesh (nx): " << nMeshX << "\t Mesh (ny): " << nMeshY
64 << "\t Mesh (nz): " << nMeshZ << std::endl
65 << " Mesh (x_lines): " << nX << "\t Mesh (y_lines): " << nY
66 << "\t Mesh (z_lines): " << nZ << std::endl
67 << " Nodes (scalar): " << nNS << "\t Nodes (x): " << nNx
68 << "\t Nodes (y): " << nNy << "\t Nodes (z): " << nNz << "\n"
69 << " Field (scalar): " << nES << "\t Field (x): " << nEx
70 << "\t Field (y): " << nEy << "\t Field (z): " << nEz << "\n"
71 << " Elements: " << nEM << "\t Materials: " << nMaterials
72 << std::endl;
73 }
74 return true;
75}
76
77}
78namespace Garfield {
79
81 // Default bounding box
82 m_minBoundingBox[2] = -50.;
83 m_maxBoundingBox[2] = 50.;
84 m_deleteBackground = false;
85}
86
87bool ComponentCST::Initialise(std::string elist, std::string nlist,
88 std::string mplist, std::string prnsol,
89 std::string unit) {
90 Reset();
91 // Keep track of the success
92 bool ok = true;
93
94 // Buffer for reading
95 const int size = 200;
96 char line[size];
97 // Open the material list
98 std::ifstream fmplist(mplist);
99 if (!fmplist) {
100 PrintCouldNotOpen("Initialise", mplist);
101 return false;
102 }
103
104 // Read the material list
105 int il = 0;
106 bool readerror = false;
107 while (fmplist.getline(line, size, '\n')) {
108 il++;
109 // Split the line in tokens
110 char* token = strtok(line, " ");
111 // Skip blank lines and headers
112 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
113 int(token[0]) == 10 || int(token[0]) == 13)
114 continue;
115 // Read number of materials,
116 // ensure it does not exceed the maximum and initialize the list
117 if (strcmp(token, "Materials") == 0) {
118 token = strtok(nullptr, " ");
119 const int nMaterials = ReadInteger(token, -1, readerror);
120 if (readerror) {
121 std::cerr << m_className << "::Initialise:\n"
122 << " Error reading file " << mplist << " (line " << il
123 << ")." << std::endl;
124 fmplist.close();
125 return false;
126 }
127 m_materials.resize(nMaterials);
128 for (auto& material : m_materials) {
129 material.ohm = -1;
130 material.eps = -1;
131 material.medium = nullptr;
132 }
133 if (m_debug) {
134 std::cout << m_className << "::Initialise:" << std::endl;
135 std::cout << " Number of materials: " << nMaterials << "\n";
136 }
137 } else if (strcmp(token, "Material") == 0) {
138 token = strtok(nullptr, " ");
139 int imat = ReadInteger(token, -1, readerror);
140 if (readerror) {
141 std::cerr << m_className << "::Initialise:" << std::endl;
142 std::cerr << " Error reading file " << mplist << " (line " << il
143 << ").\n";
144 fmplist.close();
145 return false;
146 } else if (imat < 1 || imat > (int)m_materials.size()) {
147 std::cerr << m_className << "::Initialise:\n"
148 << " Found out-of-range material index " << imat << "in\n"
149 << " material properties file " << mplist << ".\n";
150 ok = false;
151 } else {
152 token = strtok(nullptr, " ");
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 << " Unknown material property flag " << token << "\n"
161 << " in material properties file " << mplist
162 << " (line " << il << ").\n";
163 ok = false;
164 }
165 token = strtok(nullptr, " ");
166 if (itype == 1) {
167 m_materials[imat - 1].eps = ReadDouble(token, -1, readerror);
168 } else if (itype == 2) {
169 m_materials[imat - 1].ohm = ReadDouble(token, -1, readerror);
170 token = strtok(nullptr, " ");
171 if (strcmp(token, "PERX") != 0) {
172 std::cerr << m_className << "::Initialise:\n"
173 << " Unknown material property flag " << token << "\n"
174 << " in material file " << mplist << " (material "
175 << imat << ").\n";
176 ok = false;
177 } else {
178 token = strtok(nullptr, " ");
179 m_materials[imat - 1].eps = ReadDouble(token, -1, readerror);
180 }
181 }
182 if (readerror) {
183 std::cerr << m_className << "::Initialise:\n"
184 << " Error reading file " << mplist
185 << " (line " << il << ")." << std::endl;
186 fmplist.close();
187 return false;
188 }
189 if (m_debug) {
190 std::cout << m_className << "::Initialise:" << std::endl;
191 std::cout << " Read material properties for material "
192 << (imat - 1) << "" << std::endl;
193 if (itype == 2) {
194 std::cout << " eps = " << m_materials[imat - 1].eps
195 << " ohm = " << m_materials[imat - 1].ohm << ""
196 << std::endl;
197 } else {
198 std::cout << " eps = " << m_materials[imat - 1].eps << ""
199 << std::endl;
200 }
201 }
202 }
203 }
204 }
205 // Close the file
206 fmplist.close();
207
208 // Find lowest epsilon, check for eps = 0, set default drift medium.
209 if (!SetDefaultDriftMedium()) ok = false;
210
211 // Tell how many lines read
212 std::cout << m_className << "::Initialise:\n"
213 << " Read properties of " << m_materials.size() << " materials\n"
214 << " from file " << mplist << "." << std::endl;
215 if (m_debug) PrintMaterials();
216
217 // Check the value of the unit
218 double funit = ScalingFactor(unit);
219 if (funit <= 0.) {
220 std::cerr << m_className << "::Initialise:\n"
221 << " Unknown length unit " << unit << ".\n";
222 ok = false;
223 funit = 1.0;
224 }
225 if (m_debug) {
226 std::cout << m_className << "::Initialise: Unit scaling factor = "
227 << funit << ".\n";
228 }
229
230 // Open the node list
231 std::ifstream fnlist(nlist);
232 if (!fnlist) {
233 PrintCouldNotOpen("Initialise", nlist);
234 return false;
235 }
236 // Read the node list
237 m_nNodes = 0;
238 il = 0;
239 int xlines = 0, ylines = 0, zlines = 0;
240 int lines_type = -1;
241 double line_tmp;
242 while (fnlist.getline(line, size, '\n')) {
243 il++;
244 // Split the line in tokens
245 char* token = strtok(line, " ");
246 // Skip blank lines and headers
247 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
248 int(token[0]) == 10 || int(token[0]) == 13)
249 continue;
250 // Read max sizes
251 if (strcmp(token, "xmax") == 0) {
252 token = strtok(nullptr, " ");
253 xlines = ReadInteger(token, -1, readerror);
254 token = strtok(nullptr, " ");
255 token = strtok(nullptr, " ");
256 ylines = ReadInteger(token, -1, readerror);
257 token = strtok(nullptr, " ");
258 token = strtok(nullptr, " ");
259 zlines = ReadInteger(token, -1, readerror);
260 if (readerror) break;
261 continue;
262 }
263 if (strcmp(token, "x-lines\n") == 0 || strcmp(token, "x-lines") == 0) {
264 lines_type = 1;
265 if (m_debug) {
266 std::cout << m_className << "::Initialise:\n"
267 << " Reading x-lines from file " << nlist << ".\n";
268 }
269 continue;
270 }
271 if (strcmp(token, "y-lines\n") == 0 || strcmp(token, "y-lines") == 0) {
272 lines_type = 2;
273 if (m_debug) {
274 std::cout << m_className << "::Initialise:\n"
275 << " Reading y-lines from file " << nlist << ".\n";
276 }
277 continue;
278 }
279 if (strcmp(token, "z-lines\n") == 0 || strcmp(token, "z-lines") == 0) {
280 lines_type = 3;
281 if (m_debug) {
282 std::cout << m_className << "::Initialise:\n"
283 << " Reading z-lines from file " << nlist << ".\n";
284 }
285 continue;
286 }
287 line_tmp = ReadDouble(token, -1, readerror);
288 if (lines_type == 1)
289 m_xlines.push_back(line_tmp * funit);
290 else if (lines_type == 2)
291 m_ylines.push_back(line_tmp * funit);
292 else if (lines_type == 3)
293 m_zlines.push_back(line_tmp * funit);
294 else {
295 std::cerr << m_className << "::Initialise:" << std::endl;
296 std::cerr << " Line type was not set in " << nlist << " (line " << il
297 << ", token = " << token << ")." << std::endl;
298 std::cerr << " Maybe it is in the wrong format" << std::endl;
299 std::cerr << " e.g. missing tailing space after x-lines." << std::endl;
300 ok = false;
301 break;
302 }
303 if (readerror) break;
304 }
305 // Check syntax
306 if (readerror) {
307 std::cerr << m_className << "::Initialise:\n"
308 << " Error reading file " << nlist
309 << " (line " << il << ").\n";
310 fnlist.close();
311 return false;
312 }
313 // Close the file
314 fnlist.close();
315
316 if ((unsigned)xlines == m_xlines.size() &&
317 (unsigned)ylines == m_ylines.size() &&
318 (unsigned)zlines == m_zlines.size()) {
319 std::cout << m_className << "::Initialise:" << std::endl;
320 std::cout << " Found in file " << nlist << "\n " << xlines
321 << " x-lines\n " << ylines << " y-lines\n " << zlines
322 << " z-lines" << std::endl;
323 } else {
324 std::cerr << m_className << "::Initialise:" << std::endl;
325 std::cerr << " There should be " << xlines << " x-lines, " << ylines
326 << " y-lines and " << zlines << " z-lines in file " << nlist
327 << " but I found :\n " << m_xlines.size() << " x-lines, "
328 << m_ylines.size() << " x-lines, " << m_zlines.size()
329 << " z-lines." << std::endl;
330 }
331 m_nx = m_xlines.size();
332 m_ny = m_ylines.size();
333 m_nz = m_zlines.size();
334 m_nNodes = m_nx * m_ny * m_nz;
335 m_nElements = (m_nx - 1) * (m_ny - 1) * (m_nz - 1);
336
337 // Tell how many lines read
338 std::cout << m_className << "::Initialise:" << std::endl;
339 std::cout << " Read " << m_nNodes << " nodes from file " << nlist << "."
340 << std::endl;
341
342 // Open the element list
343 std::ifstream felist(elist);
344 if (!felist) {
345 PrintCouldNotOpen("Initialise", elist);
346 return false;
347 }
348 // Read the element list
349 m_elementMaterial.resize(m_nElements);
350 il = 0;
351 while (felist.getline(line, size, '\n')) {
352 il++;
353 // Split the line in tokens
354 char* token = strtok(line, " ");
355 // Skip blank lines and headers
356 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
357 int(token[0]) == 10 || int(token[0]) == 13 ||
358 strcmp(token, "LIST") == 0 || strcmp(token, "ELEM") == 0)
359 continue;
360 // Read the element
361 int ielem = ReadInteger(token, -1, readerror);
362 token = strtok(nullptr, " ");
363 if (!token) continue;
364 unsigned char imat = atoi(token);
365 // construct node numbers
366 std::vector<int> node_nb;
367 try {
368 // Read element material - the number of the material is stored (1, 2,
369 // ...) but we need the index (0, 1, ...)
370 m_elementMaterial.at(ielem) = (imat - 1);
371 } catch (...) {
372 std::cerr << m_className << "::Initialise:" << std::endl;
373 std::cerr << " Error reading file " << elist << " (line " << il << ")."
374 << std::endl;
375 std::cerr << " The element index (" << ielem
376 << ") is not in the expected range: 0 - " << m_nElements
377 << std::endl;
378 ok = false;
379 }
380 // Check the material number and ensure that epsilon is non-negative
381 // int check_mat = imat;
382 if (imat < 1 || imat > m_materials.size()) {
383 std::cerr << m_className << "::Initialise:" << std::endl;
384 std::cerr << " Out-of-range material number on file " << elist
385 << " (line " << il << ")." << std::endl;
386 std::cerr << " Element: " << ielem << ", material: " << imat
387 << std::endl;
388 ok = false;
389 }
390 if (m_materials[imat - 1].eps < 0) {
391 std::cerr << m_className << "::Initialise:" << std::endl;
392 std::cerr << " Element " << ielem << " in element list " << elist
393 << " uses material " << imat << " which" << std::endl;
394 std::cerr << " has not been assigned a positive permittivity"
395 << std::endl;
396 std::cerr << " in material list " << mplist << "." << std::endl;
397 ok = false;
398 }
399 }
400 // Close the file
401 felist.close();
402 // Tell how many lines read
403 std::cout << m_className << "::Initialise:" << std::endl;
404 std::cout << " Read " << m_nElements << " elements.\n";
405
406 // Open the voltage list
407 m_potential.resize(m_nNodes);
408 std::ifstream fprnsol(prnsol);
409 if (!fprnsol) {
410 PrintCouldNotOpen("Initialise", prnsol);
411 return false;
412 }
413 // Read the voltage list
414 il = 0;
415 int nread = 0;
416 readerror = false;
417 while (fprnsol.getline(line, size, '\n')) {
418 il++;
419 // Split the line in tokens
420 char* token = strtok(line, " ");
421 // Skip blank lines and headers
422 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
423 int(token[0]) == 10 || int(token[0]) == 13 || strcmp(token, "Max") == 0)
424 continue;
425 // Read node potential (in prnsol node id starts with 1 and here we will use
426 // 0 as first node...)
427 int inode = ReadInteger(token, -1, readerror);
428 token = strtok(nullptr, " ");
429 double volt = ReadDouble(token, -1, readerror);
430
431 try {
432 m_potential.at(inode - 1) = volt;
433 nread++;
434 } catch (...) {
435 std::cerr << m_className << "::Initialise:" << std::endl;
436 std::cerr << " Error reading file " << prnsol << " (line " << il
437 << ")." << std::endl;
438 std::cerr << " The node index (" << inode - 1
439 << ") is not in the expected range: 0 - " << m_nNodes
440 << std::endl;
441 ok = false;
442 }
443 }
444 // Close the file
445 fprnsol.close();
446 // Tell how many lines read
447 std::cout << m_className << "::Initialise:" << std::endl;
448 std::cout << " Read " << nread << "/" << m_nNodes
449 << " (expected) potentials from file " << prnsol << "."
450 << std::endl;
451 // Check number of nodes
452 if (nread != (int)m_nNodes) {
453 std::cerr << m_className << "::Initialise:" << std::endl;
454 std::cerr << " Number of nodes read (" << nread << ") on potential file "
455 << prnsol << " does not" << std::endl;
456 std::cerr << " match the node list (" << m_nNodes << ").\n";
457 ok = false;
458 }
459 // Set the ready flag
460 if (ok) {
461 m_ready = true;
462 } else {
463 std::cerr << m_className << "::Initialise:" << std::endl;
464 std::cerr << " Field map could not be read and cannot be interpolated."
465 << std::endl;
466 return false;
467 }
468 Prepare();
469 return true;
470}
471
472bool ComponentCST::Initialise(std::string dataFile, std::string unit) {
473 m_ready = false;
474
475 // Keep track of the success
476 bool ok = true;
477 // Check the value of the unit
478 double funit = ScalingFactor(unit);
479 if (funit <= 0.) {
480 std::cerr << m_className << "::Initialise:\n"
481 << " Unknown length unit " << unit << ".\n";
482 ok = false;
483 funit = 1.0;
484 }
485 if (m_debug) {
486 std::cout << m_className << "::Initialise: Unit scaling factor = "
487 << funit << ".\n";
488 }
489 FILE* f = fopen(dataFile.c_str(), "rb");
490 if (f == nullptr) {
491 PrintCouldNotOpen("Initialise", dataFile);
492 return false;
493 }
494
495 struct stat fileStatus;
496 stat(dataFile.c_str(), &fileStatus);
497 int fileSize = fileStatus.st_size;
498
499 int nLinesX = 0, nLinesY = 0, nLinesZ = 0;
500 int nNS = 0, nES = 0, nEM = 0;
501 int nMaterials = 0;
502 if (!ReadHeader(f, fileSize, m_debug, nLinesX, nLinesY, nLinesZ,
503 nNS, nES, nEM, nMaterials)) {
504 fclose(f);
505 return false;
506 }
507 m_nx = nLinesX;
508 m_ny = nLinesY;
509 m_nz = nLinesZ;
510 m_nNodes = m_nx * m_ny * m_nz;
511 m_nElements = (m_nx - 1) * (m_ny - 1) * (m_nz - 1);
512
513 m_xlines.resize(nLinesX);
514 m_ylines.resize(nLinesY);
515 m_zlines.resize(nLinesZ);
516 m_potential.resize(nNS);
517 m_elementMaterial.resize(nEM);
518 m_materials.resize(nMaterials);
519 auto result = fread(m_xlines.data(), sizeof(double), m_xlines.size(), f);
520 if (result != m_xlines.size()) {
521 fputs("Reading error while reading xlines.", stderr);
522 exit(3);
523 } else if (result == 0) {
524 fputs("No xlines are stored in the data file.", stderr);
525 exit(3);
526 }
527 result = fread(m_ylines.data(), sizeof(double), m_ylines.size(), f);
528 if (result != m_ylines.size()) {
529 fputs("Reading error while reading ylines", stderr);
530 exit(3);
531 } else if (result == 0) {
532 fputs("No ylines are stored in the data file.", stderr);
533 exit(3);
534 }
535 result = fread(m_zlines.data(), sizeof(double), m_zlines.size(), f);
536 if (result != m_zlines.size()) {
537 fputs("Reading error while reading zlines", stderr);
538 exit(3);
539 } else if (result == 0) {
540 fputs("No zlines are stored in the data file.", stderr);
541 exit(3);
542 }
543 result = fread(m_potential.data(), sizeof(float), m_potential.size(), f);
544 if (result != m_potential.size()) {
545 fputs("Reading error while reading nodes.", stderr);
546 exit(3);
547 } else if (result == 0) {
548 fputs("No potentials are stored in the data file.", stderr);
549 exit(3);
550 }
551 fseek(f, nES * sizeof(float), SEEK_CUR);
552 // not needed in principle - thus it is ok if nothing is read
553 result = fread(m_elementMaterial.data(), sizeof(unsigned char),
554 m_elementMaterial.size(), f);
555 if (result != m_elementMaterial.size()) {
556 fputs("Reading error while reading element material", stderr);
557 exit(3);
558 }
559 std::stringstream st;
560 st << m_className << "::Initialise:" << std::endl;
561 /*
562 * The material vector is filled according to the material id!
563 * Thus material.at(0) is material with id 0.
564 */
565 for (unsigned int i = 0; i < m_materials.size(); i++) {
566 float id;
567 result = fread(&(id), sizeof(float), 1, f);
568 if (result != 1) {
569 fputs("Input error while reading material id.", stderr);
570 exit(3);
571 }
572 // const unsigned int index = id;
573 const unsigned int index = i;
574 unsigned int description_size = 0;
575 result = fread(&(description_size), sizeof(int), 1, f);
576 if (result != 1) {
577 fputs("Input error while reading material description size.", stderr);
578 exit(3);
579 }
580 char* c = new char[description_size];
581 result = fread(c, sizeof(char), description_size, f);
582 if (result != description_size) {
583 fputs("Input error while reading material description.", stderr);
584 exit(3);
585 }
586 std::string name = c;
587 st << " Read material: " << name;
588 if (name.compare("gas") == 0) {
589 st << " (considered as drift medium)";
590 m_materials.at(index).driftmedium = true;
591 } else {
592 m_materials.at(index).driftmedium = false;
593 }
594 delete[] c;
595 float eps;
596 result = fread(&(eps), sizeof(float), 1, f);
597 m_materials.at(index).eps = eps;
598 if (result != 1) {
599 fputs("Reading error while reading eps.", stderr);
600 exit(3);
601 }
602 st << "; eps is: " << m_materials.at(index).eps;
603 // float mue;
604 // result = fread(&(mue), sizeof(float), 1, f);
605 // if (result != 1) {
606 // fputs ("Reading error while reading mue.", stderr);
607 // exit (3);
608 // }
609 // st << "\t mue is: " << mue;
610 // float rho;
611 // result = fread(&(rho), sizeof(float), 1, f);
612 // if (result != 1) {
613 // fputs ("Reading error while reading rho.", stderr);
614 // exit (3);
615 // }
616 // st << "\t rho is: " << rho;
617 st << "\t id is: " << id << std::endl;
618 // Skip mue and rho
619 fseek(f, 2 * sizeof(float), SEEK_CUR);
620 // ToDo: Check if rho should be used to decide, which material is driftable
621 }
622 // To be sure that they are sorted (should be already be the case)
623 std::sort(m_xlines.begin(), m_xlines.end());
624 std::sort(m_ylines.begin(), m_ylines.end());
625 std::sort(m_zlines.begin(), m_zlines.end());
626 if (funit != 1) {
627 std::transform(m_xlines.begin(), m_xlines.end(), m_xlines.begin(), [funit](double x) { return x * funit;});
628 std::transform(m_ylines.begin(), m_ylines.end(), m_ylines.begin(), [funit](double x) { return x * funit;});
629 std::transform(m_zlines.begin(), m_zlines.end(), m_zlines.begin(), [funit](double x) { return x * funit;});
630 }
631
632 std::cout << m_className << "::Initialise" << std::endl;
633 std::cout << " x range: " << *(m_xlines.begin()) << " - "
634 << *(m_xlines.end() - 1) << std::endl;
635 std::cout << " y range: " << *(m_ylines.begin()) << " - "
636 << *(m_ylines.end() - 1) << std::endl;
637 std::cout << " z range: " << *(m_zlines.begin()) << " - "
638 << *(m_zlines.end() - 1) << std::endl;
639 fclose(f);
640 // Set the ready flag
641 if (ok) {
642 m_ready = true;
643 } else {
644 std::cerr << m_className << "::Initialise:" << std::endl;
645 std::cerr << " Field map could not be read and cannot be interpolated."
646 << std::endl;
647 return false;
648 }
649
650 SetRange();
652 return true;
653}
654
655bool ComponentCST::SetWeightingField(std::string prnsol, std::string label,
656 bool isBinary) {
657 std::vector<float> potentials(m_nNodes);
658 if (!m_ready) {
659 std::cerr << m_className << "::SetWeightingField:" << std::endl;
660 std::cerr << " No valid field map is present." << std::endl;
661 std::cerr << " Weighting field cannot be added." << std::endl;
662 return false;
663 }
664
665 // Open the voltage list
666 std::ifstream fprnsol(prnsol);
667 if (!fprnsol) {
668 PrintCouldNotOpen("SetWeightingField", prnsol);
669 return false;
670 }
671 // Check if a weighting field with the same label already exists.
672 auto it = m_weightingFields.find(label);
673 if (it != m_weightingFields.end()) {
674 std::cout << m_className << "::SetWeightingField:" << std::endl;
675 std::cout << " Replacing existing weighting field " << label << "."
676 << std::endl;
677 }
678
679 int nread = 0;
680 bool ok = true;
681
682 if (isBinary) {
683 std::cout << m_className << "::SetWeightingField:" << std::endl;
684 std::cout << " Reading weighting field from binary file:"
685 << prnsol << std::endl;
686 FILE* f = fopen(prnsol.c_str(), "rb");
687 if (f == nullptr) {
688 PrintCouldNotOpen("SetWeightingField", prnsol);
689 return false;
690 }
691
692 struct stat fileStatus;
693 stat(prnsol.c_str(), &fileStatus);
694 int fileSize = fileStatus.st_size;
695
696 int nLinesX = 0, nLinesY = 0, nLinesZ = 0;
697 int nES = 0, nEM = 0;
698 int nMaterials = 0;
699 if (!ReadHeader(f, fileSize, m_debug, nLinesX, nLinesY, nLinesZ,
700 nread, nES, nEM, nMaterials)) {
701 fclose(f);
702 return false;
703 }
704 // Skip everything, but the potential
705 fseek(f, nLinesX * sizeof(double), SEEK_CUR);
706 fseek(f, nLinesY * sizeof(double), SEEK_CUR);
707 fseek(f, nLinesZ * sizeof(double), SEEK_CUR);
708 auto result = fread(potentials.data(), sizeof(float), potentials.size(), f);
709 if (result != potentials.size()) {
710 fputs("Reading error while reading nodes.", stderr);
711 exit(3);
712 } else if (result == 0) {
713 fputs("No weighting potentials are stored in the data file.", stderr);
714 exit(3);
715 }
716 fprnsol.close();
717 } else {
718 std::cout << m_className << "::SetWeightingField:" << std::endl;
719 std::cout << " Reading weighting field from text file:" << prnsol
720 << std::endl;
721 // Buffer for reading
722 const int size = 100;
723 char line[size];
724
725 // Read the voltage list
726 int il = 0;
727
728 bool readerror = false;
729 while (fprnsol.getline(line, size, '\n')) {
730 il++;
731 // Split the line in tokens
732 char* token = strtok(line, " ");
733 // Skip blank lines and headers
734 if (!token || strcmp(token, " ") == 0 || strcmp(token, "\n") == 0 ||
735 int(token[0]) == 10 || int(token[0]) == 13 ||
736 strcmp(token, "PRINT") == 0 || strcmp(token, "*****") == 0 ||
737 strcmp(token, "LOAD") == 0 || strcmp(token, "TIME=") == 0 ||
738 strcmp(token, "MAXIMUM") == 0 || strcmp(token, "VALUE") == 0 ||
739 strcmp(token, "NODE") == 0)
740 continue;
741 // Read the element
742 int inode = ReadInteger(token, -1, readerror);
743 token = strtok(nullptr, " ");
744 double volt = ReadDouble(token, -1, readerror);
745 try {
746 potentials.at(inode - 1) = volt;
747 nread++;
748 } catch (...) {
749 std::cerr << m_className << "::SetWeightingField:" << std::endl;
750 std::cerr << " Node number " << inode << " out of range."
751 << std::endl;
752 std::cerr << " on potential file " << prnsol << " (line " << il
753 << ")." << std::endl;
754 std::cerr << " Size of the potential vector is: "
755 << potentials.size() << std::endl;
756 ok = false;
757 }
758 }
759 // Close the file
760 fprnsol.close();
761 }
762 // Tell how many lines read
763 std::cout << m_className << "::SetWeightingField:" << std::endl;
764 std::cout << " Read " << nread << "/" << m_nNodes
765 << " (expected) potentials from file " << prnsol << "."
766 << std::endl;
767 // Check number of nodes
768 if (nread != (int)m_nNodes) {
769 std::cerr << m_className << "::SetWeightingField:" << std::endl;
770 std::cerr << " Number of nodes read (" << nread << ")"
771 << " on potential file (" << prnsol << ")" << std::endl;
772 std::cerr << " does not match the node list (" << m_nNodes << ")."
773 << std::endl;
774 ok = false;
775 }
776 if (!ok) {
777 std::cerr << m_className << "::SetWeightingField:" << std::endl;
778 std::cerr << " Field map could not be read "
779 << "and cannot be interpolated." << std::endl;
780 return false;
781 }
782
783 m_weightingFields[label] = potentials;
784 return true;
785}
786
787void ComponentCST::ShiftComponent(const double xShift, const double yShift,
788 const double zShift) {
789 std::transform(m_xlines.begin(), m_xlines.end(), m_xlines.begin(), [xShift](double x) { return x + xShift;});
790 std::transform(m_ylines.begin(), m_ylines.end(), m_ylines.begin(), [yShift](double x) { return x + yShift;});
791 std::transform(m_zlines.begin(), m_zlines.end(), m_zlines.begin(), [zShift](double x) { return x + zShift;});
792 SetRange();
794
795 std::cout << m_className << "::ShiftComponent:" << std::endl;
796 std::cout << " Shifted component in x-direction: " << xShift
797 << "\t y-direction: " << yShift << "\t z-direction: " << zShift
798 << std::endl;
799}
800
801void ComponentCST::ElectricField(const double xin, const double yin,
802 const double zin, double& ex, double& ey,
803 double& ez, Medium*& m, int& status) {
804 double volt;
805 ElectricFieldBinary(xin, yin, zin, ex, ey, ez, volt, m, status);
806}
807
808void ComponentCST::ElectricField(const double xin, const double yin,
809 const double zin, double& ex, double& ey,
810 double& ez, double& volt, Medium*& m,
811 int& status) {
812 ElectricFieldBinary(xin, yin, zin, ex, ey, ez, volt, m, status, true);
813}
814
815void ComponentCST::WeightingField(const double xin, const double yin,
816 const double zin, double& wx, double& wy,
817 double& wz, const std::string& label) {
818 // Initial values
819 wx = wy = wz = 0;
820
821 // Do not proceed if not properly initialised.
822 if (!m_ready) return;
823
824 // Look for the label.
825 auto it = m_weightingFields.find(label);
826 if (it == m_weightingFields.end()) {
827 // Do not proceed if the requested weighting field does not exist.
828 std::cerr << "No weighting field named " << label << " found!\n";
829 return;
830 }
831
832 // Check if the weighting field is properly initialised.
833 if (m_weightingFields[label].empty()) return;
834
835 // Copy the coordinates
836 double x = xin, y = yin, z = zin;
837
838 // Map the coordinates onto field map coordinates and get indexes
839 bool mirrored[3];
840 unsigned int i, j, k;
841 double pos[3] = {0., 0., 0.};
842 if (!Coordinate2Index(x, y, z, i, j, k, pos, mirrored)) {
843 return;
844 }
845
846 double rx = (pos[0] - m_xlines.at(i)) / (m_xlines.at(i + 1) - m_xlines.at(i));
847 double ry = (pos[1] - m_ylines.at(j)) / (m_ylines.at(j + 1) - m_ylines.at(j));
848 double rz = (pos[2] - m_zlines.at(k)) / (m_zlines.at(k + 1) - m_zlines.at(k));
849
850 float fwx = 0., fwy = 0., fwz = 0.;
851 if (!disableFieldComponent[0])
852 fwx = GetFieldComponent(i, j, k, rx, ry, rz, 'x', (*it).second);
853 if (!disableFieldComponent[1])
854 fwy = GetFieldComponent(i, j, k, rx, ry, rz, 'y', (*it).second);
855 if (!disableFieldComponent[2])
856 fwz = GetFieldComponent(i, j, k, rx, ry, rz, 'z', (*it).second);
857
858 if (m_elementMaterial.size() > 0 && doShaping) {
859 ShapeField(fwx, fwy, fwz, rx, ry, rz, i, j, k, (*it).second);
860 }
861 if (mirrored[0]) fwx *= -1.f;
862 if (mirrored[1]) fwy *= -1.f;
863 if (mirrored[2]) fwz *= -1.f;
864 if (m_warning) PrintWarning("WeightingField");
865 if (m_materials.at(m_elementMaterial.at(Index2Element(i, j, k))).driftmedium) {
866 if (!disableFieldComponent[0]) wx = fwx;
867 if (!disableFieldComponent[1]) wy = fwy;
868 if (!disableFieldComponent[2]) wz = fwz;
869 }
870}
871
872double ComponentCST::WeightingPotential(const double xin, const double yin,
873 const double zin,
874 const std::string& label) {
875 // Do not proceed if not properly initialised.
876 if (!m_ready) return 0.;
877
878 // Look for the label.
879 auto it = m_weightingFields.find(label);
880 if (it == m_weightingFields.end()) {
881 // Do not proceed if the requested weighting field does not exist.
882 std::cerr << "No weighting field named " << label << " found!\n";
883 return 0.;
884 }
885
886 // Check if the weighting field is properly initialised.
887 if (m_weightingFields[label].empty()) return 0.;
888
889 // Copy the coordinates
890 double x = xin, y = yin, z = zin;
891
892 // Map the coordinates onto field map coordinates
893 bool mirrored[3];
894 unsigned int i, j, k;
895 double pos[3] = {0., 0., 0.};
896 if (!Coordinate2Index(x, y, z, i, j, k, pos, mirrored)) {
897 return 0.;
898 }
899 double rx = (pos[0] - m_xlines.at(i)) /
900 (m_xlines.at(i + 1) - m_xlines.at(i));
901 double ry = (pos[1] - m_ylines.at(j)) /
902 (m_ylines.at(j + 1) - m_ylines.at(j));
903 double rz = (pos[2] - m_zlines.at(k)) /
904 (m_zlines.at(k + 1) - m_zlines.at(k));
905
906 double potential = GetPotential(i, j, k, rx, ry, rz, (*it).second);
907
908 if (m_debug) {
909 std::cout << m_className << "::WeightingPotential:" << std::endl;
910 std::cout << " Global: (" << x << "," << y << "," << z << "),"
911 << std::endl;
912 std::cout << " Local: (" << rx << "," << ry << "," << rz
913 << ") in element with indexes: i=" << i << ", j=" << j
914 << ", k=" << k << std::endl;
915 std::cout << " Node xyzV:" << std::endl;
916 std::cout << "Node 0 position: " << Index2Node(i + 1, j, k)
917 << "\t potential: " << ((*it).second).at(Index2Node(i + 1, j, k))
918 << "Node 1 position: " << Index2Node(i + 1, j + 1, k)
919 << "\t potential: "
920 << ((*it).second).at(Index2Node(i + 1, j + 1, k))
921 << "Node 2 position: " << Index2Node(i, j + 1, k)
922 << "\t potential: " << ((*it).second).at(Index2Node(i, j + 1, k))
923 << "Node 3 position: " << Index2Node(i, j, k)
924 << "\t potential: " << ((*it).second).at(Index2Node(i, j, k))
925 << "Node 4 position: " << Index2Node(i + 1, j, k + 1)
926 << "\t potential: "
927 << ((*it).second).at(Index2Node(i + 1, j, k + 1))
928 << "Node 5 position: " << Index2Node(i + 1, j + 1, k + 1)
929 << "\t potential: "
930 << ((*it).second).at(Index2Node(i + 1, j + 1, k + 1))
931 << "Node 6 position: " << Index2Node(i, j + 1, k + 1)
932 << "\t potential: "
933 << ((*it).second).at(Index2Node(i, j + 1, k + 1))
934 << "Node 7 position: " << Index2Node(i, j, k + 1)
935 << "\t potential: " << ((*it).second).at(Index2Node(i, j, k))
936 << std::endl;
937 }
938 return potential;
939}
940
941void ComponentCST::GetNumberOfMeshLines(unsigned int& n_x, unsigned int& n_y,
942 unsigned int& n_z) const {
943 n_x = m_xlines.size();
944 n_y = m_ylines.size();
945 n_z = m_zlines.size();
946}
947
948bool ComponentCST::GetElement(const size_t element, size_t& mat, bool& drift,
949 std::vector<size_t>& nodes) const {
950 if (element >= m_nElements || element >= m_elementMaterial.size()) {
951 std::cerr << m_className << "::GetElement: Index out of range.\n";
952 return false;
953 }
954 mat = m_elementMaterial[element];
955 drift = m_materials[mat].driftmedium;
956 nodes.clear();
957 unsigned int i0 = 0, j0 = 0, k0 = 0;
958 Element2Index(element, i0, j0, k0);
959 const auto i1 = i0 + 1;
960 const auto j1 = j0 + 1;
961 const auto k1 = k0 + 1;
962 nodes.push_back(Index2Node(i0, j0, k0));
963 nodes.push_back(Index2Node(i1, j0, k0));
964 nodes.push_back(Index2Node(i0, j1, k0));
965 nodes.push_back(Index2Node(i1, j1, k0));
966 nodes.push_back(Index2Node(i0, j0, k1));
967 nodes.push_back(Index2Node(i1, j0, k1));
968 nodes.push_back(Index2Node(i0, j1, k1));
969 nodes.push_back(Index2Node(i1, j1, k1));
970 return true;
971}
972
973bool ComponentCST::GetNode(const size_t node,
974 double& x, double& y, double& z) const {
975 if (node >= m_nNodes) {
976 std::cerr << m_className << "::GetNode: Index out of range.\n";
977 return false;
978 }
979 unsigned int i = 0, j = 0, k = 0;
980 Node2Index(node, i, j, k);
981 x = m_xlines[i];
982 y = m_ylines[j];
983 z = m_zlines[k];
984 return true;
985}
986
987void ComponentCST::GetElementBoundaries(unsigned int element, double& xmin,
988 double& xmax, double& ymin,
989 double& ymax, double& zmin,
990 double& zmax) const {
991 unsigned int i, j, k;
992 Element2Index(element, i, j, k);
993 xmin = m_xlines.at(i);
994 xmax = m_xlines.at(i + 1);
995 ymin = m_ylines.at(j);
996 ymax = m_ylines.at(j + 1);
997 zmin = m_zlines.at(k);
998 zmax = m_zlines.at(k + 1);
999}
1000
1001Medium* ComponentCST::GetMedium(const double x, const double y,
1002 const double z) {
1003 unsigned int i, j, k;
1004 Coordinate2Index(x, y, z, i, j, k);
1005 if (m_debug) {
1006 std::cout << m_className << "::GetMedium:\n"
1007 << " Position (" << x << ", " << y << ", " << z << "):\n"
1008 << " Indices are: x: " << i << "/" << m_xlines.size()
1009 << "\t y: " << j << "/" << m_ylines.size()
1010 << "\t z: " << k << "/" << m_zlines.size() << std::endl;
1011 const auto element = Index2Element(i, j, k);
1012 std::cout << " Element index: " << element << std::endl
1013 << " Material index: "
1014 << (int)m_elementMaterial.at(element) << std::endl;
1015 }
1016 return m_materials.at(m_elementMaterial.at(Index2Element(i, j, k))).medium;
1017}
1018
1020 // Establish the ranges
1021 m_mapmin[0] = m_xlines.front();
1022 m_mapmax[0] = m_xlines.back();
1023 m_mapmin[1] = m_ylines.front();
1024 m_mapmax[1] = m_ylines.back();
1025 m_mapmin[2] = m_zlines.front();
1026 m_mapmax[2] = m_zlines.back();
1027 m_mapvmin = *std::min_element(m_potential.begin(), m_potential.end());
1028 m_mapvmax = *std::max_element(m_potential.begin(), m_potential.end());
1029
1030 // Set provisional cell dimensions.
1031 m_minBoundingBox[0] = m_mapmin[0];
1032 m_maxBoundingBox[0] = m_mapmax[0];
1033 m_minBoundingBox[1] = m_mapmin[1];
1034 m_maxBoundingBox[1] = m_mapmax[1];
1035 if (m_is3d) {
1036 m_minBoundingBox[2] = m_mapmin[2];
1037 m_maxBoundingBox[2] = m_mapmax[2];
1038 } else {
1039 m_mapmin[2] = m_minBoundingBox[2];
1040 m_mapmax[2] = m_maxBoundingBox[2];
1041 }
1042 m_hasBoundingBox = true;
1043}
1044
1045void ComponentCST::SetRangeZ(const double zmin, const double zmax) {
1046 if (fabs(zmax - zmin) <= 0.) {
1047 std::cerr << m_className << "::SetRangeZ:" << std::endl;
1048 std::cerr << " Zero range is not permitted." << std::endl;
1049 return;
1050 }
1051 m_minBoundingBox[2] = std::min(zmin, zmax);
1052 m_maxBoundingBox[2] = std::max(zmin, zmax);
1053}
1054
1055bool ComponentCST::Coordinate2Index(const double x, const double y,
1056 const double z, unsigned int& i,
1057 unsigned int& j, unsigned int& k) const {
1058 bool mirrored[3] = {false, false, false};
1059 double pos[3] = {0., 0., 0.};
1060 return Coordinate2Index(x, y, z, i, j, k, pos, mirrored);
1061}
1062
1063
1064bool ComponentCST::Coordinate2Index(const double xin, const double yin,
1065 const double zin, unsigned int& i,
1066 unsigned int& j, unsigned int& k,
1067 double* pos, bool* mirrored) const {
1068 // Map the coordinates onto field map coordinates
1069 pos[0] = xin;
1070 pos[1] = yin;
1071 pos[2] = zin;
1072 double rcoordinate = 0.;
1073 double rotation = 0.;
1074 MapCoordinates(pos[0], pos[1], pos[2],
1075 mirrored[0], mirrored[1], mirrored[2], rcoordinate, rotation);
1076
1077 auto it_x =
1078 std::lower_bound(m_xlines.begin(), m_xlines.end(), pos[0]);
1079 auto it_y =
1080 std::lower_bound(m_ylines.begin(), m_ylines.end(), pos[1]);
1081 auto it_z =
1082 std::lower_bound(m_zlines.begin(), m_zlines.end(), pos[2]);
1083 if (it_x == m_xlines.end() || it_y == m_ylines.end() ||
1084 it_z == m_zlines.end() || pos[0] < m_xlines.at(0) ||
1085 pos[1] < m_ylines.at(0) ||
1086 pos[2] < m_zlines.at(0)) {
1087 if (m_debug) {
1088 std::cerr << m_className << "::ElectricFieldBinary:" << std::endl;
1089 std::cerr << " Could not find the given coordinate!" << std::endl;
1090 std::cerr << " You ask for the following position: " << xin << ", "
1091 << yin << ", " << zin << std::endl;
1092 std::cerr << " The mapped position is: " << pos[0] << ", "
1093 << pos[1] << ", " << pos[2]
1094 << std::endl;
1095 }
1096 return false;
1097 }
1098 /* Lower bound returns the next mesh line behind the position in question.
1099 * If the position in question is on a mesh line this mesh line is returned.
1100 * Since we are interested in the mesh line before the position in question we
1101 * need to move the
1102 * iterator to the left except for the very first mesh line!
1103 */
1104 if (it_x == m_xlines.begin())
1105 i = 0;
1106 else
1107 i = std::distance(m_xlines.begin(), it_x - 1);
1108 if (it_y == m_ylines.begin())
1109 j = 0;
1110 else
1111 j = std::distance(m_ylines.begin(), it_y - 1);
1112 if (it_z == m_zlines.begin())
1113 k = 0;
1114 else
1115 k = std::distance(m_zlines.begin(), it_z - 1);
1116 return true;
1117}
1118
1119int ComponentCST::Index2Element(const unsigned int i, const unsigned int j,
1120 const unsigned int k) const {
1121 if (i > m_nx - 2 || j > m_ny - 2 || k > m_nz - 2) {
1122 throw "ComponentCST::Index2Element: Error. Element indices out of bounds.";
1123 }
1124 return i + j * (m_nx - 1) + k * (m_nx - 1) * (m_ny - 1);
1125}
1126
1127void ComponentCST::GetAspectRatio(const size_t element, double& dmin,
1128 double& dmax) const {
1129 if (element >= m_nElements) {
1130 dmin = dmax = 0.;
1131 return;
1132 }
1133 unsigned int i, j, k;
1134 Element2Index(element, i, j, k);
1135 const double dx = fabs(m_xlines.at(i + 1) - m_xlines.at(i));
1136 const double dy = fabs(m_ylines.at(j + 1) - m_ylines.at(j));
1137 const double dz = fabs(m_zlines.at(k + 1) - m_zlines.at(k));
1138 dmin = std::min({dx, dy, dz});
1139 dmax = std::max({dx, dy, dz});
1140}
1141
1142double ComponentCST::GetElementVolume(const size_t element) const {
1143 if (element >= m_nElements) return 0.;
1144 unsigned int i, j, k;
1145 Element2Index(element, i, j, k);
1146 const double dx = fabs(m_xlines.at(i + 1) - m_xlines.at(i));
1147 const double dy = fabs(m_ylines.at(j + 1) - m_ylines.at(j));
1148 const double dz = fabs(m_zlines.at(k + 1) - m_zlines.at(k));
1149 return dx * dy * dz;
1150}
1151
1152void ComponentCST::ElectricFieldBinary(const double xin, const double yin,
1153 const double zin, double& ex, double& ey,
1154 double& ez, double& volt, Medium*& m,
1155 int& status, bool calculatePotential) const {
1156 // Copy the coordinates
1157 double x = xin, y = yin, z = zin;
1158
1159 ex = ey = ez = 0;
1160
1161 bool mirrored[3];
1162 unsigned int i, j, k;
1163 double pos[3] = {0., 0., 0.};
1164 if (!Coordinate2Index(x, y, z, i, j, k, pos, mirrored)) {
1165 return;
1166 }
1167 double rx = (pos[0] - m_xlines.at(i)) / (m_xlines.at(i + 1) - m_xlines.at(i));
1168 double ry = (pos[1] - m_ylines.at(j)) / (m_ylines.at(j + 1) - m_ylines.at(j));
1169 double rz = (pos[2] - m_zlines.at(k)) / (m_zlines.at(k + 1) - m_zlines.at(k));
1170
1171 float fex = GetFieldComponent(i, j, k, rx, ry, rz, 'x', m_potential);
1172 float fey = GetFieldComponent(i, j, k, rx, ry, rz, 'y', m_potential);
1173 float fez = GetFieldComponent(i, j, k, rx, ry, rz, 'z', m_potential);
1174
1175 if (m_elementMaterial.size() > 0 && doShaping) {
1176 ShapeField(fex, fey, fez, rx, ry, rz, i, j, k, m_potential);
1177 }
1178 if (mirrored[0]) fex *= -1.f;
1179 if (mirrored[1]) fey *= -1.f;
1180 if (mirrored[2]) fez *= -1.f;
1181 if (m_debug) {
1182 std::cout << m_className << "::ElectricFieldBinary:" << std::endl;
1183 std::cout << " Found position (" << x << ", " << y << ", " << z
1184 << "): " << std::endl;
1185 std::cout << " Indices are: x: " << i << "/" << m_xlines.size()
1186 << "\t y: " << j << "/" << m_ylines.size() << "\t z: " << k << "/"
1187 << m_zlines.size() << std::endl;
1188 if (i != 0 && j != 0 && k != 0) {
1189 std::cout << " index: " << i << "\t x before: " << m_xlines.at(i - 1)
1190 << "\t x behind: " << m_xlines.at(i) << "\t r = " << rx
1191 << "\n index: " << j << "\t y before: " << m_ylines.at(j - 1)
1192 << "\t y behind: " << m_ylines.at(j) << "\t r = " << ry
1193 << "\n index: " << k << "\t z before: " << m_zlines.at(k - 1)
1194 << "\t z behind: " << m_zlines.at(k) << "\t r = " << rz
1195 << std::endl;
1196 }
1197 std::cout << " Electric field is: " << fex << ", " << fey << ", " << fez
1198 << "): " << std::endl;
1199 }
1200 // Get the material index of the element and return the medium taken from the
1201 // materials (since the material id is equal to the material vector position)
1202 const auto imat = m_elementMaterial.at(Index2Element(i, j, k));
1203 m = m_materials.at(imat).medium;
1204 // m = materials[elements[imap].matmap].medium;
1205 status = -5;
1206 if (m_materials.at(imat).driftmedium) {
1207 if (m) {
1208 if (m->IsDriftable()) status = 0;
1209 }
1210 }
1211 if (!disableFieldComponent[0]) ex = fex;
1212 if (!disableFieldComponent[1]) ey = fey;
1213 if (!disableFieldComponent[2]) ez = fez;
1214 if (calculatePotential)
1215 volt = GetPotential(i, j, k, rx, ry, rz, m_potential);
1216}
1217
1218float ComponentCST::GetFieldComponent(
1219 const unsigned int i, const unsigned int j, const unsigned int k,
1220 const double rx, const double ry, const double rz,
1221 const char component, const std::vector<float>& potentials) const {
1222 float e = 0.;
1223 if (component == 'x') {
1224 const float dv1 = potentials.at(Index2Node(i + 1, j, k)) -
1225 potentials.at(Index2Node(i, j, k));
1226 const float dv2 = potentials.at(Index2Node(i + 1, j + 1, k)) -
1227 potentials.at(Index2Node(i, j + 1, k));
1228 const float dv3 = potentials.at(Index2Node(i + 1, j + 1, k + 1)) -
1229 potentials.at(Index2Node(i, j + 1, k + 1));
1230 const float dv4 = potentials.at(Index2Node(i + 1, j, k + 1)) -
1231 potentials.at(Index2Node(i, j, k + 1));
1232
1233 const float dv11 = dv1 + (dv4 - dv1) * rz;
1234 const float dv21 = dv2 + (dv3 - dv2) * rz;
1235 const float dv = dv11 + (dv21 - dv11) * ry;
1236 e = -1 * dv / (m_xlines.at(i + 1) - m_xlines.at(i));
1237 }
1238 if (component == 'y') {
1239 const float dv1 = potentials.at(Index2Node(i, j + 1, k)) -
1240 potentials.at(Index2Node(i, j, k));
1241 const float dv2 = potentials.at(Index2Node(i, j + 1, k + 1)) -
1242 potentials.at(Index2Node(i, j, k + 1));
1243 const float dv3 = potentials.at(Index2Node(i + 1, j + 1, k + 1)) -
1244 potentials.at(Index2Node(i + 1, j, k + 1));
1245 const float dv4 = potentials.at(Index2Node(i + 1, j + 1, k)) -
1246 potentials.at(Index2Node(i + 1, j, k));
1247
1248 const float dv11 = dv1 + (dv4 - dv1) * rx;
1249 const float dv21 = dv2 + (dv3 - dv2) * rx;
1250 const float dv = dv11 + (dv21 - dv11) * rz;
1251 e = -1 * dv / (m_ylines.at(j + 1) - m_ylines.at(j));
1252 }
1253 if (component == 'z') {
1254 const float dv1 = potentials.at(Index2Node(i, j, k + 1)) -
1255 potentials.at(Index2Node(i, j, k));
1256 const float dv2 = potentials.at(Index2Node(i + 1, j, k + 1)) -
1257 potentials.at(Index2Node(i + 1, j, k));
1258 const float dv3 = potentials.at(Index2Node(i + 1, j + 1, k + 1)) -
1259 potentials.at(Index2Node(i + 1, j + 1, k));
1260 const float dv4 = potentials.at(Index2Node(i, j + 1, k + 1)) -
1261 potentials.at(Index2Node(i, j + 1, k));
1262
1263 const float dv11 = dv1 + (dv4 - dv1) * ry;
1264 const float dv21 = dv2 + (dv3 - dv2) * ry;
1265 const float dv = dv11 + (dv21 - dv11) * rx;
1266 e = -1 * dv / (m_zlines.at(k + 1) - m_zlines.at(k));
1267 }
1268 return e;
1269}
1270
1271float ComponentCST::GetPotential(
1272 const unsigned int i, const unsigned int j, const unsigned int k,
1273 const double rx, const double ry, const double rz,
1274 const std::vector<float>& potentials) const {
1275 double t1 = rx * 2. - 1;
1276 double t2 = ry * 2. - 1;
1277 double t3 = rz * 2. - 1;
1278 return (potentials.at(Index2Node(i + 1, j, k)) * (1 - t1) * (1 - t2) *
1279 (1 - t3) +
1280 potentials.at(Index2Node(i + 1, j + 1, k)) * (1 + t1) * (1 - t2) *
1281 (1 - t3) +
1282 potentials.at(Index2Node(i, j + 1, k)) * (1 + t1) * (1 + t2) *
1283 (1 - t3) +
1284 potentials.at(Index2Node(i, j, k)) * (1 - t1) * (1 + t2) * (1 - t3) +
1285 potentials.at(Index2Node(i + 1, j, k + 1)) * (1 - t1) * (1 - t2) *
1286 (1 + t3) +
1287 potentials.at(Index2Node(i + 1, j + 1, k + 1)) * (1 + t1) *
1288 (1 - t2) * (1 + t3) +
1289 potentials.at(Index2Node(i, j + 1, k + 1)) * (1 + t1) * (1 + t2) *
1290 (1 + t3) +
1291 potentials.at(Index2Node(i, j, k + 1)) * (1 - t1) * (1 + t2) *
1292 (1 + t3)) /
1293 8.;
1294}
1295
1296void ComponentCST::ShapeField(float& ex, float& ey, float& ez,
1297 const double rx, const double ry, const double rz,
1298 const unsigned int i, const unsigned int j, const unsigned int k,
1299 const std::vector<float>& potentials) const {
1300
1301 const auto m1 = m_elementMaterial.at(Index2Element(i, j, k));
1302 const auto imax = m_xlines.size() - 2;
1303 if ((i == 0 && rx >= 0.5) || (i == imax && rx < 0.5) || (i > 0 && i < imax)) {
1304 if (rx >= 0.5) {
1305 const auto m2 = m_elementMaterial.at(Index2Element(i + 1, j, k));
1306 if (m1 == m2) {
1307 float ex_next =
1308 GetFieldComponent(i + 1, j, k, 0.5, ry, rz, 'x', potentials);
1309 ex = ex +
1310 (rx - 0.5) * (ex_next - ex) *
1311 (m_xlines.at(i + 1) - m_xlines.at(i)) /
1312 (m_xlines.at(i + 2) - m_xlines.at(i + 1));
1313 }
1314 } else {
1315 const auto m2 = m_elementMaterial.at(Index2Element(i - 1, j, k));
1316 if (m1 == m2) {
1317 float ex_before =
1318 GetFieldComponent(i - 1, j, k, 0.5, ry, rz, 'x', potentials);
1319 ex = ex_before +
1320 (rx + 0.5) * (ex - ex_before) *
1321 (m_xlines.at(i) - m_xlines.at(i - 1)) /
1322 (m_xlines.at(i + 1) - m_xlines.at(i));
1323 }
1324 }
1325 }
1326
1327 const auto jmax = m_ylines.size() - 2;
1328 if ((j == 0 && ry >= 0.5) || (j == jmax && ry < 0.5) || (j > 0 && j < jmax)) {
1329 if (ry >= 0.5) {
1330 const auto m2 = m_elementMaterial.at(Index2Element(i, j + 1, k));
1331 if (m1 == m2) {
1332 float ey_next =
1333 GetFieldComponent(i, j + 1, k, rx, 0.5, rz, 'y', potentials);
1334 ey = ey +
1335 (ry - 0.5) * (ey_next - ey) *
1336 (m_ylines.at(j + 1) - m_ylines.at(j)) /
1337 (m_ylines.at(j + 2) - m_ylines.at(j + 1));
1338 }
1339 } else {
1340 const auto m2 = m_elementMaterial.at(Index2Element(i, j - 1, k));
1341 if (m1 == m2) {
1342 float ey_next =
1343 GetFieldComponent(i, j - 1, k, rx, 0.5, rz, 'y', potentials);
1344 ey = ey_next +
1345 (ry + 0.5) * (ey - ey_next) *
1346 (m_ylines.at(j) - m_ylines.at(j - 1)) /
1347 (m_ylines.at(j + 1) - m_ylines.at(j));
1348 }
1349 }
1350 }
1351 const auto kmax = m_zlines.size() - 2;
1352 if ((k == 0 && rz >= 0.5) || (k == kmax && rz < 0.5) || (k > 0 && k < kmax)) {
1353 if (rz >= 0.5) {
1354 const auto m2 = m_elementMaterial.at(Index2Element(i, j, k + 1));
1355 if (m1 == m2) {
1356 float ez_next =
1357 GetFieldComponent(i, j, k + 1, rx, ry, 0.5, 'z', potentials);
1358 ez = ez +
1359 (rz - 0.5) * (ez_next - ez) *
1360 (m_zlines.at(k + 1) - m_zlines.at(k)) /
1361 (m_zlines.at(k + 2) - m_zlines.at(k + 1));
1362 }
1363 } else {
1364 const auto m2 = m_elementMaterial.at(Index2Element(i, j, k - 1));
1365 if (m1 == m2) {
1366 float ez_next =
1367 GetFieldComponent(i, j, k - 1, rx, ry, 0.5, 'z', potentials);
1368 ez = ez_next +
1369 (rz + 0.5) * (ez - ez_next) *
1370 (m_zlines.at(k) - m_zlines.at(k - 1)) /
1371 (m_zlines.at(k + 1) - m_zlines.at(k));
1372 }
1373 }
1374 }
1375}
1376
1377void ComponentCST::Element2Index(const size_t element,
1378 unsigned int& i, unsigned int& j, unsigned int& k) const {
1379 const auto nx = m_xlines.size() - 1;
1380 const auto ny = m_ylines.size() - 1;
1381 const auto nxy = nx * ny;
1382 k = element / nxy;
1383 const auto tmp = element - k * nxy;
1384 j = tmp / nx;
1385 i = tmp - j * nx;
1386}
1387
1388int ComponentCST::Index2Node(const unsigned int i, const unsigned int j,
1389 const unsigned int k) const {
1390 if (i > m_nx - 1 || j > m_ny - 1 || k > m_nz - 1) {
1391 throw "ComponentCST::Index2Node: Error. Node indices out of bounds.";
1392 }
1393 return i + j * m_nx + k * m_nx * m_ny;
1394}
1395
1396void ComponentCST::Node2Index(const size_t node,
1397 unsigned int& i, unsigned int& j, unsigned int& k) const {
1398
1399 const auto nx = m_xlines.size();
1400 const auto ny = m_ylines.size();
1401 const auto nxy = nx * ny;
1402 k = node / nxy;
1403 const auto tmp = node - k * nxy;
1404 j = tmp / nx;
1405 i = tmp - j * nx;
1406}
1407
1408}
double GetPotential(int ele, Point3D *localP)
bool Coordinate2Index(const double x, const double y, const double z, unsigned int &i, unsigned int &j, unsigned int &k) const
bool GetElement(const size_t i, size_t &mat, bool &drift, std::vector< size_t > &nodes) const override
Return the material and node indices of a mesh element.
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status) override
void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label) override
bool Initialise(std::string elist, std::string nlist, std::string mplist, std::string prnsol, std::string unit="cm")
bool GetNode(const size_t i, double &x, double &y, double &z) const override
Medium * GetMedium(const double x, const double y, const double z) override
Get the medium at a given location (x, y, z).
void GetElementBoundaries(unsigned int element, double &xmin, double &xmax, double &ymin, double &ymax, double &zmin, double &zmax) const
void GetNumberOfMeshLines(unsigned int &nx, unsigned int &ny, unsigned int &nz) const
double GetElementVolume(const size_t i) const override
bool SetWeightingField(std::string prnsol, std::string label, bool isBinary=true)
double WeightingPotential(const double x, const double y, const double z, const std::string &label) override
void ShiftComponent(const double xShift, const double yShift, const double zShift)
void SetRange() override
void GetAspectRatio(const size_t i, double &dmin, double &dmax) const override
void SetRangeZ(const double zmin, const double zmax)
ComponentCST()
Constructor.
int Index2Element(const unsigned int i, const unsigned int j, const unsigned int k) const
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)
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)
std::array< double, 3 > m_maxBoundingBox
std::array< double, 3 > m_mapmin
std::array< double, 3 > m_minBoundingBox
static double ScalingFactor(std::string unit)
void UpdatePeriodicity() override
Verify periodicities.
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::array< double, 3 > m_mapmax
void Reset() override
Reset the component.
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
Abstract base class for media.
Definition Medium.hh:16
bool IsDriftable() const
Is charge carrier transport enabled in this medium?
Definition Medium.hh:77