Garfield++ 3.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
ComponentFieldMap.cc
Go to the documentation of this file.
1#include <stdio.h>
2#include <algorithm>
3#include <fstream>
4#include <iostream>
5
6#include <math.h>
7#include <string>
8
11
12namespace Garfield {
13
15 m_className = "ComponentFieldMap";
16}
17
19 if (m_tetTree) delete m_tetTree;
20}
21
23 // Do not proceed if not properly initialised.
24 if (!m_ready) PrintNotReady("PrintMaterials");
25
26 if (materials.empty()) {
27 std::cerr << m_className << "::PrintMaterials:\n"
28 << " No materials are currently defined.\n";
29 return;
30 }
31
32 std::cout << m_className << "::PrintMaterials:\n"
33 << " Currently " << m_nMaterials << " materials are defined.\n"
34 << " Index Permittivity Resistivity Notes\n";
35 for (unsigned int i = 0; i < m_nMaterials; ++i) {
36 printf(" %5d %12g %12g", i, materials[i].eps, materials[i].ohm);
37 if (materials[i].medium) {
38 std::string name = materials[i].medium->GetName();
39 std::cout << " " << name;
40 if (materials[i].medium->IsDriftable()) std::cout << ", drift medium";
41 if (materials[i].medium->IsIonisable()) std::cout << ", ionisable";
42 }
43 if (materials[i].driftmedium) {
44 std::cout << " (drift medium)\n";
45 } else {
46 std::cout << "\n";
47 }
48 }
49}
50
51void ComponentFieldMap::DriftMedium(const unsigned int imat) {
52 // Do not proceed if not properly initialised.
53 if (!m_ready) PrintNotReady("DriftMedium");
54
55 // Check value
56 if (imat >= m_nMaterials) {
57 std::cerr << m_className << "::DriftMedium: Index out of range.\n";
58 return;
59 }
60
61 // Make drift medium
62 materials[imat].driftmedium = true;
63}
64
65void ComponentFieldMap::NotDriftMedium(const unsigned int imat) {
66 // Do not proceed if not properly initialised.
67 if (!m_ready) PrintNotReady("NotDriftMedium");
68
69 // Check value
70 if (imat >= m_nMaterials) {
71 std::cerr << m_className << "::NotDriftMedium: Index out of range.\n";
72 return;
73 }
74
75 // Make drift medium
76 materials[imat].driftmedium = false;
77}
78
79double ComponentFieldMap::GetPermittivity(const unsigned int imat) const {
80 if (imat >= m_nMaterials) {
81 std::cerr << m_className << "::GetPermittivity: Index out of range.\n";
82 return -1.;
83 }
84
85 return materials[imat].eps;
86}
87
88double ComponentFieldMap::GetConductivity(const unsigned int imat) const {
89 if (imat >= m_nMaterials) {
90 std::cerr << m_className << "::GetConductivity: Index out of range.\n";
91 return -1.;
92 }
93
94 return materials[imat].ohm;
95}
96
97void ComponentFieldMap::SetMedium(const unsigned int imat, Medium* m) {
98 if (imat >= m_nMaterials) {
99 std::cerr << m_className << "::SetMedium:\n";
100 std::cerr << " Material index " << imat << " is out of range.\n";
101 return;
102 }
103
104 if (!m) {
105 std::cerr << m_className << "::SetMedium: Null pointer.\n";
106 return;
107 }
108
109 if (m_debug) {
110 std::cout << m_className << "::SetMedium:\n Associated material " << imat
111 << " with medium " << m->GetName() << ".\n";
112 }
113
114 materials[imat].medium = m;
115}
116
117Medium* ComponentFieldMap::GetMedium(const unsigned int imat) const {
118 if (imat >= m_nMaterials) {
119 std::cerr << m_className << "::GetMedium:\n"
120 << " Material index " << imat << " is out of range.\n";
121 return nullptr;
122 }
123
124 return materials[imat].medium;
125}
126
127bool ComponentFieldMap::GetElement(const unsigned int i, double& vol,
128 double& dmin, double& dmax) {
129 if ((int)i >= nElements) {
130 std::cerr << m_className << "::GetElement:\n";
131 std::cerr << " Element index (" << i << ") out of range.\n";
132 return false;
133 }
134
135 vol = GetElementVolume(i);
136 GetAspectRatio(i, dmin, dmax);
137 return true;
138}
139
140int ComponentFieldMap::FindElement5(const double x, const double y,
141 double const z, double& t1, double& t2,
142 double& t3, double& t4, double jac[4][4],
143 double& det) {
144 // Check if bounding boxes of elements have been computed
145 if (!m_cacheElemBoundingBoxes) {
146 std::cout << m_className << "::FindElement5:\n"
147 << " Caching the bounding boxes of all elements...";
148 CalculateElementBoundingBoxes();
149 std::cout << " done.\n";
150 m_cacheElemBoundingBoxes = true;
151 }
152
153 // Tetra list in the block that contains the input 3D point.
154 std::vector<int> tetList;
155 if (m_useTetrahedralTree) {
156 if (!m_isTreeInitialized) {
157 if (!InitializeTetrahedralTree()) {
158 std::cerr << m_className << "::FindElement5:\n";
159 std::cerr << " Tetrahedral tree initialization failed.\n";
160 return -1;
161 }
162 }
163 tetList = m_tetTree->GetTetListInBlock(Vec3(x, y, z));
164 }
165 // Backup
166 double jacbak[4][4], detbak = 1.;
167 double t1bak = 0., t2bak = 0., t3bak = 0., t4bak = 0.;
168 int imapbak = -1;
169
170 // Initial values.
171 t1 = t2 = t3 = t4 = 0;
172
173 // Check previously used element
174 if (m_lastElement > -1 && !m_checkMultipleElement) {
175 const Element& element = elements[m_lastElement];
176 if (element.degenerate) {
177 if (Coordinates3(x, y, z, t1, t2, t3, t4, jac, det, element) == 0) {
178 if (t1 >= 0 && t1 <= +1 && t2 >= 0 && t2 <= +1 && t3 >= 0 && t3 <= +1) {
179 return m_lastElement;
180 }
181 }
182 } else {
183 if (Coordinates5(x, y, z, t1, t2, t3, t4, jac, det, element) == 0) {
184 if (t1 >= -1 && t1 <= +1 && t2 >= -1 && t2 <= +1) return m_lastElement;
185 }
186 }
187 }
188
189 // Verify the count of volumes that contain the point.
190 int nfound = 0;
191 int imap = -1;
192
193 // Number of elements to scan.
194 // With tetra tree disabled, all elements are scanned.
195 const int numElemToSearch = m_useTetrahedralTree ? tetList.size() : nElements;
196 for (int i = 0; i < numElemToSearch; ++i) {
197 const int idxToElemList = m_useTetrahedralTree ? tetList[i] : i;
198 const Element& element = elements[idxToElemList];
199 if (x < element.xmin || x > element.xmax || y < element.ymin ||
200 y > element.ymax || z < element.zmin || z > element.zmax)
201 continue;
202 if (element.degenerate) {
203 // Degenerate element
204 if (Coordinates3(x, y, z, t1, t2, t3, t4, jac, det, element) != 0) {
205 continue;
206 }
207 if (t1 < 0 || t1 > 1 || t2 < 0 || t2 > 1 || t3 < 0 || t3 > 1) continue;
208 ++nfound;
209 imap = idxToElemList;
210 m_lastElement = idxToElemList;
211 if (m_debug) {
212 std::cout << m_className << "::FindElement5:\n";
213 std::cout << " Found matching degenerate element " << idxToElemList
214 << ".\n";
215 }
216 if (!m_checkMultipleElement) return idxToElemList;
217 for (int j = 0; j < 4; ++j) {
218 for (int k = 0; k < 4; ++k) jacbak[j][k] = jac[j][k];
219 }
220 detbak = det;
221 t1bak = t1;
222 t2bak = t2;
223 t3bak = t3;
224 t4bak = t4;
225 imapbak = imap;
226 if (m_debug) {
227 PrintElement("FindElement5", x, y, z, t1, t2, t3, t4, element, 6);
228 }
229 } else {
230 // Non-degenerate element
231 if (Coordinates5(x, y, z, t1, t2, t3, t4, jac, det, element) != 0) {
232 continue;
233 }
234 if (t1 < -1 || t1 > 1 || t2 < -1 || t2 > 1) continue;
235 ++nfound;
236 imap = idxToElemList;
237 m_lastElement = idxToElemList;
238 if (m_debug) {
239 std::cout << m_className << "::FindElement5:\n";
240 std::cout << " Found matching non-degenerate element "
241 << idxToElemList << ".\n";
242 }
243 if (!m_checkMultipleElement) return idxToElemList;
244 for (int j = 0; j < 4; ++j) {
245 for (int k = 0; k < 4; ++k) jacbak[j][k] = jac[j][k];
246 }
247 detbak = det;
248 t1bak = t1;
249 t2bak = t2;
250 t3bak = t3;
251 t4bak = t4;
252 imapbak = imap;
253 if (m_debug) {
254 PrintElement("FindElement5", x, y, z, t1, t2, t3, t4, element, 8);
255 }
256 }
257 }
258
259 // In checking mode, verify the tetrahedron/triangle count.
260 if (m_checkMultipleElement) {
261 if (nfound < 1) {
262 if (m_debug) {
263 std::cout << m_className << "::FindElement5:\n";
264 std::cout << " No element matching point (" << x << ", " << y
265 << ") found.\n";
266 }
267 m_lastElement = -1;
268 return -1;
269 }
270 if (nfound > 1) {
271 std::cout << m_className << "::FindElement5:\n";
272 std::cout << " Found " << nfound << " elements matching point (" << x
273 << ", " << y << ").\n";
274 }
275 if (nfound > 0) {
276 for (int j = 0; j < 4; ++j) {
277 for (int k = 0; k < 4; ++k) jac[j][k] = jacbak[j][k];
278 }
279 det = detbak;
280 t1 = t1bak;
281 t2 = t2bak;
282 t3 = t3bak;
283 t4 = t4bak;
284 imap = imapbak;
285 m_lastElement = imap;
286 return imap;
287 }
288 }
289
290 if (m_debug) {
291 std::cout << m_className << "::FindElement5:\n";
292 std::cout << " No element matching point (" << x << ", " << y
293 << ") found.\n";
294 }
295 return -1;
296}
297
298int ComponentFieldMap::FindElement13(const double x, const double y,
299 const double z, double& t1, double& t2,
300 double& t3, double& t4, double jac[4][4],
301 double& det) {
302 // Check if bounding boxes of elements have been computed
303 if (!m_cacheElemBoundingBoxes) {
304 std::cout << m_className << "::FindElement13:\n"
305 << " Caching the bounding boxes of all elements...";
306 CalculateElementBoundingBoxes();
307 std::cout << " done.\n";
308 m_cacheElemBoundingBoxes = true;
309 }
310
311 // Backup
312 double jacbak[4][4];
313 double detbak = 1.;
314 double t1bak = 0., t2bak = 0., t3bak = 0., t4bak = 0.;
315 int imapbak = -1;
316
317 // Initial values.
318 t1 = t2 = t3 = t4 = 0.;
319
320 // Check previously used element
321 if (m_lastElement > -1 && !m_checkMultipleElement) {
322 const Element& element = elements[m_lastElement];
323 if (Coordinates13(x, y, z, t1, t2, t3, t4, jac, det, element) == 0) {
324 if (t1 >= 0 && t1 <= +1 && t2 >= 0 && t2 <= +1 && t3 >= 0 && t3 <= +1 &&
325 t4 >= 0 && t4 <= +1) {
326 return m_lastElement;
327 }
328 }
329 }
330
331 // Tetra list in the block that contains the input 3D point.
332 std::vector<int> tetList;
333 if (m_useTetrahedralTree) {
334 if (!m_isTreeInitialized) {
335 if (!InitializeTetrahedralTree()) {
336 std::cerr << m_className << "::FindElement13:\n";
337 std::cerr << " Tetrahedral tree initialization failed.\n";
338 return -1;
339 }
340 }
341 tetList = m_tetTree->GetTetListInBlock(Vec3(x, y, z));
342 }
343 // Number of elements to scan.
344 // With tetra tree disabled, all elements are scanned.
345 const int numElemToSearch = m_useTetrahedralTree ? tetList.size() : nElements;
346 // Verify the count of volumes that contain the point.
347 int nfound = 0;
348 int imap = -1;
349
350 // Scan all elements
351 for (int i = 0; i < numElemToSearch; i++) {
352 const int idxToElemList = m_useTetrahedralTree ? tetList[i] : i;
353 const Element& element = elements[idxToElemList];
354 if (x < element.xmin || x > element.xmax || y < element.ymin ||
355 y > element.ymax || z < element.zmin || z > element.zmax)
356 continue;
357 if (Coordinates13(x, y, z, t1, t2, t3, t4, jac, det, element) != 0) {
358 continue;
359 }
360 if (t1 < 0 || t1 > 1 || t2 < 0 || t2 > 1 || t3 < 0 || t3 > 1 || t4 < 0 ||
361 t4 > 1) {
362 continue;
363 }
364 ++nfound;
365 imap = idxToElemList;
366 m_lastElement = idxToElemList;
367 if (m_debug) {
368 std::cout << m_className << "::FindElement13:\n";
369 std::cout << " Found matching element " << i << ".\n";
370 }
371 if (!m_checkMultipleElement) return idxToElemList;
372 for (int j = 0; j < 4; ++j) {
373 for (int k = 0; k < 4; ++k) jacbak[j][k] = jac[j][k];
374 }
375 detbak = det;
376 t1bak = t1;
377 t2bak = t2;
378 t3bak = t3;
379 t4bak = t4;
380 imapbak = imap;
381 if (m_debug) {
382 PrintElement("FindElement13", x, y, z, t1, t2, t3, t4, element, 10);
383 }
384 }
385
386 // In checking mode, verify the tetrahedron/triangle count.
387 if (m_checkMultipleElement) {
388 if (nfound < 1) {
389 if (m_debug) {
390 std::cout << m_className << "::FindElement13:\n";
391 std::cout << " No element matching point (" << x << ", " << y << ", "
392 << z << ") found.\n";
393 }
394 m_lastElement = -1;
395 return -1;
396 }
397 if (nfound > 1) {
398 std::cerr << m_className << "::FindElement13:\n";
399 std::cerr << " Found << " << nfound << " elements matching point ("
400 << x << ", " << y << ", " << z << ").\n";
401 }
402 if (nfound > 0) {
403 for (int j = 0; j < 4; ++j) {
404 for (int k = 0; k < 4; ++k) jac[j][k] = jacbak[j][k];
405 }
406 det = detbak;
407 t1 = t1bak;
408 t2 = t2bak;
409 t3 = t3bak;
410 t4 = t4bak;
411 imap = imapbak;
412 m_lastElement = imap;
413 return imap;
414 }
415 }
416
417 if (m_debug) {
418 std::cout << m_className << "::FindElement13:\n";
419 std::cout << " No element matching point (" << x << ", " << y << ", "
420 << z << ") found.\n";
421 }
422 return -1;
423}
424
425int ComponentFieldMap::FindElementCube(const double x, const double y,
426 const double z, double& t1, double& t2,
427 double& t3, TMatrixD*& jac,
428 std::vector<TMatrixD*>& dN) {
429 int imap = -1;
430 if (m_lastElement >= 0) {
431 const Element& element = elements[m_lastElement];
432 const Node& n3 = nodes[element.emap[3]];
433 if (x >= n3.x && y >= n3.y && z >= n3.z) {
434 const Node& n0 = nodes[element.emap[0]];
435 const Node& n2 = nodes[element.emap[2]];
436 const Node& n7 = nodes[element.emap[7]];
437 if (x < n0.x && y < n2.y && z < n7.z) {
438 imap = m_lastElement;
439 }
440 }
441 }
442
443 // Default element loop
444 if (imap == -1) {
445 for (int i = 0; i < nElements; ++i) {
446 const Element& element = elements[i];
447 const Node& n3 = nodes[element.emap[3]];
448 if (x < n3.x || y < n3.y || z < n3.z) continue;
449 const Node& n0 = nodes[element.emap[0]];
450 const Node& n2 = nodes[element.emap[2]];
451 const Node& n7 = nodes[element.emap[7]];
452 if (x < n0.x && y < n2.y && z < n7.z) {
453 imap = i;
454 break;
455 }
456 }
457 }
458
459 if (imap < 0) {
460 if (m_debug) {
461 std::cout << m_className << "::FindElementCube:\n";
462 std::cout << " Point (" << x << "," << y << "," << z
463 << ") not in the mesh, it is background or PEC.\n";
464 const Node& first0 = nodes[elements.front().emap[0]];
465 const Node& first2 = nodes[elements.front().emap[2]];
466 const Node& first3 = nodes[elements.front().emap[3]];
467 const Node& first7 = nodes[elements.front().emap[7]];
468 std::cout << " First node (" << first3.x << "," << first3.y << ","
469 << first3.z << ") in the mesh.\n";
470 std::cout << " dx= " << (first0.x - first3.x)
471 << ", dy= " << (first2.y - first3.y)
472 << ", dz= " << (first7.z - first3.z) << "\n";
473 const Node& last0 = nodes[elements.back().emap[0]];
474 const Node& last2 = nodes[elements.back().emap[2]];
475 const Node& last3 = nodes[elements.back().emap[3]];
476 const Node& last5 = nodes[elements.back().emap[5]];
477 const Node& last7 = nodes[elements.back().emap[7]];
478 std::cout << " Last node (" << last5.x << "," << last5.y << ","
479 << last5.z << ") in the mesh.\n";
480 std::cout << " dx= " << (last0.x - last3.x)
481 << ", dy= " << (last2.y - last3.y)
482 << ", dz= " << (last7.z - last3.z) << "\n";
483 }
484 return -1;
485 }
486 CoordinatesCube(x, y, z, t1, t2, t3, jac, dN, elements[imap]);
487 if (m_debug) {
488 PrintElement("FindElementCube", x, y, z, t1, t2, t3, 0., elements[imap], 8);
489 }
490 return imap;
491}
492
493void ComponentFieldMap::Jacobian3(const Element& element, const double u,
494 const double v, const double w, double& det,
495 double jac[4][4]) const {
496 // Initial values
497 det = 0;
498 jac[0][0] = 0;
499 jac[0][1] = 0;
500 jac[1][0] = 0;
501 jac[1][1] = 0;
502
503 const Node& n0 = nodes[element.emap[0]];
504 const Node& n1 = nodes[element.emap[1]];
505 const Node& n2 = nodes[element.emap[2]];
506 const Node& n3 = nodes[element.emap[3]];
507 const Node& n4 = nodes[element.emap[4]];
508 const Node& n5 = nodes[element.emap[5]];
509
510 // Shorthands.
511 const double fouru = 4 * u;
512 const double fourv = 4 * v;
513 const double fourw = 4 * w;
514
515 const double ax = -n1.x + fourv * n1.x + fouru * n3.x + fourw * n5.x;
516 const double ay = -n1.y + fourv * n1.y + fouru * n3.y + fourw * n5.y;
517 const double bx = -n2.x + fourw * n2.x + fouru * n4.x + fourv * n5.x;
518 const double by = -n2.y + fourw * n2.y + fouru * n4.y + fourv * n5.y;
519 const double cx = -n0.x + fouru * n0.x + fourv * n3.x + fourw * n4.x;
520 const double cy = -n0.y + fouru * n0.y + fourv * n3.y + fourw * n4.y;
521 // Determinant of the quadratic triangular Jacobian
522 det = -((-1 + fourv) * n1.x + n2.x - fourw * n2.x + fouru * n3.x -
523 fouru * n4.x - fourv * n5.x + fourw * n5.x) *
524 cy -
525 ((-1 + fouru) * n0.x + n1.x - fourv * n1.x - fouru * n3.x +
526 fourv * n3.x + fourw * n4.x - fourw * n5.x) *
527 by +
528 ((-1 + fouru) * n0.x + n2.x - fourw * n2.x + fourv * n3.x -
529 fouru * n4.x + fourw * n4.x - fourv * n5.x) *
530 ay;
531
532 // Terms of the quadratic triangular Jacobian
533 jac[0][0] = ax * by - bx * ay;
534 jac[0][1] = (-1 + fourv) * n1.y + n2.y - fourw * n2.y + fouru * n3.y -
535 fouru * n4.y - fourv * n5.y + fourw * n5.y;
536 jac[0][2] = n1.x - fourv * n1.x + (-1 + fourw) * n2.x - fouru * n3.x +
537 fouru * n4.x + fourv * n5.x - fourw * n5.x;
538 jac[1][0] = bx * cy - cx * by;
539 jac[1][1] = n0.y - fouru * n0.y - n2.y + fourw * n2.y - fourv * n3.y +
540 fouru * n4.y - fourw * n4.y + fourv * n5.y;
541 jac[1][2] = (-1 + fouru) * n0.x + n2.x - fourw * n2.x + fourv * n3.x -
542 fouru * n4.x + fourw * n4.x - fourv * n5.x;
543 jac[2][0] = -ax * cy + cx * ay;
544 jac[2][1] = (-1 + fouru) * n0.y + n1.y - fourv * n1.y - fouru * n3.y +
545 fourv * n3.y + fourw * n4.y - fourw * n5.y;
546 jac[2][2] = n0.x - fouru * n0.x - n1.x + fourv * n1.x + fouru * n3.x -
547 fourv * n3.x - fourw * n4.x + fourw * n5.x;
548}
549
550void ComponentFieldMap::Jacobian5(const Element& element, const double u,
551 const double v, double& det,
552 double jac[4][4]) const {
553 // Initial values
554 det = 0;
555 jac[0][0] = 0;
556 jac[0][1] = 0;
557 jac[1][0] = 0;
558 jac[1][1] = 0;
559
560 const Node& n0 = nodes[element.emap[0]];
561 const Node& n1 = nodes[element.emap[1]];
562 const Node& n2 = nodes[element.emap[2]];
563 const Node& n3 = nodes[element.emap[3]];
564 const Node& n4 = nodes[element.emap[4]];
565 const Node& n5 = nodes[element.emap[5]];
566 const Node& n6 = nodes[element.emap[6]];
567 const Node& n7 = nodes[element.emap[7]];
568 const double u2 = u * u;
569 const double v2 = v * v;
570 const double twou = 2 * u;
571 const double twov = 2 * v;
572 const double two0x = 2 * n0.x;
573 const double two0y = 2 * n0.y;
574 const double two1x = 2 * n1.x;
575 const double two1y = 2 * n1.y;
576 const double two2x = 2 * n2.x;
577 const double two2y = 2 * n2.y;
578 const double two3x = 2 * n3.x;
579 const double two3y = 2 * n3.y;
580 const double two4x = 2 * n4.x;
581 const double two4y = 2 * n4.y;
582 const double two5x = 2 * n5.x;
583 const double two5y = 2 * n5.y;
584 const double two6x = 2 * n6.x;
585 const double two6y = 2 * n6.y;
586 const double two7x = 2 * n7.x;
587 const double two7y = 2 * n7.y;
588 // Determinant of the quadrilateral serendipity Jacobian
589 det =
590 (-twou * u2 * ((n2.x + n3.x - two6x) * (n0.y + n1.y - two4y) -
591 (n0.x + n1.x - two4x) * (n2.y + n3.y - two6y)) +
592 twov * v2 * (-((n0.x + n3.x - two7x) * (n1.y + n2.y - two5y)) +
593 (n1.x + n2.x - two5x) * (n0.y + n3.y - two7y)) +
594 2 * (-((n5.x - n7.x) * (n4.y - n6.y)) + (n4.x - n6.x) * (n5.y - n7.y)) +
595 v * (-(n6.x * n0.y) - two7x * n0.y + n6.x * n1.y - two7x * n1.y -
596 n6.x * n2.y - two7x * n2.y + n4.x * (n0.y - n1.y + n2.y - n3.y) +
597 n6.x * n3.y - two7x * n3.y - n0.x * n4.y + n1.x * n4.y -
598 n2.x * n4.y + n3.x * n4.y - two0x * n5.y - two1x * n5.y -
599 two2x * n5.y - two3x * n5.y + 8 * n7.x * n5.y + n0.x * n6.y -
600 n1.x * n6.y + n2.x * n6.y - n3.x * n6.y +
601 two5x * (n0.y + n1.y + n2.y + n3.y - 4 * n7.y) +
602 2 * (n0.x + n1.x + n2.x + n3.x) * n7.y) +
603 v2 * (-(n4.x * n0.y) + two5x * n0.y + n6.x * n0.y + two7x * n0.y +
604 n4.x * n1.y - two5x * n1.y - n6.x * n1.y - two7x * n1.y +
605 n4.x * n2.y + two5x * n2.y - n6.x * n2.y + two7x * n2.y -
606 n4.x * n3.y - two5x * n3.y + n6.x * n3.y - two7x * n3.y +
607 two2x * (n1.y + n3.y) - n2.x * n4.y + two5x * n4.y - two7x * n4.y -
608 two2x * n5.y - two4x * n5.y + two6x * n5.y + n2.x * n6.y -
609 two5x * n6.y + two7x * n6.y +
610 n0.x * (two1y + two3y + n4.y - two5y - n6.y - two7y) -
611 2 * (n2.x - n4.x + n6.x) * n7.y +
612 n3.x * (-two0y - two2y + n4.y + two5y - n6.y + two7y) +
613 n1.x * (-two0y - two2y - n4.y + two5y + n6.y + two7y)) +
614 u * (n5.x * n0.y - two6x * n0.y - n7.x * n0.y - n5.x * n1.y -
615 two6x * n1.y + n7.x * n1.y + n5.x * n2.y - two6x * n2.y -
616 n7.x * n2.y - n5.x * n3.y - two6x * n3.y + n7.x * n3.y -
617 two1x * n4.y - two2x * n4.y - two3x * n4.y + 8 * n6.x * n4.y +
618 n1.x * n5.y - n2.x * n5.y + n3.x * n5.y +
619 two4x * (n0.y + n1.y + n2.y + n3.y - 4 * n6.y) + two1x * n6.y +
620 two2x * n6.y + two3x * n6.y - (n1.x - n2.x + n3.x) * n7.y +
621 n0.x * (-two4y - n5.y + two6y + n7.y) +
622 v2 * (4 * n4.x * n0.y - 3 * n5.x * n0.y - 4 * n6.x * n0.y -
623 5 * n7.x * n0.y + 4 * n4.x * n1.y - 5 * n5.x * n1.y -
624 4 * n6.x * n1.y - 3 * n7.x * n1.y + 4 * n4.x * n2.y +
625 5 * n5.x * n2.y - 4 * n6.x * n2.y + 3 * n7.x * n2.y +
626 4 * n4.x * n3.y + 3 * n5.x * n3.y - 4 * n6.x * n3.y +
627 5 * n7.x * n3.y + 8 * n5.x * n4.y + 8 * n7.x * n4.y -
628 8 * n4.x * n5.y + 8 * n6.x * n5.y - 8 * n5.x * n6.y -
629 8 * n7.x * n6.y +
630 n3.x * (5 * n0.y + 3 * n1.y - 4 * n4.y - 3 * n5.y + 4 * n6.y -
631 5 * n7.y) +
632 n2.x * (3 * n0.y + 5 * n1.y - 4 * n4.y - 5 * n5.y + 4 * n6.y -
633 3 * n7.y) -
634 8 * n4.x * n7.y + 8 * n6.x * n7.y +
635 n1.x * (-5 * n2.y - 3 * n3.y - 4 * n4.y + 5 * n5.y +
636 4 * n6.y + 3 * n7.y) +
637 n0.x * (-3 * n2.y - 5 * n3.y - 4 * n4.y + 3 * n5.y +
638 4 * n6.y + 5 * n7.y)) -
639 twov * (n6.x * n0.y - 3 * n7.x * n0.y + n6.x * n1.y - n7.x * n1.y +
640 3 * n6.x * n2.y - n7.x * n2.y + 3 * n6.x * n3.y -
641 3 * n7.x * n3.y - 3 * n0.x * n4.y - 3 * n1.x * n4.y -
642 n2.x * n4.y - n3.x * n4.y + 4 * n7.x * n4.y + n0.x * n5.y +
643 3 * n1.x * n5.y + 3 * n2.x * n5.y + n3.x * n5.y -
644 4 * n6.x * n5.y - n0.x * n6.y - n1.x * n6.y -
645 3 * n2.x * n6.y - 3 * n3.x * n6.y + 4 * n7.x * n6.y -
646 n5.x * (n0.y + 3 * n1.y + 3 * n2.y + n3.y -
647 4 * (n4.y + n6.y)) +
648 (3 * n0.x + n1.x + n2.x + 3 * n3.x - 4 * n6.x) * n7.y +
649 n4.x * (3 * n0.y + 3 * n1.y + n2.y + n3.y -
650 4 * (n5.y + n7.y)))) +
651 u2 *
652 (two3x * n0.y - two4x * n0.y - n5.x * n0.y - two6x * n0.y +
653 n7.x * n0.y - two0x * n1.y + two4x * n1.y - n5.x * n1.y +
654 two6x * n1.y + n7.x * n1.y + two3x * n2.y - two4x * n2.y +
655 n5.x * n2.y - two6x * n2.y - n7.x * n2.y + two4x * n3.y +
656 n5.x * n3.y + two6x * n3.y - n7.x * n3.y - two3x * n4.y +
657 two5x * n4.y - two7x * n4.y - n3.x * n5.y - two4x * n5.y +
658 two6x * n5.y - two3x * n6.y - two5x * n6.y + two7x * n6.y +
659 n0.x * (-two3y + two4y + n5.y + two6y - n7.y) +
660 (n3.x + two4x - two6x) * n7.y +
661 n2.x * (-two1y - two3y + two4y - n5.y + two6y + n7.y) -
662 3 * v2 *
663 (n5.x * n0.y - n6.x * n0.y - n7.x * n0.y + n5.x * n1.y +
664 n6.x * n1.y - n7.x * n1.y - n5.x * n2.y + n6.x * n2.y +
665 n7.x * n2.y - n5.x * n3.y - n6.x * n3.y + n7.x * n3.y -
666 two5x * n4.y + two7x * n4.y - two6x * n5.y + two5x * n6.y -
667 two7x * n6.y +
668 n4.x * (n0.y - n1.y - n2.y + n3.y + two5y - two7y) +
669 n3.x * (n0.y - n2.y - n4.y + n5.y + n6.y - n7.y) +
670 two6x * n7.y +
671 (n0.x - n2.x) * (n1.y - n3.y - n4.y - n5.y + n6.y + n7.y)) +
672 v * (4 * n5.x * n0.y + 3 * n6.x * n0.y - 4 * n7.x * n0.y +
673 4 * n5.x * n1.y - 3 * n6.x * n1.y - 4 * n7.x * n1.y +
674 4 * n5.x * n2.y - 5 * n6.x * n2.y - 4 * n7.x * n2.y +
675 4 * n5.x * n3.y + 5 * n6.x * n3.y - 4 * n7.x * n3.y -
676 8 * n5.x * n4.y + 8 * n7.x * n4.y + 8 * n6.x * n5.y -
677 8 * n5.x * n6.y + 8 * n7.x * n6.y +
678 n4.x * (5 * n0.y - 5 * n1.y - 3 * n2.y + 3 * n3.y + 8 * n5.y -
679 8 * n7.y) -
680 8 * n6.x * n7.y +
681 n3.x * (3 * n1.y + 5 * n2.y - 3 * n4.y - 4 * n5.y - 5 * n6.y +
682 4 * n7.y) +
683 n0.x * (5 * n1.y + 3 * n2.y - 5 * n4.y - 4 * n5.y - 3 * n6.y +
684 4 * n7.y) +
685 n2.x * (-3 * n0.y - 5 * n3.y + 3 * n4.y - 4 * n5.y + 5 * n6.y +
686 4 * n7.y)) +
687 n1.x * ((-1 + v) * (-2 + 3 * v) * n0.y + two2y - two4y + n5.y -
688 two6y - n7.y +
689 v * (-3 * n3.y + 5 * n4.y - 4 * n5.y + 3 * n6.y + 4 * n7.y -
690 3 * v * (n2.y + n4.y - n5.y - n6.y + n7.y))))) /
691 8;
692 // Jacobian terms
693 jac[0][0] =
694 (u2 * (-n0.y - n1.y + n2.y + n3.y + two4y - two6y) +
695 2 * (-n4.y + n6.y + v * (n0.y + n1.y + n2.y + n3.y - two5y - two7y)) +
696 u * (n0.y - twov * n0.y - n1.y + twov * n1.y + n2.y + twov * n2.y -
697 n3.y - twov * n3.y - twov * two5y + twov * two7y)) /
698 4;
699 jac[0][1] =
700 (u2 * (n0.x + n1.x - n2.x - n3.x - two4x + two6x) -
701 2 * (-n4.x + n6.x + v * (n0.x + n1.x + n2.x + n3.x - two5x - two7x)) +
702 u * ((-1 + twov) * n0.x + n1.x - twov * n1.x - n2.x - twov * n2.x +
703 n3.x + twov * n3.x + twov * two5x - twov * two7x)) /
704 4;
705 jac[1][0] =
706 (v * (-n0.y + n1.y - n2.y + n3.y) - two5y +
707 twou * ((-1 + v) * n0.y + (-1 + v) * n1.y - n2.y - v * n2.y - n3.y -
708 v * n3.y + two4y - twov * n4.y + two6y + twov * n6.y) +
709 v2 * (n0.y - n1.y - n2.y + n3.y + two5y - two7y) + two7y) /
710 4;
711 jac[1][1] =
712 (v * (n0.x - n1.x + n2.x - n3.x) +
713 twou * (n0.x - v * n0.x + n1.x - v * n1.x + n2.x + v * n2.x + n3.x +
714 v * n3.x - two4x + twov * n4.x - two6x - twov * n6.x) +
715 two5x - two7x + v2 * (-n0.x + n1.x + n2.x - n3.x - two5x + two7x)) /
716 4;
717}
718
719void ComponentFieldMap::Jacobian13(const Element& element, const double t,
720 const double u, const double v,
721 const double w, double& det,
722 double jac[4][4]) const {
723 // Initial values
724 det = 0;
725 for (int j = 0; j < 4; ++j) {
726 for (int k = 0; k < 4; ++k) jac[j][k] = 0;
727 }
728
729 const Node& n0 = nodes[element.emap[0]];
730 const Node& n1 = nodes[element.emap[1]];
731 const Node& n2 = nodes[element.emap[2]];
732 const Node& n3 = nodes[element.emap[3]];
733 const Node& n4 = nodes[element.emap[4]];
734 const Node& n5 = nodes[element.emap[5]];
735 const Node& n6 = nodes[element.emap[6]];
736 const Node& n7 = nodes[element.emap[7]];
737 const Node& n8 = nodes[element.emap[8]];
738 const Node& n9 = nodes[element.emap[9]];
739
740 // Shorthands.
741 const double fourt = 4 * t;
742 const double fouru = 4 * u;
743 const double fourv = 4 * v;
744 const double fourw = 4 * w;
745
746 const double ttx = (-1 + fourt) * n0.x + 4 * (u * n4.x + v * n5.x + w * n6.x);
747 const double tty = (-1 + fourt) * n0.y + 4 * (u * n4.y + v * n5.y + w * n6.y);
748 const double ttz = (-1 + fourt) * n0.z + 4 * (u * n4.z + v * n5.z + w * n6.z);
749
750 const double uux = (-1 + fouru) * n1.x + 4 * (t * n4.x + v * n7.x + w * n8.x);
751 const double uuy = (-1 + fouru) * n1.y + 4 * (t * n4.y + v * n7.y + w * n8.y);
752 const double uuz = (-1 + fouru) * n1.z + 4 * (t * n4.z + v * n7.z + w * n8.z);
753
754 const double vvx =
755 fourv * n9.x - n3.x + fourw * n3.x + fourt * n6.x + fouru * n8.x;
756 const double vvy =
757 fourv * n9.y - n3.y + fourw * n3.y + fourt * n6.y + fouru * n8.y;
758 const double vvz =
759 fourv * n9.z - n3.z + fourw * n3.z + fourt * n6.z + fouru * n8.z;
760
761 const double wwx =
762 fourw * n9.x - n2.x + fourv * n2.x + fourt * n5.x + fouru * n7.x;
763 const double wwy =
764 fourw * n9.y - n2.y + fourv * n2.y + fourt * n5.y + fouru * n7.y;
765 const double wwz =
766 fourw * n9.z - n2.z + fourv * n2.z + fourt * n5.z + fouru * n7.z;
767
768 const double aax = n1.x - fouru * n1.x - n3.x + fourw * n3.x - fourt * n4.x +
769 fourt * n6.x + fourv * (n9.x - n7.x) + fouru * n8.x -
770 fourw * n8.x;
771 const double anx = -fourv * n9.x - n1.x + fouru * n1.x + n3.x - fourw * n3.x +
772 fourt * n4.x - fourt * n6.x + fourv * n7.x - fouru * n8.x +
773 fourw * n8.x;
774 const double aay = n1.y - fouru * n1.y - n3.y + fourw * n3.y - fourt * n4.y +
775 fourt * n6.y + fourv * (n9.y - n7.y) + fouru * n8.y -
776 fourw * n8.y;
777 const double any = -fourv * n9.y - n1.y + fouru * n1.y + n3.y - fourw * n3.y +
778 fourt * n4.y - fourt * n6.y + fourv * n7.y - fouru * n8.y +
779 fourw * n8.y;
780
781 const double bbx = -fourw * n9.x - n1.x + fouru * n1.x + n2.x - fourv * n2.x +
782 fourt * n4.x - fourt * n5.x - fouru * n7.x + fourv * n7.x +
783 fourw * n8.x;
784 const double bnx = n1.x - fouru * n1.x - n2.x + fourv * n2.x - fourt * n4.x +
785 fourt * n5.x + fouru * n7.x - fourv * n7.x +
786 fourw * (n9.x - n8.x);
787 const double bby = -fourw * n9.y - n1.y + fouru * n1.y + n2.y - fourv * n2.y +
788 fourt * n4.y - fourt * n5.y - fouru * n7.y + fourv * n7.y +
789 fourw * n8.y;
790 const double bny = n1.y - fouru * n1.y - n2.y + fourv * n2.y - fourt * n4.y +
791 fourt * n5.y + fouru * n7.y - fourv * n7.y +
792 fourw * (n9.y - n8.y);
793
794 const double ccx = -fourv * n9.x + fourw * n9.x - n2.x + fourv * n2.x + n3.x -
795 fourw * n3.x + fourt * n5.x - fourt * n6.x + fouru * n7.x -
796 fouru * n8.x;
797 const double cnx = -fourw * n9.x + fourv * (n9.x - n2.x) + n2.x - n3.x +
798 fourw * n3.x - fourt * n5.x + fourt * n6.x - fouru * n7.x +
799 fouru * n8.x;
800 const double ccy = -fourv * n9.y + fourw * n9.y - n2.y + fourv * n2.y + n3.y -
801 fourw * n3.y + fourt * n5.y - fourt * n6.y + fouru * n7.y -
802 fouru * n8.y;
803 const double cny = -fourw * n9.y + fourv * (n9.y - n2.y) + n2.y - n3.y +
804 fourw * n3.y - fourt * n5.y + fourt * n6.y - fouru * n7.y +
805 fouru * n8.y;
806
807 const double ddy = (-1 + fourt) * n0.y - fourv * n9.y + n3.y - fourw * n3.y +
808 fouru * n4.y + fourv * n5.y - fourt * n6.y + fourw * n6.y -
809 fouru * n8.y;
810 const double ddx = (-1 + fourt) * n0.x - fourv * n9.x + n3.x - fourw * n3.x +
811 fouru * n4.x + fourv * n5.x - fourt * n6.x + fourw * n6.x -
812 fouru * n8.x;
813
814 const double eex = (-1 + fourt) * n0.x - fourw * n9.x + n2.x - fourv * n2.x +
815 fouru * n4.x - fourt * n5.x + fourv * n5.x + fourw * n6.x -
816 fouru * n7.x;
817 const double eey = (-1 + fourt) * n0.y - fourw * n9.y + n2.y - fourv * n2.y +
818 fouru * n4.y - fourt * n5.y + fourv * n5.y + fourw * n6.y -
819 fouru * n7.y;
820
821 const double ffx =
822 (-1 + fourt) * n0.x + n1.x - fouru * n1.x +
823 4 * (-(t * n4.x) + u * n4.x + v * n5.x + w * n6.x - v * n7.x - w * n8.x);
824 const double ffy =
825 (-1 + fourt) * n0.y + n1.y - fouru * n1.y +
826 4 * (-(t * n4.y) + u * n4.y + v * n5.y + w * n6.y - v * n7.y - w * n8.y);
827
828 // Determinant of the quadrilateral serendipity Jacobian
829 det = -(anx * wwy + bnx * vvy + cnx * uuy) * ttz -
830 (aax * tty - ffx * vvy + ddx * uuy) * wwz +
831 (bnx * tty - ffx * wwy + eex * uuy) * vvz +
832 (cnx * tty + ddx * wwy - eex * vvy) * uuz;
833
834 jac[0][0] = -(uux * vvy - vvx * uuy) * wwz + (uux * wwy - wwx * uuy) * vvz +
835 (-vvx * wwy + wwx * vvy) * uuz;
836
837 jac[0][1] = aay * wwz + bby * vvz + ccy * uuz;
838 jac[0][2] = anx * wwz + bnx * vvz + cnx * uuz;
839 jac[0][3] = aax * wwy + bbx * vvy + ccx * uuy;
840
841 jac[1][0] = -(-vvx * wwy + wwx * vvy) * ttz + (-vvx * tty + ttx * vvy) * wwz -
842 (-wwx * tty + ttx * wwy) * vvz;
843
844 jac[1][1] = cny * ttz + ddy * wwz - eey * vvz;
845 jac[1][2] = ccx * ttz - ddx * wwz + eex * vvz;
846 jac[1][3] = cnx * tty + ddx * wwy - eex * vvy;
847
848 jac[2][0] = (uux * vvy - vvx * uuy) * ttz + (-uux * tty + ttx * uuy) * vvz -
849 (-vvx * tty + ttx * vvy) * uuz;
850
851 jac[2][1] = any * ttz + ffy * vvz - ddy * uuz;
852 jac[2][2] = aax * ttz - ffx * vvz + ddx * uuz;
853 jac[2][3] = anx * tty + ffx * vvy - ddx * uuy;
854
855 jac[3][0] = -(uux * wwy - wwx * uuy) * ttz - (-uux * tty + ttx * uuy) * wwz +
856 (-wwx * tty + ttx * wwy) * uuz;
857
858 jac[3][1] = bny * ttz - ffy * wwz + eey * uuz;
859 jac[3][2] = bbx * ttz + ffx * wwz - eex * uuz;
860 jac[3][3] = bnx * tty - ffx * wwy + eex * uuy;
861}
862
863void ComponentFieldMap::JacobianCube(const Element& element, const double t1,
864 const double t2, const double t3,
865 TMatrixD*& jac,
866 std::vector<TMatrixD*>& dN) const {
867 if (!jac) {
868 std::cerr << m_className << "::JacobianCube:\n";
869 std::cerr << " Pointer to Jacobian matrix is empty!\n";
870 return;
871 }
872 dN.clear();
873
874 // Here the partial derivatives of the 8 shaping functions are calculated
875 double N1[3] = {-1 * (1 - t2) * (1 - t3), (1 - t1) * -1 * (1 - t3),
876 (1 - t1) * (1 - t2) * -1};
877 double N2[3] = {+1 * (1 - t2) * (1 - t3), (1 + t1) * -1 * (1 - t3),
878 (1 + t1) * (1 - t2) * -1};
879 double N3[3] = {+1 * (1 + t2) * (1 - t3), (1 + t1) * +1 * (1 - t3),
880 (1 + t1) * (1 + t2) * -1};
881 double N4[3] = {-1 * (1 + t2) * (1 - t3), (1 - t1) * +1 * (1 - t3),
882 (1 - t1) * (1 + t2) * -1};
883 double N5[3] = {-1 * (1 - t2) * (1 + t3), (1 - t1) * -1 * (1 + t3),
884 (1 - t1) * (1 - t2) * +1};
885 double N6[3] = {+1 * (1 - t2) * (1 + t3), (1 + t1) * -1 * (1 + t3),
886 (1 + t1) * (1 - t2) * +1};
887 double N7[3] = {+1 * (1 + t2) * (1 + t3), (1 + t1) * +1 * (1 + t3),
888 (1 + t1) * (1 + t2) * +1};
889 double N8[3] = {-1 * (1 + t2) * (1 + t3), (1 - t1) * +1 * (1 + t3),
890 (1 - t1) * (1 + t2) * +1};
891 // Partial derivatives are stored in dN
892 TMatrixD* m_N1 = new TMatrixD(3, 1, N1);
893 *m_N1 = (1. / 8. * (*m_N1));
894 dN.push_back(m_N1);
895 TMatrixD* m_N2 = new TMatrixD(3, 1, N2);
896 *m_N2 = (1. / 8. * (*m_N2));
897 dN.push_back(m_N2);
898 TMatrixD* m_N3 = new TMatrixD(3, 1, N3);
899 *m_N3 = (1. / 8. * (*m_N3));
900 dN.push_back(m_N3);
901 TMatrixD* m_N4 = new TMatrixD(3, 1, N4);
902 *m_N4 = (1. / 8. * (*m_N4));
903 dN.push_back(m_N4);
904 TMatrixD* m_N5 = new TMatrixD(3, 1, N5);
905 *m_N5 = (1. / 8. * (*m_N5));
906 dN.push_back(m_N5);
907 TMatrixD* m_N6 = new TMatrixD(3, 1, N6);
908 *m_N6 = (1. / 8. * (*m_N6));
909 dN.push_back(m_N6);
910 TMatrixD* m_N7 = new TMatrixD(3, 1, N7);
911 *m_N7 = (1. / 8. * (*m_N7));
912 dN.push_back(m_N7);
913 TMatrixD* m_N8 = new TMatrixD(3, 1, N8);
914 *m_N8 = (1. / 8. * (*m_N8));
915 dN.push_back(m_N8);
916 // Calculation of the jacobian using dN
917 for (int j = 0; j < 8; ++j) {
918 const Node& node = nodes[element.emap[j]];
919 (*jac)(0, 0) += node.x * ((*dN.at(j))(0, 0));
920 (*jac)(0, 1) += node.y * ((*dN.at(j))(0, 0));
921 (*jac)(0, 2) += node.z * ((*dN.at(j))(0, 0));
922 (*jac)(1, 0) += node.x * ((*dN.at(j))(1, 0));
923 (*jac)(1, 1) += node.y * ((*dN.at(j))(1, 0));
924 (*jac)(1, 2) += node.z * ((*dN.at(j))(1, 0));
925 (*jac)(2, 0) += node.x * ((*dN.at(j))(2, 0));
926 (*jac)(2, 1) += node.y * ((*dN.at(j))(2, 0));
927 (*jac)(2, 2) += node.z * ((*dN.at(j))(2, 0));
928 }
929
930 // compute determinant
931 if (m_debug) {
932 std::cout << m_className << "::JacobianCube:" << std::endl;
933 std::cout << " Det.: " << jac->Determinant() << std::endl;
934 std::cout << " Jacobian matrix.: " << std::endl;
935 jac->Print("%11.10g");
936 std::cout << " Hexahedral coordinates (t, u, v) = (" << t1 << "," << t2
937 << "," << t3 << ")" << std::endl;
938 std::cout << " Node xyzV" << std::endl;
939 for (int j = 0; j < 8; ++j) {
940 const Node& node = nodes[element.emap[j]];
941 std::cout << " " << element.emap[j] << " " << node.x
942 << " " << node.y << " " << node.z << " "
943 << node.v << std::endl;
944 }
945 }
946}
947
948int ComponentFieldMap::Coordinates3(const double x, const double y,
949 const double z, double& t1, double& t2,
950 double& t3, double& t4, double jac[4][4],
951 double& det, const Element& element) const {
952 if (m_debug) {
953 std::cout << m_className << "::Coordinates3:\n";
954 std::cout << " Point (" << x << ", " << y << ", " << z << ")\n";
955 }
956
957 // Failure flag
958 int ifail = 1;
959
960 // Provisional values
961 t1 = t2 = t3 = t4 = 0;
962
963 // Make a first order approximation, using the linear triangle.
964 const Node& n0 = nodes[element.emap[0]];
965 const Node& n1 = nodes[element.emap[1]];
966 const Node& n2 = nodes[element.emap[2]];
967 const double tt1 = (x - n1.x) * (n2.y - n1.y) - (y - n1.y) * (n2.x - n1.x);
968 const double tt2 = (x - n2.x) * (n0.y - n2.y) - (y - n2.y) * (n0.x - n2.x);
969 const double tt3 = (x - n0.x) * (n1.y - n0.y) - (y - n0.y) * (n1.x - n0.x);
970 const double f1 =
971 (n0.x - n1.x) * (n2.y - n1.y) - (n2.x - n1.x) * (n0.y - n1.y);
972 const double f2 =
973 (n1.x - n2.x) * (n0.y - n2.y) - (n0.x - n2.x) * (n1.y - n2.y);
974 const double f3 =
975 (n2.x - n0.x) * (n1.y - n0.y) - (n1.x - n0.x) * (n2.y - n0.y);
976 if (f1 == 0 || f2 == 0 || f3 == 0) {
977 std::cerr << m_className << "::Coordinates3:\n";
978 std::cerr << " Calculation of linear coordinates failed; abandoned.\n";
979 return ifail;
980 } else {
981 t1 = tt1 / f1;
982 t2 = tt2 / f2;
983 t3 = tt3 / f3;
984 }
985 const Node& n3 = nodes[element.emap[3]];
986 const Node& n4 = nodes[element.emap[4]];
987 const Node& n5 = nodes[element.emap[5]];
988
989 // Start iterative refinement.
990 double td1 = t1, td2 = t2, td3 = t3;
991 bool converged = false;
992 for (int iter = 0; iter < 10; iter++) {
993 if (m_debug) {
994 std::cout << m_className << "::Coordinates3:\n";
995 std::cout << " Iteration " << iter << ": (u, v, w) = (" << td1
996 << ", " << td2 << ", " << td3 << "), sum = " << td1 + td2 + td3
997 << "\n";
998 }
999 // Re-compute the (x,y,z) position for this coordinate.
1000 const double xr = n0.x * td1 * (2 * td1 - 1) + n1.x * td2 * (2 * td2 - 1) +
1001 n2.x * td3 * (2 * td3 - 1) + n3.x * 4 * td1 * td2 +
1002 n4.x * 4 * td1 * td3 + n5.x * 4 * td2 * td3;
1003 const double yr = n0.y * td1 * (2 * td1 - 1) + n1.y * td2 * (2 * td2 - 1) +
1004 n2.y * td3 * (2 * td3 - 1) + n3.y * 4 * td1 * td2 +
1005 n4.y * 4 * td1 * td3 + n5.y * 4 * td2 * td3;
1006 const double sr = td1 + td2 + td3;
1007 // Compute the Jacobian.
1008 Jacobian3(element, td1, td2, td3, det, jac);
1009 // Compute the difference vector.
1010 const double diff[3] = {1 - sr, x - xr, y - yr};
1011 // Update the estimate.
1012 const double invdet = 1. / det;
1013 double corr[3] = {0., 0., 0.};
1014 for (int l = 0; l < 3; l++) {
1015 for (int k = 0; k < 3; k++) {
1016 corr[l] += jac[l][k] * diff[k] * invdet;
1017 }
1018 }
1019 // Debugging
1020 if (m_debug) {
1021 std::cout << m_className << "::Coordinates3:\n";
1022 std::cout << " Difference vector: (1, x, y) = (" << diff[0] << ", "
1023 << diff[1] << ", " << diff[2] << ").\n";
1024 std::cout << " Correction vector: (u, v, w) = (" << corr[0] << ", "
1025 << corr[1] << ", " << corr[2] << ").\n";
1026 }
1027 // Update the vector.
1028 td1 += corr[0];
1029 td2 += corr[1];
1030 td3 += corr[2];
1031 // Check for convergence.
1032 if (fabs(corr[0]) < 1.0e-5 && fabs(corr[1]) < 1.0e-5 &&
1033 fabs(corr[2]) < 1.0e-5) {
1034 if (m_debug) {
1035 std::cout << m_className << "::Coordinates3: Convergence reached.";
1036 }
1037 converged = true;
1038 break;
1039 }
1040 }
1041 // No convergence reached
1042 if (!converged) {
1043 const double xmin = std::min({n0.x, n1.x, n2.x});
1044 const double xmax = std::max({n0.x, n1.x, n2.x});
1045 const double ymin = std::min({n0.y, n1.y, n2.y});
1046 const double ymax = std::max({n0.y, n1.y, n2.y});
1047 if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) {
1048 std::cout << m_className << "::Coordinates3:\n";
1049 std::cout << " No convergence achieved "
1050 << "when refining internal isoparametric coordinates\n"
1051 << " at position (" << x << ", " << y << ").\n";
1052 t1 = t2 = t3 = t4 = 0;
1053 return ifail;
1054 }
1055 }
1056
1057 // Convergence reached.
1058 t1 = td1;
1059 t2 = td2;
1060 t3 = td3;
1061 t4 = 0;
1062 if (m_debug) {
1063 std::cout << m_className << "::Coordinates3:\n";
1064 std::cout << " Convergence reached at (t1, t2, t3) = (" << t1 << ", "
1065 << t2 << ", " << t3 << ").\n";
1066 }
1067
1068 // For debugging purposes, show position
1069 if (m_debug) {
1070 double xr = n0.x * td1 * (2 * td1 - 1) + n1.x * td2 * (2 * td2 - 1) +
1071 n2.x * td3 * (2 * td3 - 1) + n3.x * 4 * td1 * td2 +
1072 n4.x * 4 * td1 * td3 + n5.x * 4 * td2 * td3;
1073 double yr = n0.y * td1 * (2 * td1 - 1) + n1.y * td2 * (2 * td2 - 1) +
1074 n2.y * td3 * (2 * td3 - 1) + n3.y * 4 * td1 * td2 +
1075 n4.y * 4 * td1 * td3 + n5.y * 4 * td2 * td3;
1076 double sr = td1 + td2 + td3;
1077 std::cout << m_className << "::Coordinates3:\n";
1078 std::cout << " Position requested: (" << x << ", " << y << ")\n";
1079 std::cout << " Reconstructed: (" << xr << ", " << yr << ")\n";
1080 std::cout << " Difference: (" << x - xr << ", " << y - yr
1081 << ")\n";
1082 std::cout << " Checksum - 1: " << sr - 1 << "\n";
1083 }
1084
1085 // Success
1086 ifail = 0;
1087 return ifail;
1088}
1089
1090int ComponentFieldMap::Coordinates4(const double x, const double y,
1091 const double z, double& t1, double& t2,
1092 double& t3, double& t4, double jac[4][4],
1093 double& det, const Element& element) const {
1094 // Debugging
1095 if (m_debug) {
1096 std::cout << m_className << "::Coordinates4:\n";
1097 std::cout << " Point (" << x << ", " << y << ", " << z << ")\n";
1098 }
1099
1100 // Failure flag
1101 int ifail = 1;
1102
1103 // Provisional values
1104 t1 = t2 = t3 = t4 = 0.;
1105
1106 const Node& n0 = nodes[element.emap[0]];
1107 const Node& n1 = nodes[element.emap[1]];
1108 const Node& n2 = nodes[element.emap[2]];
1109 const Node& n3 = nodes[element.emap[3]];
1110 // Compute determinant.
1111 const double dd = -(n0.x * n1.y) + n3.x * n2.y - n2.x * n3.y +
1112 x * (-n0.y + n1.y - n2.y + n3.y) + n1.x * (n0.y - y) +
1113 (n0.x + n2.x - n3.x) * y;
1114 det = -(-((n0.x - n3.x) * (n1.y - n2.y)) + (n1.x - n2.x) * (n0.y - n3.y)) *
1115 (2 * x * (-n0.y + n1.y + n2.y - n3.y) -
1116 (n0.x + n3.x) * (n1.y + n2.y - 2 * y) +
1117 n1.x * (n0.y + n3.y - 2 * y) + n2.x * (n0.y + n3.y - 2 * y)) +
1118 dd * dd;
1119
1120 // Check that the determinant is non-negative
1121 // (this can happen if the point is out of range).
1122 if (det < 0) {
1123 if (m_debug) {
1124 std::cerr << m_className << "::Coordinates4:\n"
1125 << " No solution found for isoparametric coordinates\n"
1126 << " because the determinant " << det << " is < 0.\n";
1127 }
1128 return ifail;
1129 }
1130
1131 // Vector products for evaluation of T1.
1132 double prod = ((n2.x - n3.x) * (n0.y - n1.y) - (n0.x - n1.x) * (n2.y - n3.y));
1133 if (prod * prod >
1134 1.0e-12 *
1135 ((n0.x - n1.x) * (n0.x - n1.x) + (n0.y - n1.y) * (n0.y - n1.y)) *
1136 ((n2.x - n3.x) * (n2.x - n3.x) + (n2.y - n3.y) * (n2.y - n3.y))) {
1137 t1 = (-(n3.x * n0.y) + x * n0.y + n2.x * n1.y - x * n1.y - n1.x * n2.y +
1138 x * n2.y + n0.x * n3.y - x * n3.y - n0.x * y + n1.x * y - n2.x * y +
1139 n3.x * y + sqrt(det)) /
1140 prod;
1141 } else {
1142 double xp = n0.y - n1.y;
1143 double yp = n1.x - n0.x;
1144 double dn = sqrt(xp * xp + yp * yp);
1145 if (dn <= 0) {
1146 std::cerr << m_className << "::Coordinates4:\n"
1147 << " Element appears to be degenerate in the 1 - 2 axis.\n";
1148 return ifail;
1149 }
1150 xp = xp / dn;
1151 yp = yp / dn;
1152 double dpoint = xp * (x - n0.x) + yp * (y - n0.y);
1153 double dbox = xp * (n3.x - n0.x) + yp * (n3.y - n0.y);
1154 if (dbox == 0) {
1155 std::cerr << m_className << "::Coordinates4:\n"
1156 << " Element appears to be degenerate in the 1 - 3 axis.\n";
1157 return ifail;
1158 }
1159 double t = -1 + 2 * dpoint / dbox;
1160 double xt1 = n0.x + 0.5 * (t + 1) * (n3.x - n0.x);
1161 double yt1 = n0.y + 0.5 * (t + 1) * (n3.y - n0.y);
1162 double xt2 = n1.x + 0.5 * (t + 1) * (n2.x - n1.x);
1163 double yt2 = n1.y + 0.5 * (t + 1) * (n2.y - n1.y);
1164 dn = (xt1 - xt2) * (xt1 - xt2) + (yt1 - yt2) * (yt1 - yt2);
1165 if (dn <= 0) {
1166 std::cout << m_className << "::Coordinates4:\n";
1167 std::cout
1168 << " Coordinate requested at convergence point of element.\n";
1169 return ifail;
1170 }
1171 t1 = -1 + 2 * ((x - xt1) * (xt2 - xt1) + (y - yt1) * (yt2 - yt1)) / dn;
1172 }
1173
1174 // Vector products for evaluation of T2.
1175 prod = ((n0.x - n3.x) * (n1.y - n2.y) - (n1.x - n2.x) * (n0.y - n3.y));
1176 if (prod * prod >
1177 1.0e-12 *
1178 ((n0.x - n3.x) * (n0.x - n3.x) + (n0.y - n3.y) * (n0.y - n3.y)) *
1179 ((n1.x - n2.x) * (n1.x - n2.x) + (n1.y - n2.y) * (n1.y - n2.y))) {
1180 t2 = (-(n1.x * n0.y) + x * n0.y + n0.x * n1.y - x * n1.y - n3.x * n2.y +
1181 x * n2.y + n2.x * n3.y - x * n3.y - n0.x * y + n1.x * y - n2.x * y +
1182 n3.x * y - sqrt(det)) /
1183 prod;
1184 } else {
1185 double xp = n0.y - n3.y;
1186 double yp = n3.x - n0.x;
1187 double dn = sqrt(xp * xp + yp * yp);
1188 if (dn <= 0) {
1189 std::cerr << m_className << "Coordinates4:\n"
1190 << " Element appears to be degenerate in the 1 - 4 axis.\n";
1191 return ifail;
1192 }
1193 xp = xp / dn;
1194 yp = yp / dn;
1195 double dpoint = xp * (x - n0.x) + yp * (y - n0.y);
1196 double dbox = xp * (n1.x - n0.x) + yp * (n1.y - n0.y);
1197 if (dbox == 0) {
1198 std::cerr << m_className << "::Coordinates4:\n"
1199 << " Element appears to be degenerate in the 1 - 2 axis.\n";
1200 return ifail;
1201 }
1202 double t = -1 + 2 * dpoint / dbox;
1203 double xt1 = n0.x + 0.5 * (t + 1) * (n1.x - n0.x);
1204 double yt1 = n0.y + 0.5 * (t + 1) * (n1.y - n0.y);
1205 double xt2 = n3.x + 0.5 * (t + 1) * (n2.x - n3.x);
1206 double yt2 = n3.y + 0.5 * (t + 1) * (n2.y - n3.y);
1207 dn = (xt1 - xt2) * (xt1 - xt2) + (yt1 - yt2) * (yt1 - yt2);
1208 if (dn <= 0) {
1209 std::cout
1210 << m_className << "::Coordinates4:\n"
1211 << " Coordinate requested at convergence point of element.\n";
1212 return ifail;
1213 }
1214 t2 = -1 + 2 * ((x - xt1) * (xt2 - xt1) + (y - yt1) * (yt2 - yt1)) / dn;
1215 }
1216 if (m_debug) {
1217 std::cout << m_className << "::Coordinates4:\n";
1218 std::cout << " Isoparametric (u, v): (" << t1 << ", " << t2 << ").\n";
1219 }
1220
1221 // Re-compute the (x,y,z) position for this coordinate.
1222 if (m_debug) {
1223 double xr =
1224 n0.x * (1 - t1) * (1 - t2) * 0.25 + n1.x * (1 + t1) * (1 - t2) * 0.25 +
1225 n2.x * (1 + t1) * (1 + t2) * 0.25 + n3.x * (1 - t1) * (1 + t2) * 0.25;
1226 double yr =
1227 n0.y * (1 - t1) * (1 - t2) * 0.25 + n1.y * (1 + t1) * (1 - t2) * 0.25 +
1228 n2.y * (1 + t1) * (1 + t2) * 0.25 + n3.y * (1 - t1) * (1 + t2) * 0.25;
1229 std::cout << m_className << "::Coordinates4: \n";
1230 std::cout << " Position requested: (" << x << ", " << y << ")\n";
1231 std::cout << " Reconstructed: (" << xr << ", " << yr << ")\n";
1232 std::cout << " Difference: (" << x - xr << ", " << y - yr
1233 << ")\n";
1234 }
1235
1236 // This should have worked if we get this far.
1237 ifail = 0;
1238 return ifail;
1239 // Variable jac is not used.
1240 // The following lines are just for quieting the compiler.
1241 jac[0][0] = jac[0][1] = jac[0][2] = jac[0][3] = 0.;
1242 jac[1][0] = jac[1][1] = jac[1][2] = jac[1][3] = 0.;
1243 jac[2][0] = jac[2][1] = jac[2][2] = jac[2][3] = 0.;
1244 jac[3][0] = jac[3][1] = jac[3][2] = jac[3][3] = 0.;
1245}
1246
1247int ComponentFieldMap::Coordinates5(const double x, const double y,
1248 const double z, double& t1, double& t2,
1249 double& t3, double& t4, double jac[4][4],
1250 double& det, const Element& element) const {
1251 // Debugging
1252 if (m_debug) {
1253 std::cout << m_className << "::Coordinates5:\n";
1254 std::cout << " Point (" << x << ", " << y << ", " << z << ")\n";
1255 }
1256
1257 // Failure flag
1258 int ifail = 1;
1259
1260 // Provisional values
1261 t1 = t2 = t3 = t4 = 0;
1262
1263 // Degenerate elements should have been treated as triangles.
1264 if (element.degenerate) {
1265 std::cerr << m_className << "::Coordinates5:\n"
1266 << " Received degenerate element.\n";
1267 return ifail;
1268 }
1269
1270 // Set tolerance parameter.
1271 double f = 0.5;
1272
1273 // Make a first order approximation.
1274 if (Coordinates4(x, y, z, t1, t2, t3, t4, jac, det, element) > 0) {
1275 if (m_debug) {
1276 std::cout << m_className << "::Coordinates5:\n";
1277 std::cout << " Failure to obtain linear estimate of isoparametric "
1278 "coordinates\n.";
1279 }
1280 return ifail;
1281 }
1282
1283 // Check whether the point is far outside.
1284 if (t1 < -(1 + f) || t1 > (1 + f) || t2 < -(1 + f) || t2 > (1 + f)) {
1285 if (m_debug) {
1286 std::cout << m_className << "::Coordinates5:\n";
1287 std::cout << " Point far outside, (t1,t2) = (" << t1 << ", " << t2
1288 << ").\n";
1289 }
1290 return ifail;
1291 }
1292
1293 // Start iteration
1294 double td1 = t1, td2 = t2;
1295 const Node& n0 = nodes[element.emap[0]];
1296 const Node& n1 = nodes[element.emap[1]];
1297 const Node& n2 = nodes[element.emap[2]];
1298 const Node& n3 = nodes[element.emap[3]];
1299 const Node& n4 = nodes[element.emap[4]];
1300 const Node& n5 = nodes[element.emap[5]];
1301 const Node& n6 = nodes[element.emap[6]];
1302 const Node& n7 = nodes[element.emap[7]];
1303 bool converged = false;
1304 for (int iter = 0; iter < 10; iter++) {
1305 if (m_debug) {
1306 std::cout << m_className << "::Coordinates5:\n";
1307 std::cout << " Iteration " << iter << ": (t1, t2) = (" << td1
1308 << ", " << td2 << ").\n";
1309 }
1310 // Re-compute the (x,y,z) position for this coordinate.
1311 const double r0 = (-(1 - td1) * (1 - td2) * (1 + td1 + td2)) * 0.25;
1312 const double r1 = (-(1 + td1) * (1 - td2) * (1 - td1 + td2)) * 0.25;
1313 const double r2 = (-(1 + td1) * (1 + td2) * (1 - td1 - td2)) * 0.25;
1314 const double r3 = (-(1 - td1) * (1 + td2) * (1 + td1 - td2)) * 0.25;
1315 const double r4 = (1 - td1) * (1 + td1) * (1 - td2) * 0.5;
1316 const double r5 = (1 + td1) * (1 + td2) * (1 - td2) * 0.5;
1317 const double r6 = (1 - td1) * (1 + td1) * (1 + td2) * 0.5;
1318 const double r7 = (1 - td1) * (1 + td2) * (1 - td2) * 0.5;
1319 double xr = n0.x * r0 + n1.x * r1 + n2.x * r2 + n3.x * r3 + n4.x * r4 +
1320 n5.x * r5 + n6.x * r6 + n7.x * r7;
1321 double yr = n0.y * r0 + n1.y * r1 + n2.y * r2 + n3.y * r3 + n4.y * r4 +
1322 n5.y * r5 + n6.y * r6 + n7.y * r7;
1323 // Compute the Jacobian.
1324 Jacobian5(element, td1, td2, det, jac);
1325 // Compute the difference vector.
1326 double diff[2] = {x - xr, y - yr};
1327 // Update the estimate.
1328 double corr[2] = {0., 0.};
1329 for (int l = 0; l < 2; ++l) {
1330 for (int k = 0; k < 2; ++k) {
1331 corr[l] += jac[l][k] * diff[k] / det;
1332 }
1333 }
1334 // Debugging
1335 if (m_debug) {
1336 std::cout << m_className << "::Coordinates5:\n";
1337 std::cout << " Difference vector: (x, y) = (" << diff[0] << ", "
1338 << diff[1] << ").\n";
1339 std::cout << " Correction vector: (t1, t2) = (" << corr[0] << ", "
1340 << corr[1] << ").\n";
1341 }
1342 // Update the vector.
1343 td1 += corr[0];
1344 td2 += corr[1];
1345 // Check for convergence.
1346 if (fabs(corr[0]) < 1.0e-5 && fabs(corr[1]) < 1.0e-5) {
1347 if (m_debug) {
1348 std::cout << m_className << "::Coordinates5:\n";
1349 std::cout << " Convergence reached.\n";
1350 }
1351 converged = true;
1352 break;
1353 }
1354 }
1355 // No convergence reached.
1356 if (!converged) {
1357 double xmin = std::min({n0.x, n1.x, n2.x, n3.x, n4.x, n5.x, n6.x, n7.x});
1358 double xmax = std::max({n0.x, n1.x, n2.x, n3.x, n4.x, n5.x, n6.x, n7.x});
1359 double ymin = std::min({n0.y, n1.y, n2.y, n3.y, n4.y, n5.y, n6.y, n7.y});
1360 double ymax = std::max({n0.y, n1.y, n2.y, n3.y, n4.y, n5.y, n6.y, n7.y});
1361 if (x >= xmin && x <= xmax && y >= ymin && y <= ymax) {
1362 std::cout << m_className << "::Coordinates5:\n"
1363 << " No convergence achieved "
1364 << "when refining internal isoparametric coordinates\n"
1365 << " at position (" << x << ", " << y << ").\n";
1366 t1 = t2 = 0;
1367 return ifail;
1368 }
1369 }
1370
1371 // Convergence reached.
1372 t1 = td1;
1373 t2 = td2;
1374 t3 = 0;
1375 t4 = 0;
1376 if (m_debug) {
1377 std::cout << m_className << "::Coordinates5:\n";
1378 std::cout << " Convergence reached at (t1, t2) = (" << t1 << ", " << t2
1379 << ").\n";
1380 }
1381
1382 // For debugging purposes, show position.
1383 if (m_debug) {
1384 const double r0 = (-(1 - td1) * (1 - td2) * (1 + td1 + td2)) * 0.25;
1385 const double r1 = (-(1 + td1) * (1 - td2) * (1 - td1 + td2)) * 0.25;
1386 const double r2 = (-(1 + td1) * (1 + td2) * (1 - td1 - td2)) * 0.25;
1387 const double r3 = (-(1 - td1) * (1 + td2) * (1 + td1 - td2)) * 0.25;
1388 const double r4 = (1 - td1) * (1 + td1) * (1 - td2) * 0.5;
1389 const double r5 = (1 + td1) * (1 + td2) * (1 - td2) * 0.5;
1390 const double r6 = (1 - td1) * (1 + td1) * (1 + td2) * 0.5;
1391 const double r7 = (1 - td1) * (1 + td2) * (1 - td2) * 0.5;
1392 double xr = n0.x * r0 + n1.x * r1 + n2.x * r2 + n3.x * r3 + n4.x * r4 +
1393 n5.x * r5 + n6.x * r6 + n7.x * r7;
1394 double yr = n0.y * r0 + n1.y * r1 + n2.y * r2 + n3.y * r3 + n4.y * r4 +
1395 n5.y * r5 + n6.y * r6 + n7.y * r7;
1396 std::cout << m_className << "::Coordinates5:\n";
1397 std::cout << " Position requested: (" << x << ", " << y << ")\n";
1398 std::cout << " Reconstructed: (" << xr << ", " << yr << ")\n";
1399 std::cout << " Difference: (" << x - xr << ", " << y - yr
1400 << ")\n";
1401 }
1402
1403 // Success
1404 ifail = 0;
1405 return ifail;
1406}
1407
1408int ComponentFieldMap::Coordinates12(const double x, const double y,
1409 const double z, double& t1, double& t2,
1410 double& t3, double& t4,
1411 const Element& element) const {
1412 if (m_debug) {
1413 std::cout << m_className << "::Coordinates12:\n"
1414 << " Point (" << x << ", " << y << ", " << z << ").\n";
1415 }
1416
1417 // Failure flag
1418 int ifail = 1;
1419 const Node& n0 = nodes[element.emap[0]];
1420 const Node& n1 = nodes[element.emap[1]];
1421 const Node& n2 = nodes[element.emap[2]];
1422 const Node& n3 = nodes[element.emap[3]];
1423 // Compute tetrahedral coordinates.
1424 const double f1x =
1425 (n2.y - n1.y) * (n3.z - n1.z) - (n3.y - n1.y) * (n2.z - n1.z);
1426 const double f1y =
1427 (n2.z - n1.z) * (n3.x - n1.x) - (n3.z - n1.z) * (n2.x - n1.x);
1428 const double f1z =
1429 (n2.x - n1.x) * (n3.y - n1.y) - (n3.x - n1.x) * (n2.y - n1.y);
1430 t1 = (x - n1.x) * f1x + (y - n1.y) * f1y + (z - n1.z) * f1z;
1431 t1 = t1 / ((n0.x - n1.x) * f1x + (n0.y - n1.y) * f1y + (n0.z - n1.z) * f1z);
1432 const double f2x =
1433 (n0.y - n2.y) * (n3.z - n2.z) - (n3.y - n2.y) * (n0.z - n2.z);
1434 const double f2y =
1435 (n0.z - n2.z) * (n3.x - n2.x) - (n3.z - n2.z) * (n0.x - n2.x);
1436 const double f2z =
1437 (n0.x - n2.x) * (n3.y - n2.y) - (n3.x - n2.x) * (n0.y - n2.y);
1438 t2 = (x - n2.x) * f2x + (y - n2.y) * f2y + (z - n2.z) * f2z;
1439 t2 = t2 / ((n1.x - n2.x) * f2x + (n1.y - n2.y) * f2y + (n1.z - n2.z) * f2z);
1440 const double f3x =
1441 (n0.y - n3.y) * (n1.z - n3.z) - (n1.y - n3.y) * (n0.z - n3.z);
1442 const double f3y =
1443 (n0.z - n3.z) * (n1.x - n3.x) - (n1.z - n3.z) * (n0.x - n3.x);
1444 const double f3z =
1445 (n0.x - n3.x) * (n1.y - n3.y) - (n1.x - n3.x) * (n0.y - n3.y);
1446 t3 = (x - n3.x) * f3x + (y - n3.y) * f3y + (z - n3.z) * f3z;
1447 t3 = t3 / ((n2.x - n3.x) * f3x + (n2.y - n3.y) * f3y + (n2.z - n3.z) * f3z);
1448 const double f4x =
1449 (n2.y - n0.y) * (n1.z - n0.z) - (n1.y - n0.y) * (n2.z - n0.z);
1450 const double f4y =
1451 (n2.z - n0.z) * (n1.x - n0.x) - (n1.z - n0.z) * (n2.x - n0.x);
1452 const double f4z =
1453 (n2.x - n0.x) * (n1.y - n0.y) - (n1.x - n0.x) * (n2.y - n0.y);
1454 t4 = (x - n0.x) * f4x + (y - n0.y) * f4y + (z - n0.z) * f4z;
1455 t4 = t4 / ((n3.x - n0.x) * f4x + (n3.y - n0.y) * f4y + (n3.z - n0.z) * f4z);
1456
1457 // Result
1458 if (m_debug) {
1459 std::cout << m_className << "::Coordinates12:\n";
1460 std::cout << " Tetrahedral coordinates (t, u, v, w) = (" << t1 << ", "
1461 << t2 << ", " << t3 << ", " << t4
1462 << ") sum = " << t1 + t2 + t3 + t4 << ".\n";
1463 }
1464 // Re-compute the (x,y,z) position for this coordinate.
1465 if (m_debug) {
1466 const double xr = n0.x * t1 + n1.x * t2 + n2.x * t3 + n3.x * t4;
1467 const double yr = n0.y * t1 + n1.y * t2 + n2.y * t3 + n3.y * t4;
1468 const double zr = n0.z * t1 + n1.z * t2 + n2.z * t3 + n3.z * t4;
1469 const double sr = t1 + t2 + t3 + t4;
1470 std::cout << m_className << "::Coordinates12:\n";
1471 std::cout << " Position requested: (" << x << ", " << y << ", " << z
1472 << ")\n";
1473 std::cout << " Reconstructed: (" << xr << ", " << yr << ", "
1474 << zr << ")\n";
1475 std::cout << " Difference: (" << x - xr << ", " << y - yr
1476 << ", " << z - zr << ")\n";
1477 std::cout << " Checksum - 1: " << sr - 1 << "\n";
1478 }
1479
1480 // This should always work.
1481 ifail = 0;
1482 return ifail;
1483}
1484
1485int ComponentFieldMap::Coordinates13(const double x, const double y,
1486 const double z, double& t1, double& t2,
1487 double& t3, double& t4, double jac[4][4],
1488 double& det,
1489 const Element& element) const {
1490 if (m_debug) {
1491 std::cout << m_className << "::Coordinates13:\n";
1492 std::cout << " Point (" << x << ", " << y << ", " << z << ")\n";
1493 }
1494
1495 // Failure flag
1496 int ifail = 1;
1497
1498 // Provisional values
1499 t1 = t2 = t3 = t4 = 0.;
1500
1501 // Make a first order approximation.
1502 if (Coordinates12(x, y, z, t1, t2, t3, t4, element) > 0) {
1503 if (m_debug) {
1504 std::cout << m_className << "::Coordinates13:\n"
1505 << " Failure to obtain linear estimate of isoparametric "
1506 "coordinates\n";
1507 }
1508 return ifail;
1509 }
1510
1511 // Set tolerance parameter.
1512 const double f = 0.5;
1513 if (t1 < -f || t2 < -f || t3 < -f || t4 < -f || t1 > 1 + f || t2 > 1 + f ||
1514 t3 > 1 + f || t4 > 1 + f) {
1515 if (m_debug) {
1516 std::cout << m_className << "::Coordinates13:\n";
1517 std::cout << " Linear isoparametric coordinates more than\n";
1518 std::cout << " f (" << f << ") out of range.\n";
1519 }
1520 ifail = 0;
1521 return ifail;
1522 }
1523
1524 // Start iteration.
1525 double td1 = t1, td2 = t2, td3 = t3, td4 = t4;
1526 if (m_debug) {
1527 std::cout << m_className << "::Coordinates13:\n";
1528 std::cout << " Iteration starts at (t1,t2,t3,t4) = (" << td1 << ", "
1529 << td2 << ", " << td3 << ", " << td4 << ").\n";
1530 }
1531 const Node& n0 = nodes[element.emap[0]];
1532 const Node& n1 = nodes[element.emap[1]];
1533 const Node& n2 = nodes[element.emap[2]];
1534 const Node& n3 = nodes[element.emap[3]];
1535 const Node& n4 = nodes[element.emap[4]];
1536 const Node& n5 = nodes[element.emap[5]];
1537 const Node& n6 = nodes[element.emap[6]];
1538 const Node& n7 = nodes[element.emap[7]];
1539 const Node& n8 = nodes[element.emap[8]];
1540 const Node& n9 = nodes[element.emap[9]];
1541
1542 // Loop
1543 bool converged = false;
1544 double diff[4], corr[4];
1545 for (int iter = 0; iter < 10; iter++) {
1546 if (m_debug) {
1547 std::cout << m_className << "::Coordinates13:\n";
1548 std::cout << " Iteration " << iter << ": (t1,t2,t3,t4) = (" << td1
1549 << ", " << td2 << ", " << td3 << ", " << td4 << ").\n";
1550 }
1551 // Re-compute the (x,y,z) position for this coordinate.
1552 const double xr = n0.x * td1 * (2 * td1 - 1) + n1.x * td2 * (2 * td2 - 1) +
1553 n2.x * td3 * (2 * td3 - 1) + n3.x * td4 * (2 * td4 - 1) +
1554 n4.x * 4 * td1 * td2 + n5.x * 4 * td1 * td3 +
1555 n6.x * 4 * td1 * td4 + n7.x * 4 * td2 * td3 +
1556 n8.x * 4 * td2 * td4 + n9.x * 4 * td3 * td4;
1557 const double yr = n0.y * td1 * (2 * td1 - 1) + n1.y * td2 * (2 * td2 - 1) +
1558 n2.y * td3 * (2 * td3 - 1) + n3.y * td4 * (2 * td4 - 1) +
1559 n4.y * 4 * td1 * td2 + n5.y * 4 * td1 * td3 +
1560 n6.y * 4 * td1 * td4 + n7.y * 4 * td2 * td3 +
1561 n8.y * 4 * td2 * td4 + n9.y * 4 * td3 * td4;
1562 const double zr = n0.z * td1 * (2 * td1 - 1) + n1.z * td2 * (2 * td2 - 1) +
1563 n2.z * td3 * (2 * td3 - 1) + n3.z * td4 * (2 * td4 - 1) +
1564 n4.z * 4 * td1 * td2 + n5.z * 4 * td1 * td3 +
1565 n6.z * 4 * td1 * td4 + n7.z * 4 * td2 * td3 +
1566 n8.z * 4 * td2 * td4 + n9.z * 4 * td3 * td4;
1567 const double sr = td1 + td2 + td3 + td4;
1568
1569 // Compute the Jacobian.
1570 Jacobian13(element, td1, td2, td3, td4, det, jac);
1571 // Compute the difference vector.
1572 diff[0] = 1 - sr;
1573 diff[1] = x - xr;
1574 diff[2] = y - yr;
1575 diff[3] = z - zr;
1576
1577 // Update the estimate.
1578 const double invdet = 1. / det;
1579 for (int l = 0; l < 4; ++l) {
1580 corr[l] = 0;
1581 for (int k = 0; k < 4; ++k) {
1582 corr[l] += jac[l][k] * diff[k] * invdet;
1583 }
1584 }
1585
1586 // Debugging
1587 if (m_debug) {
1588 std::cout << m_className << "::Coordinates13:\n";
1589 std::cout << " Difference vector: (1, x, y, z) = (" << diff[0]
1590 << ", " << diff[1] << ", " << diff[2] << ", " << diff[3]
1591 << ").\n";
1592 std::cout << " Correction vector: (t1,t2,t3,t4) = (" << corr[0]
1593 << ", " << corr[1] << ", " << corr[2] << ", " << corr[3]
1594 << ").\n";
1595 }
1596
1597 // Update the vector.
1598 td1 += corr[0];
1599 td2 += corr[1];
1600 td3 += corr[2];
1601 td4 += corr[3];
1602
1603 // Check for convergence.
1604 if (fabs(corr[0]) < 1.0e-5 && fabs(corr[1]) < 1.0e-5 &&
1605 fabs(corr[2]) < 1.0e-5 && fabs(corr[3]) < 1.0e-5) {
1606 if (m_debug) {
1607 std::cout << m_className << "::Coordinates13: Convergence reached.\n";
1608 }
1609 converged = true;
1610 break;
1611 }
1612 }
1613
1614 // No convergence reached.
1615 if (!converged) {
1616 const double xmin = std::min({n0.x, n1.x, n2.x, n3.x});
1617 const double xmax = std::max({n0.x, n1.x, n2.x, n3.x});
1618 const double ymin = std::min({n0.y, n1.y, n2.y, n3.y});
1619 const double ymax = std::max({n0.y, n1.y, n2.y, n3.y});
1620 const double zmin = std::min({n0.z, n1.z, n2.z, n3.z});
1621 const double zmax = std::max({n0.z, n1.z, n2.z, n3.z});
1622 if (x >= xmin && x <= xmax && y >= ymin && y <= ymax && z >= zmin &&
1623 z <= zmax) {
1624 std::cout << m_className << "::Coordinates13:\n"
1625 << " No convergence achieved "
1626 << "when refining internal isoparametric coordinates\n"
1627 << " at position (" << x << ", " << y << ", " << z << ").\n";
1628 t1 = t2 = t3 = t4 = -1;
1629 return ifail;
1630 }
1631 }
1632
1633 // Convergence reached.
1634 t1 = td1;
1635 t2 = td2;
1636 t3 = td3;
1637 t4 = td4;
1638 if (m_debug) {
1639 std::cout << m_className << "::Coordinates13:\n";
1640 std::cout << " Convergence reached at (t1, t2, t3, t4) = (" << t1 << ", "
1641 << t2 << ", " << t3 << ", " << t4 << ").\n";
1642 }
1643
1644 // For debugging purposes, show position.
1645 if (m_debug) {
1646 // Re-compute the (x,y,z) position for this coordinate.
1647 double xr = n0.x * td1 * (2 * td1 - 1) + n1.x * td2 * (2 * td2 - 1) +
1648 n2.x * td3 * (2 * td3 - 1) + n3.x * td4 * (2 * td4 - 1) +
1649 n4.x * 4 * td1 * td2 + n5.x * 4 * td1 * td3 +
1650 n6.x * 4 * td1 * td4 + n7.x * 4 * td2 * td3 +
1651 n8.x * 4 * td2 * td4 + n9.x * 4 * td3 * td4;
1652 double yr = n0.y * td1 * (2 * td1 - 1) + n1.y * td2 * (2 * td2 - 1) +
1653 n2.y * td3 * (2 * td3 - 1) + n3.y * td4 * (2 * td4 - 1) +
1654 n4.y * 4 * td1 * td2 + n5.y * 4 * td1 * td3 +
1655 n6.y * 4 * td1 * td4 + n7.y * 4 * td2 * td3 +
1656 n8.y * 4 * td2 * td4 + n9.y * 4 * td3 * td4;
1657 double zr = n0.z * td1 * (2 * td1 - 1) + n1.z * td2 * (2 * td2 - 1) +
1658 n2.z * td3 * (2 * td3 - 1) + n3.z * td4 * (2 * td4 - 1) +
1659 n4.z * 4 * td1 * td2 + n5.z * 4 * td1 * td3 +
1660 n6.z * 4 * td1 * td4 + n7.z * 4 * td2 * td3 +
1661 n8.z * 4 * td2 * td4 + n9.z * 4 * td3 * td4;
1662 double sr = td1 + td2 + td3 + td4;
1663 std::cout << m_className << "::Coordinates13:\n";
1664 std::cout << " Position requested: (" << x << ", " << y << ", " << z
1665 << ")\n";
1666 std::cout << " Reconstructed: (" << xr << ", " << yr << ", "
1667 << zr << ")\n";
1668 std::cout << " Difference: (" << x - xr << ", " << y - yr
1669 << ", " << z - zr << ")\n";
1670 std::cout << " Checksum - 1: " << sr - 1 << "\n";
1671 }
1672
1673 // Success
1674 ifail = 0;
1675 return ifail;
1676}
1677
1678int ComponentFieldMap::CoordinatesCube(const double x, const double y,
1679 const double z, double& t1, double& t2,
1680 double& t3, TMatrixD*& jac,
1681 std::vector<TMatrixD*>& dN,
1682 const Element& element) const {
1683 /*
1684 global coordinates 7__ _ _ 6 t3 t2
1685 / /| ^ /|
1686 ^ z / / | | /
1687 | 4_______5 | | /
1688 | | | | | /
1689 | | 3 | 2 |/ t1
1690 -------> | | / ------->
1691 / y | |/ local coordinates
1692 / 0--------1
1693 /
1694 v x
1695 */
1696
1697 // Failure flag
1698 int ifail = 1;
1699
1700 const Node& n0 = nodes[element.emap[0]];
1701 const Node& n2 = nodes[element.emap[2]];
1702 const Node& n3 = nodes[element.emap[3]];
1703 const Node& n7 = nodes[element.emap[7]];
1704
1705 // Compute hexahedral coordinates (t1->[-1,1],t2->[-1,1],t3->[-1,1]) and
1706 // t1 (zeta) is in y-direction
1707 // t2 (eta) is in opposite x-direction
1708 // t3 (mu) is in z-direction
1709 // Nodes are set in that way, that node [0] has always lowest x,y,z!
1710 t2 = (2. * (x - n3.x) / (n0.x - n3.x) - 1) * -1.;
1711 t1 = 2. * (y - n3.y) / (n2.y - n3.y) - 1;
1712 t3 = 2. * (z - n3.z) / (n7.z - n3.z) - 1;
1713 // Re-compute the (x,y,z) position for this coordinate.
1714 if (m_debug) {
1715 double n[8];
1716 n[0] = 1. / 8 * (1 - t1) * (1 - t2) * (1 - t3);
1717 n[1] = 1. / 8 * (1 + t1) * (1 - t2) * (1 - t3);
1718 n[2] = 1. / 8 * (1 + t1) * (1 + t2) * (1 - t3);
1719 n[3] = 1. / 8 * (1 - t1) * (1 + t2) * (1 - t3);
1720 n[4] = 1. / 8 * (1 - t1) * (1 - t2) * (1 + t3);
1721 n[5] = 1. / 8 * (1 + t1) * (1 - t2) * (1 + t3);
1722 n[6] = 1. / 8 * (1 + t1) * (1 + t2) * (1 + t3);
1723 n[7] = 1. / 8 * (1 - t1) * (1 + t2) * (1 + t3);
1724
1725 double xr = 0;
1726 double yr = 0;
1727 double zr = 0;
1728
1729 for (int i = 0; i < 8; i++) {
1730 const Node& node = nodes[element.emap[i]];
1731 xr += node.x * n[i];
1732 yr += node.y * n[i];
1733 zr += node.z * n[i];
1734 }
1735 double sr = n[0] + n[1] + n[2] + n[3] + n[4] + n[5] + n[6] + n[7];
1736 std::cout << m_className << "::CoordinatesCube:\n";
1737 std::cout << " Position requested: (" << x << "," << y << "," << z
1738 << ")\n";
1739 std::cout << " Position reconstructed: (" << xr << "," << yr << "," << zr
1740 << ")\n";
1741 std::cout << " Difference: (" << (x - xr) << "," << (y - yr)
1742 << "," << (z - zr) << ")\n";
1743 std::cout << " Hexahedral coordinates (t, u, v) = (" << t1 << "," << t2
1744 << "," << t3 << ")\n";
1745 std::cout << " Checksum - 1: " << (sr - 1) << "\n";
1746 }
1747 if (jac != 0) JacobianCube(element, t1, t2, t3, jac, dN);
1748 // This should always work.
1749 ifail = 0;
1750 return ifail;
1751}
1752
1754 // Check the required data is available.
1755 if (!m_ready) {
1756 std::cerr << m_className << "::UpdatePeriodicityCommon:\n";
1757 std::cerr << " No valid field map available.\n";
1758 return;
1759 }
1760
1761 for (unsigned int i = 0; i < 3; ++i) {
1762 // No regular and mirror periodicity at the same time.
1763 if (m_periodic[i] && m_mirrorPeriodic[i]) {
1764 std::cerr << m_className << "::UpdatePeriodicityCommon:\n"
1765 << " Both simple and mirror periodicity requested. Reset.\n";
1766 m_periodic[i] = false;
1767 m_mirrorPeriodic[i] = false;
1768 m_warning = true;
1769 }
1770 // In case of axial periodicity,
1771 // the range must be an integral part of two pi.
1772 if (m_axiallyPeriodic[i]) {
1773 if (m_mapamin[i] >= m_mapamax[i]) {
1774 m_mapna[i] = 0;
1775 } else {
1776 m_mapna[i] = TwoPi / (m_mapamax[i] - m_mapamin[i]);
1777 }
1778 if (fabs(m_mapna[i] - int(0.5 + m_mapna[i])) > 0.001 ||
1779 m_mapna[i] < 1.5) {
1780 std::cerr
1781 << m_className << "::UpdatePeriodicityCommon:\n"
1782 << " Axial symmetry has been requested but the map\n"
1783 << " does not cover an integral fraction of 2 pi. Reset.\n";
1784 m_axiallyPeriodic[i] = false;
1785 m_warning = true;
1786 }
1787 }
1788 }
1789
1790 // Not more than 1 rotational symmetry
1794 std::cerr << m_className << "::UpdatePeriodicityCommon:\n";
1795 std::cerr << " Only 1 rotational symmetry allowed; reset.\n";
1796 m_rotationSymmetric.fill(false);
1797 m_warning = true;
1798 }
1799
1800 // No rotational symmetry as well as axial periodicity
1802 m_rotationSymmetric[2]) &&
1804 std::cerr << m_className << "::UpdatePeriodicityCommon:\n";
1805 std::cerr << " Not allowed to combine rotational symmetry\n";
1806 std::cerr << " and axial periodicity; reset.\n";
1807 m_axiallyPeriodic.fill(false);
1808 m_rotationSymmetric.fill(false);
1809 m_warning = true;
1810 }
1811
1812 // In case of rotational symmetry, the x-range should not straddle 0.
1815 if (m_mapmin[0] * m_mapmax[0] < 0) {
1816 std::cerr << m_className << "::UpdatePeriodicityCommon:\n";
1817 std::cerr << " Rotational symmetry requested, \n";
1818 std::cerr << " but x-range straddles 0; reset.\n";
1819 m_rotationSymmetric.fill(false);
1820 m_warning = true;
1821 }
1822 }
1823
1824 // Recompute the cell ranges.
1825 for (unsigned int i = 0; i < 3; ++i) {
1826 m_minBoundingBox[i] = m_mapmin[i];
1827 m_maxBoundingBox[i] = m_mapmax[i];
1828 m_cells[i] = fabs(m_mapmax[i] - m_mapmin[i]);
1829 }
1830 if (m_rotationSymmetric[0]) {
1831 m_minBoundingBox[0] = m_mapmin[1];
1832 m_maxBoundingBox[0] = m_mapmax[1];
1833 m_minBoundingBox[1] = -std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0]));
1834 m_maxBoundingBox[1] = +std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0]));
1835 m_minBoundingBox[2] = -std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0]));
1836 m_maxBoundingBox[2] = +std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0]));
1837 } else if (m_rotationSymmetric[1]) {
1838 m_minBoundingBox[0] = -std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0]));
1839 m_maxBoundingBox[0] = +std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0]));
1840 m_minBoundingBox[1] = m_mapmin[1];
1841 m_maxBoundingBox[1] = m_mapmax[1];
1842 m_minBoundingBox[2] = -std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0]));
1843 m_maxBoundingBox[2] = +std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0]));
1844 } else if (m_rotationSymmetric[2]) {
1845 m_minBoundingBox[0] = -std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0]));
1846 m_maxBoundingBox[0] = +std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0]));
1847 m_minBoundingBox[1] = -std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0]));
1848 m_maxBoundingBox[1] = +std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0]));
1849 m_minBoundingBox[2] = m_mapmin[1];
1850 m_maxBoundingBox[2] = m_mapmax[1];
1851 }
1852
1853 if (m_axiallyPeriodic[0]) {
1854 m_minBoundingBox[1] =
1855 -std::max(std::max(fabs(m_mapmin[1]), fabs(m_mapmax[1])),
1856 std::max(fabs(m_mapmin[2]), fabs(m_mapmax[2])));
1857 m_maxBoundingBox[1] =
1858 +std::max(std::max(fabs(m_mapmin[1]), fabs(m_mapmax[1])),
1859 std::max(fabs(m_mapmin[2]), fabs(m_mapmax[2])));
1860 m_minBoundingBox[2] =
1861 -std::max(std::max(fabs(m_mapmin[1]), fabs(m_mapmax[1])),
1862 std::max(fabs(m_mapmin[2]), fabs(m_mapmax[2])));
1863 m_maxBoundingBox[2] =
1864 +std::max(std::max(fabs(m_mapmin[1]), fabs(m_mapmax[1])),
1865 std::max(fabs(m_mapmin[2]), fabs(m_mapmax[2])));
1866 } else if (m_axiallyPeriodic[1]) {
1867 m_minBoundingBox[0] =
1868 -std::max(std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0])),
1869 std::max(fabs(m_mapmin[2]), fabs(m_mapmax[2])));
1870 m_maxBoundingBox[0] =
1871 +std::max(std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0])),
1872 std::max(fabs(m_mapmin[2]), fabs(m_mapmax[2])));
1873 m_minBoundingBox[2] =
1874 -std::max(std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0])),
1875 std::max(fabs(m_mapmin[2]), fabs(m_mapmax[2])));
1876 m_maxBoundingBox[2] =
1877 +std::max(std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0])),
1878 std::max(fabs(m_mapmin[2]), fabs(m_mapmax[2])));
1879 } else if (m_axiallyPeriodic[2]) {
1880 m_minBoundingBox[0] =
1881 -std::max(std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0])),
1882 std::max(fabs(m_mapmin[1]), fabs(m_mapmax[1])));
1883 m_maxBoundingBox[0] =
1884 +std::max(std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0])),
1885 std::max(fabs(m_mapmin[1]), fabs(m_mapmax[1])));
1886 m_minBoundingBox[1] =
1887 -std::max(std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0])),
1888 std::max(fabs(m_mapmin[1]), fabs(m_mapmax[1])));
1889 m_maxBoundingBox[1] =
1890 +std::max(std::max(fabs(m_mapmin[0]), fabs(m_mapmax[0])),
1891 std::max(fabs(m_mapmin[1]), fabs(m_mapmax[1])));
1892 }
1893
1894 for (unsigned int i = 0; i < 3; ++i) {
1895 if (m_periodic[i] || m_mirrorPeriodic[i]) {
1896 m_minBoundingBox[i] = -INFINITY;
1897 m_maxBoundingBox[i] = +INFINITY;
1898 }
1899 }
1900
1901 // Display the range if requested.
1902 if (m_debug) PrintRange();
1903}
1904
1906 // Check the required data is available.
1907 if (!m_ready) {
1908 std::cerr << m_className << "::UpdatePeriodicity2d:\n";
1909 std::cerr << " No valid field map available.\n";
1910 return;
1911 }
1912
1913 // No z-periodicity in 2d
1914 if (m_periodic[2] || m_mirrorPeriodic[2]) {
1915 std::cerr << m_className << "::UpdatePeriodicity2d:\n";
1916 std::cerr << " Simple or mirror periodicity along z\n";
1917 std::cerr << " requested for a 2d map; reset.\n";
1918 m_periodic[2] = false;
1919 m_mirrorPeriodic[2] = false;
1920 m_warning = true;
1921 }
1922
1923 // Only z-axial periodicity in 2d maps
1924 if (m_axiallyPeriodic[0] || m_axiallyPeriodic[1]) {
1925 std::cerr << m_className << "::UpdatePeriodicity2d:\n";
1926 std::cerr << " Axial symmetry has been requested \n";
1927 std::cerr << " around x or y for a 2D map; reset.\n";
1928 m_axiallyPeriodic[0] = false;
1929 m_axiallyPeriodic[1] = false;
1930 m_warning = true;
1931 }
1932}
1933
1935 // Initial values
1936 m_mapmin.fill(0.);
1937 m_mapmax.fill(0.);
1938 m_mapamin.fill(0.);
1939 m_mapamax.fill(0.);
1940 m_mapvmin = m_mapvmax = 0.;
1941 m_setang.fill(false);
1942
1943 // Make sure the required data is available.
1944 if (!m_ready || nNodes < 1) {
1945 std::cerr << m_className << "::SetRange:\n";
1946 std::cerr << " Field map not yet set.\n";
1947 return;
1948 }
1949 if (nNodes < 1) {
1950 std::cerr << m_className << "::SetRange:\n";
1951 std::cerr << " Number of nodes < 1.\n";
1952 return;
1953 }
1954
1955 // Loop over the nodes.
1956 m_mapmin[0] = m_mapmax[0] = nodes[0].x;
1957 m_mapmin[1] = m_mapmax[1] = nodes[0].y;
1958 m_mapmin[2] = m_mapmax[2] = nodes[0].z;
1959 m_mapvmin = m_mapvmax = nodes[0].v;
1960
1961 for (const auto& node : nodes) {
1962 const std::array<double, 3> pos = {{node.x, node.y, node.z}};
1963 for (unsigned int i = 0; i < 3; ++i) {
1964 m_mapmin[i] = std::min(m_mapmin[i], pos[i]);
1965 m_mapmax[i] = std::max(m_mapmax[i], pos[i]);
1966 }
1967 m_mapvmin = std::min(m_mapvmin, node.v);
1968 m_mapvmax = std::max(m_mapvmax, node.v);
1969
1970 if (node.y != 0 || node.z != 0) {
1971 const double ang = atan2(node.z, node.y);
1972 if (m_setang[0]) {
1973 m_mapamin[0] = std::min(m_mapamin[0], ang);
1974 m_mapamax[0] = std::max(m_mapamax[0], ang);
1975 } else {
1976 m_mapamin[0] = m_mapamax[0] = ang;
1977 m_setang[0] = true;
1978 }
1979 }
1980
1981 if (node.z != 0 || node.x != 0) {
1982 const double ang = atan2(node.x, node.z);
1983 if (m_setang[1]) {
1984 m_mapamin[1] = std::min(m_mapamin[1], ang);
1985 m_mapamax[1] = std::max(m_mapamax[1], ang);
1986 } else {
1987 m_mapamin[1] = m_mapamax[1] = ang;
1988 m_setang[1] = true;
1989 }
1990 }
1991
1992 if (node.x != 0 || node.y != 0) {
1993 const double ang = atan2(node.y, node.x);
1994 if (m_setang[2]) {
1995 m_mapamin[2] = std::min(m_mapamin[2], ang);
1996 m_mapamax[2] = std::max(m_mapamax[2], ang);
1997 } else {
1998 m_mapamin[2] = m_mapamax[2] = ang;
1999 m_setang[2] = true;
2000 }
2001 }
2002 }
2003
2004 // Fix the angular ranges.
2005 for (unsigned int i = 0; i < 3; ++i) {
2006 if (m_mapamax[i] - m_mapamin[i] > Pi) {
2007 const double aux = m_mapamin[i];
2008 m_mapamin[i] = m_mapamax[i];
2009 m_mapamax[i] = aux + TwoPi;
2010 }
2011 }
2012
2013 // Set provisional cell dimensions.
2014 m_minBoundingBox[0] = m_mapmin[0];
2015 m_maxBoundingBox[0] = m_mapmax[0];
2016 m_minBoundingBox[1] = m_mapmin[1];
2017 m_maxBoundingBox[1] = m_mapmax[1];
2018 if (m_is3d) {
2019 m_minBoundingBox[2] = m_mapmin[2];
2020 m_maxBoundingBox[2] = m_mapmax[2];
2021 } else {
2022 m_mapmin[2] = m_minBoundingBox[2];
2023 m_mapmax[2] = m_maxBoundingBox[2];
2024 }
2025 hasBoundingBox = true;
2026
2027 // Display the range if requested.
2028 if (m_debug) PrintRange();
2029}
2030
2032 std::cout << m_className << "::PrintRange:\n";
2033 std::cout << " Dimensions of the elementary block\n";
2034 printf(" %15g < x < %-15g cm,\n", m_mapmin[0], m_mapmax[0]);
2035 printf(" %15g < y < %-15g cm,\n", m_mapmin[1], m_mapmax[1]);
2036 printf(" %15g < z < %-15g cm,\n", m_mapmin[2], m_mapmax[2]);
2037 printf(" %15g < V < %-15g V.\n", m_mapvmin, m_mapvmax);
2038
2039 std::cout << " Periodicities\n";
2040 const std::array<std::string, 3> axes = {{"x", "y", "z"}};
2041 for (unsigned int i = 0; i < 3; ++i) {
2042 std::cout << " " << axes[i] << ":";
2043 if (m_periodic[i]) {
2044 std::cout << " simple with length " << m_cells[i] << " cm";
2045 }
2046 if (m_mirrorPeriodic[i]) {
2047 std::cout << " mirror with length " << m_cells[i] << " cm";
2048 }
2049 if (m_axiallyPeriodic[i]) {
2050 std::cout << " axial " << int(0.5 + m_mapna[i]) << "-fold repetition";
2051 }
2052 if (m_rotationSymmetric[i]) std::cout << " rotational symmetry";
2053 if (!(m_periodic[i] || m_mirrorPeriodic[i] || m_axiallyPeriodic[i] ||
2055 std::cout << " none";
2056 std::cout << "\n";
2057 }
2058}
2059
2060bool ComponentFieldMap::GetBoundingBox(double& xmin, double& ymin, double& zmin,
2061 double& xmax, double& ymax,
2062 double& zmax) {
2063 if (!m_ready) return false;
2064
2065 xmin = m_minBoundingBox[0];
2066 xmax = m_maxBoundingBox[0];
2067 ymin = m_minBoundingBox[1];
2068 ymax = m_maxBoundingBox[1];
2069 zmin = m_minBoundingBox[2];
2070 zmax = m_maxBoundingBox[2];
2071 return true;
2072}
2073
2074void ComponentFieldMap::MapCoordinates(double& xpos, double& ypos, double& zpos,
2075 bool& xmirrored, bool& ymirrored,
2076 bool& zmirrored, double& rcoordinate,
2077 double& rotation) const {
2078 // Initial values
2079 rotation = 0;
2080
2081 // If chamber is periodic, reduce to the cell volume.
2082 xmirrored = false;
2083 double auxr, auxphi;
2084 if (m_periodic[0]) {
2085 xpos = m_mapmin[0] + fmod(xpos - m_mapmin[0], m_mapmax[0] - m_mapmin[0]);
2086 if (xpos < m_mapmin[0]) xpos += m_mapmax[0] - m_mapmin[0];
2087 } else if (m_mirrorPeriodic[0]) {
2088 double xnew =
2089 m_mapmin[0] + fmod(xpos - m_mapmin[0], m_mapmax[0] - m_mapmin[0]);
2090 if (xnew < m_mapmin[0]) xnew += m_mapmax[0] - m_mapmin[0];
2091 int nx = int(floor(0.5 + (xnew - xpos) / (m_mapmax[0] - m_mapmin[0])));
2092 if (nx != 2 * (nx / 2)) {
2093 xnew = m_mapmin[0] + m_mapmax[0] - xnew;
2094 xmirrored = true;
2095 }
2096 xpos = xnew;
2097 }
2098 if (m_axiallyPeriodic[0] && (zpos != 0 || ypos != 0)) {
2099 auxr = sqrt(zpos * zpos + ypos * ypos);
2100 auxphi = atan2(zpos, ypos);
2101 rotation = (m_mapamax[0] - m_mapamin[0]) *
2102 floor(0.5 +
2103 (auxphi - 0.5 * (m_mapamin[0] + m_mapamax[0])) /
2104 (m_mapamax[0] - m_mapamin[0]));
2105 if (auxphi - rotation < m_mapamin[0])
2106 rotation = rotation - (m_mapamax[0] - m_mapamin[0]);
2107 if (auxphi - rotation > m_mapamax[0])
2108 rotation = rotation + (m_mapamax[0] - m_mapamin[0]);
2109 auxphi = auxphi - rotation;
2110 ypos = auxr * cos(auxphi);
2111 zpos = auxr * sin(auxphi);
2112 }
2113
2114 ymirrored = false;
2115 if (m_periodic[1]) {
2116 ypos = m_mapmin[1] + fmod(ypos - m_mapmin[1], m_mapmax[1] - m_mapmin[1]);
2117 if (ypos < m_mapmin[1]) ypos += m_mapmax[1] - m_mapmin[1];
2118 } else if (m_mirrorPeriodic[1]) {
2119 double ynew =
2120 m_mapmin[1] + fmod(ypos - m_mapmin[1], m_mapmax[1] - m_mapmin[1]);
2121 if (ynew < m_mapmin[1]) ynew += m_mapmax[1] - m_mapmin[1];
2122 int ny = int(floor(0.5 + (ynew - ypos) / (m_mapmax[1] - m_mapmin[1])));
2123 if (ny != 2 * (ny / 2)) {
2124 ynew = m_mapmin[1] + m_mapmax[1] - ynew;
2125 ymirrored = true;
2126 }
2127 ypos = ynew;
2128 }
2129 if (m_axiallyPeriodic[1] && (xpos != 0 || zpos != 0)) {
2130 auxr = sqrt(xpos * xpos + zpos * zpos);
2131 auxphi = atan2(xpos, zpos);
2132 rotation = (m_mapamax[1] - m_mapamin[1]) *
2133 floor(0.5 +
2134 (auxphi - 0.5 * (m_mapamin[1] + m_mapamax[1])) /
2135 (m_mapamax[1] - m_mapamin[1]));
2136 if (auxphi - rotation < m_mapamin[1])
2137 rotation = rotation - (m_mapamax[1] - m_mapamin[1]);
2138 if (auxphi - rotation > m_mapamax[1])
2139 rotation = rotation + (m_mapamax[1] - m_mapamin[1]);
2140 auxphi = auxphi - rotation;
2141 zpos = auxr * cos(auxphi);
2142 xpos = auxr * sin(auxphi);
2143 }
2144
2145 zmirrored = false;
2146 if (m_periodic[2]) {
2147 zpos = m_mapmin[2] + fmod(zpos - m_mapmin[2], m_mapmax[2] - m_mapmin[2]);
2148 if (zpos < m_mapmin[2]) zpos += m_mapmax[2] - m_mapmin[2];
2149 } else if (m_mirrorPeriodic[2]) {
2150 double znew =
2151 m_mapmin[2] + fmod(zpos - m_mapmin[2], m_mapmax[2] - m_mapmin[2]);
2152 if (znew < m_mapmin[2]) znew += m_mapmax[2] - m_mapmin[2];
2153 int nz = int(floor(0.5 + (znew - zpos) / (m_mapmax[2] - m_mapmin[2])));
2154 if (nz != 2 * (nz / 2)) {
2155 znew = m_mapmin[2] + m_mapmax[2] - znew;
2156 zmirrored = true;
2157 }
2158 zpos = znew;
2159 }
2160 if (m_axiallyPeriodic[2] && (ypos != 0 || xpos != 0)) {
2161 auxr = sqrt(ypos * ypos + xpos * xpos);
2162 auxphi = atan2(ypos, xpos);
2163 rotation = (m_mapamax[2] - m_mapamin[2]) *
2164 floor(0.5 +
2165 (auxphi - 0.5 * (m_mapamin[2] + m_mapamax[2])) /
2166 (m_mapamax[2] - m_mapamin[2]));
2167 if (auxphi - rotation < m_mapamin[2])
2168 rotation = rotation - (m_mapamax[2] - m_mapamin[2]);
2169 if (auxphi - rotation > m_mapamax[2])
2170 rotation = rotation + (m_mapamax[2] - m_mapamin[2]);
2171 auxphi = auxphi - rotation;
2172 xpos = auxr * cos(auxphi);
2173 ypos = auxr * sin(auxphi);
2174 }
2175
2176 // If we have a rotationally symmetric field map, store coordinates.
2177 rcoordinate = 0;
2178 double zcoordinate = 0;
2179 if (m_rotationSymmetric[0]) {
2180 rcoordinate = sqrt(ypos * ypos + zpos * zpos);
2181 zcoordinate = xpos;
2182 } else if (m_rotationSymmetric[1]) {
2183 rcoordinate = sqrt(xpos * xpos + zpos * zpos);
2184 zcoordinate = ypos;
2185 } else if (m_rotationSymmetric[2]) {
2186 rcoordinate = sqrt(xpos * xpos + ypos * ypos);
2187 zcoordinate = zpos;
2188 }
2189
2192 xpos = rcoordinate;
2193 ypos = zcoordinate;
2194 zpos = 0;
2195 }
2196}
2197
2198void ComponentFieldMap::UnmapFields(double& ex, double& ey, double& ez,
2199 double& xpos, double& ypos, double& zpos,
2200 bool& xmirrored, bool& ymirrored,
2201 bool& zmirrored, double& rcoordinate,
2202 double& rotation) const {
2203 // Apply mirror imaging.
2204 if (xmirrored) ex = -ex;
2205 if (ymirrored) ey = -ey;
2206 if (zmirrored) ez = -ez;
2207
2208 // Rotate the field.
2209 double er, theta;
2210 if (m_axiallyPeriodic[0]) {
2211 er = sqrt(ey * ey + ez * ez);
2212 theta = atan2(ez, ey);
2213 theta += rotation;
2214 ey = er * cos(theta);
2215 ez = er * sin(theta);
2216 }
2217 if (m_axiallyPeriodic[1]) {
2218 er = sqrt(ez * ez + ex * ex);
2219 theta = atan2(ex, ez);
2220 theta += rotation;
2221 ez = er * cos(theta);
2222 ex = er * sin(theta);
2223 }
2224 if (m_axiallyPeriodic[2]) {
2225 er = sqrt(ex * ex + ey * ey);
2226 theta = atan2(ey, ex);
2227 theta += rotation;
2228 ex = er * cos(theta);
2229 ey = er * sin(theta);
2230 }
2231
2232 // Take care of symmetry.
2233 double eaxis;
2234 er = ex;
2235 eaxis = ey;
2236
2237 // Rotational symmetry
2238 if (m_rotationSymmetric[0]) {
2239 if (rcoordinate <= 0) {
2240 ex = eaxis;
2241 ey = 0;
2242 ez = 0;
2243 } else {
2244 ex = eaxis;
2245 ey = er * ypos / rcoordinate;
2246 ez = er * zpos / rcoordinate;
2247 }
2248 }
2249 if (m_rotationSymmetric[1]) {
2250 if (rcoordinate <= 0) {
2251 ex = 0;
2252 ey = eaxis;
2253 ez = 0;
2254 } else {
2255 ex = er * xpos / rcoordinate;
2256 ey = eaxis;
2257 ez = er * zpos / rcoordinate;
2258 }
2259 }
2260 if (m_rotationSymmetric[2]) {
2261 if (rcoordinate <= 0) {
2262 ex = 0;
2263 ey = 0;
2264 ez = eaxis;
2265 } else {
2266 ex = er * xpos / rcoordinate;
2267 ey = er * ypos / rcoordinate;
2268 ez = eaxis;
2269 }
2270 }
2271}
2272
2273int ComponentFieldMap::ReadInteger(char* token, int def, bool& error) {
2274 if (!token) {
2275 error = true;
2276 return def;
2277 }
2278
2279 return atoi(token);
2280}
2281
2282double ComponentFieldMap::ReadDouble(char* token, double def, bool& error) {
2283 if (!token) {
2284 error = true;
2285 return def;
2286 }
2287 return atof(token);
2288}
2289
2290void ComponentFieldMap::CalculateElementBoundingBoxes(void) {
2291 // Do not proceed if not properly initialised.
2292 if (!m_ready) {
2293 PrintNotReady("CalculateElementBoundingBoxes");
2294 return;
2295 }
2296
2297 // Calculate the bounding boxes of all elements
2298 for (auto& element : elements) {
2299 const Node& n0 = nodes[element.emap[0]];
2300 const Node& n1 = nodes[element.emap[1]];
2301 const Node& n2 = nodes[element.emap[2]];
2302 const Node& n3 = nodes[element.emap[3]];
2303 element.xmin = std::min({n0.x, n1.x, n2.x, n3.x});
2304 element.xmax = std::max({n0.x, n1.x, n2.x, n3.x});
2305 element.ymin = std::min({n0.y, n1.y, n2.y, n3.y});
2306 element.ymax = std::max({n0.y, n1.y, n2.y, n3.y});
2307 element.zmin = std::min({n0.z, n1.z, n2.z, n3.z});
2308 element.zmax = std::max({n0.z, n1.z, n2.z, n3.z});
2309 // Add tolerances.
2310 constexpr double f = 0.2;
2311 const double tolx = f * (element.xmax - element.xmin);
2312 element.xmin -= tolx;
2313 element.xmax += tolx;
2314 const double toly = f * (element.ymax - element.ymin);
2315 element.ymin -= toly;
2316 element.ymax += toly;
2317 const double tolz = f * (element.zmax - element.zmin);
2318 element.zmin -= tolz;
2319 element.zmax += tolz;
2320 }
2321}
2322
2323bool ComponentFieldMap::InitializeTetrahedralTree() {
2324 // Do not proceed if not properly initialised.
2325 if (!m_ready) {
2326 PrintNotReady("InitializeTetrahedralTree");
2327 return false;
2328 }
2329
2330 if (m_debug) {
2331 std::cout << m_className << "::InitializeTetrahedralTree:\n"
2332 << " About to initialize the tetrahedral tree.\n";
2333 }
2334
2335 // Cache the bounding boxes if it has not been done yet.
2336 if (!m_cacheElemBoundingBoxes) CalculateElementBoundingBoxes();
2337
2338 if (nodes.empty()) {
2339 std::cerr << m_className << "::InitializeTetrahedralTree: Empty mesh.\n";
2340 return false;
2341 }
2342
2343 // Determine the bounding box
2344 double xmin = nodes.front().x;
2345 double ymin = nodes.front().y;
2346 double zmin = nodes.front().z;
2347 double xmax = xmin;
2348 double ymax = ymin;
2349 double zmax = zmin;
2350 for (unsigned int i = 0; i < nodes.size(); i++) {
2351 const Node& n = nodes[i];
2352 xmin = std::min(xmin, n.x);
2353 xmax = std::max(xmax, n.x);
2354 ymin = std::min(ymin, n.y);
2355 ymax = std::max(ymax, n.y);
2356 zmin = std::min(zmin, n.z);
2357 zmax = std::max(zmax, n.z);
2358 }
2359
2360 if (m_debug) {
2361 std::cout << " Bounding box:\n"
2362 << std::scientific << "\tx: " << xmin << " -> " << xmax << "\n"
2363 << std::scientific << "\ty: " << ymin << " -> " << ymax << "\n"
2364 << std::scientific << "\tz: " << zmin << " -> " << zmax << "\n";
2365 }
2366
2367 const double hx = 0.5 * (xmax - xmin);
2368 const double hy = 0.5 * (ymax - ymin);
2369 const double hz = 0.5 * (zmax - zmin);
2370 m_tetTree = new TetrahedralTree(Vec3(xmin + hx, ymin + hy, zmin + hz),
2371 Vec3(hx, hy, hz));
2372
2373 if (m_debug) std::cout << " Tree instantiated.\n";
2374
2375 // Insert all mesh nodes in the tree
2376 for (unsigned int i = 0; i < nodes.size(); i++) {
2377 const Node& n = nodes[i];
2378 m_tetTree->InsertMeshNode(Vec3(n.x, n.y, n.z), i);
2379 }
2380
2381 if (m_debug) std::cout << " Tree nodes initialized successfully.\n";
2382
2383 // Insert all mesh elements (tetrahedrons) in the tree
2384 for (unsigned int i = 0; i < elements.size(); i++) {
2385 const Element& e = elements[i];
2386 const double bb[6] = {e.xmin, e.ymin, e.zmin, e.xmax, e.ymax, e.zmax};
2387 m_tetTree->InsertTetrahedron(bb, i);
2388 }
2389
2390 std::cout << m_className << "::InitializeTetrahedralTree: Success.\n";
2391
2392 m_isTreeInitialized = true;
2393 return true;
2394}
2395
2396void ComponentFieldMap::PrintElement(const std::string& header, const double x,
2397 const double y, const double z,
2398 const double t1, const double t2,
2399 const double t3, const double t4,
2400 const Element& element,
2401 const unsigned int n, const int iw) const {
2402 std::cout << m_className << "::" << header << ":\n"
2403 << " Global = (" << x << ", " << y << ", " << z << ")\n"
2404 << " Local = (" << t1 << ", " << t2 << ", " << t3 << ", " << t4
2405 << ")\n";
2406 if (element.degenerate) std::cout << " Element is degenerate.\n";
2407 std::cout << " Node x y z V\n";
2408 for (unsigned int ii = 0; ii < n; ++ii) {
2409 const Node& node = nodes[element.emap[ii]];
2410 const double v = iw < 0 ? node.v : node.w[iw];
2411 printf(" %-5d %12g %12g %12g %12g\n", element.emap[ii], node.x, node.y,
2412 node.z, v);
2413 }
2414}
2415}
Abstract base class for components.
std::array< bool, 3 > m_periodic
Simple periodicity in x, y, z.
std::array< bool, 3 > m_rotationSymmetric
Rotation symmetry around x-axis, y-axis, z-axis.
std::array< bool, 3 > m_axiallyPeriodic
Axial periodicity in x, y, z.
bool m_ready
Ready for use?
std::array< bool, 3 > m_mirrorPeriodic
Mirror periodicity in x, y, z.
std::string m_className
Class name.
bool m_debug
Switch on/off debugging messages.
void DriftMedium(const unsigned int imat)
Flag a field map material as a drift medium.
void PrintRange()
Show x, y, z, V and angular ranges.
virtual double GetElementVolume(const unsigned int i)=0
void SetMedium(const unsigned int imat, Medium *medium)
Associate a field map material with a Medium class.
void PrintMaterials()
List all currently defined materials.
std::array< double, 3 > m_mapamin
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.
virtual void GetAspectRatio(const unsigned int i, double &dmin, double &dmax)=0
std::array< double, 3 > m_maxBoundingBox
std::array< double, 3 > m_mapmin
std::array< double, 3 > m_minBoundingBox
bool GetBoundingBox(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax) override
Get the bounding box coordinates.
int ReadInteger(char *token, int def, bool &error)
int FindElementCube(const double x, const double y, const double z, double &t1, double &t2, double &t3, TMatrixD *&jac, std::vector< TMatrixD * > &dN)
Find the element for a point in a cube.
virtual ~ComponentFieldMap()
Destructor.
std::array< double, 3 > m_mapna
double GetConductivity(const unsigned int imat) const
Return the conductivity of a field map material.
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.
double GetPermittivity(const unsigned int imat) const
Return the permittivity of a field map material.
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.
Medium * GetMedium(const unsigned int i) const
Return the Medium associated to a field map material.
void NotDriftMedium(const unsigned int imat)
Flag a field map materials as a non-drift medium.
std::array< double, 3 > m_mapamax
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_cells
bool GetElement(const unsigned int i, double &vol, double &dmin, double &dmax)
Return the volume and aspect ratio of a mesh element.
std::array< bool, 3 > m_setang
virtual void SetRange()
Calculate x, y, z, V and angular ranges.
std::vector< Element > elements
std::array< double, 3 > m_mapmax
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.
Definition: Medium.hh:13
const std::string & GetName() const
Get the medium name/identifier.
Definition: Medium.hh:23
std::vector< int > GetTetListInBlock(const Vec3 &point)
void InsertTetrahedron(const double elemBoundingBox[6], const int elemIndex)
void InsertMeshNode(Vec3 point, const int nodeIndex)
DoubleAc fabs(const DoubleAc &f)
Definition: DoubleAc.h:615
DoubleAc sqrt(const DoubleAc &f)
Definition: DoubleAc.cpp:314