10void PrintErrorReadingFile(
const std::string& hdr,
const std::string& file,
12 std::cerr << hdr <<
"\n Error reading file " << file <<
" (line " << line
23 const std::string& elist,
24 const std::string& nlist,
25 const std::string& mplist,
26 const std::string& volt,
const std::string& unit)
28 Initialise(header, elist, nlist, mplist, volt, unit);
32 const std::string& elist,
33 const std::string& nlist,
34 const std::string& mplist,
35 const std::string& volt,
36 const std::string& unit) {
37 const std::string hdr =
m_className +
"::Initialise:";
44 constexpr int size = 100;
48 std::ifstream fheader;
49 fheader.open(header.c_str(), std::ios::in);
57 bool readerror =
false;
58 bool readstop =
false;
62 fheader.getline(line, size,
'\n');
63 token = strtok(line,
" ");
64 const int nNodes =
ReadInteger(token, 0, readerror);
65 token = strtok(NULL,
" ");
66 const int nElements =
ReadInteger(token, 0, readerror);
67 std::cout << hdr <<
"\n Read " << nNodes <<
" nodes and " << nElements
68 <<
" elements from file " << header <<
".\n";
70 PrintErrorReadingFile(hdr, header, il);
80 fnodes.open(nlist.c_str(), std::ios::in);
89 std::cerr << hdr <<
" Unknown length unit " << unit <<
".\n";
93 if (
m_debug) std::cout << hdr <<
" Unit scaling factor = " << funit <<
".\n";
96 for (il = 0; il < nNodes; il++) {
98 fnodes.getline(line, size,
'\n');
101 token = strtok(line,
" ");
102 token = strtok(NULL,
" ");
105 token = strtok(NULL,
" ");
106 double xnode =
ReadDouble(token, -1, readerror);
107 token = strtok(NULL,
" ");
108 double ynode =
ReadDouble(token, -1, readerror);
109 token = strtok(NULL,
" ");
110 double znode =
ReadDouble(token, -1, readerror);
112 PrintErrorReadingFile(hdr, nlist, il);
120 newNode.
x = xnode * funit;
121 newNode.
y = ynode * funit;
122 newNode.
z = znode * funit;
123 m_nodes.push_back(std::move(newNode));
131 fvolt.open(volt.c_str(), std::ios::in);
141 while (!readstop && fvolt.getline(line, size,
'\n')) {
142 token = strtok(line,
" ");
143 if (strcmp(token,
"Perm:") == 0) readstop =
true;
149 std::cerr << hdr <<
"\n Error reading past header of potentials file "
156 for (
int tl = 0; tl < nNodes; tl++) {
157 fvolt.getline(line, size,
'\n');
162 for (
int tl = 0; tl < nNodes; tl++) {
163 fvolt.getline(line, size,
'\n');
164 token = strtok(line,
" ");
167 PrintErrorReadingFile(hdr, volt, il);
179 std::ifstream fmplist;
180 fmplist.open(mplist.c_str(), std::ios::in);
181 if (fmplist.fail()) {
187 fmplist.getline(line, size,
'\n');
188 token = strtok(line,
" ");
190 std::cerr << hdr <<
"\n Error reading number of materials from "
195 const unsigned int nMaterials =
ReadInteger(token, 0, readerror);
200 material.medium =
nullptr;
202 for (il = 2; il < ((int)nMaterials + 2); il++) {
203 fmplist.getline(line, size,
'\n');
204 token = strtok(line,
" ");
206 token = strtok(NULL,
" ");
207 double dc =
ReadDouble(token, -1.0, readerror);
209 PrintErrorReadingFile(hdr, mplist, il);
214 std::cout << hdr <<
"\n Set material " << il - 2 <<
" of "
215 << nMaterials <<
" to eps " << dc <<
".\n";
225 std::ifstream felems;
226 felems.open(elist.c_str(), std::ios::in);
236 for (il = 0; il < nElements; il++) {
238 felems.getline(line, size,
'\n');
241 token = strtok(line,
" ");
249 token = strtok(NULL,
" ");
251 token = strtok(NULL,
" ");
252 token = strtok(NULL,
" ");
254 token = strtok(NULL,
" ");
256 token = strtok(NULL,
" ");
258 token = strtok(NULL,
" ");
260 token = strtok(NULL,
" ");
262 token = strtok(NULL,
" ");
264 token = strtok(NULL,
" ");
266 token = strtok(NULL,
" ");
268 token = strtok(NULL,
" ");
270 token = strtok(NULL,
" ");
274 std::cout <<
" Read nodes " << in0 <<
", " << in1 <<
", " << in2
275 <<
", " << in3 <<
", ... from element " << il + 1 <<
" of "
276 << nElements <<
" with mat " << imat <<
".\n";
281 PrintErrorReadingFile(hdr, elist, il);
287 if (imat < 0 || imat > (
int)nMaterials) {
288 std::cerr << hdr <<
"\n Out-of-range material number on file " << elist
289 <<
" (line " << il <<
").\n";
290 std::cerr <<
" Element: " << il <<
", material: " << imat <<
"\n";
291 std::cerr <<
" nodes: (" << in0 <<
", " << in1 <<
", " << in2 <<
", "
292 << in3 <<
", " << in4 <<
", " << in5 <<
", " << in6 <<
", "
293 << in7 <<
", " << in8 <<
", " << in9 <<
")\n";
297 std::cerr << hdr <<
"\n Element " << il <<
" in element list " << elist
298 <<
"\n uses material " << imat
299 <<
" which has not been assigned a positive permittivity in "
305 if (in0 < 1 || in1 < 1 || in2 < 1 || in3 < 1 || in4 < 1 || in5 < 1 ||
306 in6 < 1 || in7 < 1 || in8 < 1 || in9 < 1) {
307 std::cerr << hdr <<
"\n Found a node number < 1 on file " << elist
308 <<
" (line " << il <<
").\n Element: " << il
309 <<
", material: " << imat <<
"\n nodes: (" << in0 <<
", "
310 << in1 <<
", " << in2 <<
", " << in3 <<
", " << in4 <<
", "
311 << in5 <<
", " << in6 <<
", " << in7 <<
", " << in8 <<
", "
315 if (in0 > highestnode) highestnode = in0;
316 if (in1 > highestnode) highestnode = in1;
317 if (in2 > highestnode) highestnode = in2;
318 if (in3 > highestnode) highestnode = in3;
319 if (in4 > highestnode) highestnode = in4;
320 if (in5 > highestnode) highestnode = in5;
321 if (in6 > highestnode) highestnode = in6;
322 if (in7 > highestnode) highestnode = in7;
323 if (in8 > highestnode) highestnode = in8;
324 if (in9 > highestnode) highestnode = in9;
327 if (in0 == in1 || in0 == in2 || in0 == in3 || in0 == in4 || in0 == in5 ||
328 in0 == in6 || in0 == in7 || in0 == in8 || in0 == in9 || in1 == in2 ||
329 in1 == in3 || in1 == in4 || in1 == in5 || in1 == in6 || in1 == in7 ||
330 in1 == in8 || in1 == in9 || in2 == in3 || in2 == in4 || in2 == in5 ||
331 in2 == in6 || in2 == in7 || in2 == in8 || in2 == in9 || in3 == in4 ||
332 in3 == in5 || in3 == in6 || in3 == in7 || in3 == in8 || in3 == in9 ||
333 in4 == in5 || in4 == in6 || in4 == in7 || in4 == in8 || in4 == in9 ||
334 in5 == in6 || in5 == in7 || in5 == in8 || in5 == in9 || in6 == in7 ||
335 in6 == in8 || in6 == in9 || in7 == in8 || in7 == in9 || in8 == in9) {
336 std::cerr << hdr <<
"\n Element " << il <<
" of file " << elist
337 <<
" is degenerate,\n"
338 <<
" no such elements are allowed in this type of map.\n";
348 newElement.
emap[0] = in0 - 1;
349 newElement.
emap[1] = in1 - 1;
350 newElement.
emap[2] = in2 - 1;
351 newElement.
emap[3] = in3 - 1;
352 newElement.
emap[4] = in4 - 1;
353 newElement.
emap[7] = in5 - 1;
354 newElement.
emap[5] = in6 - 1;
355 newElement.
emap[6] = in7 - 1;
356 newElement.
emap[8] = in8 - 1;
357 newElement.
emap[9] = in9 - 1;
368 std::cerr << hdr <<
"\n Field map could not be "
369 <<
"read and cannot be interpolated.\n";
373 std::cout << hdr <<
" Finished.\n";
380 const std::string hdr =
m_className +
"::SetWeightingField:";
383 std::cerr <<
" Weighting field cannot be added.\n";
388 std::ifstream fwvolt;
389 fwvolt.open(wvolt.c_str(), std::ios::in);
398 std::cout <<
m_className <<
"::SetWeightingField:\n"
399 <<
" Replacing existing weighting field " << label <<
".\n";
404 constexpr int size = 100;
407 bool readerror =
false;
408 bool readstop =
false;
412 while (!readstop && fwvolt.getline(line, size,
'\n')) {
413 token = strtok(line,
" ");
414 if (strcmp(token,
"Perm:") == 0) readstop =
true;
420 std::cerr << hdr <<
"\n Error reading past header of potentials file "
427 const int nNodes =
m_nodes.size();
428 for (
int tl = 0; tl < nNodes; tl++) {
429 fwvolt.getline(line, size,
'\n');
434 for (
int tl = 0; tl < nNodes; tl++) {
436 fwvolt.getline(line, size,
'\n');
437 token = strtok(line,
" ");
440 PrintErrorReadingFile(hdr, wvolt, il);
450 std::cout << hdr <<
"\n Read potentials from file " << wvolt <<
".\n";
458 const double z,
double& ex,
double& ey,
459 double& ez,
Medium*& m,
int& status) {
465 const double zin,
double& ex,
double& ey,
466 double& ez,
double& volt,
Medium*& m,
469 double x = xin, y = yin, z = zin;
472 bool xmirr, ymirr, zmirr;
473 double rcoordinate, rotation;
474 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
477 ex = ey = ez = volt = 0.;
491 double t1, t2, t3, t4, jac[4][4], det;
492 const int imap =
FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
495 std::cout <<
m_className <<
"::ElectricField:\n Point (" << x <<
", "
496 << y <<
", " << z <<
") is not in the mesh.\n";
504 PrintElement(
"ElectricField", x, y, z, t1, t2, t3, t4, element, 10);
517 const double fourt1 = 4 * t1;
518 const double fourt2 = 4 * t2;
519 const double fourt3 = 4 * t3;
520 const double fourt4 = 4 * t4;
521 const double invdet = 1. / det;
523 volt = n0.
v * t1 * (2 * t1 - 1) + n1.
v * t2 * (2 * t2 - 1) +
524 n2.
v * t3 * (2 * t3 - 1) + n3.
v * t4 * (2 * t4 - 1) +
525 4 * n4.
v * t1 * t2 + 4 * n5.
v * t1 * t3 + 4 * n6.
v * t1 * t4 +
526 4 * n7.
v * t2 * t3 + 4 * n8.
v * t2 * t4 + 4 * n9.
v * t3 * t4;
527 ex = -(n0.
v * (fourt1 - 1) * jac[0][1] + n1.
v * (fourt2 - 1) * jac[1][1] +
528 n2.
v * (fourt3 - 1) * jac[2][1] + n3.
v * (fourt4 - 1) * jac[3][1] +
529 n4.
v * (fourt2 * jac[0][1] + fourt1 * jac[1][1]) +
530 n5.
v * (fourt3 * jac[0][1] + fourt1 * jac[2][1]) +
531 n6.
v * (fourt4 * jac[0][1] + fourt1 * jac[3][1]) +
532 n7.
v * (fourt3 * jac[1][1] + fourt2 * jac[2][1]) +
533 n8.
v * (fourt4 * jac[1][1] + fourt2 * jac[3][1]) +
534 n9.
v * (fourt4 * jac[2][1] + fourt3 * jac[3][1])) *
536 ey = -(n0.
v * (fourt1 - 1) * jac[0][2] + n1.
v * (fourt2 - 1) * jac[1][2] +
537 n2.
v * (fourt3 - 1) * jac[2][2] + n3.
v * (fourt4 - 1) * jac[3][2] +
538 n4.
v * (fourt2 * jac[0][2] + fourt1 * jac[1][2]) +
539 n5.
v * (fourt3 * jac[0][2] + fourt1 * jac[2][2]) +
540 n6.
v * (fourt4 * jac[0][2] + fourt1 * jac[3][2]) +
541 n7.
v * (fourt3 * jac[1][2] + fourt2 * jac[2][2]) +
542 n8.
v * (fourt4 * jac[1][2] + fourt2 * jac[3][2]) +
543 n9.
v * (fourt4 * jac[2][2] + fourt3 * jac[3][2])) *
545 ez = -(n0.
v * (fourt1 - 1) * jac[0][3] + n1.
v * (fourt2 - 1) * jac[1][3] +
546 n2.
v * (fourt3 - 1) * jac[2][3] + n3.
v * (fourt4 - 1) * jac[3][3] +
547 n4.
v * (fourt2 * jac[0][3] + fourt1 * jac[1][3]) +
548 n5.
v * (fourt3 * jac[0][3] + fourt1 * jac[2][3]) +
549 n6.
v * (fourt4 * jac[0][3] + fourt1 * jac[3][3]) +
550 n7.
v * (fourt3 * jac[1][3] + fourt2 * jac[2][3]) +
551 n8.
v * (fourt4 * jac[1][3] + fourt2 * jac[3][3]) +
552 n9.
v * (fourt4 * jac[2][3] + fourt3 * jac[3][3])) *
556 UnmapFields(ex, ey, ez, x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
561 std::cout <<
m_className <<
"::ElectricField:\n Material "
570 const double zin,
double& wx,
double& wy,
571 double& wz,
const std::string& label) {
586 double x = xin, y = yin, z = zin;
589 bool xmirr, ymirr, zmirr;
590 double rcoordinate, rotation;
591 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
596 double t1, t2, t3, t4, jac[4][4], det;
597 const int imap =
FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
599 if (imap < 0)
return;
603 PrintElement(
"WeightingField", x, y, z, t1, t2, t3, t4, element, 10, iw);
616 const double fourt1 = 4 * t1;
617 const double fourt2 = 4 * t2;
618 const double fourt3 = 4 * t3;
619 const double fourt4 = 4 * t4;
620 const double invdet = 1. / det;
622 wx = -(n0.
w[iw] * (fourt1 - 1) * jac[0][1] +
623 n1.
w[iw] * (fourt2 - 1) * jac[1][1] +
624 n2.
w[iw] * (fourt3 - 1) * jac[2][1] +
625 n3.
w[iw] * (fourt4 - 1) * jac[3][1] +
626 n4.
w[iw] * (fourt2 * jac[0][1] + fourt1 * jac[1][1]) +
627 n5.
w[iw] * (fourt3 * jac[0][1] + fourt1 * jac[2][1]) +
628 n6.
w[iw] * (fourt4 * jac[0][1] + fourt1 * jac[3][1]) +
629 n7.
w[iw] * (fourt3 * jac[1][1] + fourt2 * jac[2][1]) +
630 n8.
w[iw] * (fourt4 * jac[1][1] + fourt2 * jac[3][1]) +
631 n9.
w[iw] * (fourt4 * jac[2][1] + fourt3 * jac[3][1])) *
633 wy = -(n0.
w[iw] * (fourt1 - 1) * jac[0][2] +
634 n1.
w[iw] * (fourt2 - 1) * jac[1][2] +
635 n2.
w[iw] * (fourt3 - 1) * jac[2][2] +
636 n3.
w[iw] * (fourt4 - 1) * jac[3][2] +
637 n4.
w[iw] * (fourt2 * jac[0][2] + fourt1 * jac[1][2]) +
638 n5.
w[iw] * (fourt3 * jac[0][2] + fourt1 * jac[2][2]) +
639 n6.
w[iw] * (fourt4 * jac[0][2] + fourt1 * jac[3][2]) +
640 n7.
w[iw] * (fourt3 * jac[1][2] + fourt2 * jac[2][2]) +
641 n8.
w[iw] * (fourt4 * jac[1][2] + fourt2 * jac[3][2]) +
642 n9.
w[iw] * (fourt4 * jac[2][2] + fourt3 * jac[3][2])) *
644 wz = -(n0.
w[iw] * (fourt1 - 1) * jac[0][3] +
645 n1.
w[iw] * (fourt2 - 1) * jac[1][3] +
646 n2.
w[iw] * (fourt3 - 1) * jac[2][3] +
647 n3.
w[iw] * (fourt4 - 1) * jac[3][3] +
648 n4.
w[iw] * (fourt2 * jac[0][3] + fourt1 * jac[1][3]) +
649 n5.
w[iw] * (fourt3 * jac[0][3] + fourt1 * jac[2][3]) +
650 n6.
w[iw] * (fourt4 * jac[0][3] + fourt1 * jac[3][3]) +
651 n7.
w[iw] * (fourt3 * jac[1][3] + fourt2 * jac[2][3]) +
652 n8.
w[iw] * (fourt4 * jac[1][3] + fourt2 * jac[3][3]) +
653 n9.
w[iw] * (fourt4 * jac[2][3] + fourt3 * jac[3][3])) *
657 UnmapFields(wx, wy, wz, x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
662 const std::string& label) {
674 double x = xin, y = yin, z = zin;
677 bool xmirr, ymirr, zmirr;
678 double rcoordinate, rotation;
679 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
684 double t1, t2, t3, t4, jac[4][4], det;
685 const int imap =
FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
686 if (imap < 0)
return 0.;
690 PrintElement(
"WeightingPotential", x, y, z, t1, t2, t3, t4, element, 10,
704 return n0.
w[iw] * t1 * (2 * t1 - 1) + n1.
w[iw] * t2 * (2 * t2 - 1) +
705 n2.
w[iw] * t3 * (2 * t3 - 1) + n3.
w[iw] * t4 * (2 * t4 - 1) +
706 4 * n4.
w[iw] * t1 * t2 + 4 * n5.
w[iw] * t1 * t3 +
707 4 * n6.
w[iw] * t1 * t4 + 4 * n7.
w[iw] * t2 * t3 +
708 4 * n8.
w[iw] * t2 * t4 + 4 * n9.
w[iw] * t3 * t4;
714 double x = xin, y = yin, z = zin;
717 bool xmirr, ymirr, zmirr;
718 double rcoordinate, rotation;
719 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
729 double t1, t2, t3, t4, jac[4][4], det;
730 const int imap =
FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
733 std::cout <<
m_className <<
"::GetMedium:\n Point (" << x <<
", " << y
734 <<
", " << z <<
") is not in the mesh.\n";
741 std::cerr <<
m_className <<
"::GetMedium:\n Point (" << x <<
", " << y
742 <<
", " << z <<
") has out of range material number " << imap
765 ((n1.
y - n0.
y) * (n2.
z - n0.
z) - (n2.
y - n0.
y) * (n1.
z - n0.
z)) +
767 ((n1.
z - n0.
z) * (n2.
x - n0.
x) - (n2.
z - n0.
z) * (n1.
x - n0.
x)) +
768 (n3.
z - n0.
z) * ((n1.
x - n0.
x) * (n2.
y - n0.
y) -
769 (n3.
x - n0.
x) * (n1.
y - n0.
y))) /
784 for (
int j = 0; j < np - 1; ++j) {
786 for (
int k = j + 1; k < np; ++k) {
789 const double dx = nj.
x - nk.
x;
790 const double dy = nj.
y - nk.
y;
791 const double dz = nj.
z - nk.
z;
792 const double dist = sqrt(dx * dx + dy * dy + dz * dz);
796 if (dist < dmin) dmin = dist;
797 if (dist > dmax) dmax = dist;
void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label) override
bool Initialise(const std::string &header="mesh.header", const std::string &elist="mesh.elements", const std::string &nlist="mesh.nodes", const std::string &mplist="dielectrics.dat", const std::string &volt="out.result", const std::string &unit="cm")
bool SetWeightingField(std::string prnsol, std::string label)
Import a list of voltages to be used as weighting field.
ComponentElmer()
Default constructor.
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status) override
double GetElementVolume(const unsigned int i) override
void GetAspectRatio(const unsigned int i, double &dmin, double &dmax) override
double WeightingPotential(const double x, const double y, const double z, const std::string &label) override
Medium * GetMedium(const double x, const double y, const double z) override
Get the medium at a given location (x, y, z).
Base class for components based on finite-element field maps.
bool SetDefaultDriftMedium()
Find lowest epsilon, check for eps = 0, set default drift media flags.
double ReadDouble(char *token, double def, bool &error)
void MapCoordinates(double &xpos, double &ypos, double &zpos, bool &xmirrored, bool &ymirrored, bool &zmirrored, double &rcoordinate, double &rotation) const
Move (xpos, ypos, zpos) to field map coordinates.
void PrintWarning(const std::string &header)
static double ScalingFactor(std::string unit)
int ReadInteger(char *token, int def, bool &error)
std::vector< Material > m_materials
std::vector< bool > m_wfieldsOk
size_t GetWeightingFieldIndex(const std::string &label) const
std::vector< Node > m_nodes
void PrintCouldNotOpen(const std::string &header, const std::string &filename) const
std::vector< std::string > m_wfields
int FindElement13(const double x, const double y, const double z, double &t1, double &t2, double &t3, double &t4, double jac[4][4], double &det)
Find the element for a point in curved quadratic tetrahedra.
std::vector< Element > m_elements
void PrintElement(const std::string &header, const double x, const double y, const double z, const double t1, const double t2, const double t3, const double t4, const Element &element, const unsigned int n, const int iw=-1) const
void Reset() override
Reset the component.
void UnmapFields(double &ex, double &ey, double &ez, double &xpos, double &ypos, double &zpos, bool &xmirrored, bool &ymirrored, bool &zmirrored, double &rcoordinate, double &rotation) const
Move (ex, ey, ez) to global coordinates.
void PrintNotReady(const std::string &header) const
size_t GetOrCreateWeightingFieldIndex(const std::string &label)
bool m_debug
Switch on/off debugging messages.
std::string m_className
Class name.
bool m_ready
Ready for use?
Abstract base class for media.
bool IsDriftable() const
Is charge carrier transport enabled in this medium?