10void PrintErrorReadingFile(
const std::string& hdr,
const std::string& file,
12 std::cerr << hdr <<
"\n Error reading file " << file <<
" (line " << line
29 const std::string& elist,
30 const std::string& nlist,
31 const std::string& mplist,
32 const std::string& volt,
33 const std::string& unit)
36 Initialise(header, elist, nlist, mplist, volt, unit);
40 const std::string& elist,
41 const std::string& nlist,
42 const std::string& mplist,
43 const std::string& volt,
44 const std::string& unit) {
45 const std::string hdr =
m_className +
"::Initialise:";
52 constexpr int size = 100;
56 std::ifstream fheader;
57 fheader.open(header.c_str(), std::ios::in);
65 bool readerror =
false;
66 bool readstop =
false;
70 fheader.getline(line, size,
'\n');
71 token = strtok(line,
" ");
72 const int nNodes =
ReadInteger(token, 0, readerror);
73 token = strtok(NULL,
" ");
74 const int nElements =
ReadInteger(token, 0, readerror);
75 std::cout << hdr <<
"\n Read " << nNodes <<
" nodes and " << nElements
76 <<
" elements from file " << header <<
".\n";
78 PrintErrorReadingFile(hdr, header, il);
88 fnodes.open(nlist.c_str(), std::ios::in);
97 std::cerr << hdr <<
" Unknown length unit " << unit <<
".\n";
101 if (
m_debug) std::cout << hdr <<
" Unit scaling factor = " << funit <<
".\n";
104 for (il = 0; il < nNodes; il++) {
106 fnodes.getline(line, size,
'\n');
109 token = strtok(line,
" ");
110 token = strtok(NULL,
" ");
113 token = strtok(NULL,
" ");
114 double xnode =
ReadDouble(token, -1, readerror);
115 token = strtok(NULL,
" ");
116 double ynode =
ReadDouble(token, -1, readerror);
117 token = strtok(NULL,
" ");
118 double znode =
ReadDouble(token, -1, readerror);
120 PrintErrorReadingFile(hdr, nlist, il);
128 newNode.
x = xnode * funit;
129 newNode.
y = ynode * funit;
130 newNode.
z = znode * funit;
131 m_nodes.push_back(std::move(newNode));
139 fvolt.open(volt.c_str(), std::ios::in);
149 while (!readstop && fvolt.getline(line, size,
'\n')) {
150 token = strtok(line,
" ");
151 if (strcmp(token,
"Perm:") == 0) readstop =
true;
157 std::cerr << hdr <<
"\n Error reading past header of potentials file "
164 for (
int tl = 0; tl < nNodes; tl++) {
165 fvolt.getline(line, size,
'\n');
170 for (
int tl = 0; tl < nNodes; tl++) {
171 fvolt.getline(line, size,
'\n');
172 token = strtok(line,
" ");
175 PrintErrorReadingFile(hdr, volt, il);
187 std::ifstream fmplist;
188 fmplist.open(mplist.c_str(), std::ios::in);
189 if (fmplist.fail()) {
195 fmplist.getline(line, size,
'\n');
196 token = strtok(line,
" ");
198 std::cerr << hdr <<
"\n Error reading number of materials from "
203 const unsigned int nMaterials =
ReadInteger(token, 0, readerror);
208 material.medium =
nullptr;
210 for (il = 2; il < ((int)nMaterials + 2); il++) {
211 fmplist.getline(line, size,
'\n');
212 token = strtok(line,
" ");
214 token = strtok(NULL,
" ");
215 double dc =
ReadDouble(token, -1.0, readerror);
217 PrintErrorReadingFile(hdr, mplist, il);
222 std::cout << hdr <<
"\n Set material " << il - 2 <<
" of "
223 << nMaterials <<
" to eps " << dc <<
".\n";
233 std::ifstream felems;
234 felems.open(elist.c_str(), std::ios::in);
243 for (il = 0; il < nElements; il++) {
245 felems.getline(line, size,
'\n');
248 token = strtok(line,
" ");
250 token = strtok(NULL,
" ");
252 token = strtok(NULL,
" ");
253 token = strtok(NULL,
" ");
255 token = strtok(NULL,
" ");
257 token = strtok(NULL,
" ");
259 token = strtok(NULL,
" ");
261 token = strtok(NULL,
" ");
263 token = strtok(NULL,
" ");
265 token = strtok(NULL,
" ");
267 token = strtok(NULL,
" ");
269 token = strtok(NULL,
" ");
272 std::cout <<
" Read nodes " << in0 <<
", " << in1 <<
", " << in2
273 <<
", " << in3 <<
", " << in4 <<
", " << in5 <<
", " << in6
274 <<
", " << in7 <<
", ... from element " << il + 1 <<
" of "
275 << nElements <<
" with mat " << imat <<
".\n";
280 PrintErrorReadingFile(hdr, elist, il);
286 if (imat < 0 || imat > (
int)nMaterials) {
287 std::cerr << hdr <<
"\n Out-of-range material number on file " << elist
288 <<
" (line " << il <<
").\n";
289 std::cerr <<
" Element: " << il <<
", material: " << imat <<
"\n";
290 std::cerr <<
" nodes: (" << in0 <<
", " << in1 <<
", " << in2 <<
", "
291 << in3 <<
", " << in4 <<
", " << in5 <<
", " << in6 <<
", "
296 std::cerr << hdr <<
"\n Element " << il <<
" in element list " << elist
297 <<
"\n uses material " << imat
298 <<
" which has not been assigned a positive permittivity in "
304 if (in0 < 1 || in1 < 1 || in2 < 1 || in3 < 1 || in4 < 1 || in5 < 1 ||
305 in6 < 1 || in7 < 1) {
306 std::cerr << hdr <<
"\n Found a node number < 1 on file " << elist
307 <<
" (line " << il <<
").\n Element: " << il
308 <<
", material: " << imat <<
"\n nodes: (" << in0 <<
", "
309 << in1 <<
", " << in2 <<
", " << in3 <<
", " << in4 <<
", "
310 << in5 <<
", " << in6 <<
", " << in7 <<
")\n";
313 if (in0 > highestnode) highestnode = in0;
314 if (in1 > highestnode) highestnode = in1;
315 if (in2 > highestnode) highestnode = in2;
316 if (in3 > highestnode) highestnode = in3;
317 if (in4 > highestnode) highestnode = in4;
318 if (in5 > highestnode) highestnode = in5;
319 if (in6 > highestnode) highestnode = in6;
320 if (in7 > highestnode) highestnode = in7;
323 if (in0 == in1 || in0 == in2 || in0 == in3 || in0 == in4 || in0 == in5 ||
324 in0 == in6 || in0 == in7 || in1 == in2 || in1 == in3 || in1 == in4 ||
325 in1 == in5 || in1 == in6 || in1 == in7 || in2 == in3 || in2 == in4 ||
326 in2 == in5 || in2 == in6 || in2 == in7 || in3 == in4 || in3 == in5 ||
327 in3 == in6 || in3 == in7 || in4 == in5 || in4 == in6 || in4 == in7 ||
328 in5 == in6 || in5 == in7 || in6 == in7) {
329 std::cerr << hdr <<
"\n Element " << il <<
" of file " << elist
330 <<
" is degenerate,\n"
331 <<
" no such elements are allowed in this type of map.\n";
352 double crossprod = x01*y12 - y01*x12;
354 newElement.
emap[3] = in0 - 1;
355 newElement.
emap[2] = in1 - 1;
356 newElement.
emap[1] = in2 - 1;
357 newElement.
emap[0] = in3 - 1;
358 newElement.
emap[6] = in4 - 1;
359 newElement.
emap[5] = in5 - 1;
360 newElement.
emap[4] = in6 - 1;
361 newElement.
emap[7] = in7 - 1;
363 newElement.
emap[0] = in0 - 1;
364 newElement.
emap[1] = in1 - 1;
365 newElement.
emap[2] = in2 - 1;
366 newElement.
emap[3] = in3 - 1;
367 newElement.
emap[4] = in4 - 1;
368 newElement.
emap[5] = in5 - 1;
369 newElement.
emap[6] = in6 - 1;
370 newElement.
emap[7] = in7 - 1;
382 std::cerr << hdr <<
"\n Field map could not be "
383 <<
"read and cannot be interpolated.\n";
387 std::cout << hdr <<
" Finished.\n";
398 const std::string hdr =
m_className +
"::SetWeightingField:";
401 std::cerr <<
" Weighting field cannot be added.\n";
406 std::ifstream fwvolt;
407 fwvolt.open(wvolt.c_str(), std::ios::in);
416 std::cout <<
m_className <<
"::SetWeightingField:\n"
417 <<
" Replacing existing weighting field " << label <<
".\n";
422 constexpr int size = 100;
425 bool readerror =
false;
426 bool readstop =
false;
430 while (!readstop && fwvolt.getline(line, size,
'\n')) {
431 token = strtok(line,
" ");
432 if (strcmp(token,
"Perm:") == 0) readstop =
true;
438 std::cerr << hdr <<
"\n Error reading past header of potentials file "
445 const int nNodes =
m_nodes.size();
446 for (
int tl = 0; tl < nNodes; tl++) {
447 fwvolt.getline(line, size,
'\n');
452 for (
int tl = 0; tl < nNodes; tl++) {
454 fwvolt.getline(line, size,
'\n');
455 token = strtok(line,
" ");
458 PrintErrorReadingFile(hdr, wvolt, il);
468 std::cout << hdr <<
"\n Read potentials from file " << wvolt <<
".\n";
476 const double z,
double& ex,
double& ey,
477 double& ez,
Medium*& m,
int& status) {
483 const double zin,
double& ex,
double& ey,
484 double& ez,
double& volt,
Medium*& m,
487 double x = xin, y = yin, z = 0.;
490 bool xmirr, ymirr, zmirr;
491 double rcoordinate, rotation;
492 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
495 ex = ey = ez = volt = 0.;
515 double t1, t2, t3, t4, jac[4][4], det;
516 const int imap =
FindElement5(x, y, z, t1, t2, t3, t4, jac, det);
519 std::cout <<
m_className <<
"::ElectricField:\n Point (" << x <<
", "
520 << y <<
", " << z <<
") is not in the mesh.\n";
528 PrintElement(
"ElectricField", x, y, z, t1, t2, t3, t4, element, 10);
540 const double invdet = 1. / det;
541 volt = -n0.
v * (1 - t1) * (1 - t2) * (1 + t1 + t2) * 0.25 -
542 n1.
v * (1 + t1) * (1 - t2) * (1 - t1 + t2) * 0.25 -
543 n2.
v * (1 + t1) * (1 + t2) * (1 - t1 - t2) * 0.25 -
544 n3.
v * (1 - t1) * (1 + t2) * (1 + t1 - t2) * 0.25 +
545 n4.
v * (1 - t1) * (1 + t1) * (1 - t2) * 0.5 +
546 n5.
v * (1 + t1) * (1 + t2) * (1 - t2) * 0.5 +
547 n6.
v * (1 - t1) * (1 + t1) * (1 + t2) * 0.5 +
548 n7.
v * (1 - t1) * (1 + t2) * (1 - t2) * 0.5;
549 ex = -(n0.
v * ((1 - t2) * (2 * t1 + t2) * jac[0][0] +
550 (1 - t1) * (t1 + 2 * t2) * jac[1][0]) *
552 n1.
v * ((1 - t2) * (2 * t1 - t2) * jac[0][0] -
553 (1 + t1) * (t1 - 2 * t2) * jac[1][0]) *
555 n2.
v * ((1 + t2) * (2 * t1 + t2) * jac[0][0] +
556 (1 + t1) * (t1 + 2 * t2) * jac[1][0]) *
558 n3.
v * ((1 + t2) * (2 * t1 - t2) * jac[0][0] -
559 (1 - t1) * (t1 - 2 * t2) * jac[1][0]) *
561 n4.
v * (t1 * (t2 - 1) * jac[0][0] +
562 (t1 - 1) * (t1 + 1) * jac[1][0] * 0.5) +
563 n5.
v * ((1 - t2) * (1 + t2) * jac[0][0] * 0.5 -
564 (1 + t1) * t2 * jac[1][0]) +
565 n6.
v * (-t1 * (1 + t2) * jac[0][0] +
566 (1 - t1) * (1 + t1) * jac[1][0] * 0.5) +
567 n7.
v * ((t2 - 1) * (t2 + 1) * jac[0][0] * 0.5 +
568 (t1 - 1) * t2 * jac[1][0])) *
570 ey = -(n0.
v * ((1 - t2) * (2 * t1 + t2) * jac[0][1] +
571 (1 - t1) * (t1 + 2 * t2) * jac[1][1]) *
573 n1.
v * ((1 - t2) * (2 * t1 - t2) * jac[0][1] -
574 (1 + t1) * (t1 - 2 * t2) * jac[1][1]) *
576 n2.
v * ((1 + t2) * (2 * t1 + t2) * jac[0][1] +
577 (1 + t1) * (t1 + 2 * t2) * jac[1][1]) *
579 n3.
v * ((1 + t2) * (2 * t1 - t2) * jac[0][1] -
580 (1 - t1) * (t1 - 2 * t2) * jac[1][1]) *
582 n4.
v * (t1 * (t2 - 1) * jac[0][1] +
583 (t1 - 1) * (t1 + 1) * jac[1][1] * 0.5) +
584 n5.
v * ((1 - t2) * (1 + t2) * jac[0][1] * 0.5 -
585 (1 + t1) * t2 * jac[1][1]) +
586 n6.
v * (-t1 * (1 + t2) * jac[0][1] +
587 (1 - t1) * (1 + t1) * jac[1][1] * 0.5) +
588 n7.
v * ((t2 - 1) * (t2 + 1) * jac[0][1] * 0.5 +
589 (t1 - 1) * t2 * jac[1][1])) *
593 UnmapFields(ex, ey, ez, x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
598 std::cout <<
m_className <<
"::ElectricField:\n Material "
607 const double zin,
double& wx,
double& wy,
608 double& wz,
const std::string& label) {
623 double x = xin, y = yin, z = 0.;
626 bool xmirr, ymirr, zmirr;
627 double rcoordinate, rotation;
628 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
638 double t1, t2, t3, t4, jac[4][4], det;
639 const int imap =
FindElement5(x, y, z, t1, t2, t3, t4, jac, det);
641 if (imap < 0)
return;
645 PrintElement(
"WeightingField", x, y, z, t1, t2, t3, t4, element, 10, iw);
656 const double invdet = 1. / det;
657 wx = -(n0.
w[iw] * ((1 - t2) * (2 * t1 + t2) * jac[0][0] +
658 (1 - t1) * (t1 + 2 * t2) * jac[1][0]) *
660 n1.
w[iw] * ((1 - t2) * (2 * t1 - t2) * jac[0][0] -
661 (1 + t1) * (t1 - 2 * t2) * jac[1][0]) *
663 n2.
w[iw] * ((1 + t2) * (2 * t1 + t2) * jac[0][0] +
664 (1 + t1) * (t1 + 2 * t2) * jac[1][0]) *
666 n3.
w[iw] * ((1 + t2) * (2 * t1 - t2) * jac[0][0] -
667 (1 - t1) * (t1 - 2 * t2) * jac[1][0]) *
669 n4.
w[iw] * (t1 * (t2 - 1) * jac[0][0] +
670 (t1 - 1) * (t1 + 1) * jac[1][0] * 0.5) +
671 n5.
w[iw] * ((1 - t2) * (1 + t2) * jac[0][0] * 0.5 -
672 (1 + t1) * t2 * jac[1][0]) +
673 n6.
w[iw] * (-t1 * (1 + t2) * jac[0][0] +
674 (1 - t1) * (1 + t1) * jac[1][0] * 0.5) +
675 n7.
w[iw] * ((t2 - 1) * (1 + t2) * jac[0][0] * 0.5 +
676 (t1 - 1) * t2 * jac[1][0])) *
678 wy = -(n0.
w[iw] * ((1 - t2) * (2 * t1 + t2) * jac[0][1] +
679 (1 - t1) * (t1 + 2 * t2) * jac[1][1]) *
681 n1.
w[iw] * ((1 - t2) * (2 * t1 - t2) * jac[0][1] -
682 (1 + t1) * (t1 - 2 * t2) * jac[1][1]) *
684 n2.
w[iw] * ((1 + t2) * (2 * t1 + t2) * jac[0][1] +
685 (1 + t1) * (t1 + 2 * t2) * jac[1][1]) *
687 n3.
w[iw] * ((1 + t2) * (2 * t1 - t2) * jac[0][1] -
688 (1 - t1) * (t1 - 2 * t2) * jac[1][1]) *
690 n4.
w[iw] * (t1 * (t2 - 1) * jac[0][1] +
691 (t1 - 1) * (t1 + 1) * jac[1][1] * 0.5) +
692 n5.
w[iw] * ((1 - t2) * (1 + t2) * jac[0][1] * 0.5 -
693 (1 + t1) * t2 * jac[1][1]) +
694 n6.
w[iw] * (-t1 * (1 + t2) * jac[0][1] +
695 (1 - t1) * (1 + t1) * jac[1][1] * 0.5) +
696 n7.
w[iw] * ((t2 - 1) * (t2 + 1) * jac[0][1] * 0.5 +
697 (t1 - 1) * t2 * jac[1][1])) *
701 UnmapFields(wx, wy, wz, x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
706 const std::string& label) {
718 double x = xin, y = yin, z = 0.;
721 bool xmirr, ymirr, zmirr;
722 double rcoordinate, rotation;
723 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
733 double t1, t2, t3, t4, jac[4][4], det;
734 const int imap =
FindElement5(x, y, z, t1, t2, t3, t4, jac, det);
735 if (imap < 0)
return 0.;
739 PrintElement(
"WeightingPotential", x, y, z, t1, t2, t3, t4, element, 10,
750 return -n0.
w[iw] * (1 - t1) * (1 - t2) * (1 + t1 + t2) * 0.25 -
751 n1.
w[iw] * (1 + t1) * (1 - t2) * (1 - t1 + t2) * 0.25 -
752 n2.
w[iw] * (1 + t1) * (1 + t2) * (1 - t1 - t2) * 0.25 -
753 n3.
w[iw] * (1 - t1) * (1 + t2) * (1 + t1 - t2) * 0.25 +
754 n4.
w[iw] * (1 - t1) * (1 + t1) * (1 - t2) * 0.5 +
755 n5.
w[iw] * (1 + t1) * (1 + t2) * (1 - t2) * 0.5 +
756 n6.
w[iw] * (1 - t1) * (1 + t1) * (1 + t2) * 0.5 +
757 n7.
w[iw] * (1 - t1) * (1 + t2) * (1 - t2) * 0.5;
763 double x = xin, y = yin, z = 0.;
766 bool xmirr, ymirr, zmirr;
767 double rcoordinate, rotation;
768 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
782 double t1, t2, t3, t4, jac[4][4], det;
783 const int imap =
FindElement5(x, y, z, t1, t2, t3, t4, jac, det);
786 std::cout <<
m_className <<
"::GetMedium:\n Point (" << x <<
", " << y
787 <<
", " << z <<
") is not in the mesh.\n";
794 std::cerr <<
m_className <<
"::GetMedium:\n Point (" << x <<
", " << y
795 <<
", " << z <<
") has out of range material number " << imap
808 if (fabs(zmax - zmin) <= 0.) {
809 std::cerr <<
m_className <<
"::SetRangeZ: Zero range is not permitted.\n";
831 (fabs((n1.
x - n0.
x) * (n2.
y - n0.
y) - (n2.
x - n0.
x) * (n1.
y - n0.
y)) +
832 fabs((n3.
x - n0.
x) * (n2.
y - n0.
y) - (n2.
x - n0.
x) * (n3.
y - n0.
y)));
846 for (
int j = 0; j < np - 1; ++j) {
848 for (
int k = j + 1; k < np; ++k) {
851 const double dx = nj.
x - nk.
x;
852 const double dy = nj.
y - nk.
y;
853 const double dist = sqrt(dx * dx + dy * dy);
857 if (dist < dmin) dmin = dist;
858 if (dist > dmax) dmax = dist;
Component for importing field maps computed by Elmer.
Medium * GetMedium(const double x, const double y, const double z) override
Get the medium at a given location (x, y, z).
bool SetWeightingField(std::string prnsol, std::string label)
Import a list of voltages to be used as weighting field.
ComponentElmer2D()
Default constructor.
double GetElementVolume(const unsigned int i) override
double WeightingPotential(const double x, const double y, const double z, const std::string &label) override
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status) override
void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label) override
void UpdatePeriodicity() override
Verify periodicities.
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")
void SetRangeZ(const double zmin, const double zmax)
void GetAspectRatio(const unsigned int i, double &dmin, double &dmax) override
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)
std::array< double, 3 > m_maxBoundingBox
std::array< double, 3 > m_mapmin
std::array< double, 3 > m_minBoundingBox
static double ScalingFactor(std::string unit)
void UpdatePeriodicityCommon()
int ReadInteger(char *token, int def, bool &error)
std::vector< Material > m_materials
std::vector< bool > m_wfieldsOk
size_t GetWeightingFieldIndex(const std::string &label) const
std::vector< Node > m_nodes
void PrintCouldNotOpen(const std::string &header, const std::string &filename) const
int FindElement5(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 quadrilaterals.
void UpdatePeriodicity2d()
std::vector< std::string > m_wfields
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
std::array< double, 3 > m_mapmax
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?