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,
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;
160 m_wFieldOffset = {x, y, z};
164 const double z,
double& bx,
double& by,
165 double& bz,
int& status) {
167 if (m_bfields.empty()) {
173 if (!GetField(x, y, z, m_bfields, bx, by, bz, p, active)) {
186 std::array<double, 3> xx = {x, y, z};
187 for (
size_t i = 0; i < 3; ++i) {
189 if (xx[i] < m_xMin[i] || xx[i] > m_xMax[i]) {
193 if (m_active.empty())
return m_medium;
194 for (
size_t i = 0; i < 3; ++i) {
195 bool mirrored =
false;
196 xx[i] = Reduce(xx[i], m_xMin[i], m_xMax[i],
200 const double sx = (xx[0] - m_xMin[0]) * m_sX[0];
201 const double sy = (xx[1] - m_xMin[1]) * m_sX[1];
202 const double sz = (xx[2] - m_xMin[2]) * m_sX[2];
203 const unsigned int i0 =
static_cast<unsigned int>(std::floor(sx));
204 const unsigned int j0 =
static_cast<unsigned int>(std::floor(sy));
205 const unsigned int k0 =
static_cast<unsigned int>(std::floor(sz));
206 const unsigned int i1 = std::min(i0 + 1, m_nX[0] - 1);
207 const unsigned int j1 = std::min(j0 + 1, m_nX[1] - 1);
208 const unsigned int k1 = std::min(k0 + 1, m_nX[2] - 1);
209 if (m_active[i0][j0][k0] && m_active[i0][j0][k1] && m_active[i0][j1][k0] &&
210 m_active[i0][j1][k1] && m_active[i1][j0][k0] && m_active[i1][j0][k1] &&
211 m_active[i1][j1][k0] && m_active[i1][j1][k1]) {
218 const unsigned int nz,
const double xmin,
219 const double xmax,
const double ymin,
220 const double ymax,
const double zmin,
223 if (nx == 0 || ny == 0 || nz == 0) {
225 <<
" Number of mesh elements must be positive.\n";
229 std::cerr <<
m_className <<
"::SetMesh: Invalid x range.\n";
231 }
else if (ymin >= ymax) {
232 std::cerr <<
m_className <<
"::SetMesh: Invalid y range.\n";
234 }
else if (zmin >= zmax) {
235 std::cerr <<
m_className <<
"::SetMesh: Invalid z range.\n";
247 constexpr double tol = 1.e-10;
248 for (
size_t i = 0; i < 3; ++i) {
249 if (m_xMax[i] - m_xMin[i] > tol) {
250 m_sX[i] = std::max(m_nX[i] - 1., 1.) / (m_xMax[i] - m_xMin[i]);
260 unsigned int& nz,
double& xmin,
double& xmax,
261 double& ymin,
double& ymax,
double& zmin,
262 double& zmax)
const {
263 if (!m_hasMesh)
return false;
277 const std::string& fmt,
const bool withP,
278 const bool withFlag,
const double scaleX,
280 const double scaleP) {
282 m_hasPotential =
false;
283 m_active.assign(m_nX[0], std::vector<std::vector<bool> >(
284 m_nX[1], std::vector<bool>(m_nX[2],
true)));
286 m_pMin = withP ? +1. : 0.;
287 m_pMax = withP ? -1. : 0.;
288 if (!LoadData(fname, fmt, withP, withFlag, scaleX, scaleE, scaleP,
294 if (withP) m_hasPotential =
true;
299 const std::string& fmt,
const bool withP,
300 const double scaleX,
const double scaleE,
301 const double scaleP) {
303 if (!LoadData(fname, fmt, withP,
false, scaleX, scaleE, scaleP, m_wfields)) {
311 const std::string& fmt,
const double t,
312 const bool withP,
const double scaleX,
314 const double scaleP) {
315 std::vector<std::vector<std::vector<Node> > > wfield;
317 if (!LoadData(fname, fmt, withP,
false, scaleX, scaleE, scaleP, wfield)) {
320 if (m_wdtimes.empty() || t > m_wdtimes.back()) {
321 m_wdtimes.push_back(t);
322 m_wdfields.push_back(std::move(wfield));
324 const auto it = std::upper_bound(m_wdtimes.begin(), m_wdtimes.end(), t);
325 const auto n = std::distance(m_wdtimes.begin(), it);
326 m_wdtimes.insert(it, t);
327 m_wdfields.insert( m_wdfields.begin() + n, std::move(wfield));
333 const std::string& fmt,
335 const double scaleB) {
337 if (!LoadData(fname, fmt,
false,
false, scaleX, scaleB, 1., m_bfields)) {
345 const std::string& filename,
346 const std::string& format) {
348 std::cerr <<
m_className <<
"::SaveElectricField: Null pointer.\n";
352 std::cerr <<
m_className <<
"::SaveElectricField: Mesh not set.\n";
355 const auto fmt = GetFormat(format);
356 if (fmt == Format::Unknown) {
357 std::cerr <<
m_className <<
"::SaveElectricField:\n"
358 <<
" Unknown format (" << format <<
").\n";
361 std::ofstream outfile;
362 outfile.open(filename.c_str(), std::ios::out);
364 std::cerr <<
m_className <<
"::SaveElectricField:\n"
365 <<
" Could not open file " << filename <<
".\n";
368 std::cout <<
m_className <<
"::SaveElectricField:\n"
369 <<
" Exporting field/potential to " << filename <<
".\n"
370 <<
" Be patient...\n";
372 outfile <<
"# XMIN = " << m_xMin[0] <<
", XMAX = " << m_xMax[0]
373 <<
", NX = " << m_nX[0] <<
"\n";
374 outfile <<
"# YMIN = " << m_xMin[1] <<
", YMAX = " << m_xMax[1]
375 <<
", NY = " << m_nX[1] <<
"\n";
376 outfile <<
"# ZMIN = " << m_xMin[2] <<
", ZMAX = " << m_xMax[2]
377 <<
", NZ = " << m_nX[2] <<
"\n";
379 const unsigned int nValues = m_nX[0] * m_nX[1] * m_nX[2];
380 const unsigned int nPrint =
381 std::pow(10,
static_cast<unsigned int>(
382 std::max(std::floor(std::log10(nValues)) - 1, 1.)));
383 unsigned int nLines = 0;
386 const double dx = (m_xMax[0] - m_xMin[0]) / std::max(m_nX[0] - 1., 1.);
387 const double dy = (m_xMax[1] - m_xMin[1]) / std::max(m_nX[1] - 1., 1.);
388 const double dz = (m_xMax[2] - m_xMin[2]) / std::max(m_nX[2] - 1., 1.);
389 for (
unsigned int i = 0; i < m_nX[0]; ++i) {
390 const double x = m_xMin[0] + i * dx;
391 for (
unsigned int j = 0; j < m_nX[1]; ++j) {
392 const double y = m_xMin[1] + j * dy;
393 for (
unsigned int k = 0; k < m_nX[2]; ++k) {
394 const double z = m_xMin[2] + k * dz;
395 if (fmt == Format::XY) {
396 outfile << x <<
" " << y <<
" ";
397 }
else if (fmt == Format::XYZ) {
398 outfile << x <<
" " << y <<
" " << z <<
" ";
399 }
else if (fmt == Format::IJ) {
400 outfile << i <<
" " << j <<
" ";
401 }
else if (fmt == Format::IJK) {
402 outfile << i <<
" " << j <<
" " << k <<
" ";
403 }
else if (fmt == Format::YXZ) {
404 outfile << y <<
" " << x <<
" " << z <<
" ";
406 double ex = 0., ey = 0., ez = 0., v = 0.;
408 outfile << ex <<
" " << ey <<
" " << ez <<
" " << v <<
"\n";
410 if (nLines % nPrint == 0) PrintProgress(
double(nLines) / nValues);
415 std::cout << std::endl <<
m_className <<
"::SaveElectricField: Done.\n";
420 const std::string&
id,
421 const std::string& filename,
422 const std::string& format) {
424 std::cerr <<
m_className <<
"::SaveWeightingField: Null pointer.\n";
428 std::cerr <<
m_className <<
"::SaveWeightingField: Mesh not set.\n";
431 const auto fmt = GetFormat(format);
432 if (fmt == Format::Unknown) {
433 std::cerr <<
m_className <<
"::SaveWeightingField:\n"
434 <<
" Unknown format (" << format <<
").\n";
437 std::ofstream outfile;
438 outfile.open(filename.c_str(), std::ios::out);
440 std::cerr <<
m_className <<
"::SaveWeightingField:\n"
441 <<
" Could not open file " << filename <<
".\n";
444 std::cout <<
m_className <<
"::SaveWeightingField:\n"
445 <<
" Exporting field/potential to " << filename <<
".\n"
446 <<
" Be patient...\n";
448 outfile <<
"# XMIN = " << m_xMin[0] <<
", XMAX = " << m_xMax[0]
449 <<
", NX = " << m_nX[0] <<
"\n";
450 outfile <<
"# YMIN = " << m_xMin[1] <<
", YMAX = " << m_xMax[1]
451 <<
", NY = " << m_nX[1] <<
"\n";
452 outfile <<
"# ZMIN = " << m_xMin[2] <<
", ZMAX = " << m_xMax[2]
453 <<
", 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;
459 const double dx = (m_xMax[0] - m_xMin[0]) / std::max(m_nX[0] - 1., 1.);
460 const double dy = (m_xMax[1] - m_xMin[1]) / std::max(m_nX[1] - 1., 1.);
461 const double dz = (m_xMax[2] - m_xMin[2]) / std::max(m_nX[2] - 1., 1.);
462 for (
unsigned int i = 0; i < m_nX[0]; ++i) {
463 const double x = m_xMin[0] + i * dx;
464 for (
unsigned int j = 0; j < m_nX[1]; ++j) {
465 const double y = m_xMin[1] + j * dy;
466 for (
unsigned int k = 0; k < m_nX[2]; ++k) {
467 const double z = m_xMin[2] + k * dz;
468 if (fmt == Format::XY) {
469 outfile << x <<
" " << y <<
" ";
470 }
else if (fmt == Format::XYZ) {
471 outfile << x <<
" " << y <<
" " << z <<
" ";
472 }
else if (fmt == Format::IJ) {
473 outfile << i <<
" " << j <<
" ";
474 }
else if (fmt == Format::IJK) {
475 outfile << i <<
" " << j <<
" " << k <<
" ";
476 }
else if (fmt == Format::YXZ) {
477 outfile << y <<
" " << x <<
" " << z <<
" ";
479 double wx = 0., wy = 0., wz = 0.;
482 outfile << wx <<
" " << wy <<
" " << wz <<
" " << v <<
"\n";
484 if (nLines % nPrint == 0) PrintProgress(
double(nLines) / nValues);
489 std::cout << std::endl <<
m_className <<
"::SaveWeightingField: Done.\n";
493bool ComponentGrid::LoadMesh(
const std::string& filename, std::string format,
494 const double scaleX) {
495 const auto fmt = GetFormat(format);
496 if (fmt == Format::Unknown) {
498 <<
" Unknown format (" << format <<
").\n";
503 std::bitset<9> found;
505 double xmin = 0., ymin = 0., zmin = 0.;
506 double xmax = 0., ymax = 0., zmax = 0.;
507 unsigned int nx = 0, ny = 0, nz = 0;
510 std::ifstream infile;
511 infile.open(filename.c_str(), std::ios::in);
514 <<
" Could not open file " << filename <<
".\n";
518 unsigned int nLines = 0;
520 while (std::getline(infile, line)) {
525 if (line.empty())
continue;
527 if (!IsComment(line))
continue;
528 std::size_t pos0 = 0;
529 std::size_t pos1 = line.find(
"=", pos0);
530 while (pos1 != std::string::npos) {
531 std::string key = line.substr(pos0, pos1 - pos0);
532 std::transform(key.begin(), key.end(), key.begin(), toupper);
533 const std::size_t pos2 = line.find_first_of(
",;", pos1 + 1);
534 std::istringstream val(line.substr(pos1 + 1, pos2 - pos1 - 1));
535 if (key.find(
"XMIN") != std::string::npos) {
538 }
else if (key.find(
"YMIN") != std::string::npos) {
541 }
else if (key.find(
"ZMIN") != std::string::npos) {
544 }
else if (key.find(
"XMAX") != std::string::npos) {
547 }
else if (key.find(
"YMAX") != std::string::npos) {
550 }
else if (key.find(
"ZMAX") != std::string::npos) {
553 }
else if (key.find(
"NX") != std::string::npos) {
556 }
else if (key.find(
"NY") != std::string::npos) {
559 }
else if (key.find(
"NZ") != std::string::npos) {
563 if (pos2 == std::string::npos)
break;
565 pos1 = line.find(
"=", pos0);
570 if (fmt == Format::XY || fmt == Format::IJ) {
577 if (found[0] || found[1] || found[3] || found[4] || found[5]) {
593 std::printf(
"%12.6f < x [cm] < %12.6f, %5u points\n", xmin, xmax, nx);
594 std::printf(
"%12.6f < y [cm] < %12.6f, %5u points\n", ymin, ymax, ny);
595 std::printf(
"%12.6f < z [cm] < %12.6f, %5u points\n", zmin, zmax, nz);
596 return SetMesh(nx, ny, nz, xmin, xmax, ymin, ymax, zmin, zmax);
599 if ((fmt == Format::IJ || fmt == Format::IJK) && !(found[0] && found[3])) {
600 std::cerr <<
m_className <<
"::LoadMesh: x-limits not found.\n";
602 }
else if ((fmt == Format::IJ || fmt == Format::IJK) && !(found[1] && found[4])) {
603 std::cerr <<
m_className <<
"::LoadMesh: y-limits not found.\n";
605 }
else if (fmt == Format::IJK && !(found[2] && found[5])) {
606 std::cerr <<
m_className <<
"::LoadMesh: z-limits not found.\n";
610 unsigned int nValues = 0;
611 infile.open(filename.c_str(), std::ios::in);
614 <<
" Could not open file " << filename <<
".\n";
618 if (!found[0]) xmin = std::numeric_limits<double>::max();
619 if (!found[1]) ymin = std::numeric_limits<double>::max();
620 if (!found[2]) zmin = std::numeric_limits<double>::max();
621 if (!found[3]) xmax = std::numeric_limits<double>::min();
622 if (!found[4]) ymax = std::numeric_limits<double>::min();
623 if (!found[5]) zmax = std::numeric_limits<double>::min();
624 constexpr double tol = 1.e-10;
625 auto cmp = [](
double x,
double y) {
626 return x <
y - tol * (std::fabs(x) + std::fabs(y));
628 std::set<double,
decltype(cmp)> xLines(cmp);
629 std::set<double,
decltype(cmp)> yLines(cmp);
630 std::set<double,
decltype(cmp)> zLines(cmp);
634 while (std::getline(infile, line)) {
639 if (line.empty())
continue;
641 if (IsComment(line))
continue;
642 std::istringstream data;
644 if (fmt == Format::XY) {
648 PrintError(
m_className +
"::LoadMesh", nLines,
"coordinates");
654 if (!found[0]) xmin = std::min(x, xmin);
655 if (!found[1]) ymin = std::min(y, ymin);
656 if (!found[3]) xmax = std::max(x, xmax);
657 if (!found[4]) ymax = std::max(y, ymax);
660 }
else if (fmt == Format::XYZ) {
664 PrintError(
m_className +
"::LoadMesh", nLines,
"coordinates");
671 if (!found[0]) xmin = std::min(x, xmin);
672 if (!found[1]) ymin = std::min(y, ymin);
673 if (!found[2]) zmin = std::min(z, zmin);
674 if (!found[3]) xmax = std::max(x, xmax);
675 if (!found[4]) ymax = std::max(y, ymax);
676 if (!found[5]) zmax = std::max(z, zmax);
680 }
else if (fmt == Format::IJ) {
681 unsigned int i = 0, j = 0;
684 PrintError(
m_className +
"::LoadMesh", nLines,
"indices");
688 if (!found[6]) nx = std::max(nx, i);
689 if (!found[7]) ny = std::max(ny, j);
690 }
else if (fmt == Format::IJK) {
691 unsigned int i = 0, j = 0, k = 0;
694 PrintError(
m_className +
"::LoadMesh", nLines,
"indices");
698 if (!found[6]) nx = std::max(nx, i);
699 if (!found[7]) ny = std::max(ny, j);
700 if (!found[8]) nz = std::max(nz, k);
701 }
else if (fmt == Format::YXZ) {
705 PrintError(
m_className +
"::LoadMesh", nLines,
"coordinates");
712 if (!found[0]) xmin = std::min(x, xmin);
713 if (!found[1]) ymin = std::min(y, ymin);
714 if (!found[2]) zmin = std::min(z, zmin);
715 if (!found[3]) xmax = std::max(x, xmax);
716 if (!found[4]) ymax = std::max(y, ymax);
717 if (!found[5]) zmax = std::max(z, zmax);
725 if (bad)
return false;
727 if (fmt == Format::XY || fmt == Format::XYZ || fmt == Format::YXZ) {
728 if (!found[6]) nx = xLines.size();
729 if (!found[7]) ny = yLines.size();
730 if (!found[8]) nz = zLines.size();
734 std::printf(
"%12.6f < x [cm] < %12.6f, %5u points\n", xmin, xmax, nx);
735 std::printf(
"%12.6f < y [cm] < %12.6f, %5u points\n", ymin, ymax, ny);
736 std::printf(
"%12.6f < z [cm] < %12.6f, %5u points\n", zmin, zmax, nz);
737 unsigned int nExpected = nx * ny;
738 if (fmt == Format::XYZ || fmt == Format::IJK || fmt == Format::YXZ) {
741 if (nExpected != nValues) {
743 <<
" Warning: Expected " << nExpected <<
" lines, read "
746 return SetMesh(nx, ny, nz, xmin, xmax, ymin, ymax, zmin, zmax);
749bool ComponentGrid::LoadData(
750 const std::string& filename, std::string format,
const bool withPotential,
751 const bool withFlag,
const double scaleX,
const double scaleF,
753 std::vector<std::vector<std::vector<Node> > >& fields) {
755 if (!LoadMesh(filename, format, scaleX)) {
756 std::cerr <<
m_className <<
"::LoadData: Mesh not set.\n";
761 const auto fmt = GetFormat(format);
762 if (fmt == Format::Unknown) {
764 <<
" Unknown format (" << format <<
").\n";
771 unsigned int nValues = 0;
773 std::vector<std::vector<std::vector<bool> > > isSet(
775 std::vector<std::vector<bool> >(m_nX[1], std::vector<bool>(m_nX[2],
false)));
777 std::ifstream infile;
778 infile.open(filename.c_str(), std::ios::in);
781 <<
" Could not open file " << filename <<
".\n";
786 unsigned int nLines = 0;
789 while (std::getline(infile, line)) {
794 if (line.empty())
continue;
796 if (IsComment(line))
continue;
804 std::istringstream data;
806 if (fmt == Format::XY) {
810 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
817 const double u = std::round((x - m_xMin[0]) * m_sX[0]);
818 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
819 if (i >= m_nX[0]) i = m_nX[0] - 1;
822 const double v = std::round((y - m_xMin[1]) * m_sX[1]);
823 j = v < 0. ? 0 :
static_cast<unsigned int>(v);
824 if (j >= m_nX[1]) j = m_nX[1] - 1;
826 }
else if (fmt == Format::XYZ) {
830 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
838 const double u = std::round((x - m_xMin[0]) * m_sX[0]);
839 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
840 if (i >= m_nX[0]) i = m_nX[0] - 1;
843 const double v = std::round((y - m_xMin[1]) * m_sX[1]);
844 j = v < 0. ? 0 :
static_cast<unsigned int>(v);
845 if (j >= m_nX[1]) j = m_nX[1] - 1;
848 const double w = std::round((z - m_xMin[2]) * m_sX[2]);
849 k = w < 0. ? 0 :
static_cast<unsigned int>(w);
850 if (k >= m_nX[2]) k = m_nX[2] - 1;
852 }
else if (fmt == Format::IJ) {
855 PrintError(
m_className +
"::LoadData", nLines,
"indices");
859 }
else if (fmt == Format::IJK) {
862 PrintError(
m_className +
"::LoadData", nLines,
"indices");
866 }
else if (fmt == Format::YXZ) {
870 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
878 const double u = std::round((x - m_xMin[0]) * m_sX[0]);
879 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
880 if (i >= m_nX[0]) i = m_nX[0] - 1;
883 const double v = std::round((y - m_xMin[1]) * m_sX[1]);
884 j = v < 0. ? 0 :
static_cast<unsigned int>(v);
885 if (j >= m_nX[1]) j = m_nX[1] - 1;
888 const double w = std::round((z - m_xMin[2]) * m_sX[2]);
889 k = w < 0. ? 0 :
static_cast<unsigned int>(w);
890 if (k >= m_nX[2]) k = m_nX[2] - 1;
894 if (i >= m_nX[0] || j >= m_nX[1] || k >= m_nX[2]) {
896 <<
" Error reading line " << nLines <<
".\n"
897 <<
" Index (" << i <<
", " << j <<
", " << k
898 <<
") out of range.\n";
901 if (isSet[i][j][k]) {
903 <<
" Error reading line " << nLines <<
".\n"
904 <<
" Node (" << i <<
", " << j <<
", " << k
905 <<
") has already been set.\n";
909 if (fmt == Format::XY || fmt == Format::IJ) {
913 }
else if (fmt == Format::YXZ) {
914 data >> fy >> fx >> fz;
916 data >> fx >> fy >> fz;
919 PrintError(
m_className +
"::LoadData", nLines,
"field components");
929 PrintError(
m_className +
"::LoadData", nLines,
"potential");
934 if (m_pMin > m_pMax) {
939 if (p < m_pMin) m_pMin = p;
940 if (p > m_pMax) m_pMax = p;
947 PrintError(
m_className +
"::LoadData", nLines,
"region");
952 const bool isActive = flag == 0 ? false :
true;
953 if (fmt == Format::XY || fmt == Format::IJ) {
955 for (
unsigned int kk = 0; kk < m_nX[2]; ++kk) {
956 fields[i][j][kk].fx = fx;
957 fields[i][j][kk].fy = fy;
958 fields[i][j][kk].fz = fz;
959 fields[i][j][kk].v = p;
960 if (withFlag) m_active[i][j][kk] = isActive;
961 isSet[i][j][kk] =
true;
964 fields[i][j][k].fx = fx;
965 fields[i][j][k].fy = fy;
966 fields[i][j][k].fz = fz;
967 fields[i][j][k].v = p;
968 isSet[i][j][k] =
true;
973 if (bad)
return false;
975 <<
" Read " << nValues <<
" values from " << filename <<
".\n";
976 unsigned int nExpected = m_nX[0] * m_nX[1];
977 if (fmt == Format::XYZ || fmt == Format::IJK || fmt == Format::YXZ) {
978 nExpected *= m_nX[2];
980 if (nExpected != nValues) {
982 <<
" Expected " << nExpected <<
" values.\n";
988 double& xmax,
double& ymax,
double& zmax) {
1017 double& xmin,
double& ymin,
double& zmin,
1018 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[0]; ++i) {
1049 for (
unsigned int j = 0; j < m_nX[1]; ++j) {
1050 for (
unsigned int k = 0; k < m_nX[2]; ++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 std::array<bool, 3> mirrored = {
false,
false,
false};
1083 std::array<double, 3> xx = {xi, yi, zi};
1084 for (
size_t i = 0; i < 3; ++i) {
1085 xx[i] = Reduce(xx[i], m_xMin[i], m_xMax[i],
1087 if (xx[i] < m_xMin[i] || xx[i] > m_xMax[i])
return false;
1090 const double sx = (xx[0] - m_xMin[0]) * m_sX[0];
1091 const double sy = (xx[1] - m_xMin[1]) * m_sX[1];
1092 const double sz = (xx[2] - m_xMin[2]) * m_sX[2];
1093 const unsigned int i0 =
static_cast<unsigned int>(std::floor(sx));
1094 const unsigned int j0 =
static_cast<unsigned int>(std::floor(sy));
1095 const unsigned int k0 =
static_cast<unsigned int>(std::floor(sz));
1096 const double ux = sx - i0;
1097 const double uy = sy - j0;
1098 const double uz = sz - k0;
1099 const unsigned int i1 = std::min(i0 + 1, m_nX[0] - 1);
1100 const unsigned int j1 = std::min(j0 + 1, m_nX[1] - 1);
1101 const unsigned int k1 = std::min(k0 + 1, m_nX[2] - 1);
1102 const double vx = 1. - ux;
1103 const double vy = 1. - uy;
1104 const double vz = 1. - uz;
1105 if (!m_active.empty()) {
1106 active = m_active[i0][j0][k0] && m_active[i0][j0][k1] &&
1107 m_active[i0][j1][k0] && m_active[i0][j1][k1] &&
1108 m_active[i1][j0][k0] && m_active[i1][j0][k1] &&
1109 m_active[i1][j1][k0] && m_active[i1][j1][k1];
1111 const Node& n000 = field[i0][j0][k0];
1112 const Node& n100 = field[i1][j0][k0];
1113 const Node& n010 = field[i0][j1][k0];
1114 const Node& n110 = field[i1][j1][k0];
1115 const Node& n001 = field[i0][j0][k1];
1116 const Node& n101 = field[i1][j0][k1];
1117 const Node& n011 = field[i0][j1][k1];
1118 const Node& n111 = field[i1][j1][k1];
1121 std::cout <<
m_className <<
"::GetField: Determining field at (" << xi
1122 <<
", " << yi <<
", " << zi <<
").\n"
1123 <<
" X: " << i0 <<
" (" << ux <<
") - " << i1 <<
" (" << vx
1125 <<
" Y: " << j0 <<
" (" << uy <<
") - " << j1 <<
" (" << vy
1127 <<
" Z: " << k0 <<
" (" << uz <<
") - " << k1 <<
" (" << vz
1130 fx = ((n000.fx * vx + n100.fx * ux) * vy +
1131 (n010.fx * vx + n110.fx * ux) * uy) *
1133 ((n001.fx * vx + n101.fx * ux) * vy +
1134 (n011.fx * vx + n111.fx * ux) * uy) *
1136 fy = ((n000.fy * vx + n100.fy * ux) * vy +
1137 (n010.fy * vx + n110.fy * ux) * uy) *
1139 ((n001.fy * vx + n101.fy * ux) * vy +
1140 (n011.fy * vx + n111.fy * ux) * uy) *
1142 fz = ((n000.fz * vx + n100.fz * ux) * vy +
1143 (n010.fz * vx + n110.fz * ux) * uy) *
1145 ((n001.fz * vx + n101.fz * ux) * vy +
1146 (n011.fz * vx + n111.fz * ux) * uy) *
1148 p = ((n000.v * vx + n100.v * ux) * vy + (n010.v * vx + n110.v * ux) * uy) *
1150 ((n001.v * vx + n101.v * ux) * vy + (n011.v * vx + n111.v * ux) * uy) *
1152 if (mirrored[0]) fx = -fx;
1153 if (mirrored[1]) fy = -fy;
1154 if (mirrored[2]) fz = -fz;
1159 const unsigned int k,
double& v,
1160 double& ex,
double& ey,
double& ez)
const {
1161 v = ex = ey = ez = 0.;
1164 std::cerr <<
m_className <<
"::GetElectricField: Mesh not set.\n";
1167 PrintNotReady(
m_className +
"::GetElectricField");
1170 if (i >= m_nX[0] || j >= m_nX[1] || k >= m_nX[2]) {
1171 std::cerr <<
m_className <<
"::GetElectricField: Index out of range.\n";
1174 const Node& node = m_efields[i][j][k];
1186 std::cout <<
" Mesh not set.\n";
1189 std::printf(
" %15.8f < x [cm] < %15.8f, %10u nodes\n",
1190 m_xMin[0], m_xMax[0], m_nX[0]);
1191 std::printf(
" %15.8f < y [cm] < %15.8f, %10u nodes\n",
1192 m_xMin[1], m_xMax[1], m_nX[1]);
1193 std::printf(
" %15.8f < z [cm] < %15.8f, %10u nodes\n",
1194 m_xMin[2], m_xMax[2], m_nX[2]);
1195 if (m_efields.empty() && m_bfields.empty() &&
1196 m_wfields.empty() && m_wdfields.empty() &&
1197 m_eAttachment.empty() && m_hAttachment.empty() &&
1198 m_eVelocity.empty() && m_hVelocity.empty()) {
1199 std::cout <<
" Available data: None.\n";
1202 std::cout <<
" Available data:\n";
1203 if (!m_efields.empty()) std::cout <<
" Electric field.\n";
1204 if (!m_bfields.empty()) std::cout <<
" Magnetic field.\n";
1205 if (!m_wfields.empty()) std::cout <<
" Weighting field.\n";
1206 if (!m_wdfields.empty()) {
1207 std::cout <<
" Delayed weighting field.\n";
1209 if (!m_eVelocity.empty()) {
1210 std::cout <<
" Electron drift velocity.\n";
1212 if (!m_hVelocity.empty()) {
1213 std::cout <<
" Hole drift velocity.\n";
1215 if (!m_eAttachment.empty()) {
1216 std::cout <<
" Electron attachment coefficient.\n";
1218 if (!m_hAttachment.empty()) {
1219 std::cout <<
" Hole attachment coefficient.\n";
1223void ComponentGrid::Reset() {
1227 m_eAttachment.clear();
1228 m_hAttachment.clear();
1229 m_eVelocity.clear();
1230 m_hVelocity.clear();
1240 m_sX[0] = m_sX[1] = m_sX[2] = 0.;
1241 m_pMin = m_pMax = 0.;
1245 m_hasPotential =
false;
1248 m_wFieldOffset.fill(0.);
1251void ComponentGrid::UpdatePeriodicity() {
1253 PrintNotReady(
m_className +
"::UpdatePeriodicity");
1258 for (
size_t i = 0; i < 3; ++i) {
1260 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1261 <<
" Both simple and mirror periodicity requested. Reset.\n";
1267 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1268 <<
" Axial symmetry is not supported. Reset.\n";
1274 std::cerr <<
m_className <<
"::UpdatePeriodicity:\n"
1275 <<
" Rotation symmetry is not supported. Reset.\n";
1280double ComponentGrid::Reduce(
const double xin,
const double xmin,
1281 const double xmax,
const bool simplePeriodic,
1282 const bool mirrorPeriodic,
bool& mirrored)
const {
1285 const double lx = xmax - xmin;
1286 if (simplePeriodic) {
1287 x = xmin + fmod(x - xmin, lx);
1288 if (x < xmin)
x += lx;
1289 }
else if (mirrorPeriodic) {
1290 double xNew = xmin + fmod(x - xmin, lx);
1291 if (xNew < xmin) xNew += lx;
1292 const int nx = int(floor(0.5 + (xNew - x) / lx));
1293 if (nx != 2 * (nx / 2)) {
1294 xNew = xmin + xmax - xNew;
1302void ComponentGrid::Initialise(
1303 std::vector<std::vector<std::vector<Node> > >& fields) {
1304 fields.resize(m_nX[0]);
1305 for (
unsigned int i = 0; i < m_nX[0]; ++i) {
1306 fields[i].resize(m_nX[1]);
1307 for (
unsigned int j = 0; j < m_nX[1]; ++j) {
1308 fields[i][j].resize(m_nX[2]);
1309 for (
unsigned int k = 0; k < m_nX[2]; ++k) {
1310 fields[i][j][k].fx = 0.;
1311 fields[i][j][k].fy = 0.;
1312 fields[i][j][k].fz = 0.;
1313 fields[i][j][k].v = 0.;
1320 const std::string& fmt,
1321 const double scaleX,
1322 const double scaleV) {
1324 if (!LoadData(fname, fmt,
false,
false, scaleX, scaleV, 1., m_eVelocity)) {
1331 const std::string& fmt,
1332 const double scaleX,
1333 const double scaleV) {
1335 if (!LoadData(fname, fmt,
false,
false, scaleX, scaleV, 1., m_hVelocity)) {
1343 double& vx,
double& vy,
double& vz) {
1344 if (m_eVelocity.empty()) {
1345 PrintNotReady(
m_className +
"::ElectronVelocity");
1350 return GetField(x, y, z, m_eVelocity, vx, vy, vz, p, active);
1355 double& vx,
double& vy,
double& vz) {
1356 if (m_hVelocity.empty()) {
1362 return GetField(x, y, z, m_hVelocity, vx, vy, vz, p, active);
1366 const std::string& fmt,
1367 const unsigned int col,
1368 const double scaleX) {
1370 return LoadData(fname, fmt, scaleX, m_eAttachment, col);
1374 const std::string& fmt,
1375 const unsigned int col,
1376 const double scaleX) {
1378 return LoadData(fname, fmt, scaleX, m_hAttachment, col);
1381bool ComponentGrid::LoadData(
1382 const std::string& filename, std::string format,
const double scaleX,
1383 std::vector<std::vector<std::vector<double> > >& tab,
1384 const unsigned int col) {
1386 if (!LoadMesh(filename, format, scaleX)) {
1387 std::cerr <<
m_className <<
"::LoadData: Mesh not set.\n";
1392 const auto fmt = GetFormat(format);
1393 if (fmt == Format::Unknown) {
1395 <<
" Unknown format (" << format <<
").\n";
1399 unsigned int offset = 0;
1400 if (fmt == Format::XY || fmt == Format::IJ) {
1403 <<
" Unexpected column index (" << col <<
").\n";
1410 <<
" Unexpected column index (" << col <<
").\n";
1419 std::vector<std::vector<double> >(m_nX[1], std::vector<double>(m_nX[2], 0.)));
1421 unsigned int nValues = 0;
1423 std::vector<std::vector<std::vector<bool> > > isSet(
1425 std::vector<std::vector<bool> >(m_nX[1], std::vector<bool>(m_nX[2],
false)));
1427 std::ifstream infile;
1428 infile.open(filename.c_str(), std::ios::in);
1431 <<
" Could not open file " << filename <<
".\n";
1436 unsigned int nLines = 0;
1439 while (std::getline(infile, line)) {
1444 if (line.empty())
continue;
1446 if (IsComment(line))
continue;
1451 std::istringstream data;
1453 if (fmt == Format::XY) {
1457 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
1464 const double u = std::round((x - m_xMin[0]) * m_sX[0]);
1465 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
1466 if (i >= m_nX[0]) i = m_nX[0] - 1;
1469 const double v = std::round((y - m_xMin[1]) * m_sX[1]);
1470 j = v < 0. ? 0 :
static_cast<unsigned int>(v);
1471 if (j >= m_nX[1]) j = m_nX[1] - 1;
1473 }
else if (fmt == Format::XYZ) {
1475 data >>
x >>
y >>
z;
1477 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
1485 const double u = std::round((x - m_xMin[0]) * m_sX[0]);
1486 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
1487 if (i >= m_nX[0]) i = m_nX[0] - 1;
1490 const double v = std::round((y - m_xMin[1]) * m_sX[1]);
1491 j = v < 0. ? 0 :
static_cast<unsigned int>(v);
1492 if (j >= m_nX[1]) j = m_nX[1] - 1;
1495 const double w = std::round((z - m_xMin[2]) * m_sX[2]);
1496 k = w < 0. ? 0 :
static_cast<unsigned int>(w);
1497 if (k >= m_nX[2]) k = m_nX[2] - 1;
1499 }
else if (fmt == Format::IJ) {
1502 PrintError(
m_className +
"::LoadData", nLines,
"indices");
1506 }
else if (fmt == Format::IJK) {
1507 data >> i >> j >> k;
1509 PrintError(
m_className +
"::LoadData", nLines,
"indices");
1513 }
else if (fmt == Format::YXZ) {
1515 data >>
y >>
x >>
z;
1517 PrintError(
m_className +
"::LoadData", nLines,
"coordinates");
1525 const double u = std::round((x - m_xMin[0]) * m_sX[0]);
1526 i = u < 0. ? 0 :
static_cast<unsigned int>(u);
1527 if (i >= m_nX[0]) i = m_nX[0] - 1;
1530 const double v = std::round((y - m_xMin[1]) * m_sX[1]);
1531 j = v < 0. ? 0 :
static_cast<unsigned int>(v);
1532 if (j >= m_nX[1]) j = m_nX[1] - 1;
1535 const double w = std::round((z - m_xMin[2]) * m_sX[2]);
1536 k = w < 0. ? 0 :
static_cast<unsigned int>(w);
1537 if (k >= m_nX[2]) k = m_nX[2] - 1;
1541 if (i >= m_nX[0] || j >= m_nX[1] || k >= m_nX[2]) {
1543 <<
" Error reading line " << nLines <<
".\n"
1544 <<
" Index (" << i <<
", " << j <<
", " << k
1545 <<
") out of range.\n";
1548 if (isSet[i][j][k]) {
1550 <<
" Error reading line " << nLines <<
".\n"
1551 <<
" Node (" << i <<
", " << j <<
", " << k
1552 <<
") has already been set.\n";
1557 for (
unsigned int ii = 0; ii < col - offset; ++ii) {
1562 "column " + std::to_string(offset + ii));
1574 "column " + std::to_string(col));
1579 if (fmt == Format::XY || fmt == Format::IJ) {
1581 for (
unsigned int kk = 0; kk < m_nX[2]; ++kk) {
1582 tab[i][j][kk] = val;
1583 isSet[i][j][kk] =
true;
1587 isSet[i][j][k] =
true;
1592 if (bad)
return false;
1594 <<
" Read " << nValues <<
" values from " << filename <<
".\n";
1595 unsigned int nExpected = m_nX[0] * m_nX[1];
1596 if (fmt == Format::XYZ || fmt == Format::IJK || fmt == Format::YXZ) {
1597 nExpected *= m_nX[2];
1599 if (nExpected != nValues) {
1601 <<
" Expected " << nExpected <<
" values.\n";
1606bool ComponentGrid::GetData(
1607 const double xi,
const double yi,
const double zi,
1608 const std::vector<std::vector<std::vector<double> > >& tab,
double& val) {
1610 std::cerr <<
m_className <<
"::GetData: Mesh is not set.\n";
1616 bool xMirrored =
false;
1619 if (x < m_xMin[0] || x > m_xMax[0])
return false;
1620 bool yMirrored =
false;
1623 if (y < m_xMin[1] || y > m_xMax[1])
return false;
1624 bool zMirrored =
false;
1627 if (z < m_xMin[2] || z > m_xMax[2])
return false;
1630 const double sx = (
x - m_xMin[0]) * m_sX[0];
1631 const double sy = (
y - m_xMin[1]) * m_sX[1];
1632 const double sz = (
z - m_xMin[2]) * m_sX[2];
1633 const unsigned int i0 =
static_cast<unsigned int>(std::floor(sx));
1634 const unsigned int j0 =
static_cast<unsigned int>(std::floor(sy));
1635 const unsigned int k0 =
static_cast<unsigned int>(std::floor(sz));
1636 const double ux = sx - i0;
1637 const double uy = sy - j0;
1638 const double uz = sz - k0;
1639 const unsigned int i1 = std::min(i0 + 1, m_nX[0] - 1);
1640 const unsigned int j1 = std::min(j0 + 1, m_nX[1] - 1);
1641 const unsigned int k1 = std::min(k0 + 1, m_nX[2] - 1);
1642 const double vx = 1. - ux;
1643 const double vy = 1. - uy;
1644 const double vz = 1. - uz;
1645 const double n000 = tab[i0][j0][k0];
1646 const double n100 = tab[i1][j0][k0];
1647 const double n010 = tab[i0][j1][k0];
1648 const double n110 = tab[i1][j1][k0];
1649 const double n001 = tab[i0][j0][k1];
1650 const double n101 = tab[i1][j0][k1];
1651 const double n011 = tab[i0][j1][k1];
1652 const double n111 = tab[i1][j1][k1];
1655 std::cout <<
m_className <<
"::GetData: Interpolating at (" << xi
1656 <<
", " << yi <<
", " << zi <<
").\n"
1657 <<
" X: " << i0 <<
" (" << ux <<
") - " << i1 <<
" (" << vx
1659 <<
" Y: " << j0 <<
" (" << uy <<
") - " << j1 <<
" (" << vy
1661 <<
" Z: " << k0 <<
" (" << uz <<
") - " << k1 <<
" (" << vz
1664 val = ((n000 * vx + n100 * ux) * vy + (n010 * vx + n110 * ux) * uy) * vz +
1665 ((n001 * vx + n101 * ux) * vy + (n011 * vx + n111 * ux) * uy) * uz;
1671 const double z,
double& att) {
1673 if (m_eAttachment.empty()) {
1674 PrintNotReady(
m_className +
"::ElectronAttachment");
1677 return GetData(x, y, z, m_eAttachment, att);
1681 const double z,
double& att) {
1683 if (m_hAttachment.empty()) {
1687 return GetData(x, y, z, m_hAttachment, att);
1690ComponentGrid::Format ComponentGrid::GetFormat(std::string format) {
1691 std::transform(format.begin(), format.end(), format.begin(), toupper);
1692 if (format ==
"XY") {
1694 }
else if (format ==
"XYZ") {
1696 }
else if (format ==
"IJ") {
1698 }
else if (format ==
"IJK") {
1700 }
else if (format ==
"YXZ") {
1703 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)
bool SaveElectricField(Component *cmp, const std::string &filename, const std::string &format)
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 GetElementaryCell(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the coordinates of the elementary cell.
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.
bool SaveWeightingField(Component *cmp, const std::string &id, const std::string &filename, const std::string &format)
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.)
Abstract base class for components.
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.
std::array< bool, 3 > m_periodic
Simple periodicity in x, y, z.
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)
bool m_ready
Ready for use?
std::array< bool, 3 > m_axiallyPeriodic
Axial periodicity in x, y, z.
Abstract base class for media.
void ltrim(std::string &line)
DoubleAc fabs(const DoubleAc &f)