17unsigned int GetFormat(std::string format) {
19 std::transform(format.begin(), format.end(), format.begin(), toupper);
23 }
else if (format ==
"XYZ") {
25 }
else if (format ==
"IJ") {
27 }
else if (format ==
"IJK") {
29 }
else if (format ==
"YXZ") {
35void PrintError(
const std::string& fcn,
const unsigned int line,
36 const std::string& par) {
38 std::cerr << fcn <<
": Error reading line " << line <<
".\n"
39 <<
" Could not read " << par <<
".\n";
42void PrintNotReady(
const std::string& fcn) {
43 std::cerr << fcn <<
": Field map not available.\n";
46void PrintProgress(
const double f) {
49 constexpr unsigned int width = 70;
50 const unsigned int n =
static_cast<unsigned int>(std::floor(width * f));
51 std::string bar =
"[";
53 bar += std::string(width,
' ');
54 }
else if (n >= width) {
55 bar += std::string(width,
'=');
57 bar += std::string(n,
'=') +
">" + std::string(width - n - 1,
' ');
60 std::cout << bar <<
"\r" << std::flush;
72 const double z,
double& ex,
double& ey,
73 double& ez,
double& p,
Medium*& m,
87 if (!GetField(x, y, z, m_efields, ex, ey, ez, p, active)) {
100 const double z,
double& ex,
double& ey,
101 double& ez,
Medium*& m,
int& status) {
107 const double z,
double& wx,
double& wy,
108 double& wz,
const std::string& ) {
111 if (!m_hasWfield)
return;
112 const double xx = x - m_wField_xOffset;
113 const double yy = y - m_wField_yOffset;
114 const double zz = z - m_wField_zOffset;
117 GetField(xx, yy, zz, m_wfields, wx, wy, wz, wp, active);
122 const std::string& ) {
123 if (!m_hasWfield)
return 0.;
124 const double xx = x - m_wField_xOffset;
125 const double yy = y - m_wField_yOffset;
126 const double zz = z - m_wField_zOffset;
127 double wx = 0., wy = 0., wz = 0.;
130 if (!GetField(xx, yy, zz, m_wfields, wx, wy, wz, wp, active))
return 0.;
135 const double z,
const double t,
136 double& wx,
double& wy,
double& wz,
137 const std::string& ) {
140 if (m_wdtimes.empty())
return;
142 if (t < m_wdtimes.front() || t > m_wdtimes.back())
return;
144 const double xx = x - m_wField_xOffset;
145 const double yy = y - m_wField_yOffset;
146 const double zz = z - m_wField_zOffset;
148 const auto it1 = std::upper_bound(m_wdtimes.cbegin(), m_wdtimes.cend(), t);
149 const auto it0 = std::prev(it1);
151 const double dt = t - *it0;
153 const unsigned int i0 = it0 - m_wdtimes.cbegin();
154 double wx0 = 0., wy0 = 0., wz0 = 0.;
156 if (!GetField(xx, yy, zz, m_wdfields[i0], wx0, wy0, wz0, wp, active))
return;
158 if (dt < Small || it1 == m_wdtimes.cend()) {
164 const unsigned int i1 = it1 - m_wdtimes.cbegin();
165 double wx1 = 0., wy1 = 0., wz1 = 0.;
166 if (!GetField(xx, yy, zz, m_wdfields[i1], wx1, wy1, wz1, wp, active))
return;
168 const double f1 = dt / (*it1 - *it0);
169 const double f0 = 1. - f1;
170 wx = f0 * wx0 + f1 * wx1;
171 wy = f0 * wy0 + f1 * wy1;
172 wz = f0 * wz0 + f1 * wz1;
177 m_wField_xOffset = x;
178 m_wField_yOffset = y;
179 m_wField_zOffset = z;
183 const double z,
double& bx,
double& by,
184 double& bz,
int& status) {
192 if (!GetField(x, y, z, m_bfields, bx, by, bz, p, active)) {
214 if (m_active.empty())
return m_medium;
216 bool mirrored =
false;
224 const double sx = (xx - m_xMin) / m_dx;
225 const double sy = (yy - m_yMin) / m_dy;
226 const double sz = (zz - m_zMin) / m_dz;
227 const unsigned int i0 =
static_cast<unsigned int>(std::floor(sx));
228 const unsigned int j0 =
static_cast<unsigned int>(std::floor(sy));
229 const unsigned int k0 =
static_cast<unsigned int>(std::floor(sz));
230 const unsigned int i1 = std::min(i0 + 1, m_nX - 1);
231 const unsigned int j1 = std::min(j0 + 1, m_nY - 1);
232 const unsigned int k1 = std::min(k0 + 1, m_nZ - 1);
233 if (m_active[i0][j0][k0] && m_active[i0][j0][k1] &&
234 m_active[i0][j1][k0] && m_active[i0][j1][k1] &&
235 m_active[i1][j0][k0] && m_active[i1][j0][k1] &&
236 m_active[i1][j1][k0] && m_active[i1][j1][k1]) {
243 const unsigned int nz,
const double xmin,
244 const double xmax,
const double ymin,
245 const double ymax,
const double zmin,
248 if (nx == 0 || ny == 0 || nz == 0) {
250 <<
" Number of mesh elements must be positive.\n";
254 std::cerr <<
m_className <<
"::SetMesh: Invalid x range.\n";
256 }
else if (ymin >= ymax) {
257 std::cerr <<
m_className <<
"::SetMesh: Invalid y range.\n";
259 }
else if (zmin >= zmax) {
260 std::cerr <<
m_className <<
"::SetMesh: Invalid z range.\n";
272 m_dx = m_nX > 1 ? (m_xMax - m_xMin) / (m_nX - 1) : (m_xMax - m_xMin);
273 m_dy = m_nY > 1 ? (m_yMax - m_yMin) / (m_nY - 1) : (m_yMax - m_yMin);
274 m_dz = m_nZ > 1 ? (m_zMax - m_zMin) / (m_nZ - 1) : (m_zMax - m_zMin);
280 unsigned int& nx,
unsigned int& ny,
unsigned int& nz,
281 double& xmin,
double& xmax,
double& ymin,
double& ymax,
282 double& zmin,
double& zmax)
const {
284 if (!m_hasMesh)
return false;
298 const std::string& fmt,
const bool withP,
299 const bool withFlag,
const double scaleX,
301 const double scaleP) {
303 m_hasPotential = m_hasEfield =
false;
304 m_active.assign(m_nX, std::vector<std::vector<bool> >(m_nY, std::vector<bool>(m_nZ,
true)));
306 m_pMin = withP ? +1. : 0.;
307 m_pMax = withP ? -1. : 0.;
308 if (!LoadData(fname, fmt, withP, withFlag,
309 scaleX, scaleE, scaleP, m_efields)) {
314 if (withP) m_hasPotential =
true;
319 const std::string& fmt,
323 const double scaleP) {
326 if (!LoadData(fname, fmt, withP,
false, scaleX, scaleE, scaleP, m_wfields)) {
333 const std::string& fmt,
334 const double t,
const bool withP,
335 const double scaleX,
const double scaleE,
336 const double scaleP) {
338 std::vector<std::vector<std::vector<Node> > > wfield;
340 if (!LoadData(fname, fmt, withP,
false, scaleX, scaleE, scaleP, wfield)) {
343 if (m_wdtimes.empty() || t > m_wdtimes.back()) {
344 m_wdtimes.push_back(t);
345 m_wdfields.push_back(std::move(wfield));
347 const auto it = std::upper_bound(m_wdtimes.cbegin(), m_wdtimes.cend(), t);
348 const auto n = std::distance(m_wdtimes.cbegin(), it);
349 m_wdtimes.insert(it, t);
350 m_wdfields.insert(m_wdfields.cbegin() + n, std::move(wfield));
356 const std::string& fmt,
358 const double scaleB) {
361 if (!LoadData(fname, fmt,
false,
false, scaleX, scaleB, 1., m_bfields)) {
369 const std::string& filename,
const std::string& format) {
372 std::cerr <<
m_className <<
"::SaveElectricField: Null pointer.\n";
376 std::cerr <<
m_className <<
"::SaveElectricField: Mesh not set.\n";
379 const unsigned int fmt = GetFormat(format);
381 std::cerr <<
m_className <<
"::SaveElectricField:\n"
382 <<
" Unknown format (" << format <<
").\n";
385 std::ofstream outfile;
386 outfile.open(filename.c_str(), std::ios::out);
388 std::cerr <<
m_className <<
"::SaveElectricField:\n"
389 <<
" Could not open file " << filename <<
".\n";
392 std::cout <<
m_className <<
"::SaveElectricField:\n"
393 <<
" Exporting field/potential to " << filename <<
".\n"
394 <<
" Be patient...\n";
396 outfile <<
"# XMIN = " << m_xMin <<
", XMAX = " << m_xMax <<
", NX = "
398 outfile <<
"# YMIN = " << m_yMin <<
", YMAX = " << m_yMax <<
", NY = "
400 outfile <<
"# ZMIN = " << m_zMin <<
", ZMAX = " << m_zMax <<
", NZ = "
403 const unsigned int nValues = m_nX * m_nY * m_nZ;
404 const unsigned int nPrint = std::pow(10,
static_cast<unsigned int>(
405 std::max(std::floor(std::log10(nValues)) - 1, 1.)));
406 unsigned int nLines = 0;
409 for (
unsigned int i = 0; i < m_nX; ++i) {
410 const double x = m_xMin + i * m_dx;
411 for (
unsigned int j = 0; j < m_nY; ++j) {
412 const double y = m_yMin + j * m_dy;
413 for (
unsigned int k = 0; k < m_nZ; ++k) {
414 const double z = m_zMin + k * m_dz;
416 outfile << x <<
" " << y <<
" ";
417 }
else if (fmt == 2) {
418 outfile << x <<
" " << y <<
" " << z <<
" ";
419 }
else if (fmt == 3) {
420 outfile << i <<
" " << j <<
" ";
421 }
else if (fmt == 4) {
422 outfile << i <<
" " << j <<
" " << k <<
" ";
423 }
else if (fmt == 5) {
424 outfile << y <<
" " << x <<
" " << z <<
" ";
426 double ex = 0., ey = 0., ez = 0., v = 0.;
428 outfile << ex <<
" " << ey <<
" " << ez <<
" " << v <<
"\n";
430 if (nLines % nPrint == 0) PrintProgress(
double(nLines) / nValues);
435 std::cout << std::endl <<
m_className <<
"::SaveElectricField: Done.\n";
440 const std::string&
id,
const std::string& filename,
441 const std::string& format) {
444 std::cerr <<
m_className <<
"::SaveWeightingField: Null pointer.\n";
448 std::cerr <<
m_className <<
"::SaveWeightingField: Mesh not set.\n";
451 const unsigned int fmt = GetFormat(format);
453 std::cerr <<
m_className <<
"::SaveWeightingField:\n"
454 <<
" Unknown format (" << format <<
").\n";
457 std::ofstream outfile;
458 outfile.open(filename.c_str(), std::ios::out);
460 std::cerr <<
m_className <<
"::SaveWeightingField:\n"
461 <<
" Could not open file " << filename <<
".\n";
464 std::cout <<
m_className <<
"::SaveWeightingField:\n"
465 <<
" Exporting field/potential to " << filename <<
".\n"
466 <<
" Be patient...\n";
468 outfile <<
"# XMIN = " << m_xMin <<
", XMAX = " << m_xMax <<
", NX = "
470 outfile <<
"# YMIN = " << m_yMin <<
", YMAX = " << m_yMax <<
", NY = "
472 outfile <<
"# ZMIN = " << m_zMin <<
", ZMAX = " << m_zMax <<
", NZ = "
474 const unsigned int nValues = m_nX * m_nY * m_nZ;
475 const unsigned int nPrint = std::pow(10,
static_cast<unsigned int>(
476 std::max(std::floor(std::log10(nValues)) - 1, 1.)));
477 unsigned int nLines = 0;
478 for (
unsigned int i = 0; i < m_nX; ++i) {
479 const double x = m_xMin + i * m_dx;
480 for (
unsigned int j = 0; j < m_nY; ++j) {
481 const double y = m_yMin + j * m_dy;
482 for (
unsigned int k = 0; k < m_nZ; ++k) {
483 const double z = m_zMin + k * m_dz;
485 outfile << x <<
" " << y <<
" ";
486 }
else if (fmt == 2) {
487 outfile << x <<
" " << y <<
" " << z <<
" ";
488 }
else if (fmt == 3) {
489 outfile << i <<
" " << j <<
" ";
490 }
else if (fmt == 4) {
491 outfile << i <<
" " << j <<
" " << k <<
" ";
492 }
else if (fmt == 5) {
493 outfile << y <<
" " << x <<
" " << z <<
" ";
495 double wx = 0., wy = 0., wz = 0.;
498 outfile << wx <<
" " << wy <<
" " << wz <<
" " << v <<
"\n";
500 if (nLines % nPrint == 0) PrintProgress(
double(nLines) / nValues);
505 std::cout << std::endl <<
m_className <<
"::SaveWeightingField: Done.\n";
509bool ComponentGrid::LoadMesh(
const std::string& filename, std::string format,
510 const double scaleX) {
512 const unsigned int fmt = GetFormat(format);
515 <<
" Unknown format (" << format <<
").\n";
520 std::bitset<9> found;
522 double xmin = 0., ymin = 0., zmin = 0.;
523 double xmax = 0., ymax = 0., zmax = 0.;
524 unsigned int nx = 0, ny = 0, nz = 0;
527 std::ifstream infile;
528 infile.open(filename.c_str(), std::ios::in);
531 <<
" Could not open file " << filename <<
".\n";
535 unsigned int nLines = 0;
536 while (!infile.fail()) {
538 std::getline(infile, line);
543 if (line.empty())
continue;
545 if (line[0] !=
'#' && !(line[0] ==
'/' && line[1] ==
'/')) {
548 std::size_t pos0 = 0;
549 std::size_t pos1 = line.find(
"=", pos0);
550 while (pos1 != std::string::npos) {
551 std::string key = line.substr(pos0, pos1 - pos0);
552 std::transform(key.begin(), key.end(), key.begin(), toupper);
553 const std::size_t pos2 = line.find_first_of(
",;", pos1 + 1);
554 std::istringstream val(line.substr(pos1 + 1, pos2 - pos1 - 1));
555 if (key.find(
"XMIN") != std::string::npos) {
558 }
else if (key.find(
"YMIN") != std::string::npos) {
561 }
else if (key.find(
"ZMIN") != std::string::npos) {
564 }
else if (key.find(
"XMAX") != std::string::npos) {
567 }
else if (key.find(
"YMAX") != std::string::npos) {
570 }
else if (key.find(
"ZMAX") != std::string::npos) {
573 }
else if (key.find(
"NX") != std::string::npos) {
576 }
else if (key.find(
"NY") != std::string::npos) {
579 }
else if (key.find(
"NZ") != std::string::npos) {
583 if (pos2 == std::string::npos)
break;
585 pos1 = line.find(
"=", pos0);
590 if (fmt == 1 || fmt == 3) {
597 if (found[0] || found[1] || found[3] || found[4] || found[5]) {
598 zmin = -std::max({
fabs(xmin),
fabs(xmax),
606 zmax = std::max({
fabs(xmin),
fabs(xmax),
613 std::printf(
"%12.6f < x [cm] < %12.6f, %5u points\n", xmin, xmax, nx);
614 std::printf(
"%12.6f < y [cm] < %12.6f, %5u points\n", ymin, ymax, ny);
615 std::printf(
"%12.6f < z [cm] < %12.6f, %5u points\n", zmin, zmax, nz);
616 return SetMesh(nx, ny, nz, xmin, xmax, ymin, ymax, zmin, zmax);
619 if ((fmt == 3 || fmt == 4) && !(found[0] && found[3])) {
620 std::cerr <<
m_className <<
"::LoadMesh: x-limits not found.\n";
622 }
else if ((fmt == 3 || fmt == 4) && !(found[1] && found[4])) {
623 std::cerr <<
m_className <<
"::LoadMesh: y-limits not found.\n";
625 }
else if (fmt == 4 && !(found[2] && found[5])) {
626 std::cerr <<
m_className <<
"::LoadMesh: z-limits not found.\n";
630 unsigned int nValues = 0;
631 infile.open(filename.c_str(), std::ios::in);
634 <<
" Could not open file " << filename <<
".\n";
638 if (!found[0]) xmin = std::numeric_limits<double>::max();
639 if (!found[1]) ymin = std::numeric_limits<double>::max();
640 if (!found[2]) zmin = std::numeric_limits<double>::max();
641 if (!found[3]) xmax = std::numeric_limits<double>::min();
642 if (!found[4]) ymax = std::numeric_limits<double>::min();
643 if (!found[5]) zmax = std::numeric_limits<double>::min();
644 constexpr double tol = 1.e-10;
645 auto cmp = [](
double x,
double y) {
646 return x <
y - tol * (std::fabs(x) + std::fabs(y));
648 std::set<double,
decltype(cmp)> xLines(cmp);
649 std::set<double,
decltype(cmp)> yLines(cmp);
650 std::set<double,
decltype(cmp)> zLines(cmp);
653 while (!infile.fail()) {
655 std::getline(infile, line);
660 if (line.empty())
continue;
662 if (line[0] ==
'#')
continue;
663 if (line[0] ==
'/' && line[1] ==
'/')
continue;
664 std::istringstream data;
671 PrintError(
m_className +
"::LoadMesh", nLines,
"coordinates");
677 if (!found[0]) xmin = std::min(x, xmin);
678 if (!found[1]) ymin = std::min(y, ymin);
679 if (!found[3]) xmax = std::max(x, xmin);
680 if (!found[4]) ymax = std::max(y, ymin);
683 }
else if (fmt == 2) {
688 PrintError(
m_className +
"::LoadMesh", nLines,
"coordinates");
695 if (!found[0]) xmin = std::min(x, xmin);
696 if (!found[1]) ymin = std::min(y, ymin);
697 if (!found[2]) zmin = std::min(z, zmin);
698 if (!found[3]) xmax = std::max(x, xmax);
699 if (!found[4]) ymax = std::max(y, ymax);
700 if (!found[5]) zmax = std::max(z, zmax);
704 }
else if (fmt == 3) {
706 unsigned int i = 0, j = 0;
709 PrintError(
m_className +
"::LoadMesh", nLines,
"indices");
713 if (!found[6]) nx = std::max(nx, i);
714 if (!found[7]) ny = std::max(ny, j);
715 }
else if (fmt == 4) {
717 unsigned int i = 0, j = 0, k = 0;
720 PrintError(
m_className +
"::LoadMesh", nLines,
"indices");
724 if (!found[6]) nx = std::max(nx, i);
725 if (!found[7]) ny = std::max(ny, j);
726 if (!found[8]) nz = std::max(nz, k);
727 }
else if (fmt == 5) {
732 PrintError(
m_className +
"::LoadMesh", nLines,
"coordinates");
739 if (!found[0]) xmin = std::min(x, xmin);
740 if (!found[1]) ymin = std::min(y, ymin);
741 if (!found[2]) zmin = std::min(z, zmin);
742 if (!found[3]) xmax = std::max(x, xmax);
743 if (!found[4]) ymax = std::max(y, ymax);
744 if (!found[5]) zmax = std::max(z, zmax);
752 if (bad)
return false;
754 if (fmt == 1 || fmt == 2 || fmt == 5) {
755 if (!found[6]) nx = xLines.size();
756 if (!found[7]) ny = yLines.size();
757 if (!found[8]) nz = zLines.size();
761 std::printf(
"%12.6f < x [cm] < %12.6f, %5u points\n", xmin, xmax, nx);
762 std::printf(
"%12.6f < y [cm] < %12.6f, %5u points\n", ymin, ymax, ny);
763 std::printf(
"%12.6f < z [cm] < %12.6f, %5u points\n", zmin, zmax, nz);
764 unsigned int nExpected = nx * ny;
765 if (fmt == 2 || fmt == 4 || fmt == 5) nExpected *= nz;
766 if (nExpected != nValues) {
768 <<
" Warning: Expected " << nExpected <<
" lines, read "
771 return SetMesh(nx, ny, nz, xmin, xmax, ymin, ymax, zmin, zmax);
774bool ComponentGrid::LoadData(
const std::string& filename, std::string format,
775 const bool withPotential,
const bool withFlag,
776 const double scaleX,
const double scaleF,
const double scaleP,
777 std::vector<std::vector<std::vector<Node> > >& fields) {
780 if (!LoadMesh(filename, format, scaleX)) {
781 std::cerr <<
m_className <<
"::LoadData: Mesh not set.\n";
786 const unsigned int fmt = GetFormat(format);
789 <<
" Unknown format (" << format <<
").\n";
796 unsigned int nValues = 0;
798 std::vector<std::vector<std::vector<bool> > > isSet(
800 std::vector<std::vector<bool> >(m_nY, std::vector<bool>(m_nZ,
false)));
802 std::ifstream infile;
803 infile.open(filename.c_str(), std::ios::in);
806 <<
" Could not open file " << filename <<
".\n";
811 unsigned int nLines = 0;
813 while (!infile.fail()) {
815 std::getline(infile, line);
820 if (line.empty())
continue;
822 if (line[0] ==
'#')
continue;
823 if (line[0] ==
'/' && line[1] ==
'/')
continue;
831 std::istringstream data;
838 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
844 const double u = std::round((x - m_xMin) / m_dx);
845 const double v = std::round((y - m_yMin) / m_dy);
846 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
847 j = v < 0. ? 0 :
static_cast<unsigned int>(v);
848 if (i >= m_nX) i = m_nX - 1;
849 if (j >= m_nY) j = m_nY - 1;
850 }
else if (fmt == 2) {
855 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
862 const double u = std::round((x - m_xMin) / m_dx);
863 const double v = std::round((y - m_yMin) / m_dy);
864 const double w = std::round((z - m_zMin) / m_dz);
865 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
866 j = v < 0. ? 0 :
static_cast<unsigned int>(v);
867 j = w < 0. ? 0 :
static_cast<unsigned int>(w);
868 if (i >= m_nX) i = m_nX - 1;
869 if (j >= m_nY) j = m_nY - 1;
870 if (k >= m_nZ) k = m_nZ - 1;
871 }
else if (fmt == 3) {
875 PrintError(
m_className +
"::LoadData", nLines,
"indices");
879 }
else if (fmt == 4) {
883 PrintError(
m_className +
"::LoadData", nLines,
"indices");
887 }
else if (fmt == 5) {
892 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
899 const double u = std::round((x - m_xMin) / m_dx);
900 const double v = std::round((y - m_yMin) / m_dy);
901 const double w = std::round((z - m_zMin) / m_dz);
902 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
903 j = v < 0. ? 0 :
static_cast<unsigned int>(v);
904 j = w < 0. ? 0 :
static_cast<unsigned int>(w);
905 if (i >= m_nX) i = m_nX - 1;
906 if (j >= m_nY) j = m_nY - 1;
907 if (k >= m_nZ) k = m_nZ - 1;
910 if (i >= m_nX || j >= m_nY || k >= m_nZ) {
912 <<
" Error reading line " << nLines <<
".\n"
913 <<
" Index (" << i <<
", " << j <<
", " << k
914 <<
") out of range.\n";
917 if (isSet[i][j][k]) {
919 <<
" Error reading line " << nLines <<
".\n"
920 <<
" Mesh element (" << i <<
", " << j <<
", " << k
921 <<
") has already been set.\n";
925 if (fmt == 1 || fmt == 3) {
929 }
else if (fmt == 5) {
930 data >> fy >> fx >> fz;
932 data >> fx >> fy >> fz;
935 PrintError(
m_className +
"::LoadData", nLines,
"field components");
945 PrintError(
m_className +
"::LoadData", nLines,
"potential");
950 if (m_pMin > m_pMax) {
955 if (p < m_pMin) m_pMin = p;
956 if (p > m_pMax) m_pMax = p;
963 PrintError(
m_className +
"::LoadData", nLines,
"region");
968 const bool isActive = flag == 0 ? false :
true;
969 if (fmt == 1 || fmt == 3) {
971 for (
unsigned int kk = 0; kk < m_nZ; ++kk) {
972 fields[i][j][kk].fx = fx;
973 fields[i][j][kk].fy = fy;
974 fields[i][j][kk].fz = fz;
975 fields[i][j][kk].v = p;
976 if (withFlag) m_active[i][j][kk] = isActive;
977 isSet[i][j][kk] =
true;
980 fields[i][j][k].fx = fx;
981 fields[i][j][k].fy = fy;
982 fields[i][j][k].fz = fz;
983 fields[i][j][k].v = p;
984 isSet[i][j][k] =
true;
989 if (bad)
return false;
991 <<
" Read " << nValues <<
" values from " << filename <<
".\n";
992 unsigned int nExpected = m_nX * m_nY;
993 if (fmt == 2 || fmt == 4 || fmt == 5) nExpected *= m_nZ;
994 if (nExpected != nValues) {
996 <<
" Expected " << nExpected <<
" values.\n";
1002 double& xmax,
double& ymax,
double& zmax) {
1038 double& eymin,
double& eymax,
1039 double& ezmin,
double& ezmax) {
1041 PrintNotReady(
m_className +
"::GetElectricFieldRange");
1045 exmin = exmax = m_efields[0][0][0].fx;
1046 eymin = eymax = m_efields[0][0][0].fy;
1047 ezmin = ezmax = m_efields[0][0][0].fz;
1048 for (
unsigned int i = 0; i < m_nX; ++i) {
1049 for (
unsigned int j = 0; j < m_nY; ++j) {
1050 for (
unsigned int k = 0; k < m_nZ; ++k) {
1051 const Node& node = m_efields[i][j][k];
1052 if (node.fx < exmin) exmin = node.fx;
1053 if (node.fx > exmax) exmax = node.fx;
1054 if (node.fy < eymin) eymin = node.fy;
1055 if (node.fy > eymax) eymax = node.fy;
1056 if (node.fz < ezmin) ezmin = node.fz;
1057 if (node.fz > ezmax) ezmax = node.fz;
1066 std::cerr <<
m_className <<
"::SetMedium: Null pointer.\n";
1071bool ComponentGrid::GetField(
1072 const double xi,
const double yi,
const double zi,
1073 const std::vector<std::vector<std::vector<Node> > >& field,
double& fx,
1074 double& fy,
double& fz,
double& p,
bool& active) {
1076 std::cerr <<
m_className <<
"::GetField: Mesh is not set.\n";
1082 bool xMirrored =
false;
1085 if (x < m_xMin || x > m_xMax)
return false;
1086 bool yMirrored =
false;
1089 if (y < m_yMin || y > m_yMax)
return false;
1090 bool zMirrored =
false;
1093 if (z < m_zMin || z > m_zMax)
return false;
1096 const double sx = (x - m_xMin) / m_dx;
1097 const double sy = (y - m_yMin) / m_dy;
1098 const double sz = (z - m_zMin) / m_dz;
1099 const unsigned int i0 =
static_cast<unsigned int>(std::floor(sx));
1100 const unsigned int j0 =
static_cast<unsigned int>(std::floor(sy));
1101 const unsigned int k0 =
static_cast<unsigned int>(std::floor(sz));
1102 const double ux = sx - i0;
1103 const double uy = sy - j0;
1104 const double uz = sz - k0;
1105 const unsigned int i1 = std::min(i0 + 1, m_nX - 1);
1106 const unsigned int j1 = std::min(j0 + 1, m_nY - 1);
1107 const unsigned int k1 = std::min(k0 + 1, m_nZ - 1);
1108 const double vx = 1. - ux;
1109 const double vy = 1. - uy;
1110 const double vz = 1. - uz;
1111 if (!m_active.empty()) {
1112 active = m_active[i0][j0][k0] && m_active[i0][j0][k1] &&
1113 m_active[i0][j1][k0] && m_active[i0][j1][k1] &&
1114 m_active[i1][j0][k0] && m_active[i1][j0][k1] &&
1115 m_active[i1][j1][k0] && m_active[i1][j1][k1];
1117 const Node& n000 = field[i0][j0][k0];
1118 const Node& n100 = field[i1][j0][k0];
1119 const Node& n010 = field[i0][j1][k0];
1120 const Node& n110 = field[i1][j1][k0];
1121 const Node& n001 = field[i0][j0][k1];
1122 const Node& n101 = field[i1][j0][k1];
1123 const Node& n011 = field[i0][j1][k1];
1124 const Node& n111 = field[i1][j1][k1];
1127 std::cout <<
m_className <<
"::GetField: Determining field at ("
1128 << xi <<
", " << yi <<
", " << zi <<
").\n"
1129 <<
" X: " << i0 <<
" (" << ux <<
") - "
1130 << i1 <<
" (" << vx <<
").\n"
1131 <<
" Y: " << j0 <<
" (" << uy <<
") - "
1132 << j1 <<
" (" << vy <<
").\n"
1133 <<
" Z: " << k0 <<
" (" << uz <<
") - "
1134 << k1 <<
" (" << vz <<
").\n";
1136 fx = ((n000.fx * vx + n100.fx * ux) * vy +
1137 (n010.fx * vx + n110.fx * ux) * uy) *
1139 ((n001.fx * vx + n101.fx * ux) * vy +
1140 (n011.fx * vx + n111.fx * ux) * uy) *
1142 fy = ((n000.fy * vx + n100.fy * ux) * vy +
1143 (n010.fy * vx + n110.fy * ux) * uy) *
1145 ((n001.fy * vx + n101.fy * ux) * vy +
1146 (n011.fy * vx + n111.fy * ux) * uy) *
1148 fz = ((n000.fz * vx + n100.fz * ux) * vy +
1149 (n010.fz * vx + n110.fz * ux) * uy) *
1151 ((n001.fz * vx + n101.fz * ux) * vy +
1152 (n011.fz * vx + n111.fz * ux) * uy) *
1154 p = ((n000.v * vx + n100.v * ux) * vy + (n010.v * vx + n110.v * ux) * uy) *
1156 ((n001.v * vx + n101.v * ux) * vy + (n011.v * vx + n111.v * ux) * uy) *
1158 if (xMirrored) fx = -fx;
1159 if (yMirrored) fy = -fy;
1160 if (zMirrored) fz = -fz;
1165 const unsigned int i,
const unsigned int j,
const unsigned int k,
1166 double& v,
double& ex,
double& ey,
double& ez)
const {
1167 v = ex = ey = ez = 0.;
1170 std::cerr <<
m_className <<
"::GetElectricField: Mesh not set.\n";
1173 PrintNotReady(
m_className +
"::GetElectricField");
1176 if (i >= m_nX || j >= m_nY || k >= m_nZ) {
1177 std::cerr <<
m_className <<
"::GetElectricField: Index out of range.\n";
1180 const Node& node = m_efields[i][j][k];
1188void ComponentGrid::Reset() {
1198 m_nX = m_nY = m_nZ = 0;
1199 m_xMin = m_yMin = m_zMin = 0.;
1200 m_xMax = m_yMax = m_zMax = 0.;
1201 m_pMin = m_pMax = 0.;
1205 m_hasPotential =
false;
1206 m_hasEfield =
false;
1207 m_hasBfield =
false;
1208 m_hasWfield =
false;
1211 m_wField_xOffset = 0.;
1212 m_wField_yOffset = 0.;
1213 m_wField_zOffset = 0.;
1216void ComponentGrid::UpdatePeriodicity() {
1218 PrintNotReady(
m_className +
"::UpdatePeriodicity");
1223 for (
unsigned int i = 0; i < 3; ++i) {
1225 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1226 <<
" Both simple and mirror periodicity requested. Reset.\n";
1232 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1233 <<
" Axial symmetry is not supported. Reset.\n";
1239 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1240 <<
" Rotation symmetry is not supported. Reset.\n";
1245double ComponentGrid::Reduce(
const double xin,
const double xmin,
1246 const double xmax,
const bool simplePeriodic,
1247 const bool mirrorPeriodic,
bool& mirrored)
const {
1250 const double lx = xmax - xmin;
1251 if (simplePeriodic) {
1252 x = xmin + fmod(x - xmin, lx);
1253 if (x < xmin)
x += lx;
1254 }
else if (mirrorPeriodic) {
1255 double xNew = xmin + fmod(x - xmin, lx);
1256 if (xNew < xmin) xNew += lx;
1257 const int nx = int(floor(0.5 + (xNew - x) / lx));
1258 if (nx != 2 * (nx / 2)) {
1259 xNew = xmin + xmax - xNew;
1267void ComponentGrid::Initialise(
1268 std::vector<std::vector<std::vector<Node> > >& fields) {
1270 fields.resize(m_nX);
1271 for (
unsigned int i = 0; i < m_nX; ++i) {
1272 fields[i].resize(m_nY);
1273 for (
unsigned int j = 0; j < m_nY; ++j) {
1274 fields[i][j].resize(m_nZ);
1275 for (
unsigned int k = 0; k < m_nZ; ++k) {
1276 fields[i][j][k].fx = 0.;
1277 fields[i][j][k].fy = 0.;
1278 fields[i][j][k].fz = 0.;
1279 fields[i][j][k].v = 0.;
Abstract base class for components.
std::array< bool, 3 > m_periodic
Simple periodicity in x, y, z.
virtual void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status)=0
std::array< bool, 3 > m_rotationSymmetric
Rotation symmetry around x-axis, y-axis, z-axis.
virtual double WeightingPotential(const double x, const double y, const double z, const std::string &label)
std::array< bool, 3 > m_axiallyPeriodic
Axial periodicity in x, y, z.
virtual void MagneticField(const double x, const double y, const double z, double &bx, double &by, double &bz, int &status)
bool m_ready
Ready for use?
std::array< bool, 3 > m_mirrorPeriodic
Mirror periodicity in x, y, z.
virtual void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label)
std::string m_className
Class name.
bool m_debug
Switch on/off debugging messages.
bool SetMesh(const unsigned int nx, const unsigned int ny, const unsigned int nz, const double xmin, const double xmax, const double ymin, const double ymax, const double zmin, const double zmax)
bool SaveElectricField(ComponentBase *cmp, const std::string &filename, const std::string &format)
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the bounding box coordinates.
ComponentGrid()
Constructor.
bool LoadElectricField(const std::string &filename, const std::string &format, const bool withPotential, const bool withFlag, const double scaleX=1., const double scaleE=1., const double scaleP=1.)
void DelayedWeightingField(const double x, const double y, const double z, const double t, double &wx, double &wy, double &wz, const std::string &label) override
bool GetMesh(unsigned int &nx, unsigned int &ny, unsigned int &nz, double &xmin, double &xmax, double &ymin, double &ymax, double &zmin, double &zmax) const
Retrieve the parameters of the grid.
double WeightingPotential(const double x, const double y, const double z, const std::string &label) override
bool GetVoltageRange(double &vmin, double &vmax) override
Calculate the voltage range [V].
bool SaveWeightingField(ComponentBase *cmp, const std::string &id, const std::string &filename, const std::string &format)
void SetMedium(Medium *m)
Set the medium.
Medium * GetMedium() const
Get the medium.
bool LoadMagneticField(const std::string &filename, const std::string &format, const double scaleX=1., const double scaleB=1.)
Import magnetic field values from a file.
bool GetElectricField(const unsigned int i, const unsigned int j, const unsigned int k, double &v, double &ex, double &ey, double &ez) const
Return the field at a given node.
bool LoadWeightingField(const std::string &filename, const std::string &format, const bool withPotential, const double scaleX=1., const double scaleE=1., const double scaleP=1.)
Import (prompt) weighting field from file.
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, double &v, Medium *&m, int &status) override
Calculate the drift field [V/cm] and potential [V] at (x, y, z).
bool GetElectricFieldRange(double &exmin, double &exmax, double &eymin, double &eymax, double &ezmin, double &ezmax)
void MagneticField(const double x, const double y, const double z, double &bx, double &by, double &bz, int &status) override
void SetWeightingFieldOffset(const double x, const double y, const double z)
void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label) override
Abstract base class for media.
void ltrim(std::string &line)
DoubleAc fabs(const DoubleAc &f)