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