12void printErrorReadingFile(
const std::string& hdr,
const std::string& file,
14 std::cerr << hdr <<
":\n Error reading file " << file <<
" (line "
18void printErrorOpeningFile(
const std::string& hdr,
19 const std::string& filetype,
20 const std::string& filename) {
22 std::cerr << hdr <<
":\n Could not open " << filetype <<
" file "
23 << filename <<
" for reading.\n";
24 std::cerr <<
" The file perhaps does not exist.\n";
36 const std::string& elist,
37 const std::string& nlist,
38 const std::string& mplist,
39 const std::string& volt,
40 const std::string& unit)
44 Initialise(header, elist, nlist, mplist, volt, unit);
48 const std::string& elist,
49 const std::string& nlist,
50 const std::string& mplist,
51 const std::string& volt,
52 const std::string& unit) {
67 std::ifstream fheader;
68 fheader.open(header.c_str(), std::ios::in);
70 printErrorOpeningFile(
m_className +
"::Initialise",
"header", header);
75 bool readerror =
false;
76 bool readstop =
false;
80 fheader.getline(line, size,
'\n');
81 token = strtok(line,
" ");
83 token = strtok(NULL,
" ");
87 <<
" elements from file " << header <<
".\n";
89 printErrorReadingFile(
m_className +
"::Initialise", header, il);
99 fnodes.open(nlist.c_str(), std::ios::in);
101 printErrorOpeningFile(
m_className +
"::Initialise",
"nodes", nlist);
106 if (strcmp(unit.c_str(),
"mum") == 0 || strcmp(unit.c_str(),
"micron") == 0 ||
107 strcmp(unit.c_str(),
"micrometer") == 0) {
109 }
else if (strcmp(unit.c_str(),
"mm") == 0 ||
110 strcmp(unit.c_str(),
"millimeter") == 0) {
112 }
else if (strcmp(unit.c_str(),
"cm") == 0 ||
113 strcmp(unit.c_str(),
"centimeter") == 0) {
115 }
else if (strcmp(unit.c_str(),
"m") == 0 ||
116 strcmp(unit.c_str(),
"meter") == 0) {
120 <<
" Unknown length unit " << unit <<
".\n";
126 <<
" Unit scaling factor = " << funit <<
".\n";
132 for (il = 0; il <
nNodes; il++) {
135 fnodes.getline(line, size,
'\n');
138 token = strtok(line,
" ");
139 token = strtok(NULL,
" ");
142 token = strtok(NULL,
" ");
143 double xnode =
ReadDouble(token, -1, readerror);
144 token = strtok(NULL,
" ");
145 double ynode =
ReadDouble(token, -1, readerror);
146 token = strtok(NULL,
" ");
147 double znode =
ReadDouble(token, -1, readerror);
149 printErrorReadingFile(
m_className +
"::Initialise", nlist, il);
155 newNode.
x = xnode * funit;
156 newNode.
y = ynode * funit;
157 newNode.
z = znode * funit;
158 nodes.push_back(newNode);
166 fvolt.open(volt.c_str(), std::ios::in);
168 printErrorOpeningFile(
m_className +
"::Initialise",
"potentials", volt);
175 while (!readstop && fvolt.getline(line, size,
'\n')) {
176 token = strtok(line,
" ");
177 if (strcmp(token,
"Perm:") == 0) readstop =
true;
183 std::cerr <<
m_className <<
"::Initialise:\n Error reading past header "
184 <<
"of potentials file " << volt <<
".\n";
190 for (
int tl = 0; tl <
nNodes; tl++) {
191 fvolt.getline(line, size,
'\n');
196 for (
int tl = 0; tl <
nNodes; tl++) {
198 fvolt.getline(line, size,
'\n');
199 token = strtok(line,
" ");
202 printErrorReadingFile(
m_className +
"::Initialise", volt, il);
214 std::ifstream fmplist;
215 fmplist.open(mplist.c_str(), std::ios::in);
216 if (fmplist.fail()) {
217 printErrorOpeningFile(
m_className +
"::Initialise",
"materials", mplist);
221 fmplist.getline(line, size,
'\n');
222 token = strtok(line,
" ");
225 <<
"Error reading number of materials from " << mplist <<
".\n";
238 fmplist.getline(line, size,
'\n');
239 token = strtok(line,
" ");
241 token = strtok(NULL,
" ");
242 double dc =
ReadDouble(token, -1.0, readerror);
244 printErrorReadingFile(
m_className +
"::Initialise", mplist, il);
250 std::cout <<
m_className <<
"::Initialise:\n Set material " << il - 2
259 unsigned int iepsmin = 0;
260 for (
unsigned int imat = 0; imat <
m_nMaterials; ++imat) {
263 std::cerr <<
m_className <<
"::Initialise:\n Material " << imat
264 <<
" has been assigned a permittivity equal to zero in\n "
267 }
else if (epsmin < 0. || epsmin >
materials[imat].eps) {
275 <<
" No material with positive permittivity found \n"
276 <<
" in material list " << mplist <<
".\n";
279 for (
unsigned int imat = 0; imat <
m_nMaterials; ++imat) {
280 if (imat == iepsmin) {
289 std::ifstream felems;
290 felems.open(elist.c_str(), std::ios::in);
292 printErrorOpeningFile(
m_className +
"::Initialise",
"elements", elist);
302 felems.getline(line, size,
'\n');
305 token = strtok(line,
" ");
313 token = strtok(NULL,
" ");
315 token = strtok(NULL,
" ");
316 token = strtok(NULL,
" ");
318 token = strtok(NULL,
" ");
320 token = strtok(NULL,
" ");
322 token = strtok(NULL,
" ");
324 token = strtok(NULL,
" ");
326 token = strtok(NULL,
" ");
328 token = strtok(NULL,
" ");
330 token = strtok(NULL,
" ");
332 token = strtok(NULL,
" ");
334 token = strtok(NULL,
" ");
338 std::cout <<
" Read nodes " << in0 <<
", " << in1 <<
", " << in2
339 <<
", " << in3 <<
", ... from element " << il + 1 <<
" of "
340 <<
nElements <<
" with mat " << imat <<
".\n";
345 printErrorReadingFile(
m_className +
"::Initialise", elist, il);
354 std::cerr <<
" Out-of-range material number on file " << elist
355 <<
" (line " << il <<
").\n";
356 std::cerr <<
" Element: " << il <<
", material: " << imat <<
"\n";
357 std::cerr <<
" nodes: (" << in0 <<
", " << in1 <<
", " << in2 <<
", "
358 << in3 <<
", " << in4 <<
", " << in5 <<
", " << in6 <<
", "
359 << in7 <<
", " << in8 <<
", " << in9 <<
")\n";
364 std::cerr <<
" Element " << il <<
" in element list " << elist <<
"\n";
365 std::cerr <<
" uses material " << imat
366 <<
" which has not been assigned\n";
367 std::cerr <<
" a positive permittivity in material list " << mplist
373 if (in0 < 1 || in1 < 1 || in2 < 1 || in3 < 1 || in4 < 1 || in5 < 1 ||
374 in6 < 1 || in7 < 1 || in8 < 1 || in9 < 1) {
376 std::cerr <<
" Found a node number < 1 on file " << elist <<
" (line "
378 std::cerr <<
" Element: " << il <<
", material: " << imat <<
"\n";
379 std::cerr <<
" nodes: (" << in0 <<
", " << in1 <<
", " << in2 <<
", "
380 << in3 <<
", " << in4 <<
", " << in5 <<
", " << in6 <<
", "
381 << in7 <<
", " << in8 <<
", " << in9 <<
")\n";
384 if (in0 > highestnode) highestnode = in0;
385 if (in1 > highestnode) highestnode = in1;
386 if (in2 > highestnode) highestnode = in2;
387 if (in3 > highestnode) highestnode = in3;
388 if (in4 > highestnode) highestnode = in4;
389 if (in5 > highestnode) highestnode = in5;
390 if (in6 > highestnode) highestnode = in6;
391 if (in7 > highestnode) highestnode = in7;
392 if (in8 > highestnode) highestnode = in8;
393 if (in9 > highestnode) highestnode = in9;
396 if (in0 == in1 || in0 == in2 || in0 == in3 || in0 == in4 || in0 == in5 ||
397 in0 == in6 || in0 == in7 || in0 == in8 || in0 == in9 || in1 == in2 ||
398 in1 == in3 || in1 == in4 || in1 == in5 || in1 == in6 || in1 == in7 ||
399 in1 == in8 || in1 == in9 || in2 == in3 || in2 == in4 || in2 == in5 ||
400 in2 == in6 || in2 == in7 || in2 == in8 || in2 == in9 || in3 == in4 ||
401 in3 == in5 || in3 == in6 || in3 == in7 || in3 == in8 || in3 == in9 ||
402 in4 == in5 || in4 == in6 || in4 == in7 || in4 == in8 || in4 == in9 ||
403 in5 == in6 || in5 == in7 || in5 == in8 || in5 == in9 || in6 == in7 ||
404 in6 == in8 || in6 == in9 || in7 == in8 || in7 == in9 || in8 == in9) {
405 std::cerr <<
m_className <<
"::Initialise:\n Element " << il
406 <<
" of file " << elist <<
" is degenerate,\n"
407 <<
" no such elements are allowed in this type of map.\n";
417 newElement.
emap[0] = in0 - 1;
418 newElement.
emap[1] = in1 - 1;
419 newElement.
emap[2] = in2 - 1;
420 newElement.
emap[3] = in3 - 1;
421 newElement.
emap[4] = in4 - 1;
422 newElement.
emap[7] = in5 - 1;
423 newElement.
emap[5] = in6 - 1;
424 newElement.
emap[6] = in7 - 1;
425 newElement.
emap[8] = in8 - 1;
426 newElement.
emap[9] = in9 - 1;
437 std::cerr <<
m_className <<
"::Initialise:\n Field map could not be "
438 <<
"read and cannot be interpolated.\n";
442 std::cout <<
m_className <<
"::Initialise:\n Finished.\n";
459 std::cerr <<
" Weighting field cannot be added.\n";
467 std::ifstream fwvolt;
468 fwvolt.open(wvolt.c_str(), std::ios::in);
470 printErrorOpeningFile(
m_className +
"::SetWeightingField",
488 for (
int j =
nNodes; j--;) {
492 std::cout <<
m_className <<
"::SetWeightingField:\n"
493 <<
" Replacing existing weighting field " << label <<
".\n";
499 const int size = 100;
502 bool readerror =
false;
503 bool readstop =
false;
507 while (!readstop && fwvolt.getline(line, size,
'\n')) {
508 token = strtok(line,
" ");
509 if (strcmp(token,
"Perm:") == 0) readstop =
true;
515 std::cerr <<
m_className <<
"::SetWeightingField:\n Error reading past "
516 <<
"header of potentials file " << wvolt <<
".\n";
523 for (
int tl = 0; tl <
nNodes; tl++) {
524 fwvolt.getline(line, size,
'\n');
529 for (
int tl = 0; tl <
nNodes; tl++) {
531 fwvolt.getline(line, size,
'\n');
532 token = strtok(line,
" ");
535 printErrorReadingFile(
m_className +
"::SetWeightingField", wvolt, il);
546 std::cout <<
m_className <<
"::SetWeightingField:\n"
547 <<
" Read potentials from file " << wvolt.c_str() <<
".\n";
552 std::cerr <<
m_className <<
"::SetWeightingField:\n Field map could not "
553 <<
"be read and cannot be interpolated.\n";
560 const double z,
double& ex,
double& ey,
561 double& ez,
Medium*& m,
int& status) {
568 const double zin,
double& ex,
double& ey,
569 double& ez,
double& volt,
Medium*& m,
573 double x = xin, y = yin, z = zin;
576 bool xmirr, ymirr, zmirr;
577 double rcoordinate, rotation;
578 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
581 ex = ey = ez = volt = 0.;
595 double t1, t2, t3, t4, jac[4][4], det;
596 const int imap =
FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
599 std::cout <<
m_className <<
"::ElectricField:\n Point ("
600 << x <<
", " << y <<
", " << z <<
") is not in the mesh.\n";
607 PrintElement(
"ElectricField", x, y, z, t1, t2, t3, t4, imap, 10);
622 volt = n0.
v * t1 * (2 * t1 - 1) + n1.
v * t2 * (2 * t2 - 1) +
623 n2.
v * t3 * (2 * t3 - 1) + n3.
v * t4 * (2 * t4 - 1) +
624 4 * n4.
v * t1 * t2 + 4 * n5.
v * t1 * t3 + 4 * n6.
v * t1 * t4 +
625 4 * n7.
v * t2 * t3 + 4 * n8.
v * t2 * t4 + 4 * n9.
v * t3 * t4;
626 const double invdet = 1. / det;
627 ex = -(n0.
v * (4 * t1 - 1) * jac[0][1] + n1.
v * (4 * t2 - 1) * jac[1][1] +
628 n2.
v * (4 * t3 - 1) * jac[2][1] + n3.
v * (4 * t4 - 1) * jac[3][1] +
629 n4.
v * (4 * t2 * jac[0][1] + 4 * t1 * jac[1][1]) +
630 n5.
v * (4 * t3 * jac[0][1] + 4 * t1 * jac[2][1]) +
631 n6.
v * (4 * t4 * jac[0][1] + 4 * t1 * jac[3][1]) +
632 n7.
v * (4 * t3 * jac[1][1] + 4 * t2 * jac[2][1]) +
633 n8.
v * (4 * t4 * jac[1][1] + 4 * t2 * jac[3][1]) +
634 n9.
v * (4 * t4 * jac[2][1] + 4 * t3 * jac[3][1])) * invdet;
635 ey = -(n0.
v * (4 * t1 - 1) * jac[0][2] + n1.
v * (4 * t2 - 1) * jac[1][2] +
636 n2.
v * (4 * t3 - 1) * jac[2][2] + n3.
v * (4 * t4 - 1) * jac[3][2] +
637 n4.
v * (4 * t2 * jac[0][2] + 4 * t1 * jac[1][2]) +
638 n5.
v * (4 * t3 * jac[0][2] + 4 * t1 * jac[2][2]) +
639 n6.
v * (4 * t4 * jac[0][2] + 4 * t1 * jac[3][2]) +
640 n7.
v * (4 * t3 * jac[1][2] + 4 * t2 * jac[2][2]) +
641 n8.
v * (4 * t4 * jac[1][2] + 4 * t2 * jac[3][2]) +
642 n9.
v * (4 * t4 * jac[2][2] + 4 * t3 * jac[3][2])) * invdet;
643 ez = -(n0.
v * (4 * t1 - 1) * jac[0][3] + n1.
v * (4 * t2 - 1) * jac[1][3] +
644 n2.
v * (4 * t3 - 1) * jac[2][3] + n3.
v * (4 * t4 - 1) * jac[3][3] +
645 n4.
v * (4 * t2 * jac[0][3] + 4 * t1 * jac[1][3]) +
646 n5.
v * (4 * t3 * jac[0][3] + 4 * t1 * jac[2][3]) +
647 n6.
v * (4 * t4 * jac[0][3] + 4 * t1 * jac[3][3]) +
648 n7.
v * (4 * t3 * jac[1][3] + 4 * t2 * jac[2][3]) +
649 n8.
v * (4 * t4 * jac[1][3] + 4 * t2 * jac[3][3]) +
650 n9.
v * (4 * t4 * jac[2][3] + 4 * t3 * jac[3][3])) * invdet;
653 UnmapFields(ex, ey, ez, x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
658 std::cout <<
m_className <<
"::ElectricField:\n Material "
667 const double zin,
double& wx,
double& wy,
668 double& wz,
const std::string& label) {
693 double x = xin, y = yin, z = zin;
696 bool xmirr, ymirr, zmirr;
697 double rcoordinate, rotation;
698 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
703 double t1, t2, t3, t4, jac[4][4], det;
704 const int imap =
FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
706 if (imap < 0)
return;
709 PrintElement(
"WeightingField", x, y, z, t1, t2, t3, t4, imap, 10, iw);
724 const double invdet = 1. / det;
725 wx = -(n0.
w[iw] * (4 * t1 - 1) * jac[0][1] +
726 n1.
w[iw] * (4 * t2 - 1) * jac[1][1] +
727 n2.
w[iw] * (4 * t3 - 1) * jac[2][1] +
728 n3.
w[iw] * (4 * t4 - 1) * jac[3][1] +
729 n4.
w[iw] * (4 * t2 * jac[0][1] + 4 * t1 * jac[1][1]) +
730 n5.
w[iw] * (4 * t3 * jac[0][1] + 4 * t1 * jac[2][1]) +
731 n6.
w[iw] * (4 * t4 * jac[0][1] + 4 * t1 * jac[3][1]) +
732 n7.
w[iw] * (4 * t3 * jac[1][1] + 4 * t2 * jac[2][1]) +
733 n8.
w[iw] * (4 * t4 * jac[1][1] + 4 * t2 * jac[3][1]) +
734 n9.
w[iw] * (4 * t4 * jac[2][1] + 4 * t3 * jac[3][1])) * invdet;
735 wy = -(n0.
w[iw] * (4 * t1 - 1) * jac[0][2] +
736 n1.
w[iw] * (4 * t2 - 1) * jac[1][2] +
737 n2.
w[iw] * (4 * t3 - 1) * jac[2][2] +
738 n3.
w[iw] * (4 * t4 - 1) * jac[3][2] +
739 n4.
w[iw] * (4 * t2 * jac[0][2] + 4 * t1 * jac[1][2]) +
740 n5.
w[iw] * (4 * t3 * jac[0][2] + 4 * t1 * jac[2][2]) +
741 n6.
w[iw] * (4 * t4 * jac[0][2] + 4 * t1 * jac[3][2]) +
742 n7.
w[iw] * (4 * t3 * jac[1][2] + 4 * t2 * jac[2][2]) +
743 n8.
w[iw] * (4 * t4 * jac[1][2] + 4 * t2 * jac[3][2]) +
744 n9.
w[iw] * (4 * t4 * jac[2][2] + 4 * t3 * jac[3][2])) * invdet;
745 wz = -(n0.
w[iw] * (4 * t1 - 1) * jac[0][3] +
746 n1.
w[iw] * (4 * t2 - 1) * jac[1][3] +
747 n2.
w[iw] * (4 * t3 - 1) * jac[2][3] +
748 n3.
w[iw] * (4 * t4 - 1) * jac[3][3] +
749 n4.
w[iw] * (4 * t2 * jac[0][3] + 4 * t1 * jac[1][3]) +
750 n5.
w[iw] * (4 * t3 * jac[0][3] + 4 * t1 * jac[2][3]) +
751 n6.
w[iw] * (4 * t4 * jac[0][3] + 4 * t1 * jac[3][3]) +
752 n7.
w[iw] * (4 * t3 * jac[1][3] + 4 * t2 * jac[2][3]) +
753 n8.
w[iw] * (4 * t4 * jac[1][3] + 4 * t2 * jac[3][3]) +
754 n9.
w[iw] * (4 * t4 * jac[2][3] + 4 * t3 * jac[3][3])) * invdet;
757 UnmapFields(wx, wy, wz, x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
762 const std::string& label) {
779 if (!found)
return 0.;
784 double x = xin, y = yin, z = zin;
787 bool xmirr, ymirr, zmirr;
788 double rcoordinate, rotation;
789 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
794 double t1, t2, t3, t4, jac[4][4], det;
795 const int imap =
FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
796 if (imap < 0)
return 0.;
799 PrintElement(
"WeightingPotential", x, y, z, t1, t2, t3, t4, imap, 10, iw);
814 return n0.
w[iw] * t1 * (2 * t1 - 1) + n1.
w[iw] * t2 * (2 * t2 - 1) +
815 n2.
w[iw] * t3 * (2 * t3 - 1) + n3.
w[iw] * t4 * (2 * t4 - 1) +
816 4 * n4.
w[iw] * t1 * t2 + 4 * n5.
w[iw] * t1 * t3 +
817 4 * n6.
w[iw] * t1 * t4 + 4 * n7.
w[iw] * t2 * t3 +
818 4 * n8.
w[iw] * t2 * t4 + 4 * n9.
w[iw] * t3 * t4;
825 double x = xin, y = yin, z = zin;
828 bool xmirr, ymirr, zmirr;
829 double rcoordinate, rotation;
830 MapCoordinates(x, y, z, xmirr, ymirr, zmirr, rcoordinate, rotation);
840 double t1, t2, t3, t4, jac[4][4], det;
841 const int imap =
FindElement13(x, y, z, t1, t2, t3, t4, jac, det);
844 std::cout <<
m_className <<
"::GetMedium:\n Point ("
845 << x <<
", " << y <<
", " << z <<
") is not in the mesh.\n";
852 std::cerr <<
m_className <<
"::GetMedium:\n Point ("
853 << x <<
", " << y <<
", " << z
854 <<
") has out of range material number " << imap <<
".\n";
866 if (i >=
elements.size())
return 0.;
877 ((n1.
y - n0.
y) * (n2.
z - n0.
z) - (n2.
y - n0.
y) * (n1.
z - n0.
z)) +
879 ((n1.
z - n0.
z) * (n2.
x - n0.
x) - (n2.
z - n0.
z) * (n1.
x - n0.
x)) +
880 (n3.
z - n0.
z) * ((n1.
x - n0.
x) * (n2.
y - n0.
y) -
881 (n3.
x - n0.
x) * (n1.
y - n0.
y))) /
897 for (
int j = 0; j < np - 1; ++j) {
899 for (
int k = j + 1; k < np; ++k) {
902 const double dx = nj.
x - nk.
x;
903 const double dy = nj.
y - nk.
y;
904 const double dz = nj.
z - nk.
z;
905 const double dist = sqrt(dx * dx + dy * dy + dz * dz);
909 if (dist < dmin) dmin = dist;
910 if (dist > dmax) dmax = dist;
bool m_ready
Ready for use?
std::string m_className
Class name.
bool m_debug
Switch on/off debugging messages.
double WeightingPotential(const double x, const double y, const double z, const std::string &label)
Medium * GetMedium(const double x, const double y, const double z)
Get the medium at a given location (x, y, z).
void ElectricField(const double x, const double y, const double z, double &ex, double &ey, double &ez, Medium *&m, int &status)
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 GetAspectRatio(const unsigned int i, double &dmin, double &dmax)
bool SetWeightingField(std::string prnsol, std::string label)
Import a list of voltages to be used as weighting field.
ComponentElmer()
Default constructor.
void WeightingField(const double x, const double y, const double z, double &wx, double &wy, double &wz, const std::string &label)
void UpdatePeriodicity()
Verify periodicities.
double GetElementVolume(const unsigned int i)
Base class for components based on finite-element field maps.
double ReadDouble(char *token, double def, bool &error)
std::vector< bool > wfieldsOk
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)
int ReadInteger(char *token, int def, bool &error)
unsigned int m_nMaterials
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 unsigned int i, const unsigned int n, const int iw=-1) const
std::vector< Material > materials
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< Node > nodes
virtual void SetRange()
Calculate x, y, z, V and angular ranges.
std::vector< Element > elements
std::vector< std::string > wfields
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
Abstract base class for media.