16bool ReadHeader(FILE* f,
const int fileSize,
const bool debug,
17 int& nX,
int& nY,
int& nZ,
int& nNS,
18 int& nES,
int& nEM,
int& nMaterials) {
22 static constexpr int headerSize = 1000;
23 if (fileSize < headerSize) {
24 std::cerr <<
"ComponentCST::ReadHeader:\n"
25 <<
" Error. The file is extremely short and does not seem to "
26 <<
"contain a header or data." << std::endl;
29 char header[headerSize];
30 size_t result = fread(header,
sizeof(
char), headerSize, f);
31 if (result != headerSize) {
32 std::cerr <<
"ComponentCST::ReadHeader: Could not read the header.\n";
36 int nMeshX = 0, nMeshY = 0, nMeshZ = 0;
37 int nNx = 0, nNy = 0, nNz = 0;
38 int nEx = 0, nEy = 0, nEz = 0;
40 std::string fmt =
"mesh_nx=%d mesh_ny=%d mesh_nz=%d\n";
41 fmt +=
"mesh_xlines=%d mesh_ylines=%d mesh_zlines=%d\n";
42 fmt +=
"nodes_scalar=%d ";
43 fmt +=
"nodes_vector_x=%d nodes_vector_y=%d nodes_vector_z=%d\n";
44 fmt +=
"elements_scalar=%d elements_vector_x=%d ";
45 fmt +=
"elements_vector_y=%d elements_vector_z=%d\n";
46 fmt +=
"elements_material=%d\n";
47 fmt +=
"n_materials=%d\n";
48 int filled = std::sscanf(header, fmt.c_str(),
49 &nMeshX, &nMeshY, &nMeshZ, &nX, &nY, &nZ,
50 &nNS, &nNx, &nNy, &nNz, &nES, &nEx, &nEy, &nEz, &nEM, &nMaterials);
52 std::cerr <<
"ComponentCST::ReadHeader: File header is broken.\n";
55 if (fileSize < 1000 + (nX + nY + nZ) * 8 +
56 (nNS + nNx + nNy + nNz + nES + nEx + nEy + nEz) * 4 +
57 nEM * 1 + nMaterials * 20) {
58 std::cerr <<
"ComponentCST::ReadHeader: Unexpected file size.\n";
62 std::cout <<
"ComponentCST::ReadHeader:\n"
63 <<
" Mesh (nx): " << nMeshX <<
"\t Mesh (ny): " << nMeshY
64 <<
"\t Mesh (nz): " << nMeshZ << std::endl
65 <<
" Mesh (x_lines): " << nX <<
"\t Mesh (y_lines): " << nY
66 <<
"\t Mesh (z_lines): " << nZ << std::endl
67 <<
" Nodes (scalar): " << nNS <<
"\t Nodes (x): " << nNx
68 <<
"\t Nodes (y): " << nNy <<
"\t Nodes (z): " << nNz <<
"\n"
69 <<
" Field (scalar): " << nES <<
"\t Field (x): " << nEx
70 <<
"\t Field (y): " << nEy <<
"\t Field (z): " << nEz <<
"\n"
71 <<
" Elements: " << nEM <<
"\t Materials: " << nMaterials
88 std::string mplist, std::string prnsol,
98 std::ifstream fmplist;
99 fmplist.open(mplist.c_str(), std::ios::in);
100 if (fmplist.fail()) {
107 bool readerror =
false;
108 while (fmplist.getline(line, size,
'\n')) {
112 token = strtok(line,
" ");
114 if (!token || strcmp(token,
" ") == 0 || strcmp(token,
"\n") == 0 ||
115 int(token[0]) == 10 ||
int(token[0]) == 13)
119 if (strcmp(token,
"Materials") == 0) {
120 token = strtok(NULL,
" ");
121 const int nMaterials =
ReadInteger(token, -1, readerror);
124 <<
" Error reading file " << mplist <<
" (line " << il
125 <<
")." << std::endl;
133 material.medium =
nullptr;
136 std::cout <<
m_className <<
"::Initialise:" << std::endl;
137 std::cout <<
" Number of materials: " << nMaterials <<
"\n";
139 }
else if (strcmp(token,
"Material") == 0) {
140 token = strtok(NULL,
" ");
143 std::cerr <<
m_className <<
"::Initialise:" << std::endl;
144 std::cerr <<
" Error reading file " << mplist <<
" (line " << il
148 }
else if (imat < 1 || imat > (
int)
m_materials.size()) {
150 <<
" Found out-of-range material index " << imat <<
"in\n"
151 <<
" material properties file " << mplist <<
".\n";
154 token = strtok(NULL,
" ");
156 if (strcmp(token,
"PERX") == 0) {
158 }
else if (strcmp(token,
"RSVX") == 0) {
162 <<
" Unknown material property flag " << token <<
"\n"
163 <<
" in material properties file " << mplist
164 <<
" (line " << il <<
").\n";
167 token = strtok(NULL,
" ");
170 }
else if (itype == 2) {
172 token = strtok(NULL,
" ");
173 if (strcmp(token,
"PERX") != 0) {
175 <<
" Unknown material property flag " << token <<
"\n"
176 <<
" in material file " << mplist <<
" (material "
180 token = strtok(NULL,
" ");
186 <<
" Error reading file " << mplist
187 <<
" (line " << il <<
")." << std::endl;
192 std::cout <<
m_className <<
"::Initialise:" << std::endl;
193 std::cout <<
" Read material properties for material "
194 << (imat - 1) <<
"" << std::endl;
196 std::cout <<
" eps = " <<
m_materials[imat - 1].eps
200 std::cout <<
" eps = " <<
m_materials[imat - 1].eps <<
""
215 <<
" Read properties of " <<
m_materials.size() <<
" materials\n"
216 <<
" from file " << mplist <<
"." << std::endl;
223 <<
" Unknown length unit " << unit <<
".\n";
228 std::cout <<
m_className <<
"::Initialise: Unit scaling factor = "
233 std::ifstream fnlist;
234 fnlist.open(nlist.c_str(), std::ios::in);
242 int xlines = 0, ylines = 0, zlines = 0;
245 while (fnlist.getline(line, size,
'\n')) {
250 token = strtok(line,
" ");
252 if (!token || strcmp(token,
" ") == 0 || strcmp(token,
"\n") == 0 ||
253 int(token[0]) == 10 ||
int(token[0]) == 13)
256 if (strcmp(token,
"xmax") == 0) {
257 token = strtok(NULL,
" ");
259 token = strtok(NULL,
" ");
260 token = strtok(NULL,
" ");
262 token = strtok(NULL,
" ");
263 token = strtok(NULL,
" ");
265 if (readerror)
break;
268 if (strcmp(token,
"x-lines\n") == 0 || strcmp(token,
"x-lines") == 0) {
272 <<
" Reading x-lines from file " << nlist <<
".\n";
276 if (strcmp(token,
"y-lines\n") == 0 || strcmp(token,
"y-lines") == 0) {
280 <<
" Reading y-lines from file " << nlist <<
".\n";
284 if (strcmp(token,
"z-lines\n") == 0 || strcmp(token,
"z-lines") == 0) {
288 <<
" Reading z-lines from file " << nlist <<
".\n";
294 m_xlines.push_back(line_tmp * funit);
295 else if (lines_type == 2)
296 m_ylines.push_back(line_tmp * funit);
297 else if (lines_type == 3)
298 m_zlines.push_back(line_tmp * funit);
300 std::cerr <<
m_className <<
"::Initialise:" << std::endl;
301 std::cerr <<
" Line type was not set in " << nlist <<
" (line " << il
302 <<
", token = " << token <<
")." << std::endl;
303 std::cerr <<
" Maybe it is in the wrong format" << std::endl;
304 std::cerr <<
" e.g. missing tailing space after x-lines." << std::endl;
308 if (readerror)
break;
313 <<
" Error reading file " << nlist
314 <<
" (line " << il <<
").\n";
321 if ((
unsigned)xlines == m_xlines.size() &&
322 (
unsigned)ylines == m_ylines.size() &&
323 (
unsigned)zlines == m_zlines.size()) {
324 std::cout <<
m_className <<
"::Initialise:" << std::endl;
325 std::cout <<
" Found in file " << nlist <<
"\n " << xlines
326 <<
" x-lines\n " << ylines <<
" y-lines\n " << zlines
327 <<
" z-lines" << std::endl;
329 std::cerr <<
m_className <<
"::Initialise:" << std::endl;
330 std::cerr <<
" There should be " << xlines <<
" x-lines, " << ylines
331 <<
" y-lines and " << zlines <<
" z-lines in file " << nlist
332 <<
" but I found :\n " << m_xlines.size() <<
" x-lines, "
333 << m_ylines.size() <<
" x-lines, " << m_zlines.size()
334 <<
" z-lines." << std::endl;
336 m_nx = m_xlines.size();
337 m_ny = m_ylines.size();
338 m_nz = m_zlines.size();
339 m_nNodes = m_nx * m_ny * m_nz;
340 m_nElements = (m_nx - 1) * (m_ny - 1) * (m_nz - 1);
343 std::cout <<
m_className <<
"::Initialise:" << std::endl;
344 std::cout <<
" Read " << m_nNodes <<
" nodes from file " << nlist <<
"."
348 std::ifstream felist;
349 felist.open(elist.c_str(), std::ios::in);
355 m_elementMaterial.resize(m_nElements);
357 while (felist.getline(line, size,
'\n')) {
362 token = strtok(line,
" ");
364 if (!token || strcmp(token,
" ") == 0 || strcmp(token,
"\n") == 0 ||
365 int(token[0]) == 10 ||
int(token[0]) == 13 ||
366 strcmp(token,
"LIST") == 0 || strcmp(token,
"ELEM") == 0)
370 token = strtok(NULL,
" ");
371 unsigned char imat = atoi(token);
373 std::vector<int> node_nb;
377 m_elementMaterial.at(ielem) = (imat - 1);
379 std::cerr <<
m_className <<
"::Initialise:" << std::endl;
380 std::cerr <<
" Error reading file " << elist <<
" (line " << il <<
")."
382 std::cerr <<
" The element index (" << ielem
383 <<
") is not in the expected range: 0 - " << m_nElements
390 std::cerr <<
m_className <<
"::Initialise:" << std::endl;
391 std::cerr <<
" Out-of-range material number on file " << elist
392 <<
" (line " << il <<
")." << std::endl;
393 std::cerr <<
" Element: " << ielem <<
", material: " << imat
398 std::cerr <<
m_className <<
"::Initialise:" << std::endl;
399 std::cerr <<
" Element " << ielem <<
" in element list " << elist
400 <<
" uses material " << imat <<
" which" << std::endl;
401 std::cerr <<
" has not been assigned a positive permittivity"
403 std::cerr <<
" in material list " << mplist <<
"." << std::endl;
410 std::cout <<
m_className <<
"::Initialise:" << std::endl;
411 std::cout <<
" Read " << m_nElements <<
" elements.\n";
414 m_potential.resize(m_nNodes);
415 std::ifstream fprnsol;
416 fprnsol.open(prnsol.c_str(), std::ios::in);
417 if (fprnsol.fail()) {
425 while (fprnsol.getline(line, size,
'\n')) {
429 token = strtok(line,
" ");
431 if (!token || strcmp(token,
" ") == 0 || strcmp(token,
"\n") == 0 ||
432 int(token[0]) == 10 ||
int(token[0]) == 13 || strcmp(token,
"Max") == 0)
437 token = strtok(NULL,
" ");
438 double volt =
ReadDouble(token, -1, readerror);
441 m_potential.at(inode - 1) = volt;
444 std::cerr <<
m_className <<
"::Initialise:" << std::endl;
445 std::cerr <<
" Error reading file " << prnsol <<
" (line " << il
446 <<
")." << std::endl;
447 std::cerr <<
" The node index (" << inode - 1
448 <<
") is not in the expected range: 0 - " << m_nNodes
456 std::cout <<
m_className <<
"::Initialise:" << std::endl;
457 std::cout <<
" Read " << nread <<
"/" << m_nNodes
458 <<
" (expected) potentials from file " << prnsol <<
"."
461 if (nread != (
int)m_nNodes) {
462 std::cerr <<
m_className <<
"::Initialise:" << std::endl;
463 std::cerr <<
" Number of nodes read (" << nread <<
") on potential file "
464 << prnsol <<
" does not" << std::endl;
465 std::cerr <<
" match the node list (" << m_nNodes <<
").\n";
472 std::cerr <<
m_className <<
"::Initialise:" << std::endl;
473 std::cerr <<
" Field map could not be read and cannot be interpolated."
490 <<
" Unknown length unit " << unit <<
".\n";
495 std::cout <<
m_className <<
"::Initialise: Unit scaling factor = "
498 FILE* f = fopen(dataFile.c_str(),
"rb");
504 struct stat fileStatus;
505 stat(dataFile.c_str(), &fileStatus);
506 int fileSize = fileStatus.st_size;
508 int nLinesX = 0, nLinesY = 0, nLinesZ = 0;
509 int nNS = 0, nES = 0, nEM = 0;
511 if (!ReadHeader(f, fileSize,
m_debug, nLinesX, nLinesY, nLinesZ,
512 nNS, nES, nEM, nMaterials)) {
519 m_nNodes = m_nx * m_ny * m_nz;
520 m_nElements = (m_nx - 1) * (m_ny - 1) * (m_nz - 1);
522 m_xlines.resize(nLinesX);
523 m_ylines.resize(nLinesY);
524 m_zlines.resize(nLinesZ);
525 m_potential.resize(nNS);
526 m_elementMaterial.resize(nEM);
528 auto result = fread(m_xlines.data(),
sizeof(
double), m_xlines.size(), f);
529 if (result != m_xlines.size()) {
530 fputs(
"Reading error while reading xlines.", stderr);
532 }
else if (result == 0) {
533 fputs(
"No xlines are stored in the data file.", stderr);
536 result = fread(m_ylines.data(),
sizeof(
double), m_ylines.size(), f);
537 if (result != m_ylines.size()) {
538 fputs(
"Reading error while reading ylines", stderr);
540 }
else if (result == 0) {
541 fputs(
"No ylines are stored in the data file.", stderr);
544 result = fread(m_zlines.data(),
sizeof(
double), m_zlines.size(), f);
545 if (result != m_zlines.size()) {
546 fputs(
"Reading error while reading zlines", stderr);
548 }
else if (result == 0) {
549 fputs(
"No zlines are stored in the data file.", stderr);
552 result = fread(m_potential.data(),
sizeof(
float), m_potential.size(), f);
553 if (result != m_potential.size()) {
554 fputs(
"Reading error while reading nodes.", stderr);
556 }
else if (result == 0) {
557 fputs(
"No potentials are stored in the data file.", stderr);
560 fseek(f, nES *
sizeof(
float), SEEK_CUR);
562 result = fread(m_elementMaterial.data(),
sizeof(
unsigned char),
563 m_elementMaterial.size(), f);
564 if (result != m_elementMaterial.size()) {
565 fputs(
"Reading error while reading element material", stderr);
568 std::stringstream st;
574 for (
unsigned int i = 0; i <
m_materials.size(); i++) {
576 result = fread(&(
id),
sizeof(
float), 1, f);
578 fputs(
"Input error while reading material id.", stderr);
582 const unsigned int index = i;
583 unsigned int description_size = 0;
584 result = fread(&(description_size),
sizeof(
int), 1, f);
586 fputs(
"Input error while reading material description size.", stderr);
589 char* c =
new char[description_size];
590 result = fread(c,
sizeof(
char), description_size, f);
591 if (result != description_size) {
592 fputs(
"Input error while reading material description.", stderr);
595 std::string name = c;
596 st <<
" Read material: " << name.c_str();
597 if (name.compare(
"gas") == 0) {
598 st <<
" (considered as drift medium)";
605 result = fread(&(eps),
sizeof(
float), 1, f);
608 fputs(
"Reading error while reading eps.", stderr);
626 st <<
"\t id is: " <<
id << std::endl;
628 fseek(f, 2 *
sizeof(
float), SEEK_CUR);
632 std::sort(m_xlines.begin(), m_xlines.end());
633 std::sort(m_ylines.begin(), m_ylines.end());
634 std::sort(m_zlines.begin(), m_zlines.end());
636 std::transform(m_xlines.begin(), m_xlines.end(), m_xlines.begin(), [funit](
double x) { return x * funit;});
637 std::transform(m_ylines.begin(), m_ylines.end(), m_ylines.begin(), [funit](
double x) { return x * funit;});
638 std::transform(m_zlines.begin(), m_zlines.end(), m_zlines.begin(), [funit](
double x) { return x * funit;});
641 std::cout <<
m_className <<
"::Initialise" << std::endl;
642 std::cout <<
" x range: " << *(m_xlines.begin()) <<
" - "
643 << *(m_xlines.end() - 1) << std::endl;
644 std::cout <<
" y range: " << *(m_ylines.begin()) <<
" - "
645 << *(m_ylines.end() - 1) << std::endl;
646 std::cout <<
" z range: " << *(m_zlines.begin()) <<
" - "
647 << *(m_zlines.end() - 1) << std::endl;
653 std::cerr <<
m_className <<
"::Initialise:" << std::endl;
654 std::cerr <<
" Field map could not be read and cannot be interpolated."
666 std::vector<float> potentials(m_nNodes);
668 std::cerr <<
m_className <<
"::SetWeightingField:" << std::endl;
669 std::cerr <<
" No valid field map is present." << std::endl;
670 std::cerr <<
" Weighting field cannot be added." << std::endl;
675 std::ifstream fprnsol;
676 fprnsol.open(prnsol.c_str(), std::ios::in);
677 if (fprnsol.fail()) {
682 auto it = m_weightingFields.find(label);
683 if (it != m_weightingFields.end()) {
684 std::cout <<
m_className <<
"::SetWeightingField:" << std::endl;
685 std::cout <<
" Replacing existing weighting field " << label <<
"."
692 if (std::distance(m_weightingFields.begin(), it) !=
695 std::cerr <<
m_className <<
"::SetWeightingField:" << std::endl;
696 std::cerr <<
" Indices of the weighting fields and the weighting field "
697 "counter are not equal!"
701 unsigned int iField = std::distance(m_weightingFields.begin(), it);
706 std::cout <<
m_className <<
"::SetWeightingField:" << std::endl;
707 std::cout <<
" Reading weighting field from binary file:"
708 << prnsol.c_str() << std::endl;
709 FILE* f = fopen(prnsol.c_str(),
"rb");
715 struct stat fileStatus;
716 stat(prnsol.c_str(), &fileStatus);
717 int fileSize = fileStatus.st_size;
719 int nLinesX = 0, nLinesY = 0, nLinesZ = 0;
720 int nES = 0, nEM = 0;
722 if (!ReadHeader(f, fileSize,
m_debug, nLinesX, nLinesY, nLinesZ,
723 nread, nES, nEM, nMaterials)) {
728 fseek(f, nLinesX *
sizeof(
double), SEEK_CUR);
729 fseek(f, nLinesY *
sizeof(
double), SEEK_CUR);
730 fseek(f, nLinesZ *
sizeof(
double), SEEK_CUR);
731 auto result = fread(potentials.data(),
sizeof(
float), potentials.size(), f);
732 if (result != potentials.size()) {
733 fputs(
"Reading error while reading nodes.", stderr);
735 }
else if (result == 0) {
736 fputs(
"No weighting potentials are stored in the data file.", stderr);
741 std::cout <<
m_className <<
"::SetWeightingField:" << std::endl;
742 std::cout <<
" Reading weighting field from text file:" << prnsol.c_str()
745 const int size = 100;
751 bool readerror =
false;
752 while (fprnsol.getline(line, size,
'\n')) {
756 token = strtok(line,
" ");
758 if (!token || strcmp(token,
" ") == 0 || strcmp(token,
"\n") == 0 ||
759 int(token[0]) == 10 ||
int(token[0]) == 13 ||
760 strcmp(token,
"PRINT") == 0 || strcmp(token,
"*****") == 0 ||
761 strcmp(token,
"LOAD") == 0 || strcmp(token,
"TIME=") == 0 ||
762 strcmp(token,
"MAXIMUM") == 0 || strcmp(token,
"VALUE") == 0 ||
763 strcmp(token,
"NODE") == 0)
767 token = strtok(NULL,
" ");
768 double volt =
ReadDouble(token, -1, readerror);
770 potentials.at(inode - 1) = volt;
773 std::cerr <<
m_className <<
"::SetWeightingField:" << std::endl;
774 std::cerr <<
" Node number " << inode <<
" out of range."
776 std::cerr <<
" on potential file " << prnsol <<
" (line " << il
777 <<
")." << std::endl;
778 std::cerr <<
" Size of the potential vector is: "
779 << potentials.size() << std::endl;
787 std::cout <<
m_className <<
"::SetWeightingField:" << std::endl;
788 std::cout <<
" Read " << nread <<
"/" << m_nNodes
789 <<
" (expected) potentials from file " << prnsol <<
"."
792 if (nread != (
int)m_nNodes) {
793 std::cerr <<
m_className <<
"::SetWeightingField:" << std::endl;
794 std::cerr <<
" Number of nodes read (" << nread <<
")"
795 <<
" on potential file (" << prnsol <<
")" << std::endl;
796 std::cerr <<
" does not match the node list (" << m_nNodes <<
")."
801 std::cerr <<
m_className <<
"::SetWeightingField:" << std::endl;
802 std::cerr <<
" Field map could not be read "
803 <<
"and cannot be interpolated." << std::endl;
807 m_weightingFields[label] = potentials;
815 const double zShift) {
816 std::transform(m_xlines.begin(), m_xlines.end(), m_xlines.begin(), [xShift](
double x) { return x + xShift;});
817 std::transform(m_ylines.begin(), m_ylines.end(), m_ylines.begin(), [yShift](
double x) { return x + yShift;});
818 std::transform(m_zlines.begin(), m_zlines.end(), m_zlines.begin(), [zShift](
double x) { return x + zShift;});
822 std::cout <<
m_className <<
"::ShiftComponent:" << std::endl;
823 std::cout <<
" Shifted component in x-direction: " << xShift
824 <<
"\t y-direction: " << yShift <<
"\t z-direction: " << zShift
829 const double zin,
double& ex,
double& ey,
830 double& ez,
Medium*& m,
int& status) {
832 ElectricFieldBinary(xin, yin, zin, ex, ey, ez, volt, m, status);
836 const double zin,
double& ex,
double& ey,
837 double& ez,
double& volt,
Medium*& m,
839 ElectricFieldBinary(xin, yin, zin, ex, ey, ez, volt, m, status,
true);
843 const double zin,
double& wx,
double& wy,
844 double& wz,
const std::string& label) {
852 auto it = m_weightingFields.find(label);
853 if (it == m_weightingFields.end()) {
855 std::cerr <<
"No weighting field named " << label.c_str() <<
" found!"
861 if (!
m_wfieldsOk[std::distance(m_weightingFields.begin(), it)])
return;
864 double x = xin, y = yin, z = zin;
868 unsigned int i, j, k;
869 double pos[3] = {0., 0., 0.};
874 double rx = (pos[0] - m_xlines.at(i)) / (m_xlines.at(i + 1) - m_xlines.at(i));
875 double ry = (pos[1] - m_ylines.at(j)) / (m_ylines.at(j + 1) - m_ylines.at(j));
876 double rz = (pos[2] - m_zlines.at(k)) / (m_zlines.at(k + 1) - m_zlines.at(k));
878 float fwx = 0., fwy = 0., fwz = 0.;
879 if (!disableFieldComponent[0])
880 fwx = GetFieldComponent(i, j, k, rx, ry, rz,
'x', (*it).second);
881 if (!disableFieldComponent[1])
882 fwy = GetFieldComponent(i, j, k, rx, ry, rz,
'y', (*it).second);
883 if (!disableFieldComponent[2])
884 fwz = GetFieldComponent(i, j, k, rx, ry, rz,
'z', (*it).second);
886 if (m_elementMaterial.size() > 0 && doShaping) {
887 ShapeField(fwx, fwy, fwz, rx, ry, rz, i, j, k, (*it).second);
889 if (mirrored[0]) fwx *= -1.f;
890 if (mirrored[1]) fwy *= -1.f;
891 if (mirrored[2]) fwz *= -1.f;
894 if (!disableFieldComponent[0]) wx = fwx;
895 if (!disableFieldComponent[1]) wy = fwy;
896 if (!disableFieldComponent[2]) wz = fwz;
902 const std::string& label) {
907 auto it = m_weightingFields.find(label);
908 if (it == m_weightingFields.end()) {
910 std::cerr <<
"No weighting field named " << label.c_str() <<
" found!"
916 if (!
m_wfieldsOk[std::distance(m_weightingFields.begin(), it)])
return 0.;
919 double x = xin, y = yin, z = zin;
923 unsigned int i, j, k;
924 double pos[3] = {0., 0., 0.};
928 double rx = (pos[0] - m_xlines.at(i)) /
929 (m_xlines.at(i + 1) - m_xlines.at(i));
930 double ry = (pos[1] - m_ylines.at(j)) /
931 (m_ylines.at(j + 1) - m_ylines.at(j));
932 double rz = (pos[2] - m_zlines.at(k)) /
933 (m_zlines.at(k + 1) - m_zlines.at(k));
935 double potential =
GetPotential(i, j, k, rx, ry, rz, (*it).second);
938 std::cout <<
m_className <<
"::WeightingPotential:" << std::endl;
939 std::cout <<
" Global: (" << x <<
"," << y <<
"," << z <<
"),"
941 std::cout <<
" Local: (" << rx <<
"," << ry <<
"," << rz
942 <<
") in element with indexes: i=" << i <<
", j=" << j
943 <<
", k=" << k << std::endl;
944 std::cout <<
" Node xyzV:" << std::endl;
945 std::cout <<
"Node 0 position: " << Index2Node(i + 1, j, k)
946 <<
"\t potential: " << ((*it).second).at(Index2Node(i + 1, j, k))
947 <<
"Node 1 position: " << Index2Node(i + 1, j + 1, k)
949 << ((*it).second).at(Index2Node(i + 1, j + 1, k))
950 <<
"Node 2 position: " << Index2Node(i, j + 1, k)
951 <<
"\t potential: " << ((*it).second).at(Index2Node(i, j + 1, k))
952 <<
"Node 3 position: " << Index2Node(i, j, k)
953 <<
"\t potential: " << ((*it).second).at(Index2Node(i, j, k))
954 <<
"Node 4 position: " << Index2Node(i + 1, j, k + 1)
956 << ((*it).second).at(Index2Node(i + 1, j, k + 1))
957 <<
"Node 5 position: " << Index2Node(i + 1, j + 1, k + 1)
959 << ((*it).second).at(Index2Node(i + 1, j + 1, k + 1))
960 <<
"Node 6 position: " << Index2Node(i, j + 1, k + 1)
962 << ((*it).second).at(Index2Node(i, j + 1, k + 1))
963 <<
"Node 7 position: " << Index2Node(i, j, k + 1)
964 <<
"\t potential: " << ((*it).second).at(Index2Node(i, j, k))
971 unsigned int& n_z)
const {
972 n_x = m_xlines.size();
973 n_y = m_ylines.size();
974 n_z = m_zlines.size();
978 std::vector<size_t>& nodes)
const {
979 if (element >= m_nElements || element >= m_elementMaterial.size()) {
980 std::cerr <<
m_className <<
"::GetElement: Index out of range.\n";
983 mat = m_elementMaterial[element];
986 unsigned int i0 = 0, j0 = 0, k0 = 0;
987 Element2Index(element, i0, j0, k0);
988 const auto i1 = i0 + 1;
989 const auto j1 = j0 + 1;
990 const auto k1 = k0 + 1;
991 nodes.push_back(Index2Node(i0, j0, k0));
992 nodes.push_back(Index2Node(i1, j0, k0));
993 nodes.push_back(Index2Node(i0, j1, k0));
994 nodes.push_back(Index2Node(i1, j1, k0));
995 nodes.push_back(Index2Node(i0, j0, k1));
996 nodes.push_back(Index2Node(i1, j0, k1));
997 nodes.push_back(Index2Node(i0, j1, k1));
998 nodes.push_back(Index2Node(i1, j1, k1));
1003 double& x,
double& y,
double& z)
const {
1004 if (node >= m_nNodes) {
1005 std::cerr <<
m_className <<
"::GetNode: Index out of range.\n";
1008 unsigned int i = 0, j = 0, k = 0;
1009 Node2Index(node, i, j, k);
1017 double& xmax,
double& ymin,
1018 double& ymax,
double& zmin,
1019 double& zmax)
const {
1020 unsigned int i, j, k;
1021 Element2Index(element, i, j, k);
1022 xmin = m_xlines.at(i);
1023 xmax = m_xlines.at(i + 1);
1024 ymin = m_ylines.at(j);
1025 ymax = m_ylines.at(j + 1);
1026 zmin = m_zlines.at(k);
1027 zmax = m_zlines.at(k + 1);
1032 unsigned int i, j, k;
1036 <<
" Position (" << x <<
", " << y <<
", " << z <<
"):\n"
1037 <<
" Indices are: x: " << i <<
"/" << m_xlines.size()
1038 <<
"\t y: " << j <<
"/" << m_ylines.size()
1039 <<
"\t z: " << k <<
"/" << m_zlines.size() << std::endl;
1041 std::cout <<
" Element index: " << element << std::endl
1042 <<
" Material index: "
1043 << (int)m_elementMaterial.at(element) << std::endl;
1056 m_mapvmin = *std::min_element(m_potential.begin(), m_potential.end());
1057 m_mapvmax = *std::max_element(m_potential.begin(), m_potential.end());
1075 if (fabs(zmax - zmin) <= 0.) {
1076 std::cerr <<
m_className <<
"::SetRangeZ:" << std::endl;
1077 std::cerr <<
" Zero range is not permitted." << std::endl;
1085 const double z,
unsigned int& i,
1086 unsigned int& j,
unsigned int& k)
const {
1087 bool mirrored[3] = {
false,
false,
false};
1088 double pos[3] = {0., 0., 0.};
1094 const double zin,
unsigned int& i,
1095 unsigned int& j,
unsigned int& k,
1096 double* pos,
bool* mirrored)
const {
1101 double rcoordinate = 0.;
1102 double rotation = 0.;
1104 mirrored[0], mirrored[1], mirrored[2], rcoordinate, rotation);
1107 std::lower_bound(m_xlines.begin(), m_xlines.end(), pos[0]);
1109 std::lower_bound(m_ylines.begin(), m_ylines.end(), pos[1]);
1111 std::lower_bound(m_zlines.begin(), m_zlines.end(), pos[2]);
1112 if (it_x == m_xlines.end() || it_y == m_ylines.end() ||
1113 it_z == m_zlines.end() || pos[0] < m_xlines.at(0) ||
1114 pos[1] < m_ylines.at(0) ||
1115 pos[2] < m_zlines.at(0)) {
1117 std::cerr <<
m_className <<
"::ElectricFieldBinary:" << std::endl;
1118 std::cerr <<
" Could not find the given coordinate!" << std::endl;
1119 std::cerr <<
" You ask for the following position: " << xin <<
", "
1120 << yin <<
", " << zin << std::endl;
1121 std::cerr <<
" The mapped position is: " << pos[0] <<
", "
1122 << pos[1] <<
", " << pos[2]
1133 if (it_x == m_xlines.begin())
1136 i = std::distance(m_xlines.begin(), it_x - 1);
1137 if (it_y == m_ylines.begin())
1140 j = std::distance(m_ylines.begin(), it_y - 1);
1141 if (it_z == m_zlines.begin())
1144 k = std::distance(m_zlines.begin(), it_z - 1);
1149 const unsigned int k)
const {
1150 if (i > m_nx - 2 || j > m_ny - 2 || k > m_nz - 2) {
1151 throw "ComponentCST::Index2Element: Error. Element indices out of bounds.";
1153 return i + j * (m_nx - 1) + k * (m_nx - 1) * (m_ny - 1);
1163 if (element >= m_nElements) {
1167 unsigned int i, j, k;
1168 Element2Index(element, i, j, k);
1169 const double dx = fabs(m_xlines.at(i + 1) - m_xlines.at(i));
1170 const double dy = fabs(m_ylines.at(j + 1) - m_ylines.at(j));
1171 const double dz = fabs(m_zlines.at(k + 1) - m_zlines.at(k));
1172 dmin = std::min({dx, dy, dz});
1173 dmax = std::max({dx, dy, dz});
1177 if (element >= m_nElements)
return 0.;
1178 unsigned int i, j, k;
1179 Element2Index(element, i, j, k);
1180 const double dx = fabs(m_xlines.at(i + 1) - m_xlines.at(i));
1181 const double dy = fabs(m_ylines.at(j + 1) - m_ylines.at(j));
1182 const double dz = fabs(m_zlines.at(k + 1) - m_zlines.at(k));
1183 return dx * dy * dz;
1186void ComponentCST::ElectricFieldBinary(
const double xin,
const double yin,
1187 const double zin,
double& ex,
double& ey,
1188 double& ez,
double& volt,
Medium*& m,
1189 int& status,
bool calculatePotential)
const {
1191 double x = xin, y = yin, z = zin;
1196 unsigned int i, j, k;
1197 double pos[3] = {0., 0., 0.};
1201 double rx = (pos[0] - m_xlines.at(i)) / (m_xlines.at(i + 1) - m_xlines.at(i));
1202 double ry = (pos[1] - m_ylines.at(j)) / (m_ylines.at(j + 1) - m_ylines.at(j));
1203 double rz = (pos[2] - m_zlines.at(k)) / (m_zlines.at(k + 1) - m_zlines.at(k));
1205 float fex = GetFieldComponent(i, j, k, rx, ry, rz,
'x', m_potential);
1206 float fey = GetFieldComponent(i, j, k, rx, ry, rz,
'y', m_potential);
1207 float fez = GetFieldComponent(i, j, k, rx, ry, rz,
'z', m_potential);
1209 if (m_elementMaterial.size() > 0 && doShaping) {
1210 ShapeField(fex, fey, fez, rx, ry, rz, i, j, k, m_potential);
1212 if (mirrored[0]) fex *= -1.f;
1213 if (mirrored[1]) fey *= -1.f;
1214 if (mirrored[2]) fez *= -1.f;
1216 std::cout <<
m_className <<
"::ElectricFieldBinary:" << std::endl;
1217 std::cout <<
" Found position (" <<
x <<
", " <<
y <<
", " <<
z
1218 <<
"): " << std::endl;
1219 std::cout <<
" Indices are: x: " << i <<
"/" << m_xlines.size()
1220 <<
"\t y: " << j <<
"/" << m_ylines.size() <<
"\t z: " << k <<
"/"
1221 << m_zlines.size() << std::endl;
1222 if (i != 0 && j != 0 && k != 0) {
1223 std::cout <<
" index: " << i <<
"\t x before: " << m_xlines.at(i - 1)
1224 <<
"\t x behind: " << m_xlines.at(i) <<
"\t r = " << rx
1225 <<
"\n index: " << j <<
"\t y before: " << m_ylines.at(j - 1)
1226 <<
"\t y behind: " << m_ylines.at(j) <<
"\t r = " << ry
1227 <<
"\n index: " << k <<
"\t z before: " << m_zlines.at(k - 1)
1228 <<
"\t z behind: " << m_zlines.at(k) <<
"\t r = " << rz
1231 std::cout <<
" Electric field is: " << fex <<
", " << fey <<
", " << fez
1232 <<
"): " << std::endl;
1236 const auto imat = m_elementMaterial.at(
Index2Element(i, j, k));
1245 if (!disableFieldComponent[0]) ex = fex;
1246 if (!disableFieldComponent[1]) ey = fey;
1247 if (!disableFieldComponent[2]) ez = fez;
1248 if (calculatePotential)
1252float ComponentCST::GetFieldComponent(
1253 const unsigned int i,
const unsigned int j,
const unsigned int k,
1254 const double rx,
const double ry,
const double rz,
1255 const char component,
const std::vector<float>& potentials)
const {
1257 if (component ==
'x') {
1258 const float dv1 = potentials.at(Index2Node(i + 1, j, k)) -
1259 potentials.at(Index2Node(i, j, k));
1260 const float dv2 = potentials.at(Index2Node(i + 1, j + 1, k)) -
1261 potentials.at(Index2Node(i, j + 1, k));
1262 const float dv3 = potentials.at(Index2Node(i + 1, j + 1, k + 1)) -
1263 potentials.at(Index2Node(i, j + 1, k + 1));
1264 const float dv4 = potentials.at(Index2Node(i + 1, j, k + 1)) -
1265 potentials.at(Index2Node(i, j, k + 1));
1267 const float dv11 = dv1 + (dv4 - dv1) * rz;
1268 const float dv21 = dv2 + (dv3 - dv2) * rz;
1269 const float dv = dv11 + (dv21 - dv11) * ry;
1270 e = -1 * dv / (m_xlines.at(i + 1) - m_xlines.at(i));
1272 if (component ==
'y') {
1273 const float dv1 = potentials.at(Index2Node(i, j + 1, k)) -
1274 potentials.at(Index2Node(i, j, k));
1275 const float dv2 = potentials.at(Index2Node(i, j + 1, k + 1)) -
1276 potentials.at(Index2Node(i, j, k + 1));
1277 const float dv3 = potentials.at(Index2Node(i + 1, j + 1, k + 1)) -
1278 potentials.at(Index2Node(i + 1, j, k + 1));
1279 const float dv4 = potentials.at(Index2Node(i + 1, j + 1, k)) -
1280 potentials.at(Index2Node(i + 1, j, k));
1282 const float dv11 = dv1 + (dv4 - dv1) * rx;
1283 const float dv21 = dv2 + (dv3 - dv2) * rx;
1284 const float dv = dv11 + (dv21 - dv11) * rz;
1285 e = -1 * dv / (m_ylines.at(j + 1) - m_ylines.at(j));
1287 if (component ==
'z') {
1288 const float dv1 = potentials.at(Index2Node(i, j, k + 1)) -
1289 potentials.at(Index2Node(i, j, k));
1290 const float dv2 = potentials.at(Index2Node(i + 1, j, k + 1)) -
1291 potentials.at(Index2Node(i + 1, j, k));
1292 const float dv3 = potentials.at(Index2Node(i + 1, j + 1, k + 1)) -
1293 potentials.at(Index2Node(i + 1, j + 1, k));
1294 const float dv4 = potentials.at(Index2Node(i, j + 1, k + 1)) -
1295 potentials.at(Index2Node(i, j + 1, k));
1297 const float dv11 = dv1 + (dv4 - dv1) * ry;
1298 const float dv21 = dv2 + (dv3 - dv2) * ry;
1299 const float dv = dv11 + (dv21 - dv11) * rx;
1300 e = -1 * dv / (m_zlines.at(k + 1) - m_zlines.at(k));
1305float ComponentCST::GetPotential(
1306 const unsigned int i,
const unsigned int j,
const unsigned int k,
1307 const double rx,
const double ry,
const double rz,
1308 const std::vector<float>& potentials)
const {
1309 double t1 = rx * 2. - 1;
1310 double t2 = ry * 2. - 1;
1311 double t3 = rz * 2. - 1;
1312 return (potentials.at(Index2Node(i + 1, j, k)) * (1 - t1) * (1 - t2) *
1314 potentials.at(Index2Node(i + 1, j + 1, k)) * (1 + t1) * (1 - t2) *
1316 potentials.at(Index2Node(i, j + 1, k)) * (1 + t1) * (1 + t2) *
1318 potentials.at(Index2Node(i, j, k)) * (1 - t1) * (1 + t2) * (1 - t3) +
1319 potentials.at(Index2Node(i + 1, j, k + 1)) * (1 - t1) * (1 - t2) *
1321 potentials.at(Index2Node(i + 1, j + 1, k + 1)) * (1 + t1) *
1322 (1 - t2) * (1 + t3) +
1323 potentials.at(Index2Node(i, j + 1, k + 1)) * (1 + t1) * (1 + t2) *
1325 potentials.at(Index2Node(i, j, k + 1)) * (1 - t1) * (1 + t2) *
1330void ComponentCST::ShapeField(
float& ex,
float& ey,
float& ez,
1331 const double rx,
const double ry,
const double rz,
1332 const unsigned int i,
const unsigned int j,
const unsigned int k,
1333 const std::vector<float>& potentials)
const {
1335 const auto m1 = m_elementMaterial.at(
Index2Element(i, j, k));
1336 const auto imax = m_xlines.size() - 2;
1337 if ((i == 0 && rx >= 0.5) || (i == imax && rx < 0.5) || (i > 0 && i < imax)) {
1339 const auto m2 = m_elementMaterial.at(
Index2Element(i + 1, j, k));
1342 GetFieldComponent(i + 1, j, k, 0.5, ry, rz,
'x', potentials);
1344 (rx - 0.5) * (ex_next - ex) *
1345 (m_xlines.at(i + 1) - m_xlines.at(i)) /
1346 (m_xlines.at(i + 2) - m_xlines.at(i + 1));
1349 const auto m2 = m_elementMaterial.at(
Index2Element(i - 1, j, k));
1352 GetFieldComponent(i - 1, j, k, 0.5, ry, rz,
'x', potentials);
1354 (rx + 0.5) * (ex - ex_before) *
1355 (m_xlines.at(i) - m_xlines.at(i - 1)) /
1356 (m_xlines.at(i + 1) - m_xlines.at(i));
1361 const auto jmax = m_ylines.size() - 2;
1362 if ((j == 0 && ry >= 0.5) || (j == jmax && ry < 0.5) || (j > 0 && j < jmax)) {
1364 const auto m2 = m_elementMaterial.at(
Index2Element(i, j + 1, k));
1367 GetFieldComponent(i, j + 1, k, rx, 0.5, rz,
'y', potentials);
1369 (ry - 0.5) * (ey_next - ey) *
1370 (m_ylines.at(j + 1) - m_ylines.at(j)) /
1371 (m_ylines.at(j + 2) - m_ylines.at(j + 1));
1374 const auto m2 = m_elementMaterial.at(
Index2Element(i, j - 1, k));
1377 GetFieldComponent(i, j - 1, k, rx, 0.5, rz,
'y', potentials);
1379 (ry + 0.5) * (ey - ey_next) *
1380 (m_ylines.at(j) - m_ylines.at(j - 1)) /
1381 (m_ylines.at(j + 1) - m_ylines.at(j));
1385 const auto kmax = m_zlines.size() - 2;
1386 if ((k == 0 && rz >= 0.5) || (k == kmax && rz < 0.5) || (k > 0 && k < kmax)) {
1388 const auto m2 = m_elementMaterial.at(
Index2Element(i, j, k + 1));
1391 GetFieldComponent(i, j, k + 1, rx, ry, 0.5,
'z', potentials);
1393 (rz - 0.5) * (ez_next - ez) *
1394 (m_zlines.at(k + 1) - m_zlines.at(k)) /
1395 (m_zlines.at(k + 2) - m_zlines.at(k + 1));
1398 const auto m2 = m_elementMaterial.at(
Index2Element(i, j, k - 1));
1401 GetFieldComponent(i, j, k - 1, rx, ry, 0.5,
'z', potentials);
1403 (rz + 0.5) * (ez - ez_next) *
1404 (m_zlines.at(k) - m_zlines.at(k - 1)) /
1405 (m_zlines.at(k + 1) - m_zlines.at(k));
1411void ComponentCST::Element2Index(
const size_t element,
1412 unsigned int& i,
unsigned int& j,
unsigned int& k)
const {
1413 const auto nx = m_xlines.size() - 1;
1414 const auto ny = m_ylines.size() - 1;
1415 const auto nxy = nx * ny;
1417 const auto tmp = element - k * nxy;
1422int ComponentCST::Index2Node(
const unsigned int i,
const unsigned int j,
1423 const unsigned int k)
const {
1424 if (i > m_nx - 1 || j > m_ny - 1 || k > m_nz - 1) {
1425 throw "ComponentCST::Index2Node: Error. Node indices out of bounds.";
1427 return i + j * m_nx + k * m_nx * m_ny;
1430void ComponentCST::Node2Index(
const size_t node,
1431 unsigned int& i,
unsigned int& j,
unsigned int& k)
const {
1433 const auto nx = m_xlines.size();
1434 const auto ny = m_ylines.size();
1435 const auto nxy = nx * ny;
1437 const auto tmp = node - k * nxy;
double GetPotential(int ele, Point3D *localP)
bool Coordinate2Index(const double x, const double y, const double z, unsigned int &i, unsigned int &j, unsigned int &k) const
void UpdatePeriodicity() override
Verify periodicities.
bool GetElement(const size_t i, size_t &mat, bool &drift, std::vector< size_t > &nodes) const override
Return the material and node indices of a mesh element.
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status) override
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")
bool GetNode(const size_t i, double &x, double &y, double &z) const override
Medium * GetMedium(const double x, const double y, const double z) override
Get the medium at a given location (x, y, z).
void GetElementBoundaries(unsigned int element, double &xmin, double &xmax, double &ymin, double &ymax, double &zmin, double &zmax) const
void GetNumberOfMeshLines(unsigned int &nx, unsigned int &ny, unsigned int &nz) const
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 GetAspectRatio(const unsigned int i, double &dmin, double &dmax) override
void SetRangeZ(const double zmin, const double zmax)
ComponentCST()
Constructor.
int Index2Element(const unsigned int i, const unsigned int j, const unsigned int k) const
Base class for components based on finite-element field maps.
void PrintMaterials()
List all currently defined materials.
bool SetDefaultDriftMedium()
Find lowest epsilon, check for eps = 0, set default drift media flags.
double ReadDouble(char *token, double def, bool &error)
void MapCoordinates(double &xpos, double &ypos, double &zpos, bool &xmirrored, bool &ymirrored, bool &zmirrored, double &rcoordinate, double &rotation) const
Move (xpos, ypos, zpos) to field map coordinates.
void PrintWarning(const std::string &header)
std::array< double, 3 > m_maxBoundingBox
std::array< double, 3 > m_mapmin
std::array< double, 3 > m_minBoundingBox
static double ScalingFactor(std::string unit)
void UpdatePeriodicityCommon()
int ReadInteger(char *token, int def, bool &error)
std::vector< Material > m_materials
std::vector< bool > m_wfieldsOk
void PrintCouldNotOpen(const std::string &header, const std::string &filename) const
void UpdatePeriodicity2d()
std::vector< std::string > m_wfields
std::array< double, 3 > m_mapmax
void Reset() override
Reset the component.
bool m_debug
Switch on/off debugging messages.
std::string m_className
Class name.
bool m_ready
Ready for use?
Abstract base class for media.
bool IsDriftable() const
Is charge carrier transport enabled in this medium?