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