17void PrintError(
const std::string& fcn,
const unsigned int line,
18 const std::string& par) {
19 std::cerr << fcn <<
": Error reading line " << line <<
".\n"
20 <<
" Could not read " << par <<
".\n";
23void PrintNotReady(
const std::string& fcn) {
24 std::cerr << fcn <<
": Map not available.\n";
27void PrintProgress(
const double f) {
29 constexpr unsigned int width = 70;
30 const unsigned int n =
static_cast<unsigned int>(std::floor(width * f));
31 std::string bar =
"[";
33 bar += std::string(width,
' ');
34 }
else if (n >= width) {
35 bar += std::string(width,
'=');
37 bar += std::string(n,
'=') +
">" + std::string(width - n - 1,
' ');
40 std::cout << bar <<
"\r" << std::flush;
43bool IsComment(
const std::string& line) {
44 if (line.empty())
return false;
45 if (line[0] ==
'#')
return true;
46 if (line.size() > 1 && (line[0] ==
'/' && line[1] ==
'/'))
return true;
57 const double z,
double& ex,
double& ey,
58 double& ez,
double& p,
Medium*& m,
64 if (m_efields.empty()) {
72 if (!GetField(x, y, z, m_efields, ex, ey, ez, p, active)) {
85 const double z,
double& ex,
double& ey,
86 double& ez,
Medium*& m,
int& status) {
92 const double z,
double& wx,
double& wy,
93 double& wz,
const std::string& ) {
95 if (m_wfields.empty())
return;
96 const double xx = x - m_wFieldOffset[0];
97 const double yy = y - m_wFieldOffset[1];
98 const double zz = z - m_wFieldOffset[2];
101 GetField(xx, yy, zz, m_wfields, wx, wy, wz, wp, active);
106 const std::string& ) {
107 if (m_wfields.empty())
return 0.;
108 const double xx = x - m_wFieldOffset[0];
109 const double yy = y - m_wFieldOffset[1];
110 const double zz = z - m_wFieldOffset[2];
111 double wx = 0., wy = 0., wz = 0.;
114 if (!GetField(xx, yy, zz, m_wfields, wx, wy, wz, wp, active))
return 0.;
119 const double z,
const double t,
120 double& wx,
double& wy,
double& wz,
121 const std::string& ) {
123 if (m_wdtimes.empty())
return;
125 if (t < m_wdtimes.front() || t > m_wdtimes.back())
return;
127 const double xx = x - m_wFieldOffset[0];
128 const double yy = y - m_wFieldOffset[1];
129 const double zz = z - m_wFieldOffset[2];
131 const auto it1 = std::upper_bound(m_wdtimes.cbegin(), m_wdtimes.cend(), t);
132 const auto it0 = std::prev(it1);
134 const double dt = t - *it0;
136 const unsigned int i0 = it0 - m_wdtimes.cbegin();
137 double wx0 = 0., wy0 = 0., wz0 = 0.;
139 if (!GetField(xx, yy, zz, m_wdfields[i0], wx0, wy0, wz0, wp, active))
return;
141 if (dt < Small || it1 == m_wdtimes.cend()) {
147 const unsigned int i1 = it1 - m_wdtimes.cbegin();
148 double wx1 = 0., wy1 = 0., wz1 = 0.;
149 if (!GetField(xx, yy, zz, m_wdfields[i1], wx1, wy1, wz1, wp, active))
return;
151 const double f1 = dt / (*it1 - *it0);
152 const double f0 = 1. - f1;
153 wx = f0 * wx0 + f1 * wx1;
154 wy = f0 * wy0 + f1 * wy1;
155 wz = f0 * wz0 + f1 * wz1;
159 const double x,
const double y,
const double z,
const double t,
160 const std::string& ) {
162 if (m_wdtimes.empty())
return 0.;
164 if (t < m_wdtimes.front() || t > m_wdtimes.back())
return 0.;
166 const double xx = x - m_wFieldOffset[0];
167 const double yy = y - m_wFieldOffset[1];
168 const double zz = z - m_wFieldOffset[2];
170 const auto it1 = std::upper_bound(m_wdtimes.cbegin(), m_wdtimes.cend(), t);
171 const auto it0 = std::prev(it1);
173 const double dt = t - *it0;
174 const unsigned int i0 = it0 - m_wdtimes.cbegin();
175 double wp0 = 0., wx0 = 0., wy0 = 0., wz0 = 0.;
177 if (!GetField(xx, yy, zz, m_wdfields[i0], wx0, wy0, wz0, wp0, active))
return 0.;
179 if (dt < Small || it1 == m_wdtimes.cend())
return wp0;
181 const unsigned int i1 = it1 - m_wdtimes.cbegin();
182 double wp1 = 0., wx1 = 0., wy1 = 0., wz1 = 0.;
183 if (!GetField(xx, yy, zz, m_wdfields[i1], wx1, wy1, wz1, wp1, active))
return 0.;
185 const double f1 = dt / (*it1 - *it0);
186 const double f0 = 1. - f1;
187 return f0 * wp0 + f1 * wp1;
192 m_wFieldOffset = {x, y, z};
196 const double z,
double& bx,
double& by,
197 double& bz,
int& status) {
199 if (m_bfields.empty()) {
205 if (!GetField(x, y, z, m_bfields, bx, by, bz, p, active)) {
217 if (m_efields.empty()) {
222 std::array<double, 3> xx = {x, y, z};
223 if (m_coordinates == Coordinates::Cylindrical) {
224 if (fabs(x) > Small || fabs(y) > Small) {
225 xx[0] = sqrt(x * x + y * y);
229 for (
size_t i = 0; i < 3; ++i) {
231 if (xx[i] < m_xMin[i] || xx[i] > m_xMax[i])
return nullptr;
233 if (m_active.empty())
return m_medium;
234 for (
size_t i = 0; i < 3; ++i) {
235 bool mirrored =
false;
236 xx[i] = Reduce(xx[i], m_xMin[i], m_xMax[i],
240 const double sx = (xx[0] - m_xMin[0]) * m_sX[0];
241 const double sy = (xx[1] - m_xMin[1]) * m_sX[1];
242 const double sz = (xx[2] - m_xMin[2]) * m_sX[2];
243 const unsigned int i0 =
static_cast<unsigned int>(std::floor(sx));
244 const unsigned int j0 =
static_cast<unsigned int>(std::floor(sy));
245 const unsigned int k0 =
static_cast<unsigned int>(std::floor(sz));
246 const unsigned int i1 = std::min(i0 + 1, m_nX[0] - 1);
247 const unsigned int j1 = std::min(j0 + 1, m_nX[1] - 1);
248 const unsigned int k1 = std::min(k0 + 1, m_nX[2] - 1);
249 if (m_active[i0][j0][k0] && m_active[i0][j0][k1] && m_active[i0][j1][k0] &&
250 m_active[i0][j1][k1] && m_active[i1][j0][k0] && m_active[i1][j0][k1] &&
251 m_active[i1][j1][k0] && m_active[i1][j1][k1]) {
258 const unsigned int nz,
const double xmin,
259 const double xmax,
const double ymin,
260 const double ymax,
const double zmin,
263 if (nx == 0 || ny == 0 || nz == 0) {
265 <<
" Number of mesh elements must be positive.\n";
269 std::cerr <<
m_className <<
"::SetMesh: Invalid x range.\n";
271 }
else if (ymin >= ymax) {
272 std::cerr <<
m_className <<
"::SetMesh: Invalid y range.\n";
274 }
else if (zmin >= zmax) {
275 std::cerr <<
m_className <<
"::SetMesh: Invalid z range.\n";
278 if (m_coordinates == Coordinates::Cylindrical) {
280 std::cerr <<
m_className <<
"::SetMesh: Invalid range.\n"
281 <<
" Radial coordinates must be >= 0.\n";
294 constexpr double tol = 1.e-10;
295 for (
size_t i = 0; i < 3; ++i) {
296 if (m_xMax[i] - m_xMin[i] > tol) {
297 m_sX[i] = std::max(m_nX[i] - 1., 1.) / (m_xMax[i] - m_xMin[i]);
302 if (m_coordinates == Coordinates::Cylindrical) {
303 if (fabs(m_xMax[1] - m_xMin[1] - TwoPi) < tol) {
305 std::cerr <<
m_className <<
"::SetMesh: Enabling theta periodicity.\n";
316 unsigned int& nz,
double& xmin,
double& xmax,
317 double& ymin,
double& ymax,
double& zmin,
318 double& zmax)
const {
319 if (!m_hasMesh)
return false;
334 if (m_xMin[0] < 0. || m_xMax[0] < 0.) {
335 std::cerr <<
m_className <<
"::SetCylindricalCoordinates:\n"
336 <<
" Invalid mesh limits. Radial coordinate must be >= 0.\n";
340 const double s = m_xMax[1] - m_xMin[1];
341 if (std::abs(TwoPi - s *
int(TwoPi / s)) > 1.e-4) {
342 std::cerr <<
m_className <<
"::SetCylindricalCoordinates:\n"
343 <<
" Angular range does not divide 2 pi.\n"
344 <<
" Switching off periodicity.\n";
349 m_coordinates = Coordinates::Cylindrical;
353 const std::string& fmt,
const bool withP,
354 const bool withFlag,
const double scaleX,
356 const double scaleP) {
358 m_hasPotential =
false;
359 m_active.assign(m_nX[0], std::vector<std::vector<bool> >(
360 m_nX[1], std::vector<bool>(m_nX[2],
true)));
362 m_pMin = withP ? +1. : 0.;
363 m_pMax = withP ? -1. : 0.;
364 if (!LoadData(fname, fmt, withP, withFlag, scaleX, scaleE, scaleP,
369 if (withP) m_hasPotential =
true;
374 const std::string& fmt,
const bool withP,
375 const double scaleX,
const double scaleE,
376 const double scaleP) {
378 if (!LoadData(fname, fmt, withP,
false, scaleX, scaleE, scaleP, m_wfields)) {
386 const std::string& fmt,
const double t,
387 const bool withP,
const double scaleX,
389 const double scaleP) {
390 std::vector<std::vector<std::vector<Node> > > wfield;
392 if (!LoadData(fname, fmt, withP,
false, scaleX, scaleE, scaleP, wfield)) {
395 if (m_wdtimes.empty() || t > m_wdtimes.back()) {
396 m_wdtimes.push_back(t);
397 m_wdfields.push_back(std::move(wfield));
399 const auto it = std::upper_bound(m_wdtimes.begin(), m_wdtimes.end(), t);
400 const auto n = std::distance(m_wdtimes.begin(), it);
401 m_wdtimes.insert(it, t);
402 m_wdfields.insert( m_wdfields.begin() + n, std::move(wfield));
408 const std::string& fmt,
410 const double scaleB) {
412 if (!LoadData(fname, fmt,
false,
false, scaleX, scaleB, 1., m_bfields)) {
420 const std::string& filename,
421 const std::string& format) {
423 std::cerr <<
m_className <<
"::SaveElectricField: Null pointer.\n";
427 std::cerr <<
m_className <<
"::SaveElectricField: Mesh not set.\n";
430 const auto fmt = GetFormat(format);
431 if (fmt == Format::Unknown) {
432 std::cerr <<
m_className <<
"::SaveElectricField:\n"
433 <<
" Unknown format (" << format <<
").\n";
436 std::ofstream outfile;
437 outfile.open(filename, std::ios::out);
439 std::cerr <<
m_className <<
"::SaveElectricField:\n"
440 <<
" Could not open file " << filename <<
".\n";
443 std::cout <<
m_className <<
"::SaveElectricField:\n"
444 <<
" Exporting field/potential to " << filename <<
".\n"
445 <<
" Be patient...\n";
447 outfile <<
"# XMIN = " << m_xMin[0] <<
", XMAX = " << m_xMax[0]
448 <<
", NX = " << m_nX[0] <<
"\n";
449 outfile <<
"# YMIN = " << m_xMin[1] <<
", YMAX = " << m_xMax[1]
450 <<
", NY = " << m_nX[1] <<
"\n";
451 outfile <<
"# ZMIN = " << m_xMin[2] <<
", ZMAX = " << m_xMax[2]
452 <<
", NZ = " << m_nX[2] <<
"\n";
454 const unsigned int nValues = m_nX[0] * m_nX[1] * m_nX[2];
455 const unsigned int nPrint =
456 std::pow(10,
static_cast<unsigned int>(
457 std::max(std::floor(std::log10(nValues)) - 1, 1.)));
458 unsigned int nLines = 0;
461 const double dx = (m_xMax[0] - m_xMin[0]) / std::max(m_nX[0] - 1., 1.);
462 const double dy = (m_xMax[1] - m_xMin[1]) / std::max(m_nX[1] - 1., 1.);
463 const double dz = (m_xMax[2] - m_xMin[2]) / std::max(m_nX[2] - 1., 1.);
464 for (
unsigned int i = 0; i < m_nX[0]; ++i) {
465 const double x = m_xMin[0] + i * dx;
466 for (
unsigned int j = 0; j < m_nX[1]; ++j) {
467 const double y = m_xMin[1] + j * dy;
468 for (
unsigned int k = 0; k < m_nX[2]; ++k) {
469 const double z = m_xMin[2] + k * dz;
470 if (fmt == Format::XY) {
471 outfile << x <<
" " << y <<
" ";
472 }
else if (fmt == Format::XZ) {
473 outfile << x <<
" " << z <<
" ";
474 }
else if (fmt == Format::XYZ) {
475 outfile << x <<
" " << y <<
" " << z <<
" ";
476 }
else if (fmt == Format::IJ) {
477 outfile << i <<
" " << j <<
" ";
478 }
else if (fmt == Format::IK) {
479 outfile << i <<
" " << k <<
" ";
480 }
else if (fmt == Format::IJK) {
481 outfile << i <<
" " << j <<
" " << k <<
" ";
482 }
else if (fmt == Format::YXZ) {
483 outfile << y <<
" " << x <<
" " << z <<
" ";
485 if (m_coordinates == Coordinates::Cylindrical) {
486 const double ct = cos(y);
487 const double st = sin(y);
488 double ex = 0., ey = 0., ez = 0., v = 0.;
489 cmp->
ElectricField(x * ct, x * st, z, ex, ey, ez, v, medium, status);
490 const double er = +ex * ct + ey * st;
491 const double et = -ex * st + ey * ct;
492 outfile << er <<
" " << et <<
" " << ez <<
" " << v <<
"\n";
494 double ex = 0., ey = 0., ez = 0., v = 0.;
496 outfile << ex <<
" " << ey <<
" " << ez <<
" " << v <<
"\n";
499 if (nLines % nPrint == 0) PrintProgress(
double(nLines) / nValues);
504 std::cout << std::endl <<
m_className <<
"::SaveElectricField: Done.\n";
509 const std::string&
id,
510 const std::string& filename,
511 const std::string& format) {
513 std::cerr <<
m_className <<
"::SaveWeightingField: Null pointer.\n";
517 std::cerr <<
m_className <<
"::SaveWeightingField: Mesh not set.\n";
520 const auto fmt = GetFormat(format);
521 if (fmt == Format::Unknown) {
522 std::cerr <<
m_className <<
"::SaveWeightingField:\n"
523 <<
" Unknown format (" << format <<
").\n";
526 std::ofstream outfile;
527 outfile.open(filename, std::ios::out);
529 std::cerr <<
m_className <<
"::SaveWeightingField:\n"
530 <<
" Could not open file " << filename <<
".\n";
533 std::cout <<
m_className <<
"::SaveWeightingField:\n"
534 <<
" Exporting field/potential to " << filename <<
".\n"
535 <<
" Be patient...\n";
537 outfile <<
"# XMIN = " << m_xMin[0] <<
", XMAX = " << m_xMax[0]
538 <<
", NX = " << m_nX[0] <<
"\n";
539 outfile <<
"# YMIN = " << m_xMin[1] <<
", YMAX = " << m_xMax[1]
540 <<
", NY = " << m_nX[1] <<
"\n";
541 outfile <<
"# ZMIN = " << m_xMin[2] <<
", ZMAX = " << m_xMax[2]
542 <<
", NZ = " << m_nX[2] <<
"\n";
543 const unsigned int nValues = m_nX[0] * m_nX[1] * m_nX[2];
544 const unsigned int nPrint =
545 std::pow(10,
static_cast<unsigned int>(
546 std::max(std::floor(std::log10(nValues)) - 1, 1.)));
547 unsigned int nLines = 0;
548 const double dx = (m_xMax[0] - m_xMin[0]) / std::max(m_nX[0] - 1., 1.);
549 const double dy = (m_xMax[1] - m_xMin[1]) / std::max(m_nX[1] - 1., 1.);
550 const double dz = (m_xMax[2] - m_xMin[2]) / std::max(m_nX[2] - 1., 1.);
551 for (
unsigned int i = 0; i < m_nX[0]; ++i) {
552 const double x = m_xMin[0] + i * dx;
553 for (
unsigned int j = 0; j < m_nX[1]; ++j) {
554 const double y = m_xMin[1] + j * dy;
555 for (
unsigned int k = 0; k < m_nX[2]; ++k) {
556 const double z = m_xMin[2] + k * dz;
557 if (fmt == Format::XY) {
558 outfile << x <<
" " << y <<
" ";
559 }
else if (fmt == Format::XZ) {
560 outfile << x <<
" " << z <<
" ";
561 }
else if (fmt == Format::XYZ) {
562 outfile << x <<
" " << y <<
" " << z <<
" ";
563 }
else if (fmt == Format::IJ) {
564 outfile << i <<
" " << j <<
" ";
565 }
else if (fmt == Format::IK) {
566 outfile << i <<
" " << k <<
" ";
567 }
else if (fmt == Format::IJK) {
568 outfile << i <<
" " << j <<
" " << k <<
" ";
569 }
else if (fmt == Format::YXZ) {
570 outfile << y <<
" " << x <<
" " << z <<
" ";
572 if (m_coordinates == Coordinates::Cylindrical) {
573 const double ct = cos(y);
574 const double st = sin(y);
575 double wx = 0., wy = 0., wz = 0.;
578 const double wr = +wx * ct + wy * st;
579 const double wt = -wx * st + wy * ct;
580 outfile << wr <<
" " << wt <<
" " << wz <<
" " << v <<
"\n";
582 double wx = 0., wy = 0., wz = 0.;
585 outfile << wx <<
" " << wy <<
" " << wz <<
" " << v <<
"\n";
588 if (nLines % nPrint == 0) PrintProgress(
double(nLines) / nValues);
593 std::cout << std::endl <<
m_className <<
"::SaveWeightingField: Done.\n";
597bool ComponentGrid::LoadMesh(
const std::string& filename, std::string format,
598 const double scaleX) {
599 const auto fmt = GetFormat(format);
600 if (fmt == Format::Unknown) {
602 <<
" Unknown format (" << format <<
").\n";
607 std::bitset<9> found;
609 double xmin = 0., ymin = 0., zmin = 0.;
610 double xmax = 0., ymax = 0., zmax = 0.;
611 unsigned int nx = 0, ny = 0, nz = 0;
612 bool cylindrical = (m_coordinates == Coordinates::Cylindrical);
614 std::ifstream infile(filename);
617 <<
" Could not open file " << filename <<
".\n";
621 unsigned int nLines = 0;
623 while (std::getline(infile, line)) {
628 if (line.empty())
continue;
630 if (!IsComment(line))
continue;
631 std::size_t pos0 = 0;
632 std::size_t pos1 = line.find(
"=", pos0);
633 while (pos1 != std::string::npos) {
634 std::string key = line.substr(pos0, pos1 - pos0);
635 std::transform(key.begin(), key.end(), key.begin(), toupper);
636 const std::size_t pos2 = line.find_first_of(
",;", pos1 + 1);
637 std::istringstream val(line.substr(pos1 + 1, pos2 - pos1 - 1));
638 if (key.find(
"XMIN") != std::string::npos) {
641 }
else if (key.find(
"YMIN") != std::string::npos) {
644 }
else if (key.find(
"ZMIN") != std::string::npos) {
647 }
else if (key.find(
"XMAX") != std::string::npos) {
650 }
else if (key.find(
"YMAX") != std::string::npos) {
653 }
else if (key.find(
"ZMAX") != std::string::npos) {
656 }
else if (key.find(
"NX") != std::string::npos) {
659 }
else if (key.find(
"NY") != std::string::npos) {
662 }
else if (key.find(
"NZ") != std::string::npos) {
665 }
else if (key.find(
"CYLINDRICAL") != std::string::npos) {
668 if (pos2 == std::string::npos)
break;
670 pos1 = line.find(
"=", pos0);
675 if (fmt == Format::XY || fmt == Format::IJ) {
682 if (found[0] || found[1] || found[3] || found[4] || found[5]) {
695 }
else if (fmt == Format::XZ || fmt == Format::IK) {
702 if (!found[1]) ymin = -Pi;
703 if (!found[4]) ymax = +Pi;
708 if (found[0] || found[2] || found[3] || found[4] || found[5]) {
724 if (cylindrical && xmin < 0.) {
726 <<
" Radial coordinate must be >= 0.\n";
730 std::printf(
"%12.6f < x [cm] < %12.6f, %5u points\n", xmin, xmax, nx);
731 std::printf(
"%12.6f < y [cm] < %12.6f, %5u points\n", ymin, ymax, ny);
732 std::printf(
"%12.6f < z [cm] < %12.6f, %5u points\n", zmin, zmax, nz);
734 m_coordinates = Coordinates::Cylindrical;
736 m_coordinates = Coordinates::Cartesian;
738 return SetMesh(nx, ny, nz, xmin, xmax, ymin, ymax, zmin, zmax);
740 if ((fmt == Format::IJ || fmt == Format::IJK || fmt == Format::IK) &&
741 !(found[0] && found[3])) {
742 std::cerr <<
m_className <<
"::LoadMesh: x-limits not found.\n";
744 }
else if ((fmt == Format::IJ || fmt == Format::IJK) &&
745 !(found[1] && found[4])) {
746 std::cerr <<
m_className <<
"::LoadMesh: y-limits not found.\n";
748 }
else if ((fmt == Format::IK || fmt == Format::IJK) &&
749 !(found[2] && found[5])) {
750 std::cerr <<
m_className <<
"::LoadMesh: z-limits not found.\n";
754 unsigned int nValues = 0;
755 infile.open(filename, std::ios::in);
758 <<
" Could not open file " << filename <<
".\n";
762 if (!found[0]) xmin = std::numeric_limits<double>::max();
763 if (!found[1]) ymin = std::numeric_limits<double>::max();
764 if (!found[2]) zmin = std::numeric_limits<double>::max();
765 if (!found[3]) xmax = std::numeric_limits<double>::min();
766 if (!found[4]) ymax = std::numeric_limits<double>::min();
767 if (!found[5]) zmax = std::numeric_limits<double>::min();
768 constexpr double tol = 1.e-10;
769 auto cmp = [](
double x,
double y) {
770 return x <
y - tol * (std::fabs(x) + std::fabs(y));
772 std::set<double,
decltype(cmp)> xLines(cmp);
773 std::set<double,
decltype(cmp)> yLines(cmp);
774 std::set<double,
decltype(cmp)> zLines(cmp);
778 while (std::getline(infile, line)) {
783 if (line.empty())
continue;
785 if (IsComment(line))
continue;
786 std::istringstream data(line);
787 if (fmt == Format::XY) {
791 PrintError(
m_className +
"::LoadMesh", nLines,
"coordinates");
797 if (!found[0]) xmin = std::min(x, xmin);
798 if (!found[1]) ymin = std::min(y, ymin);
799 if (!found[3]) xmax = std::max(x, xmax);
800 if (!found[4]) ymax = std::max(y, ymax);
803 }
else if (fmt == Format::XZ) {
807 PrintError(
m_className +
"::LoadMesh", nLines,
"coordinates");
813 if (!found[0]) xmin = std::min(x, xmin);
814 if (!found[2]) zmin = std::min(z, zmin);
815 if (!found[3]) xmax = std::max(x, xmax);
816 if (!found[5]) zmax = std::max(z, zmax);
819 }
else if (fmt == Format::XYZ) {
823 PrintError(
m_className +
"::LoadMesh", nLines,
"coordinates");
830 if (!found[0]) xmin = std::min(x, xmin);
831 if (!found[1]) ymin = std::min(y, ymin);
832 if (!found[2]) zmin = std::min(z, zmin);
833 if (!found[3]) xmax = std::max(x, xmax);
834 if (!found[4]) ymax = std::max(y, ymax);
835 if (!found[5]) zmax = std::max(z, zmax);
839 }
else if (fmt == Format::IJ) {
840 unsigned int i = 0, j = 0;
843 PrintError(
m_className +
"::LoadMesh", nLines,
"indices");
847 if (!found[6]) nx = std::max(nx, i);
848 if (!found[7]) ny = std::max(ny, j);
849 }
else if (fmt == Format::IK) {
850 unsigned int i = 0, k = 0;
853 PrintError(
m_className +
"::LoadMesh", nLines,
"indices");
857 if (!found[6]) nx = std::max(nx, i);
858 if (!found[8]) nz = std::max(nz, k);
859 }
else if (fmt == Format::IJK) {
860 unsigned int i = 0, j = 0, k = 0;
863 PrintError(
m_className +
"::LoadMesh", nLines,
"indices");
867 if (!found[6]) nx = std::max(nx, i);
868 if (!found[7]) ny = std::max(ny, j);
869 if (!found[8]) nz = std::max(nz, k);
870 }
else if (fmt == Format::YXZ) {
874 PrintError(
m_className +
"::LoadMesh", nLines,
"coordinates");
881 if (!found[0]) xmin = std::min(x, xmin);
882 if (!found[1]) ymin = std::min(y, ymin);
883 if (!found[2]) zmin = std::min(z, zmin);
884 if (!found[3]) xmax = std::max(x, xmax);
885 if (!found[4]) ymax = std::max(y, ymax);
886 if (!found[5]) zmax = std::max(z, zmax);
894 if (bad)
return false;
896 if (fmt == Format::XY || fmt == Format::XYZ ||
897 fmt == Format::XZ || fmt == Format::YXZ) {
898 if (!found[6]) nx = xLines.size();
899 if (!found[7]) ny = yLines.size();
900 if (!found[8]) nz = zLines.size();
903 if (cylindrical && xmin < 0.) {
905 <<
" Radial coordinate must be >= 0.\n";
910 std::printf(
"%12.6f < r [cm] < %12.6f, %5u points\n", xmin, xmax, nx);
911 std::printf(
"%12.6f < theta < %12.6f, %5u points\n", ymin, ymax, ny);
913 std::printf(
"%12.6f < x [cm] < %12.6f, %5u points\n", xmin, xmax, nx);
914 std::printf(
"%12.6f < y [cm] < %12.6f, %5u points\n", ymin, ymax, ny);
916 std::printf(
"%12.6f < z [cm] < %12.6f, %5u points\n", zmin, zmax, nz);
917 unsigned int nExpected = nx;
918 if (fmt == Format::XZ || fmt == Format::IK) {
923 if (fmt == Format::XYZ || fmt == Format::IJK || fmt == Format::YXZ) {
926 if (nExpected != nValues) {
928 <<
" Warning: Expected " << nExpected <<
" lines, read "
932 m_coordinates = Coordinates::Cylindrical;
934 m_coordinates = Coordinates::Cartesian;
936 return SetMesh(nx, ny, nz, xmin, xmax, ymin, ymax, zmin, zmax);
939bool ComponentGrid::LoadData(
940 const std::string& filename, std::string format,
const bool withPotential,
941 const bool withFlag,
const double scaleX,
const double scaleF,
943 std::vector<std::vector<std::vector<Node> > >& fields) {
945 if (!LoadMesh(filename, format, scaleX)) {
946 std::cerr <<
m_className <<
"::LoadData: Mesh not set.\n";
951 const auto fmt = GetFormat(format);
952 if (fmt == Format::Unknown) {
954 <<
" Unknown format (" << format <<
").\n";
961 unsigned int nValues = 0;
963 std::vector<std::vector<std::vector<bool> > > isSet(
965 std::vector<std::vector<bool> >(m_nX[1], std::vector<bool>(m_nX[2],
false)));
967 std::ifstream infile(filename);
970 <<
" Could not open file " << filename <<
".\n";
975 unsigned int nLines = 0;
978 while (std::getline(infile, line)) {
983 if (line.empty())
continue;
985 if (IsComment(line))
continue;
993 std::istringstream data(line);
994 if (fmt == Format::XY) {
998 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
1005 const double u = std::round((x - m_xMin[0]) * m_sX[0]);
1006 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
1007 if (i >= m_nX[0]) i = m_nX[0] - 1;
1010 const double v = std::round((y - m_xMin[1]) * m_sX[1]);
1011 j = v < 0. ? 0 :
static_cast<unsigned int>(v);
1012 if (j >= m_nX[1]) j = m_nX[1] - 1;
1014 }
else if (fmt == Format::XZ) {
1018 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
1025 const double u = std::round((x - m_xMin[0]) * m_sX[0]);
1026 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
1027 if (i >= m_nX[0]) i = m_nX[0] - 1;
1030 const double v = std::round((z - m_xMin[2]) * m_sX[2]);
1031 k = v < 0. ? 0 :
static_cast<unsigned int>(v);
1032 if (j >= m_nX[1]) j = m_nX[1] - 1;
1034 }
else if (fmt == Format::XYZ) {
1036 data >>
x >>
y >>
z;
1038 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
1046 const double u = std::round((x - m_xMin[0]) * m_sX[0]);
1047 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
1048 if (i >= m_nX[0]) i = m_nX[0] - 1;
1051 const double v = std::round((y - m_xMin[1]) * m_sX[1]);
1052 j = v < 0. ? 0 :
static_cast<unsigned int>(v);
1053 if (j >= m_nX[1]) j = m_nX[1] - 1;
1056 const double w = std::round((z - m_xMin[2]) * m_sX[2]);
1057 k = w < 0. ? 0 :
static_cast<unsigned int>(w);
1058 if (k >= m_nX[2]) k = m_nX[2] - 1;
1060 }
else if (fmt == Format::IJ) {
1063 PrintError(
m_className +
"::LoadData", nLines,
"indices");
1067 }
else if (fmt == Format::IJK) {
1068 data >> i >> j >> k;
1070 PrintError(
m_className +
"::LoadData", nLines,
"indices");
1074 }
else if (fmt == Format::YXZ) {
1076 data >>
y >>
x >>
z;
1078 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
1086 const double u = std::round((x - m_xMin[0]) * m_sX[0]);
1087 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
1088 if (i >= m_nX[0]) i = m_nX[0] - 1;
1091 const double v = std::round((y - m_xMin[1]) * m_sX[1]);
1092 j = v < 0. ? 0 :
static_cast<unsigned int>(v);
1093 if (j >= m_nX[1]) j = m_nX[1] - 1;
1096 const double w = std::round((z - m_xMin[2]) * m_sX[2]);
1097 k = w < 0. ? 0 :
static_cast<unsigned int>(w);
1098 if (k >= m_nX[2]) k = m_nX[2] - 1;
1102 if (i >= m_nX[0] || j >= m_nX[1] || k >= m_nX[2]) {
1104 <<
" Error reading line " << nLines <<
".\n"
1105 <<
" Index (" << i <<
", " << j <<
", " << k
1106 <<
") out of range.\n";
1109 if (isSet[i][j][k]) {
1111 <<
" Error reading line " << nLines <<
".\n"
1112 <<
" Node (" << i <<
", " << j <<
", " << k
1113 <<
") has already been set.\n";
1117 if (fmt == Format::XY || fmt == Format::IJ) {
1121 }
else if (fmt == Format::XZ || fmt == Format::IK) {
1125 }
else if (fmt == Format::YXZ) {
1126 data >> fy >> fx >> fz;
1128 data >> fx >> fy >> fz;
1131 PrintError(
m_className +
"::LoadData", nLines,
"field components");
1138 if (withPotential) {
1141 PrintError(
m_className +
"::LoadData", nLines,
"potential");
1146 if (m_pMin > m_pMax) {
1151 if (p < m_pMin) m_pMin = p;
1152 if (p > m_pMax) m_pMax = p;
1159 PrintError(
m_className +
"::LoadData", nLines,
"region");
1164 const bool isActive = flag == 0 ? false :
true;
1165 if (fmt == Format::XY || fmt == Format::IJ) {
1167 for (
unsigned int kk = 0; kk < m_nX[2]; ++kk) {
1168 fields[i][j][kk].fx = fx;
1169 fields[i][j][kk].fy = fy;
1170 fields[i][j][kk].fz = fz;
1171 fields[i][j][kk].v = p;
1172 if (withFlag) m_active[i][j][kk] = isActive;
1173 isSet[i][j][kk] =
true;
1175 }
else if (fmt == Format::XZ || fmt == Format::IK) {
1177 for (
unsigned int jj = 0; jj < m_nX[1]; ++jj) {
1178 fields[i][jj][k].fx = fx;
1179 fields[i][jj][k].fy = fy;
1180 fields[i][jj][k].fz = fz;
1181 fields[i][jj][k].v = p;
1182 if (withFlag) m_active[i][jj][k] = isActive;
1183 isSet[i][jj][k] =
true;
1186 fields[i][j][k].fx = fx;
1187 fields[i][j][k].fy = fy;
1188 fields[i][j][k].fz = fz;
1189 fields[i][j][k].v = p;
1190 isSet[i][j][k] =
true;
1195 if (bad)
return false;
1197 <<
" Read " << nValues <<
" values from " << filename <<
".\n";
1198 unsigned int nExpected = m_nX[0];
1199 if (fmt == Format::XY || fmt == Format::IJ) {
1200 nExpected *= m_nX[1];
1201 }
else if (fmt == Format::XZ || fmt == Format::IK) {
1202 nExpected *= m_nX[2];
1204 nExpected *= m_nX[1] * m_nX[2];
1206 if (nExpected != nValues) {
1208 <<
" Expected " << nExpected <<
" values.\n";
1214 double& xmax,
double& ymax,
double& zmax) {
1215 if (m_efields.empty() && m_wfields.empty() && m_bfields.empty()) {
1218 if (m_coordinates == Coordinates::Cylindrical) {
1219 const double rmax = m_xMax[0];
1255 double& xmin,
double& ymin,
double& zmin,
1256 double& xmax,
double& ymax,
double& zmax) {
1258 if (m_efields.empty() && m_wfields.empty() && m_bfields.empty()) {
1261 if (m_coordinates == Coordinates::Cylindrical) {
1262 const double rmax = m_xMax[0];
1279 if (m_efields.empty())
return false;
1286 double& eymin,
double& eymax,
1287 double& ezmin,
double& ezmax) {
1288 if (m_efields.empty()) {
1289 PrintNotReady(
m_className +
"::GetElectricFieldRange");
1293 exmin = exmax = m_efields[0][0][0].fx;
1294 eymin = eymax = m_efields[0][0][0].fy;
1295 ezmin = ezmax = m_efields[0][0][0].fz;
1296 for (
unsigned int i = 0; i < m_nX[0]; ++i) {
1297 for (
unsigned int j = 0; j < m_nX[1]; ++j) {
1298 for (
unsigned int k = 0; k < m_nX[2]; ++k) {
1299 const Node& node = m_efields[i][j][k];
1300 if (node.fx < exmin) exmin = node.fx;
1301 if (node.fx > exmax) exmax = node.fx;
1302 if (node.fy < eymin) eymin = node.fy;
1303 if (node.fy > eymax) eymax = node.fy;
1304 if (node.fz < ezmin) ezmin = node.fz;
1305 if (node.fz > ezmax) ezmax = node.fz;
1314 std::cerr <<
m_className <<
"::SetMedium: Null pointer.\n";
1319bool ComponentGrid::GetField(
1320 const double xi,
const double yi,
const double zi,
1321 const std::vector<std::vector<std::vector<Node> > >& field,
double& fx,
1322 double& fy,
double& fz,
double& p,
bool& active) {
1324 std::cerr <<
m_className <<
"::GetField: Mesh is not set.\n";
1330 std::array<bool, 3> mirrored = {
false,
false,
false};
1331 std::array<double, 3> xx = {xi, yi, zi};
1333 if (m_coordinates == Coordinates::Cylindrical) {
1334 if (
fabs(xi) > Small ||
fabs(yi) > Small) {
1335 theta = atan2(yi, xi);
1336 xx[0] =
sqrt(xi * xi + yi * yi);
1340 for (
size_t i = 0; i < 3; ++i) {
1341 xx[i] = Reduce(xx[i], m_xMin[i], m_xMax[i],
1343 if (xx[i] < m_xMin[i] || xx[i] > m_xMax[i])
return false;
1346 const double sx = (xx[0] - m_xMin[0]) * m_sX[0];
1347 const double sy = (xx[1] - m_xMin[1]) * m_sX[1];
1348 const double sz = (xx[2] - m_xMin[2]) * m_sX[2];
1350 const unsigned int i0 =
static_cast<unsigned int>(std::floor(sx));
1351 const unsigned int j0 =
static_cast<unsigned int>(std::floor(sy));
1352 const unsigned int k0 =
static_cast<unsigned int>(std::floor(sz));
1353 const double ux = sx - i0;
1354 const double uy = sy - j0;
1355 const double uz = sz - k0;
1356 const unsigned int i1 = std::min(i0 + 1, m_nX[0] - 1);
1357 const unsigned int j1 = std::min(j0 + 1, m_nX[1] - 1);
1358 const unsigned int k1 = std::min(k0 + 1, m_nX[2] - 1);
1359 const double vx = 1. - ux;
1360 const double vy = 1. - uy;
1361 const double vz = 1. - uz;
1362 if (!m_active.empty()) {
1363 active = m_active[i0][j0][k0] && m_active[i0][j0][k1] &&
1364 m_active[i0][j1][k0] && m_active[i0][j1][k1] &&
1365 m_active[i1][j0][k0] && m_active[i1][j0][k1] &&
1366 m_active[i1][j1][k0] && m_active[i1][j1][k1];
1368 const Node& n000 = field[i0][j0][k0];
1369 const Node& n100 = field[i1][j0][k0];
1370 const Node& n010 = field[i0][j1][k0];
1371 const Node& n110 = field[i1][j1][k0];
1372 const Node& n001 = field[i0][j0][k1];
1373 const Node& n101 = field[i1][j0][k1];
1374 const Node& n011 = field[i0][j1][k1];
1375 const Node& n111 = field[i1][j1][k1];
1378 std::cout <<
m_className <<
"::GetField: Determining field at (" << xi
1379 <<
", " << yi <<
", " << zi <<
").\n"
1380 <<
" X: " << i0 <<
" (" << ux <<
") - " << i1 <<
" (" << vx
1382 <<
" Y: " << j0 <<
" (" << uy <<
") - " << j1 <<
" (" << vy
1384 <<
" Z: " << k0 <<
" (" << uz <<
") - " << k1 <<
" (" << vz
1387 fx = ((n000.fx * vx + n100.fx * ux) * vy +
1388 (n010.fx * vx + n110.fx * ux) * uy) *
1390 ((n001.fx * vx + n101.fx * ux) * vy +
1391 (n011.fx * vx + n111.fx * ux) * uy) *
1393 fy = ((n000.fy * vx + n100.fy * ux) * vy +
1394 (n010.fy * vx + n110.fy * ux) * uy) *
1396 ((n001.fy * vx + n101.fy * ux) * vy +
1397 (n011.fy * vx + n111.fy * ux) * uy) *
1399 fz = ((n000.fz * vx + n100.fz * ux) * vy +
1400 (n010.fz * vx + n110.fz * ux) * uy) *
1402 ((n001.fz * vx + n101.fz * ux) * vy +
1403 (n011.fz * vx + n111.fz * ux) * uy) *
1405 p = ((n000.v * vx + n100.v * ux) * vy + (n010.v * vx + n110.v * ux) * uy) *
1407 ((n001.v * vx + n101.v * ux) * vy + (n011.v * vx + n111.v * ux) * uy) *
1409 if (mirrored[0]) fx = -fx;
1410 if (mirrored[1]) fy = -fy;
1411 if (mirrored[2]) fz = -fz;
1412 if (m_coordinates == Coordinates::Cylindrical) {
1413 const double ct =
cos(theta);
1414 const double st =
sin(theta);
1415 const double fr = fx;
1416 const double ft = fy;
1417 fx = ct * fr -
st * ft;
1418 fy =
st * fr + ct * ft;
1424 const unsigned int k,
double& v,
1425 double& ex,
double& ey,
double& ez)
const {
1426 v = ex = ey = ez = 0.;
1427 if (m_efields.empty()) {
1429 std::cerr <<
m_className <<
"::GetElectricField: Mesh not set.\n";
1432 PrintNotReady(
m_className +
"::GetElectricField");
1435 if (i >= m_nX[0] || j >= m_nX[1] || k >= m_nX[2]) {
1436 std::cerr <<
m_className <<
"::GetElectricField: Index out of range.\n";
1439 const Node& node = m_efields[i][j][k];
1451 std::cout <<
" Mesh not set.\n";
1454 std::printf(
" %15.8f < x [cm] < %15.8f, %10u nodes\n",
1455 m_xMin[0], m_xMax[0], m_nX[0]);
1456 std::printf(
" %15.8f < y [cm] < %15.8f, %10u nodes\n",
1457 m_xMin[1], m_xMax[1], m_nX[1]);
1458 std::printf(
" %15.8f < z [cm] < %15.8f, %10u nodes\n",
1459 m_xMin[2], m_xMax[2], m_nX[2]);
1460 if (m_efields.empty() && m_bfields.empty() &&
1461 m_wfields.empty() && m_wdfields.empty() &&
1462 m_eAttachment.empty() && m_hAttachment.empty() &&
1463 m_eVelocity.empty() && m_hVelocity.empty()) {
1464 std::cout <<
" Available data: None.\n";
1467 std::cout <<
" Available data:\n";
1468 if (!m_efields.empty()) std::cout <<
" Electric field.\n";
1469 if (!m_bfields.empty()) std::cout <<
" Magnetic field.\n";
1470 if (!m_wfields.empty()) std::cout <<
" Weighting field.\n";
1471 if (!m_wdfields.empty()) {
1472 std::cout <<
" Delayed weighting field.\n";
1474 if (!m_eVelocity.empty()) {
1475 std::cout <<
" Electron drift velocity.\n";
1477 if (!m_hVelocity.empty()) {
1478 std::cout <<
" Hole drift velocity.\n";
1480 if (!m_eAttachment.empty()) {
1481 std::cout <<
" Electron attachment coefficient.\n";
1483 if (!m_hAttachment.empty()) {
1484 std::cout <<
" Hole attachment coefficient.\n";
1488void ComponentGrid::Reset() {
1492 m_eAttachment.clear();
1493 m_hAttachment.clear();
1494 m_eVelocity.clear();
1495 m_hVelocity.clear();
1505 m_sX[0] = m_sX[1] = m_sX[2] = 0.;
1506 m_pMin = m_pMax = 0.;
1510 m_hasPotential =
false;
1512 m_wFieldOffset.fill(0.);
1515void ComponentGrid::UpdatePeriodicity() {
1518 for (
size_t i = 0; i < 3; ++i) {
1520 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1521 <<
" Both simple and mirror periodicity requested. Reset.\n";
1527 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1528 <<
" Axial symmetry is not supported. Reset.\n";
1534 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1535 <<
" Rotation symmetry is not supported. Reset.\n";
1540double ComponentGrid::Reduce(
const double xin,
const double xmin,
1541 const double xmax,
const bool simplePeriodic,
1542 const bool mirrorPeriodic,
bool& mirrored)
const {
1545 const double lx = xmax - xmin;
1546 if (simplePeriodic) {
1547 x = xmin + fmod(x - xmin, lx);
1548 if (x < xmin)
x += lx;
1549 }
else if (mirrorPeriodic) {
1550 double xNew = xmin + fmod(x - xmin, lx);
1551 if (xNew < xmin) xNew += lx;
1552 const int nx = int(floor(0.5 + (xNew - x) / lx));
1553 if (nx != 2 * (nx / 2)) {
1554 xNew = xmin + xmax - xNew;
1562void ComponentGrid::Initialise(
1563 std::vector<std::vector<std::vector<Node> > >& fields) {
1564 fields.resize(m_nX[0]);
1565 for (
unsigned int i = 0; i < m_nX[0]; ++i) {
1566 fields[i].resize(m_nX[1]);
1567 for (
unsigned int j = 0; j < m_nX[1]; ++j) {
1568 fields[i][j].resize(m_nX[2]);
1569 for (
unsigned int k = 0; k < m_nX[2]; ++k) {
1570 fields[i][j][k].fx = 0.;
1571 fields[i][j][k].fy = 0.;
1572 fields[i][j][k].fz = 0.;
1573 fields[i][j][k].v = 0.;
1580 const std::string& fmt,
1581 const double scaleX,
1582 const double scaleV) {
1584 if (!LoadData(fname, fmt,
false,
false, scaleX, scaleV, 1., m_eVelocity)) {
1591 const std::string& fmt,
1592 const double scaleX,
1593 const double scaleV) {
1595 if (!LoadData(fname, fmt,
false,
false, scaleX, scaleV, 1., m_hVelocity)) {
1603 double& vx,
double& vy,
double& vz) {
1604 if (m_eVelocity.empty()) {
1605 PrintNotReady(
m_className +
"::ElectronVelocity");
1610 return GetField(x, y, z, m_eVelocity, vx, vy, vz, p, active);
1615 double& vx,
double& vy,
double& vz) {
1616 if (m_hVelocity.empty()) {
1622 return GetField(x, y, z, m_hVelocity, vx, vy, vz, p, active);
1626 const std::string& fmt,
1627 const unsigned int col,
1628 const double scaleX) {
1630 return LoadData(fname, fmt, scaleX, m_eAttachment, col);
1634 const std::string& fmt,
1635 const unsigned int col,
1636 const double scaleX) {
1638 return LoadData(fname, fmt, scaleX, m_hAttachment, col);
1641bool ComponentGrid::LoadData(
1642 const std::string& filename, std::string format,
const double scaleX,
1643 std::vector<std::vector<std::vector<double> > >& tab,
1644 const unsigned int col) {
1646 if (!LoadMesh(filename, format, scaleX)) {
1647 std::cerr <<
m_className <<
"::LoadData: Mesh not set.\n";
1652 const auto fmt = GetFormat(format);
1653 if (fmt == Format::Unknown) {
1655 <<
" Unknown format (" << format <<
").\n";
1659 unsigned int offset = 0;
1660 if (fmt == Format::XY || fmt == Format::IJ) {
1663 <<
" Unexpected column index (" << col <<
").\n";
1670 <<
" Unexpected column index (" << col <<
").\n";
1679 std::vector<std::vector<double> >(m_nX[1], std::vector<double>(m_nX[2], 0.)));
1681 unsigned int nValues = 0;
1683 std::vector<std::vector<std::vector<bool> > > isSet(
1685 std::vector<std::vector<bool> >(m_nX[1], std::vector<bool>(m_nX[2],
false)));
1687 std::ifstream infile(filename);
1690 <<
" Could not open file " << filename <<
".\n";
1695 unsigned int nLines = 0;
1698 while (std::getline(infile, line)) {
1703 if (line.empty())
continue;
1705 if (IsComment(line))
continue;
1710 std::istringstream data(line);
1711 if (fmt == Format::XY) {
1715 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
1722 const double u = std::round((x - m_xMin[0]) * m_sX[0]);
1723 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
1724 if (i >= m_nX[0]) i = m_nX[0] - 1;
1727 const double v = std::round((y - m_xMin[1]) * m_sX[1]);
1728 j = v < 0. ? 0 :
static_cast<unsigned int>(v);
1729 if (j >= m_nX[1]) j = m_nX[1] - 1;
1731 }
else if (fmt == Format::XYZ) {
1733 data >>
x >>
y >>
z;
1735 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
1743 const double u = std::round((x - m_xMin[0]) * m_sX[0]);
1744 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
1745 if (i >= m_nX[0]) i = m_nX[0] - 1;
1748 const double v = std::round((y - m_xMin[1]) * m_sX[1]);
1749 j = v < 0. ? 0 :
static_cast<unsigned int>(v);
1750 if (j >= m_nX[1]) j = m_nX[1] - 1;
1753 const double w = std::round((z - m_xMin[2]) * m_sX[2]);
1754 k = w < 0. ? 0 :
static_cast<unsigned int>(w);
1755 if (k >= m_nX[2]) k = m_nX[2] - 1;
1757 }
else if (fmt == Format::IJ) {
1760 PrintError(
m_className +
"::LoadData", nLines,
"indices");
1764 }
else if (fmt == Format::IJK) {
1765 data >> i >> j >> k;
1767 PrintError(
m_className +
"::LoadData", nLines,
"indices");
1771 }
else if (fmt == Format::YXZ) {
1773 data >>
y >>
x >>
z;
1775 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
1783 const double u = std::round((x - m_xMin[0]) * m_sX[0]);
1784 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
1785 if (i >= m_nX[0]) i = m_nX[0] - 1;
1788 const double v = std::round((y - m_xMin[1]) * m_sX[1]);
1789 j = v < 0. ? 0 :
static_cast<unsigned int>(v);
1790 if (j >= m_nX[1]) j = m_nX[1] - 1;
1793 const double w = std::round((z - m_xMin[2]) * m_sX[2]);
1794 k = w < 0. ? 0 :
static_cast<unsigned int>(w);
1795 if (k >= m_nX[2]) k = m_nX[2] - 1;
1799 if (i >= m_nX[0] || j >= m_nX[1] || k >= m_nX[2]) {
1801 <<
" Error reading line " << nLines <<
".\n"
1802 <<
" Index (" << i <<
", " << j <<
", " << k
1803 <<
") out of range.\n";
1806 if (isSet[i][j][k]) {
1808 <<
" Error reading line " << nLines <<
".\n"
1809 <<
" Node (" << i <<
", " << j <<
", " << k
1810 <<
") has already been set.\n";
1815 for (
unsigned int ii = 0; ii < col - offset; ++ii) {
1820 "column " + std::to_string(offset + ii));
1832 "column " + std::to_string(col));
1837 if (fmt == Format::XY || fmt == Format::IJ) {
1839 for (
unsigned int kk = 0; kk < m_nX[2]; ++kk) {
1840 tab[i][j][kk] = val;
1841 isSet[i][j][kk] =
true;
1845 isSet[i][j][k] =
true;
1850 if (bad)
return false;
1852 <<
" Read " << nValues <<
" values from " << filename <<
".\n";
1853 unsigned int nExpected = m_nX[0] * m_nX[1];
1854 if (fmt == Format::XYZ || fmt == Format::IJK || fmt == Format::YXZ) {
1855 nExpected *= m_nX[2];
1857 if (nExpected != nValues) {
1859 <<
" Expected " << nExpected <<
" values.\n";
1864bool ComponentGrid::GetData(
1865 const double xi,
const double yi,
const double zi,
1866 const std::vector<std::vector<std::vector<double> > >& tab,
double& val) {
1868 std::cerr <<
m_className <<
"::GetData: Mesh is not set.\n";
1874 bool xMirrored =
false;
1877 if (x < m_xMin[0] || x > m_xMax[0])
return false;
1878 bool yMirrored =
false;
1881 if (y < m_xMin[1] || y > m_xMax[1])
return false;
1882 bool zMirrored =
false;
1885 if (z < m_xMin[2] || z > m_xMax[2])
return false;
1888 const double sx = (
x - m_xMin[0]) * m_sX[0];
1889 const double sy = (
y - m_xMin[1]) * m_sX[1];
1890 const double sz = (
z - m_xMin[2]) * m_sX[2];
1891 const unsigned int i0 =
static_cast<unsigned int>(std::floor(sx));
1892 const unsigned int j0 =
static_cast<unsigned int>(std::floor(sy));
1893 const unsigned int k0 =
static_cast<unsigned int>(std::floor(sz));
1894 const double ux = sx - i0;
1895 const double uy = sy - j0;
1896 const double uz = sz - k0;
1897 const unsigned int i1 = std::min(i0 + 1, m_nX[0] - 1);
1898 const unsigned int j1 = std::min(j0 + 1, m_nX[1] - 1);
1899 const unsigned int k1 = std::min(k0 + 1, m_nX[2] - 1);
1900 const double vx = 1. - ux;
1901 const double vy = 1. - uy;
1902 const double vz = 1. - uz;
1903 const double n000 = tab[i0][j0][k0];
1904 const double n100 = tab[i1][j0][k0];
1905 const double n010 = tab[i0][j1][k0];
1906 const double n110 = tab[i1][j1][k0];
1907 const double n001 = tab[i0][j0][k1];
1908 const double n101 = tab[i1][j0][k1];
1909 const double n011 = tab[i0][j1][k1];
1910 const double n111 = tab[i1][j1][k1];
1913 std::cout <<
m_className <<
"::GetData: Interpolating at (" << xi
1914 <<
", " << yi <<
", " << zi <<
").\n"
1915 <<
" X: " << i0 <<
" (" << ux <<
") - " << i1 <<
" (" << vx
1917 <<
" Y: " << j0 <<
" (" << uy <<
") - " << j1 <<
" (" << vy
1919 <<
" Z: " << k0 <<
" (" << uz <<
") - " << k1 <<
" (" << vz
1922 val = ((n000 * vx + n100 * ux) * vy + (n010 * vx + n110 * ux) * uy) * vz +
1923 ((n001 * vx + n101 * ux) * vy + (n011 * vx + n111 * ux) * uy) * uz;
1929 const double z,
double& att) {
1931 if (m_eAttachment.empty()) {
1932 PrintNotReady(
m_className +
"::ElectronAttachment");
1935 return GetData(x, y, z, m_eAttachment, att);
1939 const double z,
double& att) {
1941 if (m_hAttachment.empty()) {
1945 return GetData(x, y, z, m_hAttachment, att);
1948ComponentGrid::Format ComponentGrid::GetFormat(std::string format) {
1949 std::transform(format.begin(), format.end(), format.begin(), toupper);
1950 if (format ==
"XY") {
1952 }
else if (format ==
"XZ") {
1954 }
else if (format ==
"XYZ") {
1956 }
else if (format ==
"IJ") {
1958 }
else if (format ==
"IK") {
1960 }
else if (format ==
"IJK") {
1962 }
else if (format ==
"YXZ") {
1965 return Format::Unknown;
bool ElectronVelocity(const double x, const double y, const double z, double &vx, double &vy, double &vz) override
Get the electron drift velocity.
bool LoadElectronVelocity(const std::string &fname, const std::string &fmt, const double scaleX=1., const double scaleV=1.e-9)
void SetCylindricalCoordinates()
Use cylindrical coordinates.
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)
double DelayedWeightingPotential(const double x, const double y, const double z, const double t, const std::string &label) override
bool HasMagneticField() const override
Does the component have a non-zero magnetic field?
bool GetElementaryCell(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the coordinates of the elementary cell.
bool SaveElectricField(Component *cmp, const std::string &filename, const std::string &fmt)
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
void Print()
Print information about the mesh and the available data.
bool GetVoltageRange(double &vmin, double &vmax) override
Calculate the voltage range [V].
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 HoleVelocity(const double x, const double y, const double z, double &vx, double &vy, double &vz) override
Get the hole drift velocity.
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 LoadHoleVelocity(const std::string &fname, const std::string &fmt, const double scaleX=1., const double scaleV=1.e-9)
Import a map of hole drift velocities from a file.
bool HoleAttachment(const double x, const double y, const double z, double &att) override
Get the hole attachment coefficient.
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
bool ElectronAttachment(const double x, const double y, const double z, double &att) override
Get the electron attachment coefficient.
void SetWeightingFieldOffset(const double x, const double y, const double z)
bool LoadHoleAttachment(const std::string &fname, const std::string &fmt, const unsigned int col, const double scaleX=1.)
Import hole attachment coefficients from a file.
void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label) override
bool LoadElectronAttachment(const std::string &fname, const std::string &fmt, const unsigned int col, const double scaleX=1.)
bool SaveWeightingField(Component *cmp, const std::string &id, const std::string &filename, const std::string &fmt)
virtual double WeightingPotential(const double x, const double y, const double z, const std::string &label)
std::array< bool, 3 > m_rotationSymmetric
Rotation symmetry around x-axis, y-axis, z-axis.
std::array< bool, 3 > m_mirrorPeriodic
Mirror 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
virtual void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label)
bool m_debug
Switch on/off debugging messages.
Component()=delete
Default constructor.
std::array< bool, 3 > m_periodic
Simple periodicity in x, y, z.
virtual bool HasMagneticField() const
Does the component have a non-zero magnetic field?
std::string m_className
Class name.
virtual void MagneticField(const double x, const double y, const double z, double &bx, double &by, double &bz, int &status)
std::array< bool, 3 > m_axiallyPeriodic
Axial periodicity in x, y, z.
Abstract base class for media.
void ltrim(std::string &line)
DoubleAc cos(const DoubleAc &f)
DoubleAc fabs(const DoubleAc &f)
DoubleAc sin(const DoubleAc &f)
DoubleAc sqrt(const DoubleAc &f)