Loading [MathJax]/extensions/tex2jax.js
MAIA bb96820c
Multiphysics at AIA
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
geometry3d.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The m-AIA AUTHORS
2//
3// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
4//
5// SPDX-License-Identifier: LGPL-3.0-only
6
7#include "geometry3d.h"
8
9#include <bitset>
10#include <sys/stat.h>
11#include <sys/types.h>
12#include <unordered_set>
13#include "COMM/mpioverride.h"
14#include "GRID/partition.h"
15#include "IO/parallelio.h"
16#include "MEMORY/scratch.h"
17#include "geometryadt.h"
18#include "geometrycontext.h"
19#include "globals.h"
20
21using namespace std;
22
23Geometry3D::Geometry3D(const MInt solverId_, const MPI_Comm comm) : Geometry<3>(solverId_, comm) {
24 TRACE();
25
26 NEW_TIMER_GROUP(tg_geometry, "Geometry (solver #" + std::to_string(solverId_) + ")");
27 m_tg_geometry = tg_geometry;
28 NEW_TIMER(t_geometryAll, "complete geometry", m_tg_geometry);
29 m_t_geometryAll = t_geometryAll;
30 g_tc_geometry.emplace_back("complete geometry", m_t_geometryAll);
31 RECORD_TIMER_START(m_t_geometryAll);
32
33 NEW_SUB_TIMER(t_initGeometry, "init geometry", m_t_geometryAll);
34 g_tc_geometry.emplace_back("init geometry", t_initGeometry);
35 RECORD_TIMER_START(t_initGeometry);
36 m_log << endl;
37 m_log << "#########################################################################################################"
38 "#############"
39 << endl;
40 m_log << "## Initializing Geometry in 3D "
41 " ##"
42 << endl;
43 m_log << "#########################################################################################################"
44 "#############"
45 << endl
46 << endl;
47
48 otherCalls++;
49
50 m_adt = 0;
51 m_elements = 0;
52 m_noElements = 0;
53 m_parGeomMemFactor = 1.0;
54
55 // new parallel geometry
56 if(m_parallelGeometry) {
57 if(Context::propertyExists("parallelGeomFileName", solverId()))
69 m_parallelGeomFileName = Context::getSolverProperty<MString>("parallelGeomFileName", solverId(), AT_);
70 else {
71 stringstream errorMsg;
72 errorMsg
73 << "ERROR: parallel geometry is activated but no parallelGeomFileName is specified in the properties file"
74 << endl;
75 m_log << errorMsg.str();
76 mTerm(1, AT_, errorMsg.str());
77 }
78 if(Context::propertyExists("gridInputFileName", solverId()))
79 m_gridFileName = Context::getSolverProperty<MString>("gridInputFileName", solverId(), AT_);
80 else {
81 stringstream errorMsg;
82 errorMsg
83 << "ERROR: parallel geometry is activated but no parallelGeomFileName is specified in the properties file"
84 << endl;
85 m_log << errorMsg.str();
86 mTerm(1, AT_, errorMsg.str());
87 }
88
100 m_parGeomMemFactor = Context::getSolverProperty<MFloat>("parGeomMemFactor", solverId(), AT_, &m_parGeomMemFactor);
101 } else {
111 m_communicateSegmentsSerial = true;
112 m_communicateSegmentsSerial =
113 Context::getSolverProperty<MBool>("communicateSegmentsSerial", solverId(), AT_, &m_communicateSegmentsSerial);
114 }
115
116 // moving boundary
117 m_mbelements = 0;
118 m_noMBElements = 0;
119 m_GFieldInitFromSTL = false;
120 m_forceBoundingBox = false;
121 m_levelSetIntfBndId = 0;
122 m_noLevelSetIntfBndIds = 0;
123
124 m_GFieldInitFromSTL = Context::getSolverProperty<MBool>("GFieldInitFromSTL", solverId(), AT_, &m_GFieldInitFromSTL);
125
126 if(m_GFieldInitFromSTL) {
127 m_levelSetIntfBndId = Context::getSolverProperty<MInt>("levelSetIntfBndId", solverId(), AT_, &m_levelSetIntfBndId);
128
129 m_forceBoundingBox = Context::getSolverProperty<MBool>("forcedBoundingBox", solverId(), AT_, &m_forceBoundingBox);
130
131
132 if(Context::propertyExists("bodyBndryCndIds", solverId())
133 || Context::propertyExists("GFieldInitFromSTLBndCndIds", solverId())) {
134 const MInt noBodyBndIds = Context::propertyLength("bodyBndryCndIds", solverId());
135 const MInt noBndIds = Context::propertyLength("GFieldInitFromSTLBndCndIds", solverId());
136 m_noLevelSetIntfBndIds = noBodyBndIds + noBndIds;
137 if(domainId() == 0) {
138 cerr << " noLevelSetIntfBndIds: " << m_noLevelSetIntfBndIds << endl;
139 }
140 m_levelSetIntfBndIds = new MInt[m_noLevelSetIntfBndIds];
141
142 for(MInt i = 0; i < noBodyBndIds; i++) {
143 m_levelSetIntfBndIds[i] = Context::getSolverProperty<MFloat>("bodyBndryCndIds", solverId(), AT_, i);
144 if(domainId() == 0) {
145 cerr << " levelSetIntfBndIds: " << m_levelSetIntfBndIds[i] << endl;
146 }
147 }
148
149 for(MInt i = noBodyBndIds; i < m_noLevelSetIntfBndIds; i++) {
150 m_levelSetIntfBndIds[i] =
151 Context::getSolverProperty<MInt>("GFieldInitFromSTLBndCndIds", solverId(), AT_, i - noBodyBndIds);
152 if(domainId() == 0) {
153 cerr << " levelSetIntfBndIds: " << m_levelSetIntfBndIds[i] << endl;
154 }
155 }
156
157 } else {
158 m_levelSetIntfBndIds = nullptr;
159 // for(MInt i=0; i < m_noLevelSetIntfBndIds; i++){
160 // m_levelSetIntfBndIds[i] = m_levelSetIntfBndId;
161 // }
162 }
163 }
164
165 MString testcaseDir = "./";
166 testcaseDir = Context::getSolverProperty<MString>("testcaseDir", solverId(), AT_, &testcaseDir);
167
179 MString inputDir = "./";
180 inputDir = Context::getSolverProperty<MString>("inputDir", solverId(), AT_, &inputDir);
192 MString tmpFileName =
193 testcaseDir + inputDir + Context::getSolverProperty<MString>("geometryInputFileName", solverId(), AT_);
194
195 RECORD_TIMER_STOP(t_initGeometry);
196
197 NEW_SUB_TIMER(t_readGeomFile, "read geometry property file", m_t_geometryAll);
198 g_t_readGeomFile = t_readGeomFile;
199 g_tc_geometry.emplace_back("read geometry property file", g_t_readGeomFile);
200 RECORD_TIMER_START(g_t_readGeomFile);
201 m_log << " + Reading geometry property file " << endl;
202 if(tmpFileName.find(".toml") == MString::npos) {
203 geometryContext().readPropertyFile(NETCDF, tmpFileName.c_str());
204 } else {
205 geometryContext().readPropertyFile(TOML, tmpFileName.c_str());
206 }
207 m_bodyMap = geometryContext().getBodies();
208 RECORD_TIMER_STOP(g_t_readGeomFile);
209
222 m_gridCutTest = "SAT";
223 m_gridCutTest = Context::getSolverProperty<MString>("gridCutTest", solverId(), AT_, &m_gridCutTest);
224
225 m_bodyIt = m_bodyMap.begin();
226
227 m_noSegments = geometryContext().getNoSegments();
228 m_segmentOffsets.resize(m_noSegments + 1);
229 m_segmentOffsetsWithoutMB.resize(m_noSegments + 1); // The offsets of MB segments are deleted.
230
231
233
234 NEW_SUB_TIMER(t_correctVertices, "correct vertices", m_t_geometryAll);
235 g_tc_geometry.emplace_back("correct vertices", t_correctVertices);
236 RECORD_TIMER_START(t_correctVertices);
238 RECORD_TIMER_STOP(t_correctVertices);
239
240
241 NEW_SUB_TIMER(t_buildAdt, "building adt", m_t_geometryAll);
242 g_tc_geometry.emplace_back("building adt", t_buildAdt);
243 RECORD_TIMER_START(t_buildAdt);
244
245 m_adt = new GeometryAdt<3>(this);
246 if(m_noElements > 0) m_adt->buildTree();
247 RECORD_TIMER_STOP(t_buildAdt);
248
249 // moving boundary
250 if(m_GFieldInitFromSTL && m_noElements > 0) m_adt->buildTreeMB();
251
252 printMemoryUsage();
253 RECORD_TIMER_STOP(m_t_geometryAll);
254
255 if(m_debugParGeom) {
256 DISPLAY_ALL_GROUP_TIMERS(m_tg_geometry);
257 m_log << endl;
258 }
259
260 m_log << endl;
261
263}
264
265/*
266 * brief: generates an auxiliary geometry from an ASCII file that can be used for whatever
267 *
268 * Thomas Schilden, December 2016
269 */
270Geometry3D::Geometry3D(const MInt solverId_, const MString& filename, const MPI_Comm comm) : Geometry(solverId_, comm) {
271 TRACE();
272
273 m_log << "reading the auxiliary stl " << filename << endl;
274
276
277 m_noElements = 0;
278 m_noMBElements = 0;
279
281
282 m_log << " number of Elements: " << m_noElements << endl;
283
285
286 MInt bla = 0;
288
289 elements = &(m_elements->a[0]);
290
292
293 m_adt = new GeometryAdt<3>(this);
294 m_adt->buildTree();
295}
296
298 TRACE();
299
300 delete m_adt;
301 delete m_elements;
302
303 // moving boundary
304 if(m_mbelements != nullptr) delete m_mbelements;
305}
306
314 delete m_adt;
315
316 m_adt = new GeometryAdt<3>(this);
317 m_adt->buildTree();
318
320}
321
329 TRACE();
330
331 m_log << " + Used memmory for collectors: "
332 << ((MFloat)m_elements->memoryUseage() + (MFloat)m_adt->memoryUsage()) / 1024.0 / 1024.0
333 + (m_GFieldInitFromSTL ? ((MFloat)m_elements->memoryUseage() / 1024.0 / 1024.0) : 0.0)
334 << " MB" << endl;
335 m_log << " * triangles: " << (MFloat)m_elements->memoryUseage() / 1024.0 / 1024.0 << " MB" << endl;
337 m_log << " * mb triangles: " << (MFloat)m_mbelements->memoryUseage() / 1024.0 / 1024.0 << " MB" << endl;
338 m_log << " * adt tree: " << (MFloat)m_adt->memoryUsage() / 1024.0 / 1024.0 << " MB" << endl;
339}
340
342 TRACE();
343
344 MInt count = 3;
345 if(m_GFieldInitFromSTL) count = 4;
346
347 MFloatScratchSpace mem(noDomains() * count, AT_, "mem");
348
349 MFloatScratchSpace snd(count, AT_, "snd");
350 snd[0] = m_noElements;
351 snd[1] = (MFloat)m_elements->memoryUseage() / 1024.0 / 1024.0;
352 snd[2] = (MFloat)m_adt->memoryUsage() / 1024.0 / 1024.0;
353 if(m_GFieldInitFromSTL) snd[3] = (MFloat)m_mbelements->memoryUseage() / 1024.0 / 1024.0;
354
355 MPI_Gather(snd.getPointer(), count, MPI_DOUBLE, mem.getPointer(), count, MPI_DOUBLE, 0, mpiComm(), AT_,
356 "snd.getPointer()", "mem.getPointer()");
357
358 if(domainId() == 0) {
359 ofstream ofl;
360 ofl.open("memrep_geom.txt", std::ios_base::out | std::ios_base::trunc);
361 ofl.precision(10);
362 ofl << "###########################################################################################################"
363 "#"
364 << endl
365 << "#" << endl;
366 ofl << "# domain no_triangles triangles[MB] tree[MB] tmb_triagles[MP]" << endl << "#" << endl;
367
368 MFloatScratchSpace sums(count, AT_, "sums");
369 for(MInt i = 0; i < count; i++)
370 sums[i] = 0.0;
371
372 MFloatScratchSpace min(count, AT_, "min");
373 MFloatScratchSpace max(count, AT_, "max");
374 for(MInt i = 0; i < count; i++) {
375 min[i] = 9999999999999999.9;
376 max[i] = -1.0;
377 }
378
379 for(MInt d = 0; d < noDomains(); d++)
380 for(MInt i = 0; i < count; i++) {
381 sums[i] += mem[d * count + i];
382 if(mem[d * count + i] > max[i]) max[i] = mem[d * count + i];
383 if(mem[d * count + i] < min[i]) min[i] = mem[d * count + i];
384 }
385
386 MString names[4] = {"no_triangles", "triangles", "tree", "mb_triangles"};
387 for(MInt i = 0; i < count; i++) {
388 ofl << "# SUM " << names[i] << " = " << sums[i] << endl;
389 ofl << "# AVG " << names[i] << " = " << sums[i] / noDomains() << endl;
390 ofl << "# MIN " << names[i] << " = " << min[i] << endl;
391 ofl << "# MAX " << names[i] << " = " << max[i] << endl << endl;
392 }
393 ofl << "#" << endl
394 << "###########################################################################################################"
395 "#"
396 << endl;
397
398 for(MInt d = 0; d < noDomains(); d++) {
399 ofl << d << "\t\t";
400 for(MInt i = 0; i < count; i++)
401 ofl << mem[d * count + i] << "\t\t";
402 ofl << endl;
403 }
404 ofl.close();
405 }
406}
407
408
418inline void Geometry3D::countSegmentTrianglesASCII(MString fileName, MInt* noElements) {
419 TRACE();
420
421 *noElements = 0;
422
423 // open file in ascii format
424 ifstream ifl(fileName);
425
426 if(!ifl) {
427 stringstream errorMessage;
428 errorMessage << " ERROR in segment::readSegment, couldn't find file : " << fileName << "!";
429 mTerm(1, AT_, errorMessage.str());
430 }
431
432 char tmp[256];
433 string text;
434 // If number of elements unknown, count them...
435 while(text.find("endsolid") == std::string::npos) {
436 ifl.getline(tmp, 256);
437 text = tmp;
438 if(text.find("facet") != std::string::npos && text.find("endface") == std::string::npos)
439 *noElements = *noElements + 1;
440 }
441 ifl.close();
442}
443
457inline void Geometry3D::countSegmentTrianglesBINARY(MString fileName, MInt* noElements) {
458 TRACE();
459
460 *noElements = 0;
461
462 struct stat stat_buf {};
463 MInt rc = stat(fileName.c_str(), &stat_buf);
464 if(rc < 0) {
465 stringstream errorMessage;
466 errorMessage << " ERROR in segment::readSegment, couldn't determine file size of: " << fileName << "!";
467 mTerm(1, AT_, errorMessage.str());
468 }
469
470 *noElements = (stat_buf.st_size - (80 + 4)) / 50;
471}
472
473
485inline void Geometry3D::countSegmentTrianglesNETCDF(MString fileName, MInt* noElements, const MPI_Comm comm) {
486 TRACE();
487
488 using namespace maia::parallel_io;
489
490 *noElements = 0;
491
492 ParallelIo surface(fileName, PIO_READ, comm);
493 surface.readScalar(noElements, "noTriangles");
494}
495
496
509inline void Geometry3D::readSegmentTrianglesASCII(MString fileName, Collector<element<3>>* elemCollector, MInt bndCndId,
510 MInt segmentId, MInt* offset) {
511 TRACE();
512
513 // open file in ascii format
514 ifstream ifl(fileName);
515
516 if(!ifl) {
517 stringstream errorMessage;
518 errorMessage << " ERROR in segment::readSegment, couldn't find file : " << fileName << "!";
519 mTerm(1, AT_, errorMessage.str());
520 }
521
522 element<3>* allelements = elemCollector->a;
523 string text;
524 char tmp[1024]{};
525 while(text.find("endsolid") == std::string::npos) {
526 ifl.getline(tmp, 1024);
527 text = tmp;
528 if(text.find("normal") != std::string::npos) {
529 elemCollector->append();
530 trim(text);
531 std::vector<std::string> tokens;
532 tokenize(text, tokens, " ", true);
533
534 // Read normal vector components
535 for(MInt i = 0; i < 3; i++) {
536 tokens[i + 2] = trim(tokens[i + 2]);
537 if(tokens[i + 2].find_first_not_of("0123456789.eE-+") != std::string::npos) {
538 cerr << "ERROR: normal component " << tokens[i + 2] << " is not a number " << endl;
539 TERM(-1);
540 }
541
542 allelements[*offset].m_normal[i] = stod(tokens[i + 2]);
543 }
544 // Jump expression : outer loop
545 ifl.getline(tmp, 256);
546
547 // Read vertices
548
549 for(MInt j = 0; j < 3; j++) {
550 ifl.getline(tmp, 1024);
551
552 text = tmp;
553 trim(text);
554 std::vector<std::string> vertex;
555 tokenize(text, vertex, " ", true);
556
557 for(MInt i = 0; i < 3; i++) {
558 vertex[i + 1] = trim(vertex[i + 1]);
559 if(vertex[i + 1].find_first_not_of("0123456789.eE-+") != std::string::npos) {
560 cerr << "ERROR: vertex component " << vertex[i + 1] << " is not a number " << endl;
561 TERM(-1);
562 }
563
564
565 allelements[*offset].m_vertices[j][i] = stod(vertex[i + 1]);
566 }
567 }
568
569 allelements[*offset].boundingBox();
570 allelements[*offset].m_bndCndId = bndCndId;
571 allelements[*offset].m_segmentId = segmentId;
572 allelements[*offset].m_originalId = -1;
573
575 for(MInt id = 0; id < m_noLevelSetIntfBndIds; id++)
576 if(bndCndId == m_levelSetIntfBndIds[id]) m_noMBElements++;
577
578 *offset = *offset + 1;
579 }
580 }
581
582 ifl.close();
583}
584
592inline void Geometry3D::swap4BytesToBE(char* buf) {
593 char tmp_byte = buf[0];
594 buf[0] = buf[3];
595 buf[3] = tmp_byte;
596 tmp_byte = buf[1];
597 buf[1] = buf[2];
598 buf[2] = tmp_byte;
599}
600
609 union {
610 uint32_t i;
611 char c[4];
612 } bint = {0x01020304};
613
614 return static_cast<MInt>(bint.c[0] == 1);
615}
616
632 MInt bndCndId, MInt segmentId, MInt* offset) {
633 TRACE();
634
635 using facet_t = struct { float n[3], v1[3], v2[3], v3[3]; };
636 facet_t facet;
637
638 // open file in binary format
639 FILE* fp = nullptr;
640
641 if((fp = fopen(fileName.c_str(), "rb")) == nullptr) {
642 stringstream errorMessage;
643 errorMessage << " ERROR in segment::readSegment, couldn't find file : " << fileName << "!";
644 mTerm(1, AT_, errorMessage.str());
645 }
646
647 element<3>* allelements = elemCollector->a;
648 char header[85];
649 MUshort ibuff2 = 0;
650 if(!fread(header, 1, 84, fp)) {
651 TERMM(-1, "ERROR: Memory error!");
652 }
653
654 for(MInt i = 0; fread(&facet, 48, 1, fp) > 0; i++) {
655 if(!fread(&ibuff2, 2, 1, fp)) {
656 TERMM(-1, "ERROR: Memory error!");
657 }
658
659 elemCollector->append();
660
661 // reorder
662 for(float& k : facet.n) {
663 char* buf = (char*)(&k);
664 swap4BytesToBE(buf);
665 }
666 for(float& k : facet.v1) {
667 char* buf = (char*)(&k);
668 swap4BytesToBE(buf);
669 }
670 for(float& k : facet.v2) {
671 char* buf = (char*)(&k);
672 swap4BytesToBE(buf);
673 }
674 for(float& k : facet.v3) {
675 char* buf = (char*)(&k);
676 swap4BytesToBE(buf);
677 }
678
679
680 for(MInt j = 0; j < nDim; j++) {
681 allelements[*offset].m_normal[j] = facet.n[j];
682 allelements[*offset].m_vertices[0][j] = facet.v1[j];
683 allelements[*offset].m_vertices[1][j] = facet.v2[j];
684 allelements[*offset].m_vertices[2][j] = facet.v3[j];
685 }
686
687 allelements[*offset].boundingBox();
688 allelements[*offset].m_bndCndId = bndCndId;
689 allelements[*offset].m_segmentId = segmentId;
690 allelements[*offset].m_originalId = -1;
691
693 for(MInt id = 0; id < m_noLevelSetIntfBndIds; id++)
694 if(bndCndId == m_levelSetIntfBndIds[id]) m_noMBElements++;
695
696 *offset = *offset + 1;
697 }
698
699 fclose(fp);
700}
701
702
718 MInt bndCndId, MInt segmentId, MInt* offset) {
719 TRACE();
720
721 using facet_t = struct { float n[3], v1[3], v2[3], v3[3]; };
722 facet_t facet;
723
724 // open file in binary format
725 FILE* fp = nullptr;
726
727 if((fp = fopen(fileName.c_str(), "rb")) == nullptr) {
728 stringstream errorMessage;
729 errorMessage << " ERROR in segment::readSegment, couldn't find file : " << fileName << "!";
730 mTerm(1, AT_, errorMessage.str());
731 }
732
733 element<3>* allelements = elemCollector->a;
734 char header[85];
735 MUshort ibuff2 = 0;
736
737 if(fread(header, 1, 84, fp) == 0u) {
738 TERMM(-1, "ERROR: Memory error!");
739 }
740
741 for(MInt i = 0; fread(&facet, 48, 1, fp) > 0; i++) {
742 if(fread(&ibuff2, 2, 1, fp) == 0u) {
743 TERMM(-1, "ERROR: Memory error!");
744 }
745
746 elemCollector->append();
747
748 for(MInt j = 0; j < nDim; j++) {
749 allelements[*offset].m_normal[j] = facet.n[j];
750 allelements[*offset].m_vertices[0][j] = facet.v1[j];
751 allelements[*offset].m_vertices[1][j] = facet.v2[j];
752 allelements[*offset].m_vertices[2][j] = facet.v3[j];
753 }
754
755 allelements[*offset].boundingBox();
756 allelements[*offset].m_bndCndId = bndCndId;
757 allelements[*offset].m_segmentId = segmentId;
758 allelements[*offset].m_originalId = -1;
759
761 for(MInt id = 0; id < m_noLevelSetIntfBndIds; id++)
762 if(bndCndId == m_levelSetIntfBndIds[id]) m_noMBElements++;
763
764 *offset = *offset + 1;
765 }
766
767 fclose(fp);
768}
769
770
784 MInt bndCndId, MInt segmentId, MInt* offset, const MPI_Comm comm) {
785 TRACE();
786
787 using namespace maia::parallel_io;
788
789 MInt offsetstart = *offset;
790 MInt noTriangles = -1;
791 ParallelIo surface(fileName, PIO_READ, comm);
792 surface.readScalar(&noTriangles, "noTriangles");
793
794 MInt noEntries = noTriangles;
795
796 MFloatScratchSpace tmp_array(noEntries, AT_, "tmp_array");
797
798 element<3>* allelements = elemCollector->a;
799 for(MInt i = 0; i < noTriangles; i++) {
800 elemCollector->append();
801
802 allelements[*offset].m_bndCndId = bndCndId;
803 allelements[*offset].m_segmentId = segmentId;
804 allelements[*offset].m_originalId = -1;
805
807 for(MInt id = 0; id < m_noLevelSetIntfBndIds; id++)
808 if(bndCndId == m_levelSetIntfBndIds[id]) m_noMBElements++;
809
810 *offset = *offset + 1;
811 }
812
813 MString normalnames[3] = {"normals0", "normals1", "normals2"};
814 MString vertexnames[3][3] = {{"vertices00", "vertices01", "vertices02"},
815 {"vertices10", "vertices11", "vertices12"},
816 {"vertices20", "vertices21", "vertices22"}};
817
818 // normals
819 for(MInt d = 0; d < nDim; d++) {
820 surface.setOffset(noEntries, 0);
821 surface.readArray(tmp_array.begin(), normalnames[d]);
822
823 for(MInt i = offsetstart, j = 0; i < offsetstart + noTriangles; i++, j++)
824 allelements[i].m_normal[d] = tmp_array[j];
825 }
826
827 // vertices
828 for(MInt vtx = 0; vtx < nDim; vtx++) {
829 for(MInt coord = 0; coord < nDim; coord++) {
830 surface.setOffset(noEntries, 0);
831 surface.readArray(tmp_array.begin(), vertexnames[vtx][coord]);
832 for(MInt i = offsetstart, j = 0; i < offsetstart + noTriangles; i++, j++) {
833 allelements[i].m_vertices[vtx][coord] = tmp_array[j];
834 }
835 }
836 }
837
838 for(MInt i = offsetstart; i < offsetstart + noTriangles; i++) {
839 allelements[i].boundingBox();
840 }
841}
842
856 TRACE();
857
858 NEW_SUB_TIMER(t_countTriangles, "count triangles", m_t_readGeometry);
859 g_tc_geometry.emplace_back("count triangles", t_countTriangles);
860 RECORD_TIMER_START(t_countTriangles);
861
862 if(domainId() == 0) { // Count segments only on rank 0 and broadcast total count
863 if(m_noAllTriangles == 0) {
864 MInt segmentId = 0;
865 for(m_bodyIt = m_bodyMap.begin(); m_bodyIt != m_bodyMap.end(); m_bodyIt++) {
866 // Do not create default body!
867 if(m_bodyIt->second->name != "default") {
868 for(MInt i = 0; i < m_bodyIt->second->noSegments; i++) {
869 stringstream fileName;
870 fileName << *geometryContext().getProperty("filename", segmentId)->asString();
871
872 if(geometryContext().noPropertySegments("filename") == 1 && geometryContext().getNoSegments() > 1
873 && (m_bodyIt->second->noSegments > 1 || m_bodyMap.size() > 1)) {
874 fileName << "." << segmentId;
875 }
876
877 m_log << " - file: " << fileName.str() << endl;
878
879 MInt noElements = 0;
880 switch(string2enum(m_geomFileType)) {
881 case ASCII:
882 countSegmentTrianglesASCII(fileName.str(), &noElements);
883 break;
884 case BINARY:
885 countSegmentTrianglesBINARY(fileName.str(), &noElements);
886 break;
887 case NETCDF:
888 countSegmentTrianglesNETCDF(fileName.str(), &noElements, MPI_COMM_SELF);
889 break;
890 default:
891 break;
892 }
893
894 m_log << " * no. triangles: " << noElements << endl;
895
896 m_noElements += noElements;
897 segmentId++;
898 }
899 }
900 }
901
902 } else {
904 }
905 }
906 MPI_Bcast(&m_noElements, 1, MPI_INT, 0, mpiComm(), AT_, "m_noElements");
907 RECORD_TIMER_STOP(t_countTriangles);
908
909 m_log << " - total no. triangles: " << m_noElements << endl << endl;
910 m_log << " + Reading segments ..." << endl;
911
912 NEW_SUB_TIMER(t_readTriangles, "read triangles", m_t_readGeometry);
913 g_tc_geometry.emplace_back("read triangles", t_readTriangles);
914 RECORD_TIMER_START(t_readTriangles);
915
916 auto* m_allelements = new Collector<element<nDim>>(m_noElements, nDim, 0);
917 // Read segments only on rank 0 and communicate (if mode is not disabled)
919 vector<MInt> allBCs;
920 MInt segmentId = 0;
921 MInt counter = 0;
922
923 // This loop reads all elements from all segments
924 for(m_bodyIt = m_bodyMap.begin(); m_bodyIt != m_bodyMap.end(); m_bodyIt++) {
925 // Do not create default body!
926 if(m_bodyIt->second->name != "default") {
927 for(MInt index = 0; index < m_bodyIt->second->noSegments; index++) {
928 stringstream fileName;
929 fileName << *geometryContext().getProperty("filename", segmentId)->asString();
930
931 if(geometryContext().noPropertySegments("filename") == 1 && geometryContext().getNoSegments() > 1
932 && (m_bodyIt->second->noSegments > 1 || m_bodyMap.size() > 1)) {
933 fileName << "." << segmentId;
934 }
935 MInt bndCndId = *geometryContext().getProperty("BC", segmentId)->asInt();
936 allBCs.push_back(bndCndId);
937
938 m_log << " - file: " << fileName.str() << endl;
939
940 switch(string2enum(m_geomFileType)) {
941 case ASCII:
942 readSegmentTrianglesASCII(fileName.str(), m_allelements, bndCndId, segmentId, &counter);
943 break;
944 case BINARY:
945 if(is_big_endian() != 0)
946 readSegmentTrianglesBINARY_BE(fileName.str(), m_allelements, bndCndId, segmentId, &counter);
947 else
948 readSegmentTrianglesBINARY_LE(fileName.str(), m_allelements, bndCndId, segmentId, &counter);
949 break;
950 case NETCDF: {
951 const MPI_Comm commSelf = MPI_COMM_SELF;
952 const MPI_Comm comm = (m_communicateSegmentsSerial) ? commSelf : mpiComm();
953 readSegmentTrianglesNETCDF(fileName.str(), m_allelements, bndCndId, segmentId, &counter, comm);
954 break;
955 }
956 default:
957 break;
958 }
959
960 segmentId++;
961 m_segmentOffsets[segmentId] = counter;
962 m_segmentOffsetsWithoutMB[segmentId] = m_segmentOffsetsWithoutMB[segmentId - 1]
963 + (m_segmentOffsets[segmentId] - m_segmentOffsets[segmentId - 1]);
964 if(m_noLevelSetIntfBndIds > 0) {
965 for(MInt i = 0; i < m_noLevelSetIntfBndIds; i++) {
966 if(bndCndId == m_levelSetIntfBndIds[i])
967 m_segmentOffsetsWithoutMB[segmentId] = m_segmentOffsetsWithoutMB[segmentId - 1];
968 }
969 }
970 }
971 }
972 }
973 m_log << endl;
974
975 m_noAllBCs = allBCs.size();
976 mAlloc(m_allBCs, m_noAllBCs, "m_allBCs", 0, AT_);
977 for(MInt i = 0; i < m_noAllBCs; i++) {
978 m_allBCs[i] = allBCs[i];
979 }
980 }
981
982 // Broadcast geometry information
984 MFloatScratchSpace normalsBuffer(3 * m_noElements, AT_, "normalsBuffer");
985 MFloatScratchSpace verticesBuffer(9 * m_noElements, AT_, "verticesBuffer");
986 MIntScratchSpace idsBuffer(3 * m_noElements, AT_, "idsBuffer");
987 // Fill buffers on rank 0 and broadcast
988 if(domainId() == 0) {
989 for(MInt i = 0; i < m_noElements; i++) {
990 idsBuffer[i] = m_allelements->a[i].m_bndCndId;
991 idsBuffer[m_noElements + i] = m_allelements->a[i].m_segmentId;
992 idsBuffer[(2 * m_noElements) + i] = m_allelements->a[i].m_originalId;
993 for(MInt j = 0; j < nDim; j++) {
994 normalsBuffer[(i * nDim) + j] = m_allelements->a[i].m_normal[j];
995 for(MInt k = 0; k < nDim; k++) {
996 verticesBuffer[(i * 9) + (j * nDim) + k] = m_allelements->a[i].m_vertices[j][k];
997 }
998 }
999 }
1000 }
1002 "elemNormals");
1004 "elemVertices");
1006 "elemIds");
1007
1008 // Assemble geometry information from buffers
1009 if(domainId() != 0) {
1010 for(MInt i = 0; i < m_noElements; i++) {
1011 m_allelements->append();
1012 for(MInt j = 0; j < nDim; j++) {
1013 m_allelements->a[i].m_normal[j] = normalsBuffer[(i * nDim) + j];
1014 for(MInt k = 0; k < nDim; k++) {
1015 m_allelements->a[i].m_vertices[j][k] = verticesBuffer[(i * 9) + (j * nDim) + k];
1016 }
1017 }
1018 m_allelements->a[i].boundingBox();
1019 m_allelements->a[i].m_bndCndId = idsBuffer[i];
1020 m_allelements->a[i].m_segmentId = idsBuffer[m_noElements + i];
1021 m_allelements->a[i].m_originalId = idsBuffer[(2 * m_noElements) + i];
1022 }
1023 }
1024
1025 // Communicate remaining info from rank 0
1026 MPI_Bcast(&m_noMBElements, 1, maia::type_traits<MInt>::mpiType(), 0, mpiComm(), AT_, "m_noMBElements");
1028 "m_segmentOffsets");
1030 mpiComm(), AT_, "m_segmentOffsetsWithoutMB");
1031 MPI_Bcast(&m_noAllBCs, 1, maia::type_traits<MInt>::mpiType(), 0, mpiComm(), AT_, "m_noAllBCs");
1032 if(domainId() != 0) {
1033 mAlloc(m_allBCs, m_noAllBCs, "m_allBCs", 0, AT_);
1034 }
1036 }
1037
1038 RECORD_TIMER_STOP(t_readTriangles);
1039 return m_allelements;
1040}
1041
1073 TRACE();
1074
1075 using namespace maia::parallel_io;
1076 using namespace maia::grid;
1077
1078 NEW_SUB_TIMER(t_readTriangles, "read triangles", m_t_readGeometry);
1079 g_tc_geometry.emplace_back("read triangles", t_readTriangles);
1080 RECORD_TIMER_START(t_readTriangles);
1081
1082 m_log << " + Reading triangles ..." << endl;
1083
1084 // 1. Read the workload from the grid file
1085 stringstream filename;
1086 filename << "out/" << m_gridFileName;
1087 m_log << " - reading workload from gridfile " << filename.str() << endl;
1088
1089 MInt partitionCellsCnt = 0;
1090 MInt noLocalPartitionCells = 0;
1091 MIntScratchSpace offset(noDomains() + 1, AT_, "offset");
1092
1093 if(domainId() == 0) {
1094 ParallelIo grid(filename.str(), PIO_READ, MPI_COMM_SELF);
1095 partitionCellsCnt = (MInt)grid.getArraySize("partitionCellsGlobalId");
1096
1097 MFloatScratchSpace partitionCellsWorkLoad(partitionCellsCnt, AT_, "partitionCellsWorkLoad");
1098 grid.setOffset(partitionCellsCnt, 0);
1099 grid.readArray(partitionCellsWorkLoad.begin(), "partitionCellsWorkload");
1100
1101 if(noDomains() > 1) {
1102 m_log << " - partitioning workload" << endl;
1103 optimalPartitioningSerial(&partitionCellsWorkLoad[0], partitionCellsCnt, noDomains(), &offset[0]);
1104
1105 MPI_Bcast(offset.getPointer(), noDomains(), MPI_INT, 0, mpiComm(), AT_, "offset.getPointer()");
1106 MPI_Bcast(&partitionCellsCnt, 1, MPI_INT, 0, mpiComm(), AT_, "partitionCellsCnt");
1107 } else
1108 offset[0] = 0;
1109 } else {
1110 MPI_Bcast(offset.getPointer(), noDomains(), MPI_INT, 0, mpiComm(), AT_, "offset.getPointer()");
1111 MPI_Bcast(&partitionCellsCnt, 1, MPI_INT, 0, mpiComm(), AT_, "partitionCellsCnt");
1112 }
1113
1114 if(domainId() < noDomains() - 1)
1115 noLocalPartitionCells = offset[domainId() + 1] - offset[domainId()];
1116 else
1117 noLocalPartitionCells = partitionCellsCnt - offset[domainId()];
1118
1119 m_log << " - no. local partitionCells: " << noLocalPartitionCells << endl;
1120
1121 // 2. Read basic geometry information
1122 m_log << " - reading basic geometry information" << endl;
1123 ParallelIo geomIO(m_parallelGeomFileName, PIO_READ, mpiComm());
1124
1125 MInt noTriangles = 0;
1126 geomIO.readScalar(&noTriangles, "noTriangles");
1127 geomIO.setOffset(noLocalPartitionCells, offset[domainId()]);
1128
1129 MIntScratchSpace noTrisPerPartitionCell(noLocalPartitionCells, AT_, "noTrisPerPartitionCell");
1130 geomIO.readArray(noTrisPerPartitionCell.getPointer(), "noTrisPerPartitionCell");
1131
1132 // 2.1 Count all local elements and exchange
1133 MIntScratchSpace noAllLocalTris(noDomains(), AT_, "noAllLocalTris");
1134 MInt noL = 0;
1135 for(MInt i = 0; i < noLocalPartitionCells; i++) {
1136 noL += noTrisPerPartitionCell[i];
1137 }
1138
1139 MPI_Allgather(&noL, 1, MPI_INT, noAllLocalTris.getPointer(), 1, MPI_INT, mpiComm(), AT_, "noL",
1140 "noAllLocalTris.getPointer()");
1141
1142 MInt originalTriIdOffset = 0;
1143 // MInt noDomainSubComm = 0;
1144 for(MInt d = 0; d < domainId(); d++) {
1145 originalTriIdOffset += noAllLocalTris[d];
1146 // if(noAllLocalTris[d] > 0)
1147 // noDomainSubComm++;
1148 }
1149
1150 // create subcommunicator
1151 /*
1152 m_log << " - creating subcommunicator" << endl;
1153 MIntScratchSpace subCommDomainList (noDomainSubComm, AT_, "subCommDomainList");
1154 for(MInt d = 0, l = 0; d < domainId() ; d++)
1155 if(noAllLocalTris[d] > 0)
1156 {
1157 subCommDomainList[l] = d;
1158 l++;
1159 }
1160
1161 MPI_Group tmp_group, subCommGroup;
1162 MPI_Comm subComm;
1163
1164 MPI_Comm_group(mpiComm(), &tmp_group);
1165
1166 MPI_Group_incl(tmp_group, noDomainSubComm, subCommDomainList.getPointer(), &subCommGroup, AT_ );
1167
1168 MPI_Comm_create(mpiComm(), subCommGroup, &subComm, AT_, "subComm");
1169
1170 //no need to read anything
1171 if(noL == 0)
1172 {
1173 m_log << " - no triangles found for this domain" << endl << endl;
1174 m_noElements = 0;
1175 //return new Collector < element<nDim> > (0, nDim, 0);;
1176 }
1177 */
1178
1179 // dummies
1180 MIntScratchSpace dummyInt(1, AT_, "dummyInt");
1181 MFloatScratchSpace dummyFloat(1, AT_, "dummyFloat");
1182
1183 // 2.2 Read the original triangle ids
1184 MIntScratchSpace originalTriId(noL, AT_, "originalTriId");
1185 geomIO.setOffset(noL, originalTriIdOffset);
1186 if(noL == 0)
1187 geomIO.readArray(dummyInt.getPointer(), "originalTriId");
1188 else
1189 geomIO.readArray(originalTriId.getPointer(), "originalTriId");
1190
1191 MIntScratchSpace segEntry(noL, AT_, "segEntry");
1192 if(noL == 0)
1193 geomIO.readArray(dummyInt.getPointer(), "segmentId");
1194 else
1195 geomIO.readArray(segEntry.getPointer(), "segmentId");
1196
1197 vector<MInt> keepOffset;
1198 for(MInt i = 0; i < noL; i++) {
1199 pair<set<MInt>::iterator, MBool> ret = m_uniqueOriginalTriId.insert(originalTriId[i]);
1200 if(ret.second) keepOffset.push_back(i);
1201 }
1202
1203 if(noL == 0)
1204 m_noElements = 0;
1205 else
1207
1208 // cout << domainId() << " size " << m_noElements << endl;
1209 // 3. Init the collector holding the triangles.
1210 auto* m_allelements = new Collector<element<nDim>>(m_noElements, nDim, 0);
1211 element<nDim>* allelements = m_allelements->a;
1212
1213 for(MInt i = 0; i < m_noElements; i++)
1214 m_allelements->append();
1215
1216 // 4. Read the triangles and skip those that have already been read before.
1217 m_log << " - actiually reading triangles" << endl;
1218 MString normalnames[3] = {"normals0", "normals1", "normals2"};
1219 MString vertexnames[3][3] = {{"vertices00", "vertices01", "vertices02"},
1220 {"vertices10", "vertices11", "vertices12"},
1221 {"vertices20", "vertices21", "vertices22"}};
1222
1223 // 4.1 segmentOffsets
1224 m_log << " * segmentOffsets" << endl;
1225 for(MInt i = 0; i < m_noElements; i++)
1226 m_segmentOffsets[segEntry[keepOffset[i]] + 1]++;
1227
1228 MIntScratchSpace segmentCnt(m_noSegments, AT_, "segmentCnt");
1229
1230 for(MInt i = 0; i < m_noSegments; i++) {
1231 m_ownSegmentId[i] = false;
1233 if(m_segmentOffsets[i] != m_segmentOffsets[i + 1]) m_ownSegmentId[i] = true;
1234 segmentCnt[i] = 0;
1235 }
1236
1237 unordered_set<MInt> allBCs;
1238
1239 // 4.2 segmentIds
1240 m_log << " * segmentIds, bndCndIds, originalIds" << endl;
1241 for(MInt i = 0; i < m_noElements; i++) {
1242 MInt segmentId = segEntry[keepOffset[i]];
1254 MInt bndCndId = *geometryContext().getProperty("BC", segmentId)->asInt();
1255 MInt off = m_segmentOffsets[segmentId];
1256 allelements[segmentCnt[segmentId] + off].m_segmentId = segmentId;
1257 allelements[segmentCnt[segmentId] + off].m_bndCndId = bndCndId;
1258 allelements[segmentCnt[segmentId] + off].m_originalId = originalTriId[keepOffset[i]];
1259 allBCs.insert(bndCndId);
1260 segmentCnt[segmentId]++;
1261 }
1262
1263 m_noAllBCs = allBCs.size();
1264 mAlloc(m_allBCs, m_noAllBCs, "m_allBCs", 0, AT_);
1265 MInt iter = 0;
1266 for(auto it = allBCs.begin(); it != allBCs.end(); ++it, iter++)
1267 m_allBCs[iter] = *it;
1268
1269 // 4.3 normals
1270 m_log << " * normals" << endl;
1271 for(MInt d = 0; d < nDim; d++) {
1272 // reset
1273 for(MInt i = 0; i < m_noSegments; i++)
1274 segmentCnt[i] = 0;
1275
1276 MFloatScratchSpace normalEntry(noL, AT_, "normalEntry");
1277 if(noL == 0)
1278 geomIO.readArray(dummyFloat.getPointer(), normalnames[d]);
1279 else
1280 geomIO.readArray(normalEntry.getPointer(), normalnames[d]);
1281
1282 for(MInt i = 0; i < m_noElements; i++) {
1283 MInt segmentId = segEntry[keepOffset[i]];
1284 MInt off = m_segmentOffsets[segmentId];
1285 allelements[segmentCnt[segmentId] + off].m_normal[d] = normalEntry[keepOffset[i]];
1286 segmentCnt[segmentId]++;
1287 }
1288 }
1289
1290 // 4.4. vertices
1291 m_log << " * vertices" << endl;
1292 for(MInt v = 0; v < nDim; v++)
1293 for(MInt d = 0; d < nDim; d++) {
1294 for(MInt i = 0; i < m_noSegments; i++)
1295 segmentCnt[i] = 0;
1296
1297 MFloatScratchSpace vertexEntry(noL, AT_, "vertexEntry");
1298 if(noL == 0)
1299 geomIO.readArray(dummyFloat.getPointer(), vertexnames[v][d]);
1300 else
1301 geomIO.readArray(vertexEntry.getPointer(), vertexnames[v][d]);
1302
1303 for(MInt i = 0; i < m_noElements; i++) {
1304 MInt segmentId = segEntry[keepOffset[i]];
1305 MInt off = m_segmentOffsets[segmentId];
1306 allelements[segmentCnt[segmentId] + off].m_vertices[v][d] = vertexEntry[keepOffset[i]];
1307 segmentCnt[segmentId]++;
1308 }
1309 }
1310
1311 // 5. Calculate bounding box
1312 m_log << " * calculating bounding box for the triangles" << endl;
1313 for(MInt i = 0; i < m_noElements; i++)
1314 allelements[i].boundingBox();
1315
1316 for(MInt i = 0; i < m_noSegments; i++) {
1317 if(m_segmentOffsets[i + 1] - m_segmentOffsets[i] != 0) {
1318 m_log << " - segment id " << i << endl;
1319 m_log << " * number of triangles: " << m_segmentOffsets[i + 1] - m_segmentOffsets[i] << endl;
1320 m_log << " * offsets: " << m_segmentOffsets[i] << " - " << m_segmentOffsets[i + 1] << endl;
1321 }
1322 }
1323 m_log << endl;
1324
1325 RECORD_TIMER_STOP(t_readTriangles);
1326
1327 return m_allelements;
1328}
1329
1339 TRACE();
1340
1341 NEW_SUB_TIMER(t_readGeometry, "read geometry", m_t_geometryAll);
1342 m_t_readGeometry = t_readGeometry;
1343 g_tc_geometry.emplace_back("read geometry", m_t_readGeometry);
1344 RECORD_TIMER_START(t_readGeometry);
1345
1346 otherCalls++;
1347
1348 // check binary or ascii
1349 m_geomFileType = "ASCII";
1350 if(geometryContext().propertyExists("geomFileType", 0))
1351 m_geomFileType = *(geometryContext().getProperty("geomFileType", 0)->asString(0));
1352
1353 // check if we need to count the triangles
1354 m_noAllTriangles = 0;
1355 if(geometryContext().propertyExists("noAllTriangles", 0))
1356 m_noAllTriangles = *(geometryContext().getProperty("noAllTriangles", 0)->asInt(0));
1357
1358 string tmp;
1359
1360 // This loop only counts all elements of all segments
1361 for(MInt i = 0; i <= m_noSegments; i++) {
1362 m_segmentOffsets[i] = 0;
1364 }
1365
1366 mAlloc(m_ownSegmentId, m_noSegments, "m_ownSegmentId", true, AT_);
1367
1368 m_log << " + Geometry configuration:" << endl;
1369 m_log << " - File type is set to: " << (m_parallelGeometry ? "NETCDF" : m_geomFileType) << endl;
1370 m_log << " - endianess: " << (is_big_endian() ? "big endian" : "little endian") << endl;
1371 m_log << " - reading method: " << (m_parallelGeometry ? "parallel" : "serial") << endl << endl;
1372
1373 // trust me, this is just the definition, init will be performed in the following funtions
1374 Collector<element<3>>* m_allelements = nullptr;
1375
1377 m_allelements = readSegmentsParallel();
1378 } else {
1379 m_allelements = readSegmentsSerial();
1380 }
1381
1385 }
1386
1387 MInt initSize = m_noElements;
1388
1389 // add 15% overhead
1390 /*
1391 if(m_parallelGeometry)
1392 initSize *= m_parGeomMemFactor;
1393 */
1394
1395 m_elements = new Collector<element<nDim>>(initSize, nDim, 0);
1396 elements = m_elements->a;
1398
1399 MInt mbelem_counter = 0, elem_counter = 0;
1400 MBool mbElem = false;
1401 element<3>* allelements = m_allelements->a;
1402
1403 for(MInt allelem_counter = 0; allelem_counter < m_allelements->size(); allelem_counter++) {
1405 for(MInt id = 0; id < m_noLevelSetIntfBndIds; id++) {
1406 if(allelements[allelem_counter].m_bndCndId == m_levelSetIntfBndIds[id]) {
1407 mbElem = true;
1408 break;
1409 }
1410 }
1411
1412 // LevelSet Moving boundary elements
1413 if(mbElem) {
1414 m_mbelements->append();
1415
1416 for(MInt j = 0; j < 3; j++) {
1417 mbelements[mbelem_counter].m_normal[j] = allelements[allelem_counter].m_normal[j];
1418 for(MInt i = 0; i < 3; i++) {
1419 mbelements[mbelem_counter].m_vertices[j][i] = allelements[allelem_counter].m_vertices[j][i];
1420 }
1421 }
1422
1423 mbelements[mbelem_counter].boundingBox();
1424 mbelements[mbelem_counter].m_bndCndId = allelements[allelem_counter].m_bndCndId;
1425 mbelements[mbelem_counter].m_segmentId = allelements[allelem_counter].m_segmentId;
1426 mbelements[mbelem_counter].m_originalId = allelements[allelem_counter].m_originalId;
1427 mbelem_counter++;
1428 mbElem = false;
1429 }
1430
1431 // Non movable elements
1432 else {
1433 m_elements->append();
1434
1435 for(MInt j = 0; j < 3; j++) {
1436 elements[elem_counter].m_normal[j] = allelements[allelem_counter].m_normal[j];
1437 for(MInt i = 0; i < 3; i++) {
1438 elements[elem_counter].m_vertices[j][i] = allelements[allelem_counter].m_vertices[j][i];
1439 }
1440 }
1441 elements[elem_counter].boundingBox();
1442 elements[elem_counter].m_bndCndId = allelements[allelem_counter].m_bndCndId;
1443 elements[elem_counter].m_segmentId = allelements[allelem_counter].m_segmentId;
1444 elements[elem_counter].m_originalId = allelements[allelem_counter].m_originalId;
1445 elem_counter++;
1446 }
1447 } else {
1448 // LevelSet Moving boundary elements
1449 if(m_GFieldInitFromSTL && (m_levelSetIntfBndId == allelements[allelem_counter].m_bndCndId)) {
1450 m_mbelements->append();
1451
1452 for(MInt j = 0; j < 3; j++) {
1453 mbelements[mbelem_counter].m_normal[j] = allelements[allelem_counter].m_normal[j];
1454 for(MInt i = 0; i < 3; i++) {
1455 mbelements[mbelem_counter].m_vertices[j][i] = allelements[allelem_counter].m_vertices[j][i];
1456 }
1457 }
1458 mbelements[mbelem_counter].boundingBox();
1459 mbelements[mbelem_counter].m_bndCndId = allelements[allelem_counter].m_bndCndId;
1460 mbelements[mbelem_counter].m_segmentId = allelements[allelem_counter].m_segmentId;
1461 mbelements[mbelem_counter].m_originalId = allelements[allelem_counter].m_originalId;
1462 mbelem_counter++;
1463 } else { // Non movable elements
1464
1465 m_elements->append();
1466
1467 for(MInt j = 0; j < 3; j++) {
1468 elements[elem_counter].m_normal[j] = allelements[allelem_counter].m_normal[j];
1469 for(MInt i = 0; i < 3; i++)
1470 elements[elem_counter].m_vertices[j][i] = allelements[allelem_counter].m_vertices[j][i];
1471 }
1472 elements[elem_counter].boundingBox();
1473 elements[elem_counter].m_bndCndId = allelements[allelem_counter].m_bndCndId;
1474 elements[elem_counter].m_segmentId = allelements[allelem_counter].m_segmentId;
1475 elements[elem_counter].m_originalId = allelements[allelem_counter].m_originalId;
1476
1477 elem_counter++;
1478 }
1479 }
1480 }
1481
1482 delete m_allelements;
1483
1484 RECORD_TIMER_STOP(t_readGeometry);
1485
1486 NEW_SUB_TIMER(t_calcBndBox, "calculating bounding box", m_t_geometryAll);
1487 g_tc_geometry.emplace_back("calculating bounding box", t_calcBndBox);
1488 RECORD_TIMER_START(t_calcBndBox);
1489
1491 RECORD_TIMER_STOP(t_calcBndBox);
1492
1493 // update m_haloElementOffset
1495
1497 writeParallelGeometryVTK("readSeg");
1498 }
1499}
1500
1509 TRACE();
1510
1511 const MBool allTimerRunning = timers().isRunning(m_t_geometryAll);
1512 if(!allTimerRunning) {
1513 RECORD_TIMER_START(m_t_geometryAll);
1514 }
1515 NEW_SUB_TIMER(t_wrtParGeom, "writing parallel geometry", m_t_geometryAll);
1516 g_tc_geometry.emplace_back("writing parallel geometry", t_wrtParGeom);
1517 RECORD_TIMER_START(t_wrtParGeom);
1518
1519 stringstream name;
1520 name << "out/" << domainId() << "_" << filename << ".vtk";
1521 ofstream st;
1522 st.open(name.str());
1523 st << "# vtk DataFile Version 3.0" << endl;
1524 st << "vtk output" << endl;
1525 st << "ASCII" << endl;
1526 st << "DATASET POLYDATA" << endl;
1527 st << "POINTS " << m_noElements * nDim << " float" << endl;
1528
1529 for(MInt i = 0; i < m_noElements; i++)
1530 for(MInt v = 0; v < 3; v++) {
1531 for(MInt d = 0; d < 3; d++)
1532 st << elements[i].m_vertices[v][d] << " ";
1533 st << endl;
1534 }
1535
1536 st << endl;
1537 st << "POLYGONS " << m_noElements << " " << m_noElements * (nDim + 1) << endl;
1538 for(MInt i = 0, j = 0; i < m_noElements; i++) {
1539 st << nDim << " ";
1540 for(MInt v = 0; v < 3; v++, j++)
1541 st << j << " ";
1542 st << endl;
1543 }
1544
1545 st << endl;
1546 st << "CELL_DATA " << m_noElements << endl;
1547 st << "SCALARS domainId int 1" << endl;
1548 st << "LOOKUP_TABLE default" << endl;
1549 for(MInt i = 0; i < m_noElements; i++)
1550 st << domainId() << endl;
1551 st << endl;
1552 st << "SCALARS segmentId int 1" << endl;
1553 st << "LOOKUP_TABLE default" << endl;
1554 for(MInt i = 0; i < m_noElements; i++)
1555 st << elements[i].m_segmentId << endl;
1556 st << endl;
1557 st << "SCALARS originalCellId int 1" << endl;
1558 st << "LOOKUP_TABLE default" << endl;
1559 for(MInt i = 0; i < m_noElements; i++)
1560 st << elements[i].m_originalId << endl;
1561 st << endl;
1562 st << "SCALARS BC int 1" << endl;
1563 st << "LOOKUP_TABLE default" << endl;
1564 for(MInt i = 0; i < m_noElements; i++)
1565 st << elements[i].m_bndCndId << endl;
1566 st << "SCALARS area double 1" << endl;
1567 st << "LOOKUP_TABLE default" << endl;
1568 for(MInt i = 0; i < m_noElements; i++) {
1569 MFloat edge1[3];
1570 MFloat edge2[3];
1571 MFloat cross[3];
1572 for(MInt j = 0; j < nDim; j++) {
1573 edge1[j] = elements[i].m_vertices[1][j] - elements[i].m_vertices[0][j];
1574 edge2[j] = elements[i].m_vertices[2][j] - elements[i].m_vertices[0][j];
1575 }
1576 cross[0] = edge1[1] * edge2[2] - edge2[1] * edge1[2];
1577 cross[1] = edge1[2] * edge2[0] - edge2[2] * edge1[0];
1578 cross[2] = edge1[0] * edge2[1] - edge2[0] * edge1[1];
1579
1580 MFloat area = sqrt(cross[0] * cross[0] + cross[1] * cross[1] + cross[2] * cross[2]);
1581 st << area << endl;
1582 }
1583 st.close();
1584 RECORD_TIMER_STOP(t_wrtParGeom);
1585 if(!allTimerRunning) {
1586 RECORD_TIMER_STOP(m_t_geometryAll);
1587 }
1588}
1589
1599 TRACE();
1600
1601 m_log << " + Calculating bounding box ..." << endl;
1602 m_log << " - number of elements to consider: " << m_noElements << endl;
1603
1604 // Communicate a reference triangle for those that have no triangles available
1605 MIntScratchSpace noGlobalElem(noDomains(), AT_, "noGlobalElem");
1606 noGlobalElem[domainId()] = m_noElements;
1607
1608 MPI_Allgather(&m_noElements, 1, MPI_INT, noGlobalElem.getPointer(), 1, MPI_INT, mpiComm(), AT_, "m_noElements",
1609 "noGlobalElem.getPointer()");
1610 MInt refDomain = 0;
1611 for(MInt d = 0; d < noDomains(); d++) {
1612 if(noGlobalElem[d] > 0) {
1613 refDomain = d;
1614 break;
1615 }
1616 }
1617
1618 std::array<MFloat, 2 * nDim> triMinMax;
1619 triMinMax.fill(std::nanf(""));
1620
1621 if(domainId() == refDomain) {
1622 for(MInt j = 0; j < 2 * nDim; j++) {
1623 triMinMax[j] = elements[0].m_minMax[j];
1624 }
1625 }
1626
1627 MPI_Bcast(triMinMax.data(), 2 * nDim, MPI_DOUBLE, refDomain, mpiComm(), AT_, "triMinMax.getPointer()");
1628
1629 // Calculate bounding box of segment
1630 for(MInt j = 0; j < nDim; j++) {
1631 m_minMax[j] = triMinMax[j];
1632 m_minMax[j + nDim] = triMinMax[j + nDim];
1633 }
1634
1635 for(MInt i = 0; i < m_noElements; i++) {
1636 for(MInt j = 0; j < nDim; j++) {
1637 m_minMax[j + nDim] =
1638 (m_minMax[j + nDim] < elements[i].m_minMax[j + nDim]) ? elements[i].m_minMax[j + nDim] : m_minMax[j + nDim];
1639 m_minMax[j] = (m_minMax[j] > elements[i].m_minMax[j]) ? elements[i].m_minMax[j] : m_minMax[j];
1640 }
1641 }
1642 if(m_noElements == 0) ASSERT(m_GFieldInitFromSTL, "");
1643
1644 if(m_noElements > 0) {
1645 m_log << " - local max: ";
1646 for(MInt i = 0; i < nDim; i++) {
1647 m_log << m_minMax[i + nDim] << " ";
1648 }
1649 m_log << endl;
1650
1651 m_log << " - local min: ";
1652 for(MInt i = 0; i < nDim; i++) {
1653 m_log << m_minMax[i] << " ";
1654 }
1655 m_log << endl;
1656 }
1657
1658 if(m_parallelGeometry) {
1659 MPI_Allreduce(MPI_IN_PLACE, &m_minMax[0], nDim, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "m_minMax[0]");
1660 MPI_Allreduce(MPI_IN_PLACE, &m_minMax[0] + nDim, nDim, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
1661 "m_minMax[0]+nDim");
1662 }
1663
1664 if(m_noElements > 0) {
1665 m_log << " - max: ";
1666 for(MInt i = 0; i < nDim; i++) {
1667 m_log << m_minMax[i + nDim] << " ";
1668 }
1669 m_log << endl;
1670
1671 m_log << " - min: ";
1672 for(MInt i = 0; i < nDim; i++) {
1673 m_log << m_minMax[i] << " ";
1674 }
1675 m_log << endl << endl;
1676 }
1677
1678 // Calculate bounding box of Moving Boundary segment
1681 m_log << " Bounding box for Moving Boundary segment:" << endl;
1682 m_log << " max = ";
1683 for(MInt i = 0; i < nDim; i++)
1684 m_log << m_mbminMax[i + nDim] << " ";
1685
1686 m_log << endl;
1687 m_log << " min = ";
1688 for(MInt i = 0; i < nDim; i++)
1689 m_log << m_mbminMax[i] << " ";
1690
1691 m_log << endl;
1692
1693 if(m_forceBoundingBox) {
1694 // use the STL2levelset geometry as bounding box to define the length0 and center of gravity
1695 // this can be useful, to force a length onto a setup!
1696 for(MInt i = 0; i < nDim; i++) {
1697 if(m_mbminMax[i] < m_minMax[i]) {
1698 m_minMax[i] = m_mbminMax[i];
1699 }
1700 if(m_mbminMax[i + nDim] > m_minMax[i + nDim]) {
1701 m_minMax[i + nDim] = m_mbminMax[i + nDim];
1702 }
1703 }
1704 }
1705 }
1706}
1707
1708
1710 TRACE();
1711
1712 otherCalls++;
1713
1714
1715 MInt noEl = m_elements->size();
1716 MFloat epsilon = 0.0000001;
1717 MFloat maxCoordinate = F0;
1718 //---
1719
1720 // find the maximum coordinate
1721 for(MInt el = 0; el < noEl; el++)
1722 for(MInt i = 0; i < 3; i++)
1723 for(MInt j = 0; j < 3; j++)
1724 maxCoordinate = mMax(ABS(elements[el].m_vertices[i][j]), maxCoordinate);
1725
1726 // compute epsilon
1727 epsilon *= maxCoordinate;
1728
1729 // remove small values around zero
1730 for(MInt el = 0; el < noEl; el++) {
1731 for(MInt i = 0; i < 3; i++) {
1732 for(MInt j = 0; j < 3; j++) {
1733 if(ABS(elements[el].m_vertices[j][i]) < epsilon) elements[el].m_vertices[j][i] = F0;
1734 }
1735 }
1736 }
1737}
1738
1739
1784MInt Geometry3D::getIntersectionElements(MFloat* targetRegion, std::vector<MInt>& nodeList, MFloat cellHalfLength,
1785 const MFloat* const cell_coords) {
1786 // TRACE();
1787
1789
1790 m_adt->retrieveNodes(targetRegion, nodeList);
1791 const MInt noNodes = nodeList.size();
1792 MFloat vert_mov[MAX_SPACE_DIMENSIONS][MAX_SPACE_DIMENSIONS];
1793 MFloat edge_mov[MAX_SPACE_DIMENSIONS][MAX_SPACE_DIMENSIONS];
1794 MFloat edge_fabs[MAX_SPACE_DIMENSIONS][MAX_SPACE_DIMENSIONS];
1795 MFloat min;
1796 MFloat max;
1797 MFloat d;
1798 MFloat p0;
1799 MFloat p1;
1800 MFloat rad;
1801 MFloat normal[MAX_SPACE_DIMENSIONS];
1802 MFloat vmin[MAX_SPACE_DIMENSIONS] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
1803 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized
1804 MFloat vmax[MAX_SPACE_DIMENSIONS] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
1805 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized
1806
1807 MInt combo[3][6] = {{0, 2, 0, 2, 1, 2}, {0, 2, 0, 2, 0, 1}, {0, 1, 0, 1, 1, 2}};
1808
1809 MInt noReallyIntersectingNodes = 0;
1810 MBool cut;
1811
1812 for(MInt n = 0; n < noNodes; n++) {
1813 cut = true;
1814
1815 // Fill arrays (translate triangle)
1816 for(MInt i = 0; i < nDim; i++) {
1817 for(MInt j = 0; j < nDim; j++) {
1818 vert_mov[j][i] = elements[nodeList[n]].m_vertices[j][i] - cell_coords[i];
1819 }
1820 for(MInt j = 0; j < nDim; j++) {
1821 edge_mov[j][i] = vert_mov[(j + 1) % nDim][i] - vert_mov[j][i];
1822 edge_fabs[j][i] = fabs(edge_mov[j][i]);
1823 }
1824 }
1825
1826 MInt mul;
1827
1828 // Step 1) of the algorithm
1829 for(MInt i = 0; i < nDim; i++) {
1830 mul = 1;
1831 for(MInt l = 0, j = 2, k = 1; l < nDim; l++) {
1832 p0 = mul * edge_mov[i][j] * vert_mov[combo[i][2 * l]][k] - mul * edge_mov[i][k] * vert_mov[combo[i][2 * l]][j];
1833 p1 = mul * edge_mov[i][j] * vert_mov[combo[i][2 * l + 1]][k]
1834 - mul * edge_mov[i][k] * vert_mov[combo[i][2 * l + 1]][j];
1835
1836 (p0 < p1) ? (min = p0, max = p1) : (min = p1, max = p0);
1837 rad = cellHalfLength * (edge_fabs[i][j] + edge_fabs[i][k]);
1838
1839 if(min > rad || max < -rad) {
1840 cut = false;
1841 break;
1842 }
1843
1844 mul *= -1;
1845 j -= l;
1846 k = 0;
1847 }
1848 if(!cut) break;
1849 }
1850 if(!cut) continue;
1851
1852 // Step 2) of the algorithm
1853 for(MInt i = 0; i < nDim; i++) {
1854 min = max = vert_mov[0][i];
1855 for(MInt j = 1; j < nDim; j++) {
1856 if(vert_mov[j][i] < min) min = vert_mov[j][i];
1857 if(vert_mov[j][i] > max) max = vert_mov[j][i];
1858 }
1859
1860 if(min > cellHalfLength || max < -cellHalfLength) {
1861 cut = false;
1862 break;
1863 }
1864 }
1865 if(!cut) continue;
1866
1867 // Step 3) of the algorithm
1868 normal[0] = edge_mov[0][1] * edge_mov[1][2] - edge_mov[0][2] * edge_mov[1][1];
1869 normal[1] = edge_mov[0][2] * edge_mov[1][0] - edge_mov[0][0] * edge_mov[1][2];
1870 normal[2] = edge_mov[0][0] * edge_mov[1][1] - edge_mov[0][1] * edge_mov[1][0];
1871
1872 d = 0.0;
1873 for(MInt i = 0; i < nDim; i++)
1874 d += normal[i] * vert_mov[0][i];
1875 d *= -1;
1876
1877 for(MInt i = 0; i < nDim; i++) {
1878 if(normal[i] > 0.0f) {
1879 vmin[i] = -cellHalfLength;
1880 vmax[i] = cellHalfLength;
1881 } else {
1882 vmin[i] = cellHalfLength;
1883 vmax[i] = -cellHalfLength;
1884 }
1885 }
1886
1887 if((normal[0] * vmin[0] + normal[1] * vmin[1] + normal[2] * vmin[2]) + d > 0.0f) continue;
1888 if((normal[0] * vmax[0] + normal[1] * vmax[1] + normal[2] * vmax[2]) + d >= 0.0f) {
1889 nodeList[noReallyIntersectingNodes] = nodeList[n];
1890 noReallyIntersectingNodes++;
1891 }
1892 }
1893
1894 nodeList.resize(noReallyIntersectingNodes);
1895
1896 getIECommCounter += noReallyIntersectingNodes;
1897
1898 return noReallyIntersectingNodes;
1899}
1900
1910MInt Geometry3D::getIntersectionElements(MFloat* targetRegion, std::vector<MInt>& nodeList) {
1911 // TRACE();
1912
1914
1915 MInt noReallyIntersectingNodes = 0;
1916 // get all candidates for an intersection
1917 // Check for intersection...
1918 bitset<6> points[3];
1919 bitset<6> faceCodes[6];
1920 bitset<6> pCode;
1921 MInt spaceId;
1922 MInt spaceId1;
1923 MInt spaceId2;
1924 MInt edges[3][2] = {{0, 1}, {1, 2}, {0, 2}};
1925 // Corner points of the target regione i.e. p0=(targetRegion[targetPoints[0][0],
1926 // targetRegion[targetPoints[0][1],
1927 // targetRegion[targetPoints[0][2])
1928 MInt targetPoints[8][3] = {{0, 1, 2}, {3, 1, 2}, {0, 4, 2}, {3, 4, 2}, {0, 1, 5}, {3, 1, 5}, {0, 4, 5}, {3, 4, 5}};
1929
1930 // Edges of the targetRegion (using targetPoints)
1931 MInt targetEdges[12][2] = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, // x-edges (i.e. parallel to x-axis)
1932 {0, 2}, {1, 3}, {4, 6}, {5, 7}, // y-edes
1933 {0, 4}, {1, 5}, {2, 6}, {3, 7}}; // z-edges
1934 MFloat e1[3];
1935 MFloat e2[3];
1936 MInt rejection = 0;
1937 MBool piercePointInside = 0;
1938 MBool triviallyAccepted = 0;
1939
1940 // Each of the following arrays holds one different point for
1941 // all of the 6 planes. Points are built with the targetRegion
1942 // i.e. a = targetRegiont[pointAInPlane[0]],
1943 // targetRegiont[pointAInPlane[1]],
1944 // targetRegiont[pointAInPlane[2]])
1945 // etc.
1946 MInt pointAInPlane[6][3] = {{0, 1, 2}, {3, 4, 5}, {0, 1, 2}, {3, 4, 5}, {0, 1, 2}, {3, 4, 5}};
1947
1948 MInt pointBInPlane[6][3] = {{0, 4, 2}, {3, 1, 5}, {3, 1, 2}, {0, 4, 5}, {3, 1, 2}, {3, 1, 5}};
1949
1950 MInt pointCInPlane[6][3] = {{0, 1, 5}, {3, 4, 2}, {3, 1, 5}, {0, 4, 2}, {3, 4, 2}, {0, 1, 5}};
1951 MFloat a[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
1952 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // point in plane
1953 MFloat b[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
1954 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // point in plane
1955 MFloat c[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
1956 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // point in plane
1957 MFloat d[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
1958 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // start of piercing edge
1959 MFloat e[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
1960 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // end of piercing edge
1961 MFloat s;
1962 MFloat gamma; // For pierce point calculation
1963 MFloat p2;
1964 MFloat q;
1965 MFloat epsilon = 0.00000000001;
1966 MFloat pP[3]; // piercePoint
1967 faceCodes[0] = IPOW2(0);
1968 faceCodes[1] = IPOW2(1);
1969 faceCodes[2] = IPOW2(2);
1970 faceCodes[3] = IPOW2(3);
1971 faceCodes[4] = IPOW2(4);
1972 faceCodes[5] = IPOW2(5);
1973 // edges[0][0] = 0;
1974 // edges[0][1] = 1;
1975 // edges[1][0] = 1;
1976 // edges[1][1] = 2;
1977 // edges[2][0] = 0;
1978 // edges[2][1] = 2;
1979 bitset<6> result;
1980
1981 m_adt->retrieveNodes(targetRegion, nodeList);
1982 const MInt noNodes = nodeList.size();
1983 // return noNodes;
1984 noReallyIntersectingNodes = 0;
1985
1986 for(MInt n = 0; n < noNodes; n++) {
1987 // create edges (in 3D) AB, AC, BC and point A B C
1988 // Determine outcode (see Aftosmis, Solution Adaptive Cartesian Grid Methods for Aerodynamic flows ...)
1989
1990 // Loop over all points of an element<3>
1991 for(MInt p = 0; p < nDim; p++) {
1992 points[p] = 0;
1993 // Calculate outcode for point
1994 for(MInt j = 0; j < nDim; j++) {
1995 if(elements[nodeList[n]].m_vertices[p][j] < targetRegion[j]) {
1996 points[p] |= faceCodes[2 * j];
1997 }
1998 if(elements[nodeList[n]].m_vertices[p][j] > targetRegion[j + nDim]) {
1999 points[p] |= faceCodes[2 * j + 1];
2000 }
2001 }
2002 // m_log << points[p] << endl;
2003 }
2004 rejection = 0;
2005 // check outcode combinations for edges for trivial rejection
2006 for(MInt i = 0; i < nDim; i++) {
2007 if((points[edges[i][0]] & points[edges[i][1]]) != 0) {
2008 rejection++;
2009 } else {
2010 // If one point is inside region the element<3> is trivially accepted
2011 triviallyAccepted = false;
2012 for(MInt k = 0; k < nDim; k++) {
2013 if(points[k] == 0) {
2014 triviallyAccepted = true;
2015 break;
2016 }
2017 }
2018 if(triviallyAccepted) {
2019 break;
2020 }
2021 // No trivial rejection, check for rejection of subsegment:
2022 // For all pierce points!
2023 // 1. Calculate pierce point:
2024 // a - determine plane for pierce point calculation
2025 // b - calculate pierce point
2026 // 2. Check for rejection of new segment
2027 // a - calculate new outcode
2028 // b - check for containment in pierce planes face
2029 // 3. If all(!) pierce points are rejected -> reject edge
2030 // TODO labels:GEOM This algorith might get a problem if a triangle lies completely on
2031 // a face.
2032
2033 // 1.a
2034 result = (points[edges[i][0]] | points[edges[i][1]]);
2035 piercePointInside = false;
2036 for(MInt j = 0; j < 2 * nDim; j++) {
2037 if(result[j] == 1) {
2038 // pierce plane found
2039 // Algorithm taken von AFTOSMIS. There seems to be an
2040 // error in the calculation of s in AFTOSMIS formula, the one below
2041 // should be correct!
2042 for(MInt k = 0; k < nDim; k++) {
2043 a[k] = targetRegion[pointAInPlane[j][k]];
2044 b[k] = targetRegion[pointBInPlane[j][k]];
2045 c[k] = targetRegion[pointCInPlane[j][k]];
2046 d[k] = elements[nodeList[n]].m_vertices[edges[i][0]][k];
2047 e[k] = elements[nodeList[n]].m_vertices[edges[i][1]][k];
2048 }
2049 gamma = ((e[0] - d[0]) * ((a[2] - c[2]) * (c[1] - b[1]) - (a[1] - c[1]) * (c[2] - b[2]))
2050 - (e[1] - d[1]) * ((a[2] - c[2]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[2] - b[2]))
2051 + (e[2] - d[2]) * ((a[1] - c[1]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[1] - b[1])));
2052
2053 s = ((c[0] - d[0]) * ((a[2] - c[2]) * (c[1] - b[1]) - (a[1] - c[1]) * (c[2] - b[2]))
2054 - (c[1] - d[1]) * ((a[2] - c[2]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[2] - b[2]))
2055 + (c[2] - d[2]) * ((a[1] - c[1]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[1] - b[1])))
2056 / gamma;
2057
2058 // 1. b Pierce point pP in plane j:
2059 for(MInt k = 0; k < nDim; k++) {
2060 pP[k] = d[k] + s * (e[k] - d[k]);
2061 }
2062 pCode = 0;
2063 // 2. a Calculate outcode for pierce point
2064 for(MInt k = 0; k < nDim; k++) {
2065 if(pP[k] < targetRegion[k]) {
2066 pCode |= faceCodes[2 * k];
2067 }
2068 if(pP[k] > targetRegion[k + nDim]) {
2069 pCode |= faceCodes[2 * k + 1];
2070 }
2071 }
2072 // m_log << " outcode of pierce point :" << pCode << endl;
2073
2074 } else {
2075 continue;
2076 }
2077 // 2. b
2078 result = faceCodes[j];
2079 result.flip();
2080 result = (result & pCode);
2081 if(result == 0) { // -> is contained
2082 piercePointInside = true;
2083 }
2084 }
2085 // reject if all pierce points are off coresponding face
2086 if(!piercePointInside) {
2087 rejection++;
2088 }
2089 }
2090 }
2091 // Check for internal element<3>, i.e. completely inside target
2092 result = (points[0] | points[1] | points[2]);
2093 if(result == 0) {
2094 nodeList[noReallyIntersectingNodes] = nodeList[n];
2095 noReallyIntersectingNodes++;
2096 continue;
2097 }
2098 // If not all edges are rejected a cutting element<3> has been found
2099 // m_log << rejection << endl;
2100 if(rejection < 3) {
2101 nodeList[noReallyIntersectingNodes] = nodeList[n];
2102 noReallyIntersectingNodes++;
2103 continue;
2104 }
2105
2106 // Even if trivially rejected, check if targetRegion is completely inside triangle
2107 // For that check all edges of the cell against the plane of the triangle,
2108 // calculate all pierce points and their outcodes and finally check for containment
2109 // in the targetRegion. Before the pierce point calculation check if the current
2110 // edge is parallel to the triangle (evaluate the distance of the edgepoints to the plane)
2111 if(rejection >= 3) {
2112 for(MInt t = 0; t < 12; t++) { // Loop over all 12 edges of the targetRegion (cell-cube)
2113 for(MInt p = 0; p < nDim; p++) {
2114 e1[p] = targetRegion[targetPoints[targetEdges[t][0]][p]];
2115 e2[p] = targetRegion[targetPoints[targetEdges[t][1]][p]];
2116 }
2117
2118 if(t < 4) {
2119 spaceId = 1;
2120 spaceId1 = 2;
2121 spaceId2 = 0;
2122 } else {
2123 if(t > 3 && t < 8) {
2124 spaceId = 2;
2125 spaceId1 = 0;
2126 spaceId2 = 1;
2127 } else {
2128 spaceId = 0;
2129 spaceId1 = 1;
2130 spaceId2 = 2;
2131 }
2132 }
2133
2134 for(MInt k = 0; k < nDim; k++) {
2135 a[k] = elements[nodeList[n]].m_vertices[0][k];
2136 b[k] = elements[nodeList[n]].m_vertices[1][k];
2137 c[k] = elements[nodeList[n]].m_vertices[2][k];
2138 }
2139 if(approx(a[spaceId1], b[spaceId1], MFloatEps) && !approx(a[spaceId1], c[spaceId1], MFloatEps)) {
2140 // aspaceId != bspaceId, otherwise a and b would be the same point
2141 q = (e1[spaceId1] - a[spaceId1]) / (c[spaceId1] - a[spaceId1]);
2142 p2 = (e1[spaceId] - a[spaceId] - q * (c[spaceId] - a[spaceId])) / (b[spaceId] - a[spaceId]);
2143 } else {
2144 if(!approx(a[spaceId1], b[spaceId1], MFloatEps) && approx(a[spaceId1], c[spaceId1], MFloatEps)) {
2145 // aspaceId != cspaceId, otherwise a and c would be the same point
2146 p2 = (e1[spaceId1] - a[spaceId1]) / (b[spaceId1] - a[spaceId1]);
2147 q = (e1[spaceId] - a[spaceId] - p2 * (b[spaceId] - a[spaceId])) / (c[spaceId] - a[spaceId]);
2148 } else {
2149 if(approx(a[spaceId], b[spaceId], MFloatEps) && !approx(a[spaceId], c[spaceId], MFloatEps)) {
2150 // aspaceId1 != bspaceId1, otherwise a and b would be the same point
2151 q = (e1[spaceId] - a[spaceId]) / (c[spaceId] - a[spaceId]);
2152 p2 = (e1[spaceId1] - a[spaceId1] - q * (c[spaceId1] - a[spaceId1])) / (b[spaceId1] - a[spaceId1]);
2153 } else {
2154 if(!approx(a[spaceId], b[spaceId], MFloatEps) && approx(a[spaceId], c[spaceId], MFloatEps)) {
2155 // aspaceId1 != cspaceId1, otherwise a and c would be the same point
2156 p2 = (e1[spaceId] - a[spaceId]) / (b[spaceId] - a[spaceId]);
2157 q = (e1[spaceId1] - a[spaceId1] - p2 * (b[spaceId1] - a[spaceId1])) / (c[spaceId1] - a[spaceId1]);
2158 } else {
2159 // aspaceId1 != bspaceId1 && aspaceId1 != cspaceId1 && aspaceId != bspaceId && aspaceId != cspaceId
2160 q = ((e1[spaceId1] - a[spaceId1]) * (b[spaceId] - a[spaceId])
2161 - (b[spaceId1] - a[spaceId1]) * (e1[spaceId] - a[spaceId]))
2162 / ((c[spaceId1] - a[spaceId1]) * (b[spaceId] - a[spaceId])
2163 - (b[spaceId1] - a[spaceId1]) * (c[spaceId] - a[spaceId]));
2164 p2 = (e1[spaceId] - a[spaceId] - q * (c[spaceId] - a[spaceId])) / (b[spaceId] - a[spaceId]);
2165 }
2166 }
2167 }
2168 }
2169
2170 if(p2 * q >= 0 || p2 * q < 0) {
2171 // compute s
2172 gamma = a[spaceId2] + p2 * (b[spaceId2] - a[spaceId2]) + q * (c[spaceId2] - a[spaceId2]);
2173 s = (gamma - e1[spaceId2]) / (e2[spaceId2] - e1[spaceId2]);
2174
2175 if(s < -epsilon || s > F1 + epsilon || p2 < -epsilon || q < -epsilon || (p2 + q) > F1 + epsilon) {
2176 } else {
2178 /* if( edgeTriangleIntersection(elements[nodeList[n]].m_vertices[0],
2179 elements[nodeList[n]].m_vertices[1],
2180 elements[nodeList[n]].m_vertices[2], e1, e2) ){*/
2181 nodeList[noReallyIntersectingNodes] = nodeList[n];
2182 noReallyIntersectingNodes++;
2183 break;
2184 }
2185 }
2186 }
2187 }
2188
2189 // write nodes in reallyIntersectingNodes
2190 }
2191 // if(noNodes)
2192 if((noNodes != 0) && (noReallyIntersectingNodes == 0)) {
2193 // m_log << "Rejected ! "<< ++rejectionCounter << endl;
2194 }
2195
2196 nodeList.resize(noReallyIntersectingNodes);
2197
2198 getIECommCounter += noReallyIntersectingNodes;
2199
2200 return noReallyIntersectingNodes;
2201}
2202
2203
2208MInt Geometry3D::getIntersectionElementsTetraeder(MFloat* targetRegion, std::vector<MInt>& nodeList) {
2209 TRACE();
2210
2212
2213 MInt noReallyIntersectingNodes = 0;
2214 // get all candidates for an intersection
2215 // Check for intersection...
2216 bitset<6> points[3];
2217 bitset<6> faceCodes[6];
2218 bitset<6> pCode;
2219 MInt edges[3][2] = {{0, 1}, {1, 2}, {0, 2}};
2220 // Corner points of the target regione i.e. p0=(targetRegion[targetPoints[0][0],
2221 // targetRegion[targetPoints[0][1],
2222 // targetRegion[targetPoints[0][2])
2223 MInt targetPoints[8][3] = {{0, 1, 2}, {3, 1, 2}, {0, 4, 2}, {3, 4, 2}, {0, 1, 5}, {3, 1, 5}, {0, 4, 5}, {3, 4, 5}};
2224
2225 // Edges of the targetRegion (using targetPoints)
2226 MInt targetEdges[12][2] = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, // x-edges (i.e. parallel to x-axis)
2227 {0, 2}, {1, 3}, {4, 6}, {5, 7}, // y-edes
2228 {0, 4}, {1, 5}, {2, 6}, {3, 7}}; // z-edges
2229 MFloat e1[3];
2230 MFloat e2[3];
2231 MInt rejection = 0;
2232 MBool piercePointInside = 0;
2233 MBool triviallyAccepted = 0;
2234
2235 // Each of the following arrays holds one different point for
2236 // all of the 6 planes. Points are built with the targetRegion
2237 // i.e. a = targetRegiont[pointAInPlane[0]],
2238 // targetRegiont[pointAInPlane[1]],
2239 // targetRegiont[pointAInPlane[2]])
2240 // etc.
2241 MInt pointAInPlane[6][3] = {{0, 1, 2}, {3, 4, 5}, {0, 1, 2}, {3, 4, 5}, {0, 1, 2}, {3, 4, 5}};
2242
2243 MInt pointBInPlane[6][3] = {{0, 4, 2}, {3, 1, 5}, {3, 1, 2}, {0, 4, 5}, {3, 1, 2}, {3, 1, 5}};
2244
2245 MInt pointCInPlane[6][3] = {{0, 1, 5}, {3, 4, 2}, {3, 1, 5}, {0, 4, 2}, {3, 4, 2}, {0, 1, 5}};
2246 MFloat a[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
2247 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // point in plane
2248 MFloat b[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
2249 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // point in plane
2250 MFloat c[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
2251 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // point in plane
2252 MFloat d[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
2253 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // start of piercing edge
2254 MFloat e[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
2255 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // end of piercing edge
2256 MFloat s, gamma; // For pierce point calculation
2257 MFloat pP[3]; // piercePoint
2258 faceCodes[0] = IPOW2(0);
2259 faceCodes[1] = IPOW2(1);
2260 faceCodes[2] = IPOW2(2);
2261 faceCodes[3] = IPOW2(3);
2262 faceCodes[4] = IPOW2(4);
2263 faceCodes[5] = IPOW2(5);
2264 // edges[0][0] = 0;
2265 // edges[0][1] = 1;
2266 // edges[1][0] = 1;
2267 // edges[1][1] = 2;
2268 // edges[2][0] = 0;
2269 // edges[2][1] = 2;
2270 bitset<6> result;
2271
2272 m_adt->retrieveNodes(targetRegion, nodeList);
2273 const MInt noNodes = nodeList.size();
2274 // return noNodes;
2275 noReallyIntersectingNodes = 0;
2276
2277 for(MInt n = 0; n < noNodes; n++) {
2278 // create edges (in 3D) AB, AC, BC and point A B C
2279 // Determine outcode (see Aftosmis, Solution Adaptive Cartesian Grid Methods for Aerodynamic flows ...)
2280
2281 // Loop over all points of an element<3>
2282 for(MInt p = 0; p < nDim; p++) {
2283 points[p] = 0;
2284 // Calculate outcode for point
2285 for(MInt j = 0; j < nDim; j++) {
2286 if(elements[nodeList[n]].m_vertices[p][j] < targetRegion[j]) {
2287 points[p] |= faceCodes[2 * j];
2288 }
2289 if(elements[nodeList[n]].m_vertices[p][j] > targetRegion[j + nDim]) {
2290 points[p] |= faceCodes[2 * j + 1];
2291 }
2292 }
2293 // m_log << points[p] << endl;
2294 }
2295 rejection = 0;
2296 // check outcode combinations for edges for trivial rejection
2297 for(auto& edge : edges) {
2298 if((points[edge[0]] & points[edge[1]]) != 0) {
2299 rejection++;
2300 } else {
2301 // If one point is inside region the element<3> is trivially accepted
2302 triviallyAccepted = false;
2303 for(auto& point : points) {
2304 if(point == 0) {
2305 triviallyAccepted = true;
2306 break;
2307 }
2308 }
2309 if(triviallyAccepted) {
2310 break;
2311 }
2312 // No trivial rejection, check for rejection of subsegment:
2313 // For all pierce points!
2314 // 1. Calculate pierce point:
2315 // a - determine plane for pierce point calculation
2316 // b - calculate pierce point
2317 // 2. Check for rejection of new segment
2318 // a - calculate new outcode
2319 // b - check for containment in pierce planes face
2320 // 3. If all(!) pierce points are rejected -> reject edge
2321 // TODO labels:GEOM This algorith might get a problem if a triangle lies completely on
2322 // a face.
2323
2324 // 1.a
2325 result = (points[edge[0]] | points[edge[1]]);
2326 piercePointInside = false;
2327 for(MInt j = 0; j < 2 * nDim; j++) {
2328 if(result[j] == 1) {
2329 // pierce plane found
2330 // Algorithm taken von AFTOSMIS. There seems to be an
2331 // error in the calculation of s in AFTOSMIS formula, the one below
2332 // should be correct!
2333 for(MInt k = 0; k < nDim; k++) {
2334 a[k] = targetRegion[pointAInPlane[j][k]];
2335 b[k] = targetRegion[pointBInPlane[j][k]];
2336 c[k] = targetRegion[pointCInPlane[j][k]];
2337 d[k] = elements[nodeList[n]].m_vertices[edge[0]][k];
2338 e[k] = elements[nodeList[n]].m_vertices[edge[1]][k];
2339 }
2340 gamma = ((e[0] - d[0]) * ((a[2] - c[2]) * (c[1] - b[1]) - (a[1] - c[1]) * (c[2] - b[2]))
2341 - (e[1] - d[1]) * ((a[2] - c[2]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[2] - b[2]))
2342 + (e[2] - d[2]) * ((a[1] - c[1]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[1] - b[1])));
2343
2344 s = ((c[0] - d[0]) * ((a[2] - c[2]) * (c[1] - b[1]) - (a[1] - c[1]) * (c[2] - b[2]))
2345 - (c[1] - d[1]) * ((a[2] - c[2]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[2] - b[2]))
2346 + (c[2] - d[2]) * ((a[1] - c[1]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[1] - b[1])))
2347 / gamma;
2348
2349 // 1. b Pierce point pP in plane j:
2350 for(MInt k = 0; k < nDim; k++) {
2351 pP[k] = d[k] + s * (e[k] - d[k]);
2352 }
2353 pCode = 0;
2354 // 2. a Calculate outcode for pierce point
2355 for(MInt k = 0; k < nDim; k++) {
2356 if(pP[k] < targetRegion[k]) {
2357 pCode |= faceCodes[2 * k];
2358 }
2359 if(pP[k] > targetRegion[k + nDim]) {
2360 pCode |= faceCodes[2 * k + 1];
2361 }
2362 }
2363 // m_log << " outcode of pierce point :" << pCode << endl;
2364
2365 } else {
2366 continue;
2367 }
2368 // 2. b
2369 result = faceCodes[j];
2370 result.flip();
2371 result = (result & pCode);
2372 if(result == 0) { // -> is contained
2373 piercePointInside = true;
2374 }
2375 }
2376 // reject if all pierce points are off coresponding face
2377 if(!piercePointInside) {
2378 rejection++;
2379 }
2380 }
2381 }
2382 // Check for internal element<3>, i.e. completely inside target
2383 result = (points[0] | points[1] | points[2]);
2384 if(result == 0) {
2385 nodeList[noReallyIntersectingNodes] = nodeList[n];
2386 noReallyIntersectingNodes++;
2387 continue;
2388 }
2389 // If not all edges are rejected a cutting element<3> has been found
2390 // m_log << rejection << endl;
2391 if(rejection < 3) {
2392 nodeList[noReallyIntersectingNodes] = nodeList[n];
2393 noReallyIntersectingNodes++;
2394 continue;
2395 }
2396
2397 // Even if trivially rejected, check if targetRegion is completely inside triangle
2398 // For that check all edges of the cell against the plane of the triangle,
2399 // calculate all pierce points and their outcodes and finally check for containment
2400 // in the targetRegion. Before the pierce point calculation check if the current
2401 // edge is parallel to the triangle (evaluate the distance of the edgepoints to the plane)
2402 if(rejection >= 3) {
2403 for(auto& targetEdge : targetEdges) { // Loop over all 12 edges of the targetRegion (cell-cube)
2404 for(MInt p = 0; p < nDim; p++) {
2405 e1[p] = targetRegion[targetPoints[targetEdge[0]][p]];
2406 e2[p] = targetRegion[targetPoints[targetEdge[1]][p]];
2407 }
2409 if(edgeTriangleIntersection(elements[nodeList[n]].m_vertices[0], elements[nodeList[n]].m_vertices[1],
2410 elements[nodeList[n]].m_vertices[2], e1, e2)) {
2411 nodeList[noReallyIntersectingNodes] = nodeList[n];
2412 noReallyIntersectingNodes++;
2413 break;
2414 }
2415 }
2416 }
2417
2418 // write nodes in reallyIntersectingNodes
2419 }
2420 // if(noNodes)
2421 if(noNodes && !noReallyIntersectingNodes) {
2422 // m_log << "Rejected ! "<< ++rejectionCounter << endl;
2423 }
2424
2425 nodeList.resize(noReallyIntersectingNodes);
2426
2427 return noReallyIntersectingNodes;
2428}
2429
2434inline MBool Geometry3D::edgeTriangleIntersection(MFloat* trianglePoint1, MFloat* trianglePoint2,
2435 MFloat* trianglePoint3, MFloat* edgePoint1, MFloat* edgePoint2) {
2436 TRACE();
2437
2439
2440 MFloat volume1 = 0;
2441 MFloat volume2 = 0;
2442 MFloat volume3 = 0;
2443 MInt maxRfnLvl = (sizeof(MInt) * 8) - 6;
2444 MFloat eps = 1.0 / FPOW2(maxRfnLvl);
2445 MFloat a[3] = {trianglePoint1[0], trianglePoint1[1], trianglePoint1[2]};
2446 MFloat b[3] = {trianglePoint2[0], trianglePoint2[1], trianglePoint2[2]};
2447 MFloat c[3] = {trianglePoint3[0], trianglePoint3[1], trianglePoint3[2]};
2448 MFloat d[3];
2449 // To determine an intersection between edge and triangle we have to:
2450 // 1. Check if the edge pierces the plane of the triangle
2451 // - compute the signs of the signed tetrahedra build with the triangle points
2452 // - and first and second edge point. Equal signs means edge doesn't pierce.
2453 // 2. Check if the pierce point lies inside the triangles
2454 // - compute the signs of the 3 tetrahedra consisting of always the edge points
2455 // and one edge of the triangle
2456 // - if all signs are equal the edge pierces inside the triangle
2457
2458
2459 // 1.
2460 // Calculate signed tetraeder Volume of triangle and 1st point
2461 for(MInt i = 0; i < nDim; i++) {
2462 d[i] = edgePoint1[i];
2463 }
2464 volume1 = (b[1] * a[2] * d[0] - d[1] * a[0] * c[2] + d[1] * a[0] * b[2] + c[1] * a[0] * d[2] - b[1] * a[0] * d[2]
2465 - a[1] * c[0] * d[2] + a[1] * d[0] * c[2] - a[1] * d[0] * b[2] + d[1] * a[2] * c[0] + d[1] * c[2] * b[0]
2466 - d[1] * a[2] * b[0] - d[1] * b[2] * c[0] - c[1] * d[2] * b[0] - c[1] * a[2] * d[0] + c[1] * b[2] * d[0]
2467 - b[1] * c[2] * d[0] + b[1] * c[0] * d[2] + a[1] * b[0] * d[2] - a[1] * b[0] * c[2] - b[1] * a[2] * c[0]
2468 + a[1] * c[0] * b[2] + c[1] * a[2] * b[0] - c[1] * a[0] * b[2] + b[1] * a[0] * c[2]);
2469
2470 for(MInt i = 0; i < nDim; i++) {
2471 d[i] = edgePoint2[i];
2472 }
2473
2474 // Calculate signed tetraeder Volume of triangle and 2nd point
2475 volume2 = (b[1] * a[2] * d[0] - d[1] * a[0] * c[2] + d[1] * a[0] * b[2] + c[1] * a[0] * d[2] - b[1] * a[0] * d[2]
2476 - a[1] * c[0] * d[2] + a[1] * d[0] * c[2] - a[1] * d[0] * b[2] + d[1] * a[2] * c[0] + d[1] * c[2] * b[0]
2477 - d[1] * a[2] * b[0] - d[1] * b[2] * c[0] - c[1] * d[2] * b[0] - c[1] * a[2] * d[0] + c[1] * b[2] * d[0]
2478 - b[1] * c[2] * d[0] + b[1] * c[0] * d[2] + a[1] * b[0] * d[2] - a[1] * b[0] * c[2] - b[1] * a[2] * c[0]
2479 + a[1] * c[0] * b[2] + c[1] * a[2] * b[0] - c[1] * a[0] * b[2] + b[1] * a[0] * c[2]);
2480
2481 if(volume1 * volume2 >= eps) {
2482 // Equal signs! no pierce point with triangle plane
2483 return false;
2484 }
2485 // 2.
2486 for(MInt i = 0; i < nDim; i++) {
2487 a[i] = edgePoint1[i];
2488 b[i] = trianglePoint1[i];
2489 c[i] = trianglePoint2[i];
2490 d[i] = edgePoint2[i];
2491 }
2492 volume1 = (b[1] * a[2] * d[0] - d[1] * a[0] * c[2] + d[1] * a[0] * b[2] + c[1] * a[0] * d[2] - b[1] * a[0] * d[2]
2493 - a[1] * c[0] * d[2] + a[1] * d[0] * c[2] - a[1] * d[0] * b[2] + d[1] * a[2] * c[0] + d[1] * c[2] * b[0]
2494 - d[1] * a[2] * b[0] - d[1] * b[2] * c[0] - c[1] * d[2] * b[0] - c[1] * a[2] * d[0] + c[1] * b[2] * d[0]
2495 - b[1] * c[2] * d[0] + b[1] * c[0] * d[2] + a[1] * b[0] * d[2] - a[1] * b[0] * c[2] - b[1] * a[2] * c[0]
2496 + a[1] * c[0] * b[2] + c[1] * a[2] * b[0] - c[1] * a[0] * b[2] + b[1] * a[0] * c[2]);
2497
2498 for(MInt i = 0; i < nDim; i++) {
2499 a[i] = edgePoint1[i];
2500 b[i] = trianglePoint3[i];
2501 c[i] = trianglePoint1[i];
2502 d[i] = edgePoint2[i];
2503 }
2504 volume2 = (b[1] * a[2] * d[0] - d[1] * a[0] * c[2] + d[1] * a[0] * b[2] + c[1] * a[0] * d[2] - b[1] * a[0] * d[2]
2505 - a[1] * c[0] * d[2] + a[1] * d[0] * c[2] - a[1] * d[0] * b[2] + d[1] * a[2] * c[0] + d[1] * c[2] * b[0]
2506 - d[1] * a[2] * b[0] - d[1] * b[2] * c[0] - c[1] * d[2] * b[0] - c[1] * a[2] * d[0] + c[1] * b[2] * d[0]
2507 - b[1] * c[2] * d[0] + b[1] * c[0] * d[2] + a[1] * b[0] * d[2] - a[1] * b[0] * c[2] - b[1] * a[2] * c[0]
2508 + a[1] * c[0] * b[2] + c[1] * a[2] * b[0] - c[1] * a[0] * b[2] + b[1] * a[0] * c[2]);
2509
2510 for(MInt i = 0; i < nDim; i++) {
2511 a[i] = edgePoint1[i];
2512 b[i] = trianglePoint2[i];
2513 c[i] = trianglePoint3[i];
2514 d[i] = edgePoint2[i];
2515 }
2516 volume3 = (b[1] * a[2] * d[0] - d[1] * a[0] * c[2] + d[1] * a[0] * b[2] + c[1] * a[0] * d[2] - b[1] * a[0] * d[2]
2517 - a[1] * c[0] * d[2] + a[1] * d[0] * c[2] - a[1] * d[0] * b[2] + d[1] * a[2] * c[0] + d[1] * c[2] * b[0]
2518 - d[1] * a[2] * b[0] - d[1] * b[2] * c[0] - c[1] * d[2] * b[0] - c[1] * a[2] * d[0] + c[1] * b[2] * d[0]
2519 - b[1] * c[2] * d[0] + b[1] * c[0] * d[2] + a[1] * b[0] * d[2] - a[1] * b[0] * c[2] - b[1] * a[2] * c[0]
2520 + a[1] * c[0] * b[2] + c[1] * a[2] * b[0] - c[1] * a[0] * b[2] + b[1] * a[0] * c[2]);
2521 // if(volume1 >= eps && volume2 >= eps && volume3 >= eps)
2522 // return true;
2523 // if(volume1 <= eps && volume2 <= eps && volume3 <= eps)
2524 // return true;
2525
2526 // if(volume1*volume1 < eps*eps || volume2*volume2 < eps*eps || volume3*volume3 < eps*eps ){
2527 if(((volume1 < eps) && (volume1 > -eps)) || ((volume2 < eps) && (volume2 > -eps))
2528 || ((volume3 < eps) && (volume3 > -eps))) {
2529 m_log << " ! SINGULARITY IN TRIANGLE INTERSECTION ! At: " << a[0] << ", " << a[1] << ", " << a[2] << "; " << d[0]
2530 << ", " << d[1] << ", " << d[2] << endl;
2531 // cerr << " ! SINGULARITY IN TRIANGLE INTERSECTION ! At: " << a[0] << ", " << a[1] << ", " << a[2] << "; " <<
2532 // d[0] << ", " << d[1] << ", " << d[2] << endl;
2533 // return true;
2534 return false;
2535 }
2536
2537 if(volume1 >= 0.0 && volume2 >= 0.0 && volume3 >= 0.0) {
2538 return true;
2539 }
2540 if(volume1 <= 0.0 && volume2 <= 0.0 && volume3 <= 0.0) {
2541 return true;
2542 }
2543
2544 return false;
2545}
2546
2547
2552inline MBool Geometry3D::edgeTriangleIntersectionLB(MFloat* trianglePoint1, MFloat* trianglePoint2,
2553 MFloat* trianglePoint3, MFloat* edgePoint1, MFloat* edgePoint2) {
2554 TRACE();
2555
2556 otherCalls++;
2557
2558 MFloat volume1 = 0;
2559 MFloat volume2 = 0;
2560 MFloat volume3 = 0;
2561 MInt maxRfnLvl = (sizeof(MInt) * 8) - 6;
2562 MFloat eps = 1.0 / FPOW2(maxRfnLvl);
2563 MFloat a[3] = {trianglePoint1[0], trianglePoint1[1], trianglePoint1[2]};
2564 MFloat b[3] = {trianglePoint2[0], trianglePoint2[1], trianglePoint2[2]};
2565 MFloat c[3] = {trianglePoint3[0], trianglePoint3[1], trianglePoint3[2]};
2566 MFloat d[3];
2567 // To determine an intersection between edge and triangle we have to:
2568 // 1. Check if the edge pierces the plane of the triangle
2569 // - compute the signs of the signed tetrahedra build with the triangle points
2570 // - and first and second edge point. Equal signs means edge doesn't pierce.
2571 // 2. Check if the pierce point lies inside the triangles
2572 // - compute the signs of the 3 tetrahedra consisting of always the edge points
2573 // and one edge of the triangle
2574 // - if all signs are equal the edge pierces inside the triangle
2575
2576
2577 // 1.
2578 // Calculate signed tetraeder Volume of triangle and 1st point
2579 for(MInt i = 0; i < nDim; i++) {
2580 d[i] = edgePoint1[i];
2581 }
2582 volume1 = (b[1] * a[2] * d[0] - d[1] * a[0] * c[2] + d[1] * a[0] * b[2] + c[1] * a[0] * d[2] - b[1] * a[0] * d[2]
2583 - a[1] * c[0] * d[2] + a[1] * d[0] * c[2] - a[1] * d[0] * b[2] + d[1] * a[2] * c[0] + d[1] * c[2] * b[0]
2584 - d[1] * a[2] * b[0] - d[1] * b[2] * c[0] - c[1] * d[2] * b[0] - c[1] * a[2] * d[0] + c[1] * b[2] * d[0]
2585 - b[1] * c[2] * d[0] + b[1] * c[0] * d[2] + a[1] * b[0] * d[2] - a[1] * b[0] * c[2] - b[1] * a[2] * c[0]
2586 + a[1] * c[0] * b[2] + c[1] * a[2] * b[0] - c[1] * a[0] * b[2] + b[1] * a[0] * c[2]);
2587
2588 for(MInt i = 0; i < nDim; i++) {
2589 d[i] = edgePoint2[i];
2590 }
2591
2592 // Calculate signed tetraeder Volume of triangle and 2nd point
2593 volume2 = (b[1] * a[2] * d[0] - d[1] * a[0] * c[2] + d[1] * a[0] * b[2] + c[1] * a[0] * d[2] - b[1] * a[0] * d[2]
2594 - a[1] * c[0] * d[2] + a[1] * d[0] * c[2] - a[1] * d[0] * b[2] + d[1] * a[2] * c[0] + d[1] * c[2] * b[0]
2595 - d[1] * a[2] * b[0] - d[1] * b[2] * c[0] - c[1] * d[2] * b[0] - c[1] * a[2] * d[0] + c[1] * b[2] * d[0]
2596 - b[1] * c[2] * d[0] + b[1] * c[0] * d[2] + a[1] * b[0] * d[2] - a[1] * b[0] * c[2] - b[1] * a[2] * c[0]
2597 + a[1] * c[0] * b[2] + c[1] * a[2] * b[0] - c[1] * a[0] * b[2] + b[1] * a[0] * c[2]);
2598
2599 if(volume1 * volume2 >= eps) {
2600 // Equal signs! no pierce point with triangle plane
2601 return false;
2602 }
2603 // 2.
2604 for(MInt i = 0; i < nDim; i++) {
2605 a[i] = edgePoint1[i];
2606 b[i] = trianglePoint1[i];
2607 c[i] = trianglePoint2[i];
2608 d[i] = edgePoint2[i];
2609 }
2610 volume1 = (b[1] * a[2] * d[0] - d[1] * a[0] * c[2] + d[1] * a[0] * b[2] + c[1] * a[0] * d[2] - b[1] * a[0] * d[2]
2611 - a[1] * c[0] * d[2] + a[1] * d[0] * c[2] - a[1] * d[0] * b[2] + d[1] * a[2] * c[0] + d[1] * c[2] * b[0]
2612 - d[1] * a[2] * b[0] - d[1] * b[2] * c[0] - c[1] * d[2] * b[0] - c[1] * a[2] * d[0] + c[1] * b[2] * d[0]
2613 - b[1] * c[2] * d[0] + b[1] * c[0] * d[2] + a[1] * b[0] * d[2] - a[1] * b[0] * c[2] - b[1] * a[2] * c[0]
2614 + a[1] * c[0] * b[2] + c[1] * a[2] * b[0] - c[1] * a[0] * b[2] + b[1] * a[0] * c[2]);
2615
2616 for(MInt i = 0; i < nDim; i++) {
2617 a[i] = edgePoint1[i];
2618 b[i] = trianglePoint3[i];
2619 c[i] = trianglePoint1[i];
2620 d[i] = edgePoint2[i];
2621 }
2622 volume2 = (b[1] * a[2] * d[0] - d[1] * a[0] * c[2] + d[1] * a[0] * b[2] + c[1] * a[0] * d[2] - b[1] * a[0] * d[2]
2623 - a[1] * c[0] * d[2] + a[1] * d[0] * c[2] - a[1] * d[0] * b[2] + d[1] * a[2] * c[0] + d[1] * c[2] * b[0]
2624 - d[1] * a[2] * b[0] - d[1] * b[2] * c[0] - c[1] * d[2] * b[0] - c[1] * a[2] * d[0] + c[1] * b[2] * d[0]
2625 - b[1] * c[2] * d[0] + b[1] * c[0] * d[2] + a[1] * b[0] * d[2] - a[1] * b[0] * c[2] - b[1] * a[2] * c[0]
2626 + a[1] * c[0] * b[2] + c[1] * a[2] * b[0] - c[1] * a[0] * b[2] + b[1] * a[0] * c[2]);
2627
2628 for(MInt i = 0; i < nDim; i++) {
2629 a[i] = edgePoint1[i];
2630 b[i] = trianglePoint2[i];
2631 c[i] = trianglePoint3[i];
2632 d[i] = edgePoint2[i];
2633 }
2634 volume3 = (b[1] * a[2] * d[0] - d[1] * a[0] * c[2] + d[1] * a[0] * b[2] + c[1] * a[0] * d[2] - b[1] * a[0] * d[2]
2635 - a[1] * c[0] * d[2] + a[1] * d[0] * c[2] - a[1] * d[0] * b[2] + d[1] * a[2] * c[0] + d[1] * c[2] * b[0]
2636 - d[1] * a[2] * b[0] - d[1] * b[2] * c[0] - c[1] * d[2] * b[0] - c[1] * a[2] * d[0] + c[1] * b[2] * d[0]
2637 - b[1] * c[2] * d[0] + b[1] * c[0] * d[2] + a[1] * b[0] * d[2] - a[1] * b[0] * c[2] - b[1] * a[2] * c[0]
2638 + a[1] * c[0] * b[2] + c[1] * a[2] * b[0] - c[1] * a[0] * b[2] + b[1] * a[0] * c[2]);
2639 // if(volume1 >= eps && volume2 >= eps && volume3 >= eps)
2640 // return true;
2641 // if(volume1 <= eps && volume2 <= eps && volume3 <= eps)
2642 // return true;
2643
2644 // if(volume1*volume1 < eps*eps || volume2*volume2 < eps*eps || volume3*volume3 < eps*eps ){
2645 if(((volume1 < eps) && (volume1 > -eps)) || ((volume2 < eps) && (volume2 > -eps))
2646 || ((volume3 < eps) && (volume3 > -eps))) {
2647 m_log << " ! SINGULARITY IN TRIANGLE INTERSECTION ! At: " << a[0] << ", " << a[1] << ", " << a[2] << "; " << d[0]
2648 << ", " << d[1] << ", " << d[2] << endl;
2649 // cerr << " ! SINGULARITY IN TRIANGLE INTERSECTION ! At: " << a[0] << ", " << a[1] << ", " << a[2] << "; " <<
2650 // d[0] << ", " << d[1] << ", " << d[2] << endl;
2651 return true;
2652 // return false;
2653 }
2654
2655 if(volume1 >= 0.0 && volume2 >= 0.0 && volume3 >= 0.0) return true;
2656 if(volume1 <= 0.0 && volume2 <= 0.0 && volume3 <= 0.0) return true;
2657
2658 return false;
2659}
2660
2661
2679 // TRACE();
2680
2681 MFloat radius = 0.0;
2682 MFloat intersection[3] = {0.0, 0.0, 0.0};
2683 MFloat normal[3] = {0.0, 0.0, 0.0};
2684 MFloat lambda2 = NAN;
2685 MFloat dist = 0.0;
2686
2687 return (getLineTriangleIntersection(p1, p2, radius, v1, v2, v3, intersection, normal, &lambda2, &dist));
2688}
2689
2709 MFloat* dist) {
2710 // TRACE();
2711
2712 MFloat radius = 0.0;
2713 MFloat intersection[3] = {0.0, 0.0, 0.0};
2714 MFloat normal[3] = {0.0, 0.0, 0.0};
2715 MFloat lambda2 = NAN;
2716
2717 return (getLineTriangleIntersection(p1, p2, radius, v1, v2, v3, intersection, normal, &lambda2, dist));
2718}
2719
2720
2765MBool Geometry3D::getLineTriangleIntersection(const MFloat* const p1, const MFloat* const p2, const MFloat radius,
2766 const MFloat* const v1, const MFloat* const v2, const MFloat* const v3,
2767 MFloat* intersection, MFloat* normal, MFloat* lambda2, MFloat* dist) {
2768 // TRACE();
2769
2770 std::array<MFloat, nDim> edge1{};
2771 std::array<MFloat, nDim> edge2{};
2772 std::array<MFloat, nDim> edge3{};
2773 std::array<MFloat, nDim> line{};
2774 std::array<MFloat, nDim> line_norm{};
2775 std::array<MFloat, nDim> normal_norm{};
2776 std::array<MFloat, nDim> trans_p1{};
2777 std::array<MFloat, nDim> trans_p2{};
2778 constexpr MFloat eps = 0.0000000000000001;
2779 constexpr MFloat eps2 = 0.00000001;
2780
2781 // 1. Get the normal on the triangle
2782 for(MInt d = 0; d < nDim; d++) {
2783 edge1[d] = v2[d] - v1[d];
2784 edge2[d] = v3[d] - v1[d];
2785 edge3[d] = v3[d] - v2[d];
2786 line[d] = p2[d] - p1[d];
2787
2788 trans_p1[d] = p1[d] - v1[d];
2789 trans_p2[d] = p2[d] - v1[d];
2790 }
2791
2792
2793 MFloat line_n_length = 0.0;
2794 for(MInt d = 0; d < nDim; d++) {
2795 line_n_length += line[d] * line[d];
2796 }
2797
2798 line_n_length = sqrt(line_n_length);
2799 const MFloat F1BLine_n_length = 1.0 / line_n_length;
2800
2801 if(radius > 0.0)
2802 for(MInt d = 0; d < nDim; d++) {
2803 line[d] = (line_n_length + radius) * line[d] * F1BLine_n_length;
2804 }
2805
2806 normal[0] = edge1[1] * edge2[2] - edge2[1] * edge1[2];
2807 normal[1] = edge1[2] * edge2[0] - edge2[2] * edge1[0];
2808 normal[2] = edge1[0] * edge2[1] - edge2[0] * edge1[1];
2809
2810 MFloat n_length_sq = 0.0;
2811 for(MInt d = 0; d < nDim; d++) {
2812 n_length_sq += normal[d] * normal[d];
2813 }
2814
2815 // Normalize the normal
2816 const MFloat n_length = sqrt(n_length_sq);
2817 const MFloat F1BN_length = 1.0 / n_length;
2818 for(MInt d = 0; d < nDim; d++) {
2819 normal_norm[d] = normal[d] * F1BN_length;
2820 line_norm[d] = line[d] * F1BLine_n_length;
2821 }
2822
2823 // 2. Get the cutting-point by solving the plane-equation
2824
2825 // 2.a be careful, the dot-product of the normal and the line can 0 (they are perpendicular)
2826 const MFloat denom = (normal_norm[0] * line_norm[0] + normal_norm[1] * line_norm[1] + normal_norm[2] * line_norm[2]);
2827
2828 // 2.b Check in 2D if we have an intersection
2829 if(fabs(denom) < eps) {
2830 // Check if the points are in the plane
2831 MFloat dot1 = trans_p1[0] * normal_norm[0] + trans_p1[1] * normal_norm[1] + trans_p1[2] * normal_norm[2];
2832 MFloat dot2 = trans_p2[0] * normal_norm[0] + trans_p2[1] * normal_norm[1] + trans_p2[2] * normal_norm[2];
2833 if(fabs(dot1) < eps && fabs(dot2) < eps) {
2834 // further testing
2835 MInt l_dim = 0;
2836 MFloat max = 0.0;
2837 for(MInt d = 0; d < nDim; d++) {
2838 if(normal_norm[d] > max) l_dim = d;
2839 }
2840
2841 const std::array<const MFloat*, 3> verts = {v1, v2, v3};
2842
2843 MFloat line2d[2] = {0.0, 0.0};
2844 MFloat pl_1[2] = {0.0, 0.0};
2845 for(MInt i = 0, j = 0; i < nDim; i++) {
2846 if(i != l_dim) {
2847 line2d[j] = p2[i] - p1[i];
2848 pl_1[j] = p1[i];
2849 j++;
2850 }
2851 }
2852
2853 MBool cut = false;
2854 MFloat shortest = 10000000000.0;
2855
2856 // for each triangle edge perform cut with line
2857 for(MInt d = 0; d < nDim; d++) {
2858 MInt next = (d + 1) % nDim;
2859 MFloat tri_edge[2] = {0.0, 0.0};
2860 MFloat tri_v1[2] = {0.0, 0.0};
2861
2862 for(MInt i = 0, j = 0; i < nDim; i++) {
2863 if(i != l_dim) {
2864 tri_edge[j] = verts[next][i] - verts[d][i];
2865 tri_v1[j] = verts[d][i];
2866 j++;
2867 }
2868 }
2869
2870 MFloat denom2 = tri_edge[1] * line2d[0];
2871 if(fabs(denom2) < eps) continue;
2872
2873 MFloat denom3 = 1.0 - (line2d[1] * tri_edge[0] / denom2);
2874 if(fabs(denom3) < eps) continue;
2875
2876 MFloat alpha =
2877 denom3 * (1.0 / line2d[0]) * (tri_v1[0] - pl_1[0] + (tri_edge[0] / tri_edge[1]) * (pl_1[1] - tri_v1[1]));
2878
2879 // we have a cut
2880 if(alpha <= 1.0 && alpha >= 0.0) {
2881 MFloat beta = pl_1[1] / tri_edge[1] + alpha * line2d[1] / tri_edge[1] - tri_v1[1] / tri_edge[1];
2882 if(beta <= 1.0 && beta >= 0.0) {
2883 MFloat l = sqrt(alpha * alpha * line2d[0] * line2d[0] + alpha * alpha * line2d[1] * line2d[1]);
2884 if(l < shortest) shortest = l;
2885 cut = true;
2886 continue;
2887 }
2888 }
2889
2890 // no cut
2891 else
2892 continue;
2893 }
2894
2895 if(cut) {
2896 *dist = shortest;
2897 return true;
2898 } else {
2899 *dist = 0.0;
2900 return false;
2901 }
2902
2903 } else {
2904 *dist = 0.0;
2905 return false;
2906 }
2907 }
2908
2909 const MFloat r =
2910 (-normal_norm[0] * trans_p1[0] - normal_norm[1] * trans_p1[1] - normal_norm[2] * trans_p1[2]) / denom;
2911
2912 // 3. Check if cut-point is inside the triangle
2913 std::array<MFloat, nDim> i_v1{};
2914 std::array<MFloat, nDim> i_v2{};
2915 std::array<MFloat, nDim> i_v3{};
2916
2917 for(MInt d = 0; d < nDim; d++) {
2918 intersection[d] = p1[d] + r * line_norm[d];
2919 i_v1[d] = intersection[d] - v2[d];
2920 i_v2[d] = intersection[d] - v3[d];
2921 i_v3[d] = intersection[d] - v1[d];
2922 }
2923
2924 *dist = r;
2925
2926 if(r >= 0.0)
2927 *lambda2 = r * F1BLine_n_length;
2928 else
2929 *lambda2 = 1.1;
2930
2931 // we are already finished if the cut-point has a larger distance than the second point
2932 if(fabs(*lambda2) > 1.0) return false;
2933
2934 std::array<MFloat, nDim> normal1;
2935 std::array<MFloat, nDim> normal2;
2936 std::array<MFloat, nDim> normal3;
2937
2938 normal1[0] = edge3[1] * i_v1[2] - i_v1[1] * edge3[2];
2939 normal1[1] = edge3[2] * i_v1[0] - i_v1[2] * edge3[0];
2940 normal1[2] = edge3[0] * i_v1[1] - i_v1[0] * edge3[1];
2941
2942 normal2[0] = -edge2[1] * i_v2[2] + i_v2[1] * edge2[2];
2943 normal2[1] = -edge2[2] * i_v2[0] + i_v2[2] * edge2[0];
2944 normal2[2] = -edge2[0] * i_v2[1] + i_v2[0] * edge2[1];
2945
2946 normal3[0] = edge1[1] * i_v3[2] - i_v3[1] * edge1[2];
2947 normal3[1] = edge1[2] * i_v3[0] - i_v3[2] * edge1[0];
2948 normal3[2] = edge1[0] * i_v3[1] - i_v3[0] * edge1[1];
2949
2950 MFloat alpha;
2951 MFloat beta;
2952 MFloat gamma;
2953 alpha = beta = gamma = 0.0;
2954
2955 for(MInt d = 0; d < nDim; d++) {
2956 alpha += normal[d] * normal1[d];
2957 beta += normal[d] * normal2[d];
2958 gamma += normal[d] * normal3[d];
2959 }
2960
2961 alpha /= n_length_sq;
2962 beta /= n_length_sq;
2963 gamma /= n_length_sq;
2964
2965 // check for inside
2966 if((alpha + beta + gamma <= 1.0 + eps2) && (alpha + beta + gamma >= 1.0 - eps2))
2967 if(alpha >= 0 && beta >= 0 && gamma >= 0)
2968 return true;
2969 else
2970 return false;
2971 else
2972 return false;
2973}
2974
2975
2976//----------------------------------------------------------------------------------------
2977
2978
2990 std::vector<MInt>& nodeList) {
2991 // TRACE();
2992
2994
2995 MBool singleIntersectionPoint = 0;
2996 MInt noReallyIntersectingNodes = 0;
2997 m_adt->retrieveNodes(targetRegion, nodeList);
2998 const MInt noNodes = nodeList.size();
2999 MInt maxNoNodes = 120;
3000 MInt spaceId;
3001 MInt spaceId1;
3002 MInt spaceId2;
3003 array<MFloat, nDim> e1{};
3004 array<MFloat, nDim> e2{};
3005 MFloat epsilon = 0.00000000001;
3006 array<MFloat, nDim> a{};
3007 array<MFloat, nDim> b{};
3008 array<MFloat, nDim> c{};
3009 MFloat gamma;
3010 MFloat s;
3011 MFloat p;
3012 MFloat q;
3013 array<MFloat, nDim> pP{};
3014 auto** temp = new MFloat*[maxNoNodes];
3015 for(MInt k = 0; k < maxNoNodes; k++) {
3016 temp[k] = new MFloat[nDim];
3017 }
3018
3019 for(MInt i = 0; i < nDim; i++) {
3020 e1[i] = targetRegion[i];
3021 e2[i] = targetRegion[i + nDim];
3022 }
3023 spaceId = spaceDirection[0];
3024 spaceId1 = spaceDirection[1];
3025 spaceId2 = spaceDirection[2];
3026
3027 for(MInt n = 0; n < noNodes; n++) {
3028 for(MInt k = 0; k < nDim; k++) {
3029 a[k] = elements[nodeList[n]].m_vertices[0][k];
3030 b[k] = elements[nodeList[n]].m_vertices[1][k];
3031 c[k] = elements[nodeList[n]].m_vertices[2][k];
3032 }
3033 if(approx(a[spaceId1], b[spaceId1], MFloatEps) && !approx(a[spaceId1], c[spaceId1], MFloatEps)) {
3034 // aspaceId != bspaceId, otherwise a and b would be the same point
3035 q = (e1[spaceId1] - a[spaceId1]) / (c[spaceId1] - a[spaceId1]);
3036 p = (e1[spaceId] - a[spaceId] - q * (c[spaceId] - a[spaceId])) / (b[spaceId] - a[spaceId]);
3037 } else {
3038 if(!approx(a[spaceId1], b[spaceId1], MFloatEps) && approx(a[spaceId1], c[spaceId1], MFloatEps)) {
3039 // aspaceId != cspaceId, otherwise a and c would be the same point
3040 p = (e1[spaceId1] - a[spaceId1]) / (b[spaceId1] - a[spaceId1]);
3041 q = (e1[spaceId] - a[spaceId] - p * (b[spaceId] - a[spaceId])) / (c[spaceId] - a[spaceId]);
3042 } else {
3043 if(approx(a[spaceId], b[spaceId], MFloatEps) && !approx(a[spaceId], c[spaceId], MFloatEps)) {
3044 // aspaceId1 != bspaceId1, otherwise a and b would be the same point
3045 q = (e1[spaceId] - a[spaceId]) / (c[spaceId] - a[spaceId]);
3046 p = (e1[spaceId1] - a[spaceId1] - q * (c[spaceId1] - a[spaceId1])) / (b[spaceId1] - a[spaceId1]);
3047 } else {
3048 if(!approx(a[spaceId], b[spaceId], MFloatEps) && approx(a[spaceId], c[spaceId], MFloatEps)) {
3049 // aspaceId1 != cspaceId1, otherwise a and c would be the same point
3050 p = (e1[spaceId] - a[spaceId]) / (b[spaceId] - a[spaceId]);
3051 q = (e1[spaceId1] - a[spaceId1] - p * (b[spaceId1] - a[spaceId1])) / (c[spaceId1] - a[spaceId1]);
3052 } else {
3053 // aspaceId1 != bspaceId1 && aspaceId1 != cspaceId1 && aspaceId != bspaceId && aspaceId != cspaceId
3054 q = ((e1[spaceId1] - a[spaceId1]) * (b[spaceId] - a[spaceId])
3055 - (b[spaceId1] - a[spaceId1]) * (e1[spaceId] - a[spaceId]))
3056 / ((c[spaceId1] - a[spaceId1]) * (b[spaceId] - a[spaceId])
3057 - (b[spaceId1] - a[spaceId1]) * (c[spaceId] - a[spaceId]));
3058 p = (e1[spaceId] - a[spaceId] - q * (c[spaceId] - a[spaceId])) / (b[spaceId] - a[spaceId]);
3059 }
3060 }
3061 }
3062 }
3063
3064 if(p * q >= 0 || p * q < 0) {
3065 // compute s
3066 gamma = a[spaceId2] + p * (b[spaceId2] - a[spaceId2]) + q * (c[spaceId2] - a[spaceId2]);
3067 s = (gamma - e1[spaceId2]) / (e2[spaceId2] - e1[spaceId2]);
3068
3069 if(s < -epsilon || s > F1 + epsilon || p < -epsilon || q < -epsilon || (p + q) > F1 + epsilon) {
3070 } else {
3071 singleIntersectionPoint = true;
3072
3073 // cut point pP
3074 for(MInt g = 0; g < nDim; g++) {
3075 pP[g] = e1[g] + s * (e2[g] - e1[g]);
3076 temp[noReallyIntersectingNodes][g] = pP[g];
3077 }
3078
3079 if(noReallyIntersectingNodes == 0) {
3080 nodeList[noReallyIntersectingNodes] = nodeList[n];
3081 noReallyIntersectingNodes++;
3082 } else {
3083 for(MInt f = 0; f < noReallyIntersectingNodes; f++) {
3084 if((fabs(temp[f][0] - pP[0]) < epsilon) && (fabs(temp[f][1] - pP[1]) < epsilon)
3085 && (fabs(temp[f][2] - pP[2]) < epsilon)) {
3086 singleIntersectionPoint = false;
3087 break;
3088 }
3089 }
3090 if(singleIntersectionPoint) {
3091 nodeList[noReallyIntersectingNodes] = nodeList[n];
3092 noReallyIntersectingNodes++;
3093 }
3094 }
3095 }
3096 }
3097 }
3098 nodeList.resize(noReallyIntersectingNodes);
3099
3100 // free memory
3101 for(MInt k = 0; k < maxNoNodes; k++) {
3102 delete[] temp[k];
3103 }
3104 delete[] temp;
3105
3106 getLIE2CommCounter += noReallyIntersectingNodes;
3107
3108 return noReallyIntersectingNodes;
3109}
3110
3146// TODO labels:GEOM unify with version without nodeList parameter!
3147MInt Geometry3D::getLineIntersectionElements(MFloat* targetRegion, std::vector<MInt>& nodeList) {
3148 // TRACE();
3149
3151
3152 const MFloat eps = 0.00000000001;
3153
3154 MFloat u[nDim];
3155 MFloat v[nDim];
3156 MFloat w[nDim];
3157
3158 constexpr MInt maxNoNodes = 20; // Should prevent vector reallocation in most cases
3159 std::vector<MFloat> ips{};
3160 ips.reserve(nDim * maxNoNodes);
3161
3162 m_adt->retrieveNodes(targetRegion, nodeList);
3163 const MInt noNodes = nodeList.size();
3164 MFloat e1[3];
3165 MFloat ray[nDim];
3166 for(MInt i = 0; i < nDim; i++) {
3167 e1[i] = targetRegion[i];
3168 ray[i] = targetRegion[i + nDim] - e1[i];
3169 }
3170
3171 MInt noReallyIntersectingNodes = 0;
3172 for(MInt n = 0; n < noNodes; n++) {
3173 const MInt nodeId = nodeList[n];
3174 MFloat** const verts = elements[nodeId].m_vertices;
3175 const MFloat* const vert0 = verts[0];
3176 const MFloat* const vert1 = verts[1];
3177 const MFloat* const vert2 = verts[2];
3178
3179 // Fill triangle edges
3180 for(MInt i = 0; i < nDim; i++) {
3181 const MFloat v0 = vert0[i];
3182 u[i] = vert1[i] - v0;
3183 v[i] = vert2[i] - v0;
3184 w[i] = e1[i] - v0;
3185 }
3186
3187 // Get normal
3188 const MFloat normal0 = u[1] * v[2] - u[2] * v[1];
3189 const MFloat normal1 = u[2] * v[0] - u[0] * v[2];
3190 const MFloat normal2 = u[0] * v[1] - u[1] * v[0];
3191
3192 // dot products
3193 const MFloat a = -(normal0 * w[0] + normal1 * w[1] + normal2 * w[2]);
3194 const MFloat b = normal0 * ray[0] + normal1 * ray[1] + normal2 * ray[2];
3195
3196 if(fabs(b) < eps) {
3197 if(fabs(a) < eps) {
3198 // ray lies in triangle plane
3199 // TODO labels:GEOM commented the following two lines; check what should be done in such case as ips is not
3200 // filled for the check later; occurs in case FV/3D_MP_postprocessing_coarse - no difference in results
3201 /* nodeList[noReallyIntersectingNodes] = nodeList[n]; */
3202 /* noReallyIntersectingNodes++; */
3203 m_log << "Found ray in triangle plane" << endl;
3204 continue;
3205 } else {
3206 // ray disjoint from plane
3207 continue;
3208 }
3209 }
3210 const MFloat r = a / b;
3211
3212 const MFloat F1eps = F1 + eps;
3213 // is the ray going the right direction and is the scaling factor smaller than 1.0+eps
3214 if(r < -eps || r > F1eps) continue;
3215
3216
3217 const MFloat uu = u[0] * u[0] + u[1] * u[1] + u[2] * u[2];
3218 const MFloat uv = u[0] * v[0] + u[1] * v[1] + u[2] * v[2];
3219 const MFloat vv = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
3220
3221 MFloat wu = 0.0;
3222 MFloat wv = 0.0;
3223 MFloat ip[nDim];
3224 // dot products
3225 for(MInt i = 0; i < nDim; i++) {
3226 ip[i] = e1[i] + r * ray[i];
3227 const MFloat tmp = ip[i] - vert0[i];
3228 wu += tmp * u[i];
3229 wv += tmp * v[i];
3230 }
3231
3232 const MFloat D = uv * uv - uu * vv;
3233
3234 const MFloat s = (uv * wv - vv * wu) / D;
3235 if(s < -eps || s > F1eps)
3236 // Intersection point is outside triangle
3237 continue;
3238
3239 const MFloat t = (uv * wu - uu * wv) / D;
3240 if(t < -eps || (s + t) > F1eps)
3241 // Intersection point is outside triangle
3242 continue;
3243
3244 // Here we are checking if such an intersection point has already been found.
3245 // This can be the case if the line intersects a triange edge or a vertex.
3246 if(noReallyIntersectingNodes == 0) {
3247 ASSERT(ips.empty(), "ips not empty");
3248 for(MInt i = 0; i < nDim; i++) {
3249 ips.push_back(ip[i]);
3250 }
3251 nodeList[noReallyIntersectingNodes] = nodeList[n];
3252 noReallyIntersectingNodes++;
3253 } else {
3254 MBool singleIntersectionPoint = true;
3255 for(MInt f = 0; f < noReallyIntersectingNodes; f++) {
3256 if((fabs(ips[f * nDim] - ip[0]) < eps) && (fabs(ips[f * nDim + 1] - ip[1]) < eps)
3257 && (fabs(ips[f * nDim + 2] - ip[2]) < eps)) {
3258 singleIntersectionPoint = false;
3259 // m_log << "Found multiple points" << endl;
3260 break;
3261 }
3262 }
3263 if(singleIntersectionPoint) {
3264 for(MInt i = 0; i < nDim; i++) {
3265 ips.push_back(ip[i]);
3266 }
3267 nodeList[noReallyIntersectingNodes] = nodeList[n];
3268 noReallyIntersectingNodes++;
3269 ASSERT(ips.size() == (MUlong)(noReallyIntersectingNodes * nDim),
3270 "Error: wrong vector size of ips. " + std::to_string(ips.size())
3271 + " != " + std::to_string(noReallyIntersectingNodes * nDim));
3272 }
3273 }
3274 }
3275
3276 nodeList.resize(noReallyIntersectingNodes);
3277
3278 getLIE2CommCounter += noReallyIntersectingNodes;
3279
3280 return noReallyIntersectingNodes;
3281}
3282
3283
3285 // TRACE();
3286 TERMM(1, "should not be used anymore");
3287
3289
3290 const MFloat eps = 0.00000000001;
3291
3292 MFloat u[nDim];
3293 MFloat v[nDim];
3294 MFloat normal[nDim];
3295 MFloat w[nDim];
3296 MFloat ray[nDim];
3297 MFloat* ip = nullptr;
3298
3299 for(MInt i = 0; i < nDim; i++) {
3300 u[i] = v[i] = w[i] = numeric_limits<MFloat>::max();
3301 }
3302
3303 stack<MFloat*> allIPs;
3304
3305 MFloat a;
3306 MFloat b;
3307 MFloat r;
3308 MFloat D;
3309 MFloat uu;
3310 MFloat uv;
3311 MFloat vv;
3312 MFloat wu;
3313 MFloat wv;
3314 MFloat s;
3315 MFloat t;
3316
3317 MInt noReallyIntersectingNodes = 0;
3318
3319 std::vector<MInt> nodeList;
3320
3321 MInt maxNoNodes = 30;
3322 auto** tmp = new MFloat*[maxNoNodes];
3323 for(MInt k = 0; k < maxNoNodes; k++) {
3324 tmp[k] = new MFloat[nDim];
3325 }
3326 MBool singleIntersectionPoint;
3327
3328 m_adt->retrieveNodes(targetRegion, nodeList);
3329 const MInt noNodes = nodeList.size();
3330
3331 MFloat e1[3];
3332 MFloat e2[3];
3333 for(MInt i = 0; i < nDim; i++) {
3334 e1[i] = targetRegion[i];
3335 e2[i] = targetRegion[i + nDim];
3336 ray[i] = e2[i] - e1[i];
3337 }
3338
3339 for(MInt n = 0; n < noNodes; n++) {
3340 // Init dot products
3341 a = b = uu = uv = vv = wu = wv = 0.0;
3342
3343 // Fill triangle edges
3344 for(MInt i = 0; i < nDim; i++) {
3345 u[i] = elements[nodeList[n]].m_vertices[1][i] - elements[nodeList[n]].m_vertices[0][i];
3346 v[i] = elements[nodeList[n]].m_vertices[2][i] - elements[nodeList[n]].m_vertices[0][i];
3347 w[i] = e1[i] - elements[nodeList[n]].m_vertices[0][i];
3348 }
3349
3350 // Get normal
3351 normal[0] = u[1] * v[2] - u[2] * v[1];
3352 normal[1] = u[2] * v[0] - u[0] * v[2];
3353 normal[2] = u[0] * v[1] - u[1] * v[0];
3354
3355 // dot products
3356 for(MInt i = 0; i < nDim; i++) {
3357 a += normal[i] * w[i];
3358 b += normal[i] * ray[i];
3359 }
3360 a *= -1;
3361
3362 if(fabs(b) < eps) {
3363 if(fabs(a) < eps) {
3364 // ray lies in triangle plane
3365 nodeList[noReallyIntersectingNodes] = nodeList[n];
3366 // noReallyIntersectingNodes++;
3367 m_log << "Found ray in triangle plane" << endl;
3368 continue;
3369 } else
3370 // ray disjoint from plane
3371 continue;
3372 }
3373 r = a / b;
3374
3375 // is the ray going the right direction and is the scaling factor smaller than 1.0+eps
3376 if(r < -eps || r > F1 + eps) continue;
3377
3378 // dot products
3379 ip = new MFloat[3];
3380
3381 for(MInt i = 0; i < nDim; i++) {
3382 ip[i] = e1[i] + r * ray[i];
3383 uu += u[i] * u[i];
3384 uv += u[i] * v[i];
3385 vv += v[i] * v[i];
3386 w[i] = ip[i] - elements[nodeList[n]].m_vertices[0][i];
3387 wu += w[i] * u[i];
3388 wv += w[i] * v[i];
3389 }
3390
3391 D = uv * uv - uu * vv;
3392
3393 s = (uv * wv - vv * wu) / D;
3394 if(s < -eps || s > F1 + eps)
3395 // Intersection point is outside triangle
3396 continue;
3397 t = (uv * wu - uu * wv) / D;
3398 if(t < -eps || (s + t) > F1 + eps)
3399 // Intersection point is outside triangle
3400 continue;
3401
3402 // Here we are checking if there are multiple intersection points.
3403 // This can be the case if the line intersects a triangle edge or a vertex.
3404
3405 singleIntersectionPoint = true;
3406
3407 if(noReallyIntersectingNodes == 0) {
3408 for(MInt i = 0; i < nDim; i++)
3409 tmp[noReallyIntersectingNodes][i] = ip[i];
3410
3411 nodeList[noReallyIntersectingNodes] = nodeList[n];
3412 allIPs.push(tmp[noReallyIntersectingNodes]);
3413
3414 noReallyIntersectingNodes++;
3415 } else {
3416 for(MInt f = 0; f < noReallyIntersectingNodes; f++) {
3417 if((fabs(tmp[f][0] - ip[0]) < eps) && (fabs(tmp[f][1] - ip[1]) < eps) && (fabs(tmp[f][2] - ip[2]) < eps)) {
3418 singleIntersectionPoint = false;
3419 // m_log << "Found multiple points" << endl;
3420 break;
3421 }
3422 }
3423
3424 if(singleIntersectionPoint) {
3425 for(MInt i = 0; i < nDim; i++)
3426 tmp[noReallyIntersectingNodes][i] = ip[i];
3427
3428 nodeList[noReallyIntersectingNodes] = nodeList[n];
3429 noReallyIntersectingNodes++;
3430
3431 } else {
3432 delete[] ip;
3433 }
3434 }
3435 }
3436
3437 nodeList.resize(noReallyIntersectingNodes);
3438
3439 // free the temporary space
3440 for(MInt k = 0; k < maxNoNodes; k++) {
3441 delete[] tmp[k];
3442 tmp[k] = 0;
3443 }
3444 delete[] tmp;
3445 tmp = 0;
3446
3447 getLIE2CommCounter += noReallyIntersectingNodes;
3448
3449 return noReallyIntersectingNodes;
3450}
3451
3452
3453//==================================================
3454//==================================================
3455
3456
3457MBool Geometry3D::getClosestLineIntersectionLength(MInt bndCndId, const std::vector<MInt>& nodeList,
3458 MFloat* targetRegion, MFloat* dist) {
3459 TRACE();
3460
3461 MBool cut = false;
3462 *dist = 100000000000.0;
3463
3464 MFloat tmp_length;
3465
3466 MFloat eps = 0.00000000001;
3467
3468 MFloat u[nDim];
3469 MFloat v[nDim];
3470 MFloat normal[nDim];
3471 MFloat w[nDim];
3472 MFloat ray[nDim];
3473 MFloat ip[nDim];
3474
3475 for(MInt i = 0; i < nDim; i++) {
3476 ip[i] = w[i] = u[i] = v[i] = numeric_limits<MFloat>::max();
3477 }
3478
3479 MFloat a, b, r;
3480 MFloat D, uu, uv, vv, wu, wv;
3481 MFloat s, t;
3482
3483 MInt noReallyIntersectingNodes = 0;
3484
3485
3486 MInt maxNoNodes = 30;
3487 MFloat** tmp = new MFloat*[maxNoNodes];
3488 for(MInt k = 0; k < maxNoNodes; k++) {
3489 tmp[k] = new MFloat[nDim];
3490 }
3491 MBool singleIntersectionPoint;
3492
3493 MFloat e1[3], e2[3];
3494 for(MInt i = 0; i < nDim; i++) {
3495 e1[i] = targetRegion[i];
3496 e2[i] = targetRegion[i + nDim];
3497 ray[i] = e2[i] - e1[i];
3498 }
3499
3500 for(MInt n = 0; n < (signed)nodeList.size(); n++) {
3501 if(elements[nodeList[n]].m_bndCndId != bndCndId) continue;
3502
3503 tmp_length = 0.0;
3504
3505 // Init dot products
3506 a = b = uu = uv = vv = wu = wv = 0.0;
3507
3508 // Fill triangle edges
3509 for(MInt i = 0; i < nDim; i++) {
3510 u[i] = elements[nodeList[n]].m_vertices[1][i] - elements[nodeList[n]].m_vertices[0][i];
3511 v[i] = elements[nodeList[n]].m_vertices[2][i] - elements[nodeList[n]].m_vertices[0][i];
3512 w[i] = e1[i] - elements[nodeList[n]].m_vertices[0][i];
3513 }
3514
3515 // Get normal
3516 normal[0] = u[1] * v[2] - u[2] * v[1];
3517 normal[1] = u[2] * v[0] - u[0] * v[2];
3518 normal[2] = u[0] * v[1] - u[1] * v[0];
3519
3520 // dot products
3521 for(MInt i = 0; i < nDim; i++) {
3522 a += normal[i] * w[i];
3523 b += normal[i] * ray[i];
3524 }
3525 a *= -1;
3526
3527 if(fabs(b) < eps) {
3528 if(fabs(a) < eps) {
3529 // TODO labels:GEOM
3530 // ray lies in triangle plane
3531 noReallyIntersectingNodes++;
3532 cut = true;
3533 continue;
3534 } else
3535 // ray disjoint from plane
3536 continue;
3537 }
3538 r = a / b;
3539
3540 // is the ray going the right direction and is the scaling factor smaller than 1.0+eps
3541 if(r < -eps || r > F1 + eps) continue;
3542
3543 // dot products
3544 for(MInt i = 0; i < nDim; i++) {
3545 ip[i] = e1[i] + r * ray[i];
3546 uu += u[i] * u[i];
3547 uv += u[i] * v[i];
3548 vv += v[i] * v[i];
3549 w[i] = ip[i] - elements[nodeList[n]].m_vertices[0][i];
3550 wu += w[i] * u[i];
3551 wv += w[i] * v[i];
3552 }
3553
3554 D = uv * uv - uu * vv;
3555
3556 s = (uv * wv - vv * wu) / D;
3557 if(s < -eps || s > F1 + eps)
3558 // Intersection point is outside triangle
3559 continue;
3560 t = (uv * wu - uu * wv) / D;
3561 if(t < -eps || (s + t) > F1 + eps)
3562 // Intersection point is outside triangle
3563 continue;
3564
3565 // Here we are checking if such an intersection point has already been found.
3566 // This can be the case if the line intersects a triange edge or a vertex.
3567 singleIntersectionPoint = true;
3568
3569 if(noReallyIntersectingNodes == 0) {
3570 for(MInt i = 0; i < nDim; i++)
3571 tmp[noReallyIntersectingNodes][i] = ip[i];
3572 noReallyIntersectingNodes++;
3573 /*
3574 for(MInt dim=0; dim<nDim; dim++)
3575 tmp_length+=(ip[dim]-e1[dim])*(ip[dim]-e1[dim]);
3576 */
3577 for(MInt dim = 0; dim < nDim; dim++)
3578 tmp_length += (r * ray[dim]) * (r * ray[dim]);
3579
3580 tmp_length = sqrt(tmp_length);
3581
3582 if(tmp_length < *dist) *dist = tmp_length;
3583
3584 cut = true;
3585 } else {
3586 for(MInt f = 0; f < noReallyIntersectingNodes; f++) {
3587 if((fabs(tmp[f][0] - ip[0]) < eps) && (fabs(tmp[f][1] - ip[1]) < eps) && (fabs(tmp[f][2] - ip[2]) < eps)) {
3588 singleIntersectionPoint = false;
3589 break;
3590 }
3591 }
3592 if(singleIntersectionPoint) {
3593 for(MInt i = 0; i < nDim; i++)
3594 tmp[noReallyIntersectingNodes][i] = ip[i];
3595 noReallyIntersectingNodes++;
3596
3597 /*
3598 for(MInt dim=0; dim<nDim; dim++)
3599 tmp_length+=(ip[dim]-e1[dim])*(ip[dim]-e1[dim]);
3600 */
3601 for(MInt dim = 0; dim < nDim; dim++)
3602 tmp_length += (r * ray[dim]) * (r * ray[dim]);
3603
3604 tmp_length = sqrt(tmp_length);
3605
3606
3607 if(tmp_length < *dist) *dist = tmp_length;
3608
3609 cut = true;
3610 }
3611 }
3612 }
3613
3614 // free the temporary space
3615 for(MInt k = 0; k < maxNoNodes; k++) {
3616 delete[] tmp[k];
3617 tmp[k] = nullptr;
3618 }
3619 delete[] tmp;
3620 tmp = nullptr;
3621
3622 return cut;
3623}
3624
3625
3626MInt Geometry3D::getIntersectionMBElements(MFloat* targetRegion, std::vector<MInt>& nodeList) {
3627 TRACE();
3628
3629 otherCalls++;
3630
3631
3632 MInt noReallyIntersectingNodes = 0;
3633 // get all candidates for an intersection
3634 // Check for intersection...
3635 bitset<6> points[3];
3636 bitset<6> faceCodes[6];
3637 bitset<6> pCode;
3638 MInt spaceId;
3639 MInt spaceId1;
3640 MInt spaceId2;
3641 MInt edges[3][2] = {{0, 1}, {1, 2}, {0, 2}};
3642 // Corner points of the target regione i.e. p0=(targetRegion[targetPoints[0][0],
3643 // targetRegion[targetPoints[0][1],
3644 // targetRegion[targetPoints[0][2])
3645 MInt targetPoints[8][3] = {{0, 1, 2}, {3, 1, 2}, {0, 4, 2}, {3, 4, 2}, {0, 1, 5}, {3, 1, 5}, {0, 4, 5}, {3, 4, 5}};
3646
3647 // Edges of the targetRegion (using targetPoints)
3648 MInt targetEdges[12][2] = {{0, 1}, {2, 3}, {4, 5}, {6, 7}, // x-edges (i.e. parallel to x-axis)
3649 {0, 2}, {1, 3}, {4, 6}, {5, 7}, // y-edes
3650 {0, 4}, {1, 5}, {2, 6}, {3, 7}}; // z-edges
3651 MFloat e1[3];
3652 MFloat e2[3];
3653 MInt rejection;
3654 MBool piercePointInside;
3655 MBool triviallyAccepted;
3656
3657 // Each of the following arrays holds one different point for
3658 // all of the 6 planes. Points are built with the targetRegion
3659 // i.e. a = targetRegiont[pointAInPlane[0]],
3660 // targetRegiont[pointAInPlane[1]],
3661 // targetRegiont[pointAInPlane[2]])
3662 // etc.
3663 MInt pointAInPlane[6][3] = {{0, 1, 2}, {3, 4, 5}, {0, 1, 2}, {3, 4, 5}, {0, 1, 2}, {3, 4, 5}};
3664
3665 MInt pointBInPlane[6][3] = {{0, 4, 2}, {3, 1, 5}, {3, 1, 2}, {0, 4, 5}, {3, 1, 2}, {3, 1, 5}};
3666
3667 MInt pointCInPlane[6][3] = {{0, 1, 5}, {3, 4, 2}, {3, 1, 5}, {0, 4, 2}, {3, 4, 2}, {0, 1, 5}};
3668 MFloat a[3]; // point in plane
3669 MFloat b[3]; // point in plane
3670 MFloat c[3]; // point in plane
3671 MFloat d[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
3672 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // start of piercing edge
3673 MFloat e[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
3674 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // end of piercing edge
3675 MFloat s;
3676 MFloat gamma; // For pierce point calculation
3677 MFloat p2;
3678 MFloat q;
3679 MFloat epsilon = 0.00000000001;
3680 MFloat pP[3]; // piercePoint
3681 faceCodes[0] = IPOW2(0);
3682 faceCodes[1] = IPOW2(1);
3683 faceCodes[2] = IPOW2(2);
3684 faceCodes[3] = IPOW2(3);
3685 faceCodes[4] = IPOW2(4);
3686 faceCodes[5] = IPOW2(5);
3687 // edges[0][0] = 0;
3688 // edges[0][1] = 1;
3689 // edges[1][0] = 1;
3690 // edges[1][1] = 2;
3691 // edges[2][0] = 0;
3692 // edges[2][1] = 2;
3693 bitset<6> result;
3694 m_adt->retrieveNodesMBElements(targetRegion, nodeList);
3695 const MInt noNodes = nodeList.size();
3696 // return noNodes;
3697 noReallyIntersectingNodes = 0;
3698
3699 for(MInt n = 0; n < noNodes; n++) {
3700 // create edges (in 3D) AB, AC, BC and point A B C
3701 // Determine outcode (see Aftosmis, Solution Adaptive Cartesian Grid Methods for Aerodynamic flows ...)
3702
3703 // Loop over all points of an element<3>
3704 for(MInt p = 0; p < nDim; p++) {
3705 points[p] = 0;
3706 // Calculate outcode for point
3707 for(MInt j = 0; j < nDim; j++) {
3708 if(mbelements[nodeList[n]].m_vertices[p][j] < targetRegion[j]) {
3709 points[p] |= faceCodes[2 * j];
3710 }
3711 if(mbelements[nodeList[n]].m_vertices[p][j] > targetRegion[j + nDim]) {
3712 points[p] |= faceCodes[2 * j + 1];
3713 }
3714 }
3715 // m_log << points[p] << endl;
3716 }
3717 rejection = 0;
3718 // check outcode combinations for edges for trivial rejection
3719 for(auto& edge : edges) {
3720 if((points[edge[0]] & points[edge[1]]) != 0) {
3721 rejection++;
3722 } else {
3723 // If one point is inside region the element<3> is trivially accepted
3724 triviallyAccepted = false;
3725 for(MInt k = 0; k < nDim; k++) {
3726 if(points[k] == 0) {
3727 triviallyAccepted = true;
3728 break;
3729 }
3730 }
3731 if(triviallyAccepted) {
3732 break;
3733 }
3734 // No trivial rejection, check for rejection of subsegment:
3735 // For all pierce points!
3736 // 1. Calculate pierce point:
3737 // a - determine plane for pierce point calculation
3738 // b - calculate pierce point
3739 // 2. Check for rejection of new segment
3740 // a - calculate new outcode
3741 // b - check for containment in pierce planes face
3742 // 3. If all(!) pierce points are rejected -> reject edge
3743 // TODO labels:GEOM This algorith might get a problem if a triangle lies completely on
3744 // a face.
3745
3746 // 1.a
3747 result = (points[edge[0]] | points[edge[1]]);
3748 piercePointInside = false;
3749 for(MInt j = 0; j < 2 * nDim; j++) {
3750 if(result[j] == 1) {
3751 // pierce plane found
3752 // Algorithm taken von AFTOSMIS. There seems to be an
3753 // error in the calculation of s in AFTOSMIS formula, the one below
3754 // should be correct!
3755 for(MInt k = 0; k < nDim; k++) {
3756 a[k] = targetRegion[pointAInPlane[j][k]];
3757 b[k] = targetRegion[pointBInPlane[j][k]];
3758 c[k] = targetRegion[pointCInPlane[j][k]];
3759 d[k] = mbelements[nodeList[n]].m_vertices[edge[0]][k];
3760 e[k] = mbelements[nodeList[n]].m_vertices[edge[1]][k];
3761 }
3762 gamma = ((e[0] - d[0]) * ((a[2] - c[2]) * (c[1] - b[1]) - (a[1] - c[1]) * (c[2] - b[2]))
3763 - (e[1] - d[1]) * ((a[2] - c[2]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[2] - b[2]))
3764 + (e[2] - d[2]) * ((a[1] - c[1]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[1] - b[1])));
3765
3766 s = ((c[0] - d[0]) * ((a[2] - c[2]) * (c[1] - b[1]) - (a[1] - c[1]) * (c[2] - b[2]))
3767 - (c[1] - d[1]) * ((a[2] - c[2]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[2] - b[2]))
3768 + (c[2] - d[2]) * ((a[1] - c[1]) * (c[0] - b[0]) - (a[0] - c[0]) * (c[1] - b[1])))
3769 / gamma;
3770
3771 // 1. b Pierce point pP in plane j:
3772 for(MInt k = 0; k < nDim; k++) {
3773 pP[k] = d[k] + s * (e[k] - d[k]);
3774 }
3775 pCode = 0;
3776 // 2. a Calculate outcode for pierce point
3777 for(MInt k = 0; k < nDim; k++) {
3778 if(pP[k] < targetRegion[k]) {
3779 pCode |= faceCodes[2 * k];
3780 }
3781 if(pP[k] > targetRegion[k + nDim]) {
3782 pCode |= faceCodes[2 * k + 1];
3783 }
3784 }
3785 // m_log << " outcode of pierce point :" << pCode << endl;
3786
3787 } else {
3788 continue;
3789 }
3790 // 2. b
3791 result = faceCodes[j];
3792 result.flip();
3793 result = (result & pCode);
3794 if(result == 0) { // -> is contained
3795 piercePointInside = true;
3796 }
3797 }
3798 // reject if all pierce points are off coresponding face
3799 if(!piercePointInside) {
3800 rejection++;
3801 }
3802 }
3803 }
3804 // Check for internal element<3>, i.e. completely inside target
3805 result = (points[0] | points[1] | points[2]);
3806 if(result == 0) {
3807 nodeList[noReallyIntersectingNodes] = nodeList[n];
3808 noReallyIntersectingNodes++;
3809 continue;
3810 }
3811 // If not all edges are rejected a cutting element<3> has been found
3812 // m_log << rejection << endl;
3813 if(rejection < 3) {
3814 nodeList[noReallyIntersectingNodes] = nodeList[n];
3815 noReallyIntersectingNodes++;
3816 continue;
3817 }
3818
3819 // Even if trivially rejected, check if targetRegion is completely inside triangle
3820 // For that check all edges of the cell against the plane of the triangle,
3821 // calculate all pierce points and their outcodes and finally check for containment
3822 // in the targetRegion. Before the pierce point calculation check if the current
3823 // edge is parallel to the triangle (evaluate the distance of the edgepoints to the plane)
3824 if(rejection >= 3) {
3825 for(MInt t = 0; t < 12; t++) { // Loop over all 12 edges of the targetRegion (cell-cube)
3826 for(MInt p = 0; p < nDim; p++) {
3827 e1[p] = targetRegion[targetPoints[targetEdges[t][0]][p]];
3828 e2[p] = targetRegion[targetPoints[targetEdges[t][1]][p]];
3829 }
3830
3831 if(t < 4) {
3832 spaceId = 1;
3833 spaceId1 = 2;
3834 spaceId2 = 0;
3835 } else {
3836 if(t > 3 && t < 8) {
3837 spaceId = 2;
3838 spaceId1 = 0;
3839 spaceId2 = 1;
3840 } else {
3841 spaceId = 0;
3842 spaceId1 = 1;
3843 spaceId2 = 2;
3844 }
3845 }
3846
3847 for(MInt k = 0; k < nDim; k++) {
3848 a[k] = mbelements[nodeList[n]].m_vertices[0][k];
3849 b[k] = mbelements[nodeList[n]].m_vertices[1][k];
3850 c[k] = mbelements[nodeList[n]].m_vertices[2][k];
3851 }
3852 if(approx(a[spaceId1], b[spaceId1], MFloatEps) && !approx(a[spaceId1], c[spaceId1], MFloatEps)) {
3853 // aspaceId != bspaceId, otherwise a and b would be the same point
3854 q = (e1[spaceId1] - a[spaceId1]) / (c[spaceId1] - a[spaceId1]);
3855 p2 = (e1[spaceId] - a[spaceId] - q * (c[spaceId] - a[spaceId])) / (b[spaceId] - a[spaceId]);
3856 } else {
3857 if(!approx(a[spaceId1], b[spaceId1], MFloatEps) && approx(a[spaceId1], c[spaceId1], MFloatEps)) {
3858 // aspaceId != cspaceId, otherwise a and c would be the same point
3859 p2 = (e1[spaceId1] - a[spaceId1]) / (b[spaceId1] - a[spaceId1]);
3860 q = (e1[spaceId] - a[spaceId] - p2 * (b[spaceId] - a[spaceId])) / (c[spaceId] - a[spaceId]);
3861 } else {
3862 if(approx(a[spaceId], b[spaceId], MFloatEps) && !approx(a[spaceId], c[spaceId], MFloatEps)) {
3863 // aspaceId1 != bspaceId1, otherwise a and b would be the same point
3864 q = (e1[spaceId] - a[spaceId]) / (c[spaceId] - a[spaceId]);
3865 p2 = (e1[spaceId1] - a[spaceId1] - q * (c[spaceId1] - a[spaceId1])) / (b[spaceId1] - a[spaceId1]);
3866 } else {
3867 if(!approx(a[spaceId], b[spaceId], MFloatEps) && approx(a[spaceId], c[spaceId], MFloatEps)) {
3868 // aspaceId1 != cspaceId1, otherwise a and c would be the same point
3869 p2 = (e1[spaceId] - a[spaceId]) / (b[spaceId] - a[spaceId]);
3870 q = (e1[spaceId1] - a[spaceId1] - p2 * (b[spaceId1] - a[spaceId1])) / (c[spaceId1] - a[spaceId1]);
3871 } else {
3872 // aspaceId1 != bspaceId1 && aspaceId1 != cspaceId1 && aspaceId != bspaceId && aspaceId != cspaceId
3873 q = ((e1[spaceId1] - a[spaceId1]) * (b[spaceId] - a[spaceId])
3874 - (b[spaceId1] - a[spaceId1]) * (e1[spaceId] - a[spaceId]))
3875 / ((c[spaceId1] - a[spaceId1]) * (b[spaceId] - a[spaceId])
3876 - (b[spaceId1] - a[spaceId1]) * (c[spaceId] - a[spaceId]));
3877 p2 = (e1[spaceId] - a[spaceId] - q * (c[spaceId] - a[spaceId])) / (b[spaceId] - a[spaceId]);
3878 }
3879 }
3880 }
3881 }
3882
3883 if(p2 * q >= 0 || p2 * q < 0) {
3884 // compute s
3885 gamma = a[spaceId2] + p2 * (b[spaceId2] - a[spaceId2]) + q * (c[spaceId2] - a[spaceId2]);
3886 s = (gamma - e1[spaceId2]) / (e2[spaceId2] - e1[spaceId2]);
3887
3888 if(s < -epsilon || s > F1 + epsilon || p2 < -epsilon || q < -epsilon || (p2 + q) > F1 + epsilon) {
3889 } else {
3891 /* if( edgeTriangleIntersection(elements[nodeList[n]].m_vertices[0],
3892 elements[nodeList[n]].m_vertices[1],
3893 elements[nodeList[n]].m_vertices[2], e1, e2) ){*/
3894 nodeList[noReallyIntersectingNodes] = nodeList[n];
3895 noReallyIntersectingNodes++;
3896 break;
3897 }
3898 }
3899 }
3900 }
3901
3902 // write nodes in reallyIntersectingNodes
3903 }
3904 // if(noNodes)
3905 if(noNodes && !noReallyIntersectingNodes) {
3906 // m_log << "Rejected ! "<< ++rejectionCounter << endl;
3907 }
3908 nodeList.resize(noReallyIntersectingNodes);
3909
3910 return noReallyIntersectingNodes;
3911}
3912
3913
3914MInt Geometry3D::getSphereIntersectionMBElements(MFloat* P, MFloat radius, std::vector<MInt>& nodeList) {
3915 // TRACE();
3916
3917 otherCalls++;
3918
3919 MInt noReallyIntersectingNodes = 0;
3920
3921 // compute minimum target region that contains the sphere:
3922 MFloat target[6] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
3923 numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
3924 numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized
3925 MFloat enlargeFactor = 1.05;
3926 for(MInt i = 0; i < nDim; i++) {
3927 target[i] = P[i] - radius * enlargeFactor;
3928 target[i + nDim] = P[i] + radius * enlargeFactor;
3929 }
3930
3931 // fetch all possibly intersecting triangles in this region:
3932 m_adt->retrieveNodesMBElements(target, nodeList);
3933 const MInt noNodes = nodeList.size();
3934
3935 MFloat A[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
3936 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized
3937 MFloat B[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
3938 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized
3939 MFloat C[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
3940 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized
3941 MFloat AB[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
3942 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized
3943 MFloat BC[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
3944 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized
3945 MFloat CA[3] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
3946 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized
3947 MFloat V[3], Q1[3], Q2[3], Q3[3], QC[3], QA[3], QB[3];
3948
3949 // loop over all elements
3950 for(MInt n = 0; n < noNodes; n++) {
3951 // store the vertices of the current element<3> in A, B, C:
3952 for(MInt i = 0; i < nDim; i++) {
3953 A[i] = mbelements[nodeList[n]].m_vertices[0][i];
3954 B[i] = mbelements[nodeList[n]].m_vertices[1][i];
3955 C[i] = mbelements[nodeList[n]].m_vertices[2][i];
3956 }
3957
3958 // compute separation algorithm from http://realtimecollisiondetection.net/blog/?p=103:
3959 for(MInt i = 0; i < nDim; i++) {
3960 A[i] = A[i] - P[i];
3961 B[i] = B[i] - P[i];
3962 C[i] = C[i] - P[i];
3963 AB[i] = B[i] - A[i];
3964 BC[i] = C[i] - B[i];
3965 CA[i] = A[i] - C[i];
3966 }
3967 V[0] = -AB[1] * CA[2] + AB[2] * CA[1];
3968 V[1] = -AB[2] * CA[0] + AB[0] * CA[2];
3969 V[2] = -AB[0] * CA[1] + AB[1] * CA[0];
3970 MFloat rr = radius * radius;
3971 MFloat d = F0;
3972 MFloat e = F0;
3973 MFloat aa = F0;
3974 MFloat ab = F0;
3975 MFloat ac = F0;
3976 MFloat bb = F0;
3977 MFloat bc = F0;
3978 MFloat cc = F0;
3979 MFloat e1 = F0;
3980 MFloat e2 = F0;
3981 MFloat e3 = F0;
3982 for(MInt i = 0; i < nDim; i++) {
3983 d += A[i] * V[i];
3984 e += V[i] * V[i];
3985 aa += A[i] * A[i];
3986 ab += A[i] * B[i];
3987 ac += A[i] * C[i];
3988 bb += B[i] * B[i];
3989 bc += B[i] * C[i];
3990 cc += C[i] * C[i];
3991 e1 += AB[i] * AB[i];
3992 e2 += BC[i] * BC[i];
3993 e3 += CA[i] * CA[i];
3994 }
3995 MBool sep1 = d * d > rr * e;
3996 MBool sep2 = (aa > rr) && (ab > aa) && (ac > aa);
3997 MBool sep3 = (bb > rr) && (ab > bb) && (bc > bb);
3998 MBool sep4 = (cc > rr) && (ac > cc) && (bc > cc);
3999 MFloat d1 = ab - aa;
4000 MFloat d2 = bc - bb;
4001 MFloat d3 = ac - cc;
4002 MFloat qq1 = F0;
4003 MFloat qq2 = F0;
4004 MFloat qq3 = F0;
4005 MFloat qq1c = F0;
4006 MFloat qq2a = F0;
4007 MFloat qq3b = F0;
4008 for(MInt i = 0; i < nDim; i++) {
4009 Q1[i] = A[i] * e1 - d1 * AB[i];
4010 Q2[i] = B[i] * e2 - d2 * BC[i];
4011 Q3[i] = C[i] * e3 - d3 * CA[i];
4012 QC[i] = C[i] * e1 - Q1[i];
4013 QA[i] = A[i] * e2 - Q2[i];
4014 QB[i] = B[i] * e3 - Q3[i];
4015 qq1 += Q1[i] * Q1[i];
4016 qq2 += Q2[i] * Q2[i];
4017 qq3 += Q3[i] * Q3[i];
4018 qq1c += Q1[i] * QC[i];
4019 qq2a += Q2[i] * QA[i];
4020 qq3b += Q3[i] * QB[i];
4021 }
4022 MBool sep5 = (qq1 > rr * e1 * e1) && (qq1c > 0);
4023 MBool sep6 = (qq2 > rr * e2 * e2) && (qq2a > 0);
4024 MBool sep7 = (qq3 > rr * e3 * e3) && (qq3b > 0);
4025
4026 MBool separated = sep1 || sep2 || sep3 || sep4 || sep5 || sep6 || sep7;
4027
4028 if(!separated) {
4029 nodeList[noReallyIntersectingNodes] = nodeList[n];
4030 noReallyIntersectingNodes++;
4031 }
4032 }
4033 nodeList.resize(noReallyIntersectingNodes);
4034
4035 return noReallyIntersectingNodes;
4036}
4037
4038
4039MInt Geometry3D::getLineIntersectionMBElements(MFloat* targetRegion, std::vector<MInt>& nodeList) {
4040 TRACE();
4041
4042 otherCalls++;
4043
4044
4045 MInt noReallyIntersectingNodes = 0;
4046 m_adt->retrieveNodes(targetRegion, nodeList);
4047 const MInt noNodes = nodeList.size();
4048 MFloat e1[3], e2[3];
4049 for(MInt i = 0; i < nDim; i++) {
4050 e1[i] = targetRegion[i];
4051 e2[i] = targetRegion[i + nDim];
4052 }
4053
4054 for(MInt n = 0; n < noNodes; n++) {
4056 if(edgeTriangleIntersection(mbelements[nodeList[n]].m_vertices[0], mbelements[nodeList[n]].m_vertices[1],
4057 mbelements[nodeList[n]].m_vertices[2], e1, e2)) {
4058 nodeList[noReallyIntersectingNodes] = nodeList[n];
4059 noReallyIntersectingNodes++;
4060 }
4061 }
4062 nodeList.resize(noReallyIntersectingNodes);
4063
4064 return noReallyIntersectingNodes;
4065}
4066
4067
4068MInt Geometry3D::getLineIntersectionMBElements2(MFloat* targetRegion, MInt* spaceDirection, std::vector<MInt>& nodeList,
4069 MInt bcId) {
4070 TRACE();
4071
4072 otherCalls++;
4073
4074
4075 MBool singleIntersectionPoint;
4076 MInt noReallyIntersectingNodes = 0;
4077 m_adt->retrieveNodesMBElements(targetRegion, nodeList);
4078 const MInt noNodes = nodeList.size();
4079 // TAN maxNoNodes is low
4080 MInt maxNoNodes = noNodes; // 50;
4081 MInt spaceId, spaceId1, spaceId2;
4082 MFloat* e1 = new MFloat[nDim];
4083 MFloat* e2 = new MFloat[nDim];
4084 MFloat epsilon = 0.00000000001;
4085 MFloat* a = new MFloat[nDim];
4086 MFloat* b = new MFloat[nDim];
4087 MFloat* c = new MFloat[nDim];
4088 MFloat gamma, s, p, q;
4089 MFloat* pP = new MFloat[nDim];
4090 MFloat** temp = new MFloat*[maxNoNodes];
4091 for(MInt k = 0; k < maxNoNodes; k++) {
4092 temp[k] = new MFloat[nDim];
4093 }
4094
4095 for(MInt i = 0; i < nDim; i++) {
4096 e1[i] = targetRegion[i];
4097 e2[i] = targetRegion[i + nDim];
4098 }
4099 spaceId = spaceDirection[0];
4100 spaceId1 = spaceDirection[1];
4101 spaceId2 = spaceDirection[2];
4102
4103 for(MInt n = 0; n < noNodes; n++) {
4104 if(mbelements[nodeList[n]].m_bndCndId != bcId) continue;
4105 for(MInt k = 0; k < nDim; k++) {
4106 a[k] = mbelements[nodeList[n]].m_vertices[0][k];
4107 b[k] = mbelements[nodeList[n]].m_vertices[1][k];
4108 c[k] = mbelements[nodeList[n]].m_vertices[2][k];
4109 }
4110 if(approx(a[spaceId1], b[spaceId1], MFloatEps) && !approx(a[spaceId1], c[spaceId1], MFloatEps)) {
4111 // aspaceId != bspaceId, otherwise a and b would be the same point
4112 q = (e1[spaceId1] - a[spaceId1]) / (c[spaceId1] - a[spaceId1]);
4113 p = (e1[spaceId] - a[spaceId] - q * (c[spaceId] - a[spaceId])) / (b[spaceId] - a[spaceId]);
4114 } else {
4115 if(!approx(a[spaceId1], b[spaceId1], MFloatEps) && approx(a[spaceId1], c[spaceId1], MFloatEps)) {
4116 // aspaceId != cspaceId, otherwise a and c would be the same point
4117 p = (e1[spaceId1] - a[spaceId1]) / (b[spaceId1] - a[spaceId1]);
4118 q = (e1[spaceId] - a[spaceId] - p * (b[spaceId] - a[spaceId])) / (c[spaceId] - a[spaceId]);
4119 } else {
4120 if(approx(a[spaceId], b[spaceId], MFloatEps) && !approx(a[spaceId], c[spaceId], MFloatEps)) {
4121 // aspaceId1 != bspaceId1, otherwise a and b would be the same point
4122 q = (e1[spaceId] - a[spaceId]) / (c[spaceId] - a[spaceId]);
4123 p = (e1[spaceId1] - a[spaceId1] - q * (c[spaceId1] - a[spaceId1])) / (b[spaceId1] - a[spaceId1]);
4124 } else {
4125 if(!approx(a[spaceId], b[spaceId], MFloatEps) && approx(a[spaceId], c[spaceId], MFloatEps)) {
4126 // aspaceId1 != cspaceId1, otherwise a and c would be the same point
4127 p = (e1[spaceId] - a[spaceId]) / (b[spaceId] - a[spaceId]);
4128 q = (e1[spaceId1] - a[spaceId1] - p * (b[spaceId1] - a[spaceId1])) / (c[spaceId1] - a[spaceId1]);
4129 } else {
4130 // aspaceId1 != bspaceId1 && aspaceId1 != cspaceId1 && aspaceId != bspaceId && aspaceId != cspaceId
4131 q = ((e1[spaceId1] - a[spaceId1]) * (b[spaceId] - a[spaceId])
4132 - (b[spaceId1] - a[spaceId1]) * (e1[spaceId] - a[spaceId]))
4133 / ((c[spaceId1] - a[spaceId1]) * (b[spaceId] - a[spaceId])
4134 - (b[spaceId1] - a[spaceId1]) * (c[spaceId] - a[spaceId]));
4135 p = (e1[spaceId] - a[spaceId] - q * (c[spaceId] - a[spaceId])) / (b[spaceId] - a[spaceId]);
4136 }
4137 }
4138 }
4139 }
4140
4141 if(p * q >= 0 || p * q < 0) {
4142 // compute s
4143 gamma = a[spaceId2] + p * (b[spaceId2] - a[spaceId2]) + q * (c[spaceId2] - a[spaceId2]);
4144 s = (gamma - e1[spaceId2]) / (e2[spaceId2] - e1[spaceId2]);
4145
4146 if(s < -epsilon || s > F1 + epsilon || p < -epsilon || q < -epsilon || (p + q) > F1 + epsilon) {
4147 } else {
4148 singleIntersectionPoint = true;
4149
4150 // cut point pP
4151 for(MInt g = 0; g < nDim; g++) {
4152 pP[g] = e1[g] + s * (e2[g] - e1[g]);
4153 temp[noReallyIntersectingNodes][g] = pP[g];
4154 }
4155
4156 if(noReallyIntersectingNodes == 0) {
4157 nodeList[noReallyIntersectingNodes] = nodeList[n];
4158 noReallyIntersectingNodes++;
4159 } else {
4160 for(MInt f = 0; f < noReallyIntersectingNodes; f++) {
4161 if((fabs(temp[f][0] - pP[0]) < epsilon) && (fabs(temp[f][1] - pP[1]) < epsilon)
4162 && (fabs(temp[f][2] - pP[2]) < epsilon)) {
4163 singleIntersectionPoint = false;
4164 break;
4165 }
4166 }
4167 if(singleIntersectionPoint) {
4168 nodeList[noReallyIntersectingNodes] = nodeList[n];
4169 noReallyIntersectingNodes++;
4170 }
4171 }
4172 }
4173 }
4174 }
4175 nodeList.resize(noReallyIntersectingNodes);
4176
4177 // free memory
4178 for(MInt k = 0; k < maxNoNodes; k++) {
4179 delete[] temp[k];
4180 temp[k] = nullptr;
4181 }
4182 delete[] temp;
4183 temp = nullptr;
4184
4185 delete[] e1;
4186 e1 = nullptr;
4187 delete[] e2;
4188 e2 = nullptr;
4189 delete[] a;
4190 a = nullptr;
4191 delete[] b;
4192 b = nullptr;
4193 delete[] c;
4194 c = nullptr;
4195 delete[] pP;
4196 pP = nullptr;
4197
4198
4199 return noReallyIntersectingNodes;
4200}
4201
4203 TRACE();
4204
4205 otherCalls++;
4206
4207
4208 for(MInt e = 0; e < m_noMBElements; e++) {
4209 for(MInt j = 0; j < nDim; j++) {
4210 for(MInt i = 0; i < nDim; i++) {
4211 mbelements[e].m_vertices[j][i] += dx[i];
4212 }
4213 }
4214 }
4215}
4216
4218 TRACE();
4219
4220 otherCalls++;
4221
4222
4223 for(MInt i = 0; i < nDim; i++) {
4224 mbelements[e].m_vertices[v][i] += dx[i];
4225 }
4226}
4227
4229 TRACE();
4230
4231 otherCalls++;
4232
4233
4234 for(MInt i = 0; i < nDim; i++) {
4235 mbelements[e].m_vertices[v][i] = np[i];
4236 }
4237}
4238
4240 TRACE();
4241
4242 otherCalls++;
4243
4244
4245 MFloat v1[3], v2[3], n[3], norm_n = NAN;
4246 for(MInt i = 0; i < nDim; i++) {
4247 v1[i] = mbelements[e].m_vertices[1][i] - mbelements[e].m_vertices[0][i];
4248 v2[i] = mbelements[e].m_vertices[2][i] - mbelements[e].m_vertices[0][i];
4249 }
4250 n[0] = v1[1] * v2[2] - v2[1] * v1[2];
4251 n[1] = v1[2] * v2[0] - v2[2] * v1[0];
4252 n[2] = v1[0] * v2[1] - v2[0] * v1[1];
4253
4254 norm_n = sqrt(POW2(n[0]) + POW2(n[1]) + POW2(n[2]));
4255 for(MInt i = 0; i < nDim; i++)
4256 mbelements[e].m_normal[i] = n[i] / norm_n;
4257}
4258
4260 TRACE();
4261
4262 otherCalls++;
4263
4264
4265 for(MInt e = 0; e < m_mbelements->size(); e++) {
4266 mbelements[e].boundingBox();
4267 }
4268 for(MInt j = 0; j < nDim; j++) {
4269 m_mbminMax[j] = mbelements[0].m_minMax[j];
4270 m_mbminMax[j + nDim] = mbelements[0].m_minMax[j + nDim];
4271 }
4272 for(MInt i = 0; i < m_mbelements->size(); i++) {
4273 for(MInt j = 0; j < nDim; j++) {
4274 m_mbminMax[j + nDim] = (m_mbminMax[j + nDim] < mbelements[i].m_minMax[j + nDim])
4275 ? mbelements[i].m_minMax[j + nDim]
4276 : m_mbminMax[j + nDim];
4277 m_mbminMax[j] = (m_mbminMax[j] > mbelements[i].m_minMax[j]) ? mbelements[i].m_minMax[j] : m_mbminMax[j];
4278 }
4279 }
4280}
4281
4283 TRACE();
4284
4285 otherCalls++;
4286
4287 m_adt->buildTreeMB();
4288}
4289
4290void Geometry3D::writeSTL(const char* fileName) {
4291 TRACE();
4292
4293 ofstream ofl;
4294
4295 ofl.open(fileName);
4296 ofl.precision(12);
4297
4298 if(ofl) {
4299 ofl << "solid PRO2STL version 1.0 part " << domainId() << endl;
4300
4301 for(MInt i = 0; i < m_noElements; i++) {
4302 ofl << " facet normal";
4303 for(MInt j = 0; j < 3; j++) {
4304 ofl << " " << elements[i].m_normal[j];
4305 }
4306 ofl << endl << " outer loop" << endl;
4307
4308 for(MInt k = 0; k < 3; k++) {
4309 ofl << " vertex";
4310 for(MInt l = 0; l < 3; l++) {
4311 ofl << " " << elements[i].m_vertices[k][l];
4312 }
4313 ofl << endl;
4314 }
4315
4316 ofl << " endloop" << endl << " endfacet" << endl;
4317 }
4318 ofl << "endsolid PRO2STL version 1.0 part " << domainId() << endl;
4319 }
4320}
4321
4322void Geometry3D::writeSTLMB(const char* fileName, MInt& noNodes, MInt*& nodeList) {
4323 TRACE();
4324
4325 ofstream ofl;
4326
4327 ofl.open(fileName);
4328 ofl.precision(12);
4329
4330 if(ofl) {
4331 ofl << "solid PRO2STL version 1.0 part " << domainId() << endl;
4332
4333 for(MInt i = 0; i < noNodes; i++) {
4334 ofl << " facet normal";
4335 for(MInt j = 0; j < 3; j++) {
4336 ofl << " " << mbelements[nodeList[i]].m_normal[j];
4337 }
4338 ofl << endl << " outer loop" << endl;
4339
4340 for(MInt k = 0; k < 3; k++) {
4341 ofl << " vertex";
4342 for(MInt l = 0; l < 3; l++) {
4343 ofl << " " << mbelements[nodeList[i]].m_vertices[k][l];
4344 }
4345 ofl << endl;
4346 }
4347
4348 ofl << " endloop" << endl << " endfacet" << endl;
4349 }
4350 ofl << "endsolid PRO2STL version 1.0 part " << domainId() << endl;
4351 }
4352}
4353
4354void Geometry3D::writeADTAndSTLToNetCDF(const char* fileName) {
4355 TRACE();
4356 using namespace maia::parallel_io;
4357
4358 ParallelIo::size_type count = 0;
4359
4360 // WARNING: untested switch from NetCDF/Parallel netCDF to ParallelIo
4361 // The method previously used direct I/O calls, which were replaced by
4362 // ParallelIo methods in summer 2015. However, since the method was not
4363 // used by any of the testcases, this code is still *untested*. Thus,
4364 // if your code uses this part of the code, please make sure that the
4365 // I/O still works as expected and then remove this warning as well as
4366 // the subsequent TERMM().
4367 TERMM(1, "untested I/O method, please see comment for how to proceed");
4368 ParallelIo parallelIo(fileName, maia::parallel_io::PIO_REPLACE, MPI_COMM_SELF);
4369
4370 /*
4371 *
4372 * ParallelIo define solver --->
4373 *
4374 */
4375 ParallelIo::size_type tempDim[2];
4376 ParallelIo::size_type tempDim3D[3];
4377
4378 tempDim[0] = m_noElements;
4379 tempDim[1] = nDim;
4380
4381 tempDim3D[0] = m_noElements;
4382 tempDim3D[1] = 3;
4383 tempDim3D[2] = nDim;
4384
4385 parallelIo.defineArray(PIO_FLOAT, "minMax", 2 * nDim);
4386
4387 parallelIo.defineArray(PIO_FLOAT, "vertexNormal", 2, tempDim);
4388
4389 parallelIo.defineArray(PIO_FLOAT, "vertexCoordinates", 3, tempDim3D);
4390
4391 parallelIo.defineArray(PIO_INT, "boundaryConditionId", m_noElements);
4392
4393 /*
4394 *
4395 * <--- ParallelIo define solver
4396 *
4397 */
4398
4399 MFloatScratchSpace floatScratch(9 * m_noElements, AT_, "tmp_float_array");
4400 MFloat* tmp = floatScratch.getPointer();
4401 MIntScratchSpace intScratch(m_noElements, AT_, "tmp_int_array");
4402 MInt* tmpI = intScratch.getPointer();
4403
4404 for(MInt i = 0; i < 2 * nDim; i++) {
4405 tmp[i] = m_minMax[i];
4406 }
4407 count = 2 * nDim;
4408 parallelIo.setOffset(count, 0);
4409 parallelIo.writeArray(&tmp[0], "minMax");
4410
4411 for(MInt i = 0; i < m_noElements; i++) {
4412 for(MInt j = 0; j < 3; j++) {
4413 tmp[i * 3 + j] = elements[i].m_normal[j];
4414 }
4415 }
4416 count = m_noElements;
4417 parallelIo.setOffset(count, 0, 2);
4418 parallelIo.writeArray(&tmp[0], "vertexNormal");
4419
4420 for(MInt i = 0; i < m_noElements; i++) {
4421 for(MInt j = 0; j < 3; j++) {
4422 for(MInt k = 0; k < 3; k++) {
4423 tmp[3 * (i * 3 + j) + k] = elements[i].m_vertices[j][k];
4424 }
4425 }
4426 }
4427 count = m_noElements;
4428 parallelIo.setOffset(count, 0, 3);
4429 parallelIo.writeArray(&tmp[0], "vertexCoordinates");
4430
4431 for(MInt i = 0; i < m_noElements; i++) {
4432 tmpI[i] = elements[i].m_bndCndId;
4433 }
4434 count = m_noElements;
4435 parallelIo.setOffset(count, 0);
4436 parallelIo.writeArray(&tmpI[0], "boundaryConditionId");
4437
4438 /* If the tree needs to be saved
4439 // parIdVar = file.add_var("parentNodeId", ncInt, noNodeDim);
4440 // for(MInt i = 0; i < m_noElements; i++){
4441 // tmp[i] = m_adt->m_nodes[i].m_parent;
4442 // }
4443 // parIdVar->put(&tmp[0], m_noElements);
4444
4445 // childIdVar = file.add_var("childNodeIds", ncInt, noNodeDim, noChildDim);
4446 // tmp[2*i] = m_adt->m_nodes[i].m_leftSubtree;
4447 // tmp[2*i+1] = m_adt->m_nodes[i].m_rightSubtree;
4448 // }
4449 // childIdVar->put(&tmp[0], m_noElements, 2);
4450
4451 // levelVar = file.add_var("level", ncInt, noNodeDim);
4452 // level[i] = m_adt->m_nodes[i].m_depth;
4453 // }
4454 // levelVar->put(&tmp[0], m_noElements);
4455
4456 // vertsVar = file.add_var("vertex", ncInt, noNodeDim);
4457 // tmp[i] = m_adt->m_nodes[i].m_element;
4458 // }
4459 // vertsVar->put(&tmp[0], m_noElements);
4460 */
4461 // m_log << Scratch::printSelf();
4462}
4463
4464void Geometry3D::readSTLNetCDF(const char* fileName) {
4465 TRACE();
4466
4467 otherCalls++;
4468
4469 m_log << "domainId() = " << domainId() << endl;
4470 m_log << "noDomains = " << noDomains() << endl;
4471
4472 ParallelIo::size_type count = 0;
4473
4474 // WARNING: untested switch from NetCDF/Parallel netCDF to ParallelIo
4475 // The method previously used direct I/O calls, which were replaced by
4476 // ParallelIo methods in summer 2015. However, since the method was not
4477 // used by any of the testcases, this code is still *untested*. Thus,
4478 // if your code uses this part of the code, please make sure that the
4479 // I/O still works as expected and then remove this warning as well as
4480 // the subsequent TERMM().
4481 TERMM(1, "untested I/O method, please see comment for how to proceed");
4482 ParallelIo parallelIo(fileName, maia::parallel_io::PIO_READ, MPI_COMM_SELF);
4483
4484 ParallelIo::size_type noVerticesVarSize = 0;
4485 noVerticesVarSize = parallelIo.getArraySize("noVertices");
4486
4487 MInt domainStartRead;
4488 MInt domainEndRead;
4489 MInt elementsPerDomain = noVerticesVarSize / noDomains() + 1;
4490 domainStartRead = domainId() * elementsPerDomain;
4491
4492 if(domainId() == noDomains() - 1) {
4493 m_noElements = noVerticesVarSize - ((noDomains() - 1) * (elementsPerDomain));
4494 domainEndRead = domainStartRead + m_noElements - 1;
4495 } else {
4496 m_noElements = elementsPerDomain;
4497 domainEndRead = domainStartRead + m_noElements - 1;
4498 }
4499
4500 m_log << "no elements in file: " << noVerticesVarSize << endl;
4501 m_log << "m_noElements = " << m_noElements << endl;
4502 m_log << "domainStartRead = " << domainStartRead << endl;
4503 m_log << "domainEndRead = " << domainEndRead << endl;
4504
4505 if(m_elements != nullptr) delete m_elements;
4507 elements = m_elements->a;
4508
4509 MFloat* tmp = new MFloat[9 * m_noElements];
4510 MInt* tmpI = new MInt[m_noElements];
4511
4512 count = m_noElements;
4513 parallelIo.setOffset(count, 0, 2);
4514 parallelIo.readArray(tmp, "vertexNormal");
4515
4516 for(MInt i = 0; i < m_noElements; i++) {
4517 m_elements->append();
4518 for(MInt j = 0; j < 3; j++) {
4519 elements[i].m_normal[j] = tmp[i * 3 + j];
4520 }
4521 }
4522
4523 count = m_noElements;
4524 parallelIo.setOffset(count, 0, 3);
4525 parallelIo.readArray(tmp, "vertexCoordinates");
4526
4527 for(MInt i = 0; i < m_noElements; i++) {
4528 for(MInt j = 0; j < 3; j++) {
4529 for(MInt k = 0; k < 3; k++) {
4530 elements[i].m_vertices[j][k] = tmp[3 * (i * 3 + j) + k];
4531 }
4532 }
4533 elements[i].boundingBox();
4534 }
4535
4536 count = m_noElements;
4537 parallelIo.setOffset(count, 0);
4538 parallelIo.readArray(tmpI, "boundaryConditionId");
4539
4540 for(MInt i = 0; i < m_noElements; i++) {
4541 for(MInt j = 0; j < 3; j++) {
4542 elements[i].m_bndCndId = tmpI[i];
4543 }
4544 }
4545
4546 count = 2 * nDim;
4547 parallelIo.setOffset(count, 0);
4548 parallelIo.readArray(tmp, "minMax");
4549 for(MInt i = 0; i < 2 * nDim; i++) {
4550 m_minMax[i] = tmp[i];
4551 }
4552
4553 /*
4554 for(MInt j=0; j < nDim; j++){
4555 m_minMax[j] = elements[0].m_minMax[j];
4556 m_minMax[j + nDim] = elements[0].m_minMax[j + nDim];
4557 }
4558 for(MInt i=0; i < m_noElements; i++){
4559 for(MInt j=0; j < nDim; j++){
4560 m_minMax[j + nDim] = (m_minMax[j + nDim] <
4561 elements[i].m_minMax[j + nDim]) ? elements[i].m_minMax[j + nDim] : m_minMax[j + nDim];
4562 m_minMax[j] = (m_minMax[j] > elements[i].m_minMax[j]) ? elements[i].m_minMax[j] : m_minMax[j];
4563 }
4564 }
4565 */
4566
4567 delete[] tmp;
4568 delete[] tmpI;
4569}
4570
4580inline vector<pair<MFloat*, MFloat*>> Geometry3D::GetUniqueSegmentEdges(MInt segmentId) {
4581 TRACE();
4582
4583 vector<pair<MFloat*, MFloat*>> edges;
4584
4585 for(MInt i = m_segmentOffsetsWithoutMB[segmentId]; i < m_segmentOffsetsWithoutMB[segmentId + 1]; i++) {
4586 // this runs over all edges of the triangle
4587 for(MInt e = 0; e < nDim; e++) {
4588 MFloat* p1 = elements[i].m_vertices[e];
4589 MFloat* p2 = elements[i].m_vertices[(e + 1) % nDim];
4590
4591 // if not in yet, then add
4592 MInt del;
4593 MBool in = isEdgeAlreadyInCollection(edges, p1, p2, &del);
4594 if(!in)
4595 edges.emplace_back(p1, p2);
4596 else {
4597 auto it = edges.begin() + del;
4598 edges.erase(it);
4599 }
4600 }
4601 }
4602
4603 return edges;
4604}
4605
4606
4620inline vector<pair<MFloat*, MFloat*>> Geometry3D::GetUniqueSegmentEdgesParGeom(MFloat* tri_vx, MInt* keepOffsets,
4621 MInt size) {
4622 TRACE();
4623
4624 vector<pair<MFloat*, MFloat*>> edges;
4625
4626 for(MInt i = 0; i < size; i++) {
4627 MInt off = keepOffsets[i];
4628
4629 // this runs over all edges of the triangle
4630 for(MInt k = 0; k < nDim; k++) {
4631 MFloat* p1 = &tri_vx[off + k * nDim];
4632 MFloat* p2 = &tri_vx[off + (((k + 1) * nDim) % (nDim * nDim))];
4633
4634
4635 MInt del;
4636 MBool in = isEdgeAlreadyInCollection(edges, p1, p2, &del);
4637 if(!in)
4638 edges.emplace_back(p1, p2);
4639 else {
4640 auto it = edges.begin() + del;
4641 edges.erase(it);
4642 }
4643 }
4644 }
4645
4646 return edges;
4647}
4648
4660inline MBool Geometry3D::isEdgeAlreadyInCollection(vector<pair<MFloat*, MFloat*>> edges, MFloat* p1, MFloat* p2,
4661 MInt* to_delete) {
4662 TRACE();
4663
4664 MInt pos = 0;
4665 for(auto& edge : edges) {
4666 MBool pt1_in = true;
4667 MBool pt2_in = true;
4668
4669 MFloat* pcol1 = edge.first;
4670 MFloat* pcol2 = edge.second;
4671
4672 for(MInt d = 0; d < nDim; d++)
4673 pt1_in = pt1_in && approx(p1[d], pcol1[d], MFloatEps);
4674
4675 if(!pt1_in) {
4676 pt1_in = true;
4677 for(MInt d = 0; d < nDim; d++)
4678 pt1_in = pt1_in && approx(p1[d], pcol2[d], MFloatEps);
4679 }
4680
4681 for(MInt d = 0; d < nDim; d++)
4682 pt2_in = pt2_in && approx(p2[d], pcol1[d], MFloatEps);
4683
4684 if(!pt2_in) {
4685 pt2_in = true;
4686 for(MInt d = 0; d < nDim; d++)
4687 pt2_in = pt2_in && approx(p2[d], pcol2[d], MFloatEps);
4688 }
4689
4690 if(pt1_in && pt2_in) {
4691 *to_delete = pos;
4692 return true;
4693 }
4694 pos++;
4695 }
4696 return false;
4697}
4698
4699
4717MFloat** Geometry3D::GetBoundaryVertices(MInt segmentId, MFloat* tri_vx, MInt* keepOffsets, MInt size, MInt* num) {
4718 TRACE();
4719
4720 vector<pair<MFloat*, MFloat*>> tmp_edges;
4721 // this runs over all triangles that have a certain segment id
4722
4724 tmp_edges = GetUniqueSegmentEdgesParGeom(tri_vx, keepOffsets, size);
4725 else
4726 tmp_edges = GetUniqueSegmentEdges(segmentId);
4727
4728 if(tmp_edges.size() < 2) {
4729 stringstream errorMsg;
4730 errorMsg << "ERROR: No boundary edges found for segment " << segmentId << endl;
4731 m_log << errorMsg.str();
4732 mTerm(1, AT_, errorMsg.str());
4733 }
4734
4735 // Get distinct elements in a circular ordering
4736 vector<MFloat*> tmp_points;
4737 MBoolScratchSpace visited(tmp_edges.size(), AT_, "visited");
4738 for(MInt i = 0; i < (signed)tmp_edges.size(); i++)
4739 visited[i] = false;
4740
4741 // insert first edge
4742 tmp_points.push_back(tmp_edges[0].first);
4743 tmp_points.push_back(tmp_edges[0].second);
4744 visited[0] = true;
4745
4746 MFloat* first = tmp_points[0];
4747 MInt cmpPos = 1;
4748
4749 for(MInt i = 1; i < (signed)tmp_edges.size(); i++) {
4750 for(MInt j = 1; j < (signed)tmp_edges.size(); j++) {
4751 // skip if alrady inserted
4752 if(visited[j]) continue;
4753
4754 pair<MFloat*, MFloat*> edge = tmp_edges[j];
4755
4756 // insert in this order
4757 if(vectorsEqual(edge.first, tmp_points[cmpPos])) {
4758 tmp_points.push_back(edge.second);
4759 visited[j] = true;
4760 cmpPos++;
4761 } else if(vectorsEqual(edge.second, tmp_points[cmpPos])) {
4762 tmp_points.push_back(edge.first);
4763 visited[j] = true;
4764 cmpPos++;
4765 }
4766 }
4767 }
4768
4769 if(!vectorsEqual(tmp_points[tmp_points.size() - 1], first)) {
4770 stringstream errorMsg;
4771 errorMsg << "ERROR: Inconsistency in segment " << segmentId << endl;
4772 m_log << errorMsg.str();
4773 mTerm(1, AT_, errorMsg.str());
4774 }
4775
4776 // Fill the array
4777 MFloat** vertices = new MFloat*[tmp_points.size() - 1];
4778 for(MInt i = 0; i < (MInt)tmp_points.size() - 1; i++) {
4779 vertices[i] = new MFloat[nDim];
4780 for(MInt j = 0; j < nDim; j++)
4781 vertices[i][j] = tmp_points[i][j];
4782 }
4783
4784 *num = tmp_points.size() - 1;
4785
4786 return vertices;
4787}
4788
4799 TRACE();
4800
4801 MInt offsetStart = 0;
4802 MInt offsetEnd = 0;
4803 if(m_parallelGeometry) {
4804 offsetStart = m_segmentOffsets[segmentId];
4805 offsetEnd = m_segmentOffsets[segmentId + 1];
4806 } else {
4807 offsetStart = m_segmentOffsetsWithoutMB[segmentId];
4808 offsetEnd = m_segmentOffsetsWithoutMB[segmentId + 1];
4809 }
4810
4811 if(offsetStart == offsetEnd && !m_parallelGeometry)
4812 mTerm(1, AT_, "ERROR: You cannot choose a MB segment to calculate the characteristic Length");
4813
4814
4815 MFloat area = 0;
4816 std::array<MFloat, nDim> cross;
4817 std::array<MFloat, nDim> edge1;
4818 std::array<MFloat, nDim> edge2;
4819
4820 for(MInt i = m_segmentOffsets[segmentId]; i < m_segmentOffsets[segmentId + 1]; i++) {
4821 for(MInt j = 0; j < nDim; j++) {
4822 edge1[j] = elements[i].m_vertices[1][j] - elements[i].m_vertices[0][j];
4823 edge2[j] = elements[i].m_vertices[2][j] - elements[i].m_vertices[0][j];
4824 }
4825
4826 cross[0] = edge1[1] * edge2[2] - edge2[1] * edge1[2];
4827 cross[1] = edge1[2] * edge2[0] - edge2[2] * edge1[0];
4828 cross[2] = edge1[0] * edge2[1] - edge2[0] * edge1[1];
4829
4830 area += sqrt(cross[0] * cross[0] + cross[1] * cross[1] + cross[2] * cross[2]) / 2;
4831 }
4832
4833
4834 return area;
4835}
4836
4847MFloat Geometry3D::GetBoundarySize(MFloat* vertices, MInt* keepOffset, MInt size) {
4848 TRACE();
4849
4850 MFloat area = 0;
4851 std::array<MFloat, nDim> cross;
4852 std::array<MFloat, nDim> edge1;
4853 std::array<MFloat, nDim> edge2;
4854
4855 for(MInt i = 0; i < size; i++) {
4856 MInt off = i;
4857
4858 if(keepOffset != nullptr) off = keepOffset[i];
4859
4860 for(MInt j = 0; j < nDim; j++) {
4861 edge1[j] = vertices[off + nDim + j] - vertices[off + j];
4862 edge2[j] = vertices[off + 2 * nDim + j] - vertices[off + j];
4863 }
4864
4865 cross[0] = edge1[1] * edge2[2] - edge2[1] * edge1[2];
4866 cross[1] = edge1[2] * edge2[0] - edge2[2] * edge1[0];
4867 cross[2] = edge1[0] * edge2[1] - edge2[0] * edge1[1];
4868
4869 area += sqrt(cross[0] * cross[0] + cross[1] * cross[1] + cross[2] * cross[2]) / 2;
4870 }
4871
4872
4873 return area;
4874}
4875
4876
4878 TRACE();
4879
4880 m_log << "******************** Geometry3D statistics ********************" << endl;
4881 m_log << " Calls to getIntersectionElements: " << getIECallCounter << endl;
4882 m_log << " Comm from getIntersectionElements: " << getIECommCounter << endl;
4883 m_log << " Calls to getIntersectionElementsTetraeder: " << getIETCallCounter << endl;
4884 m_log << " Calls to getLineIntersectionElements2: " << m_getLIE2CallCounter << endl;
4885 m_log << " Comm from getLineIntersectionElements2: " << getLIE2CommCounter << endl;
4886 m_log << " Calls to edgeTriangleIntersection: " << edgeTICallCounter << endl;
4887 m_log << " Other calls in geometry3d: " << otherCalls << endl;
4888 m_log << "***************************************************************" << endl;
4889}
4890
4903void Geometry3D::determineSegmentOwnership(MInt segmentId, MInt* own, MInt* sumowners, MInt* firstOwner, MInt* owners) {
4904 TRACE();
4905
4906 *firstOwner = -1;
4907 *sumowners = 0;
4908
4909 if(m_ownSegmentId[segmentId])
4910 *own = 1;
4911 else
4912 *own = 0;
4913
4914
4915 MPI_Allgather(own, 1, MPI_INT, owners, 1, MPI_INT, mpiComm(), AT_, "own", "owners");
4916 for(MInt d = 0; d < noDomains(); d++) {
4917 if(owners[d] > 0) {
4918 if(*firstOwner < 0) *firstOwner = d;
4919 *sumowners += owners[d];
4920 }
4921 }
4922}
4923
4948 TRACE();
4949
4950 MFloat areaXY = 0.0;
4951 MFloat areaXZ = 0.0;
4952 MFloat areaYZ = 0.0;
4953 MFloat cog_tmp[3][2] = {{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}};
4954 MFloat cog[3] = {0.0, 0.0, 0.0};
4955
4956 for(MInt i = 0; i < num; i++) {
4957 MInt next = (i + 1) % num;
4958 MFloat xy = vertices[i][0] * vertices[next][1] - vertices[next][0] * vertices[i][1];
4959 MFloat xz = vertices[i][0] * vertices[next][2] - vertices[next][0] * vertices[i][2];
4960 MFloat yz = vertices[i][1] * vertices[next][2] - vertices[next][1] * vertices[i][2];
4961
4962 areaXY += xy;
4963 areaXZ += xz;
4964 areaYZ += yz;
4965
4966 cog_tmp[0][0] += (vertices[i][0] + vertices[next][0]) * xy;
4967 cog_tmp[0][1] += (vertices[i][0] + vertices[next][0]) * xz;
4968 cog_tmp[1][0] += (vertices[i][1] + vertices[next][1]) * xy;
4969 cog_tmp[1][1] += (vertices[i][1] + vertices[next][1]) * yz;
4970 cog_tmp[2][0] += (vertices[i][2] + vertices[next][2]) * xz;
4971 cog_tmp[2][1] += (vertices[i][2] + vertices[next][2]) * yz;
4972 }
4973
4974 areaXY = fabs(areaXY) * 0.5;
4975 areaXZ = fabs(areaXZ) * 0.5;
4976 areaYZ = fabs(areaYZ) * 0.5;
4977
4978 MFloat eps = 0.00000001;
4979 if(areaXY < eps) {
4980 if(areaYZ < eps) {
4981 cog[0] = 1.0 / (6.0 * areaXZ) * cog_tmp[0][1];
4982 cog[1] = vertices[0][1];
4983 cog[2] = 1.0 / (6.0 * areaXZ) * cog_tmp[2][0];
4984 } else if(areaXZ < eps) {
4985 cog[0] = vertices[0][0];
4986 cog[1] = 1.0 / (6.0 * areaYZ) * cog_tmp[1][1];
4987 cog[2] = 1.0 / (6.0 * areaYZ) * cog_tmp[2][1];
4988 } else {
4989 cog[0] = 1.0 / (6.0 * areaXZ) * cog_tmp[0][1];
4990 cog[1] = 1.0 / (6.0 * areaYZ) * cog_tmp[1][1];
4991 cog[2] = 1.0 / (6.0 * areaYZ) * cog_tmp[2][1];
4992 }
4993 } else if(areaXZ < eps) {
4994 if(areaYZ < eps) {
4995 cog[0] = 1.0 / (6.0 * areaXY) * cog_tmp[0][0];
4996 cog[1] = 1.0 / (6.0 * areaXY) * cog_tmp[1][0];
4997 cog[2] = vertices[0][2];
4998 } else {
4999 cog[0] = 1.0 / (6.0 * areaXY) * cog_tmp[0][0];
5000 cog[1] = 1.0 / (6.0 * areaYZ) * cog_tmp[1][1];
5001 cog[2] = 1.0 / (6.0 * areaYZ) * cog_tmp[2][1];
5002 }
5003 } else if(areaYZ < eps) {
5004 cog[0] = 1.0 / (6.0 * areaXZ) * cog_tmp[0][1];
5005 cog[1] = 1.0 / (6.0 * areaXY) * cog_tmp[1][0];
5006 cog[2] = 1.0 / (6.0 * areaXZ) * cog_tmp[2][0];
5007 } else {
5008 cog[0] = 1.0 / (6.0 * areaXZ) * cog_tmp[0][1];
5009 cog[1] = 1.0 / (6.0 * areaYZ) * cog_tmp[1][1];
5010 cog[2] = 1.0 / (6.0 * areaYZ) * cog_tmp[2][1];
5011 }
5012
5013 m_log << " * cog: " << cog[0] << " " << cog[1] << " " << cog[2] << endl;
5014
5015 MFloat maxRadius = 0.0;
5016
5017 for(MInt i = 0; i < num; i++) {
5018 MFloat tmp = (vertices[i][0] - cog[0]) * (vertices[i][0] - cog[0])
5019 + (vertices[i][1] - cog[1]) * (vertices[i][1] - cog[1])
5020 + (vertices[i][2] - cog[2]) * (vertices[i][2] - cog[2]);
5021
5022 if(tmp > maxRadius) maxRadius = tmp;
5023 }
5024
5025 return sqrt(maxRadius);
5026}
5027
5037 TRACE();
5038
5039 m_log << " * resizing collector: " << m_noElements << " - " << m_noElements + new_size << endl;
5040
5041 auto* tmp = new Collector<element<nDim>>(m_noElements + new_size, nDim, 0);
5042
5043 element<nDim>* fromPtr = m_elements->a;
5044 element<nDim>* toPtr = tmp->a;
5045
5046 for(MInt e = 0; e < m_noElements; e++) {
5047 tmp->append();
5048 copyElement(e, e, fromPtr, toPtr);
5049 }
5050
5051 delete m_elements;
5052 m_elements = tmp;
5053 elements = m_elements->a;
5054}
5055
5065 // TRACE();
5066
5067 m_elements->append();
5068 m_noElements++;
5069
5070 element<3>* tris = m_elements->a;
5071
5072 MInt segmentId = tri[1];
5073
5074 if(segmentId + 1 != m_noSegments)
5075 for(MInt c = m_noSegments; c > segmentId; c--) {
5077 }
5078
5079 for(MInt c = m_noSegments; c > segmentId; c--) {
5080 m_segmentOffsets[c] += 1;
5081 }
5082
5083 // insert
5084 MInt pos = m_segmentOffsets[segmentId + 1] - 1;
5085 tris[pos].m_originalId = (MInt)tri[0];
5086 tris[pos].m_segmentId = segmentId;
5087 tris[pos].m_bndCndId = (MInt)tri[2];
5088
5089 MInt j = 3;
5090 for(MInt d = 0; d < nDim; d++)
5091 tris[pos].m_normal[d] = tri[j++];
5092 for(MInt d1 = 0; d1 < nDim; d1++)
5093 for(MInt d2 = 0; d2 < nDim; d2++)
5094 tris[pos].m_vertices[d1][d2] = tri[j++];
5095
5096 tris[pos].boundingBox();
5097}
5098
5109 // TRACE();
5110 element<3>* tris = m_elements->a;
5111
5112 for(MInt d = 0; d < nDim; d++)
5113 tris[to].m_normal[d] = tris[from].m_normal[d];
5114
5115 for(MInt d1 = 0; d1 < nDim; d1++)
5116 for(MInt d2 = 0; d2 < nDim; d2++)
5117 tris[to].m_vertices[d1][d2] = tris[from].m_vertices[d1][d2];
5118
5119 for(MInt d = 0; d < 2 * nDim; d++)
5120 tris[to].m_minMax[d] = tris[from].m_minMax[d];
5121
5122 tris[to].m_segmentId = tris[from].m_segmentId;
5123 tris[to].m_bndCndId = tris[from].m_bndCndId;
5124 tris[to].m_originalId = tris[from].m_originalId;
5125}
5126
5138void Geometry3D::copyElement(MInt from, MInt to, element<3>* fromPtr, element<3>* toPtr) {
5139 // TRACE();
5140 for(MInt d = 0; d < nDim; d++)
5141 toPtr[to].m_normal[d] = fromPtr[from].m_normal[d];
5142
5143 for(MInt d1 = 0; d1 < nDim; d1++)
5144 for(MInt d2 = 0; d2 < nDim; d2++)
5145 toPtr[to].m_vertices[d1][d2] = fromPtr[from].m_vertices[d1][d2];
5146
5147 for(MInt d = 0; d < 2 * nDim; d++)
5148 toPtr[to].m_minMax[d] = fromPtr[from].m_minMax[d];
5149
5150 toPtr[to].m_segmentId = fromPtr[from].m_segmentId;
5151 toPtr[to].m_bndCndId = fromPtr[from].m_bndCndId;
5152 toPtr[to].m_originalId = fromPtr[from].m_originalId;
5153}
void mAlloc(T *&a, const MLong N, const MString &objectName, MString function)
allocates memory for one-dimensional array 'a' of size N
Definition: alloc.h:173
static MInt propertyLength(const MString &name, MInt solverId=m_noSolvers)
Returns the number of elements of a property.
Definition: context.cpp:538
static MBool propertyExists(const MString &name, MInt solver=m_noSolvers)
This function checks if a property exists in general.
Definition: context.cpp:494
virtual Collector< element< 3 > > * readSegmentsParallel()
void writeSTLMB(const char *fileName, MInt &noNodes, MInt *&nodeList) override
MBool m_GFieldInitFromSTL
Definition: geometry3d.h:113
virtual void readSegmentTrianglesBINARY_BE(MString fileName, Collector< element< 3 > > *elemCollector, MInt bndCndId, MInt segmentId, MInt *offset)
reads triangles from a BINARY file and swaps to big endian
Definition: geometry3d.cpp:631
virtual void readSegmentTrianglesBINARY_LE(MString fileName, Collector< element< 3 > > *elemCollector, MInt bndCndId, MInt segmentId, MInt *offset)
reads triangles from a BINARY file and swaps to little endian
Definition: geometry3d.cpp:717
MBool edgeTriangleIntersectionLB(MFloat *trianglePoint1, MFloat *trianglePoint2, MFloat *trianglePoint3, MFloat *edgePoint1, MFloat *edgePoint2) override
Determine intersection between an edge and a triangle.
MInt getLineIntersectionElements(MFloat *targetRegion, std::vector< MInt > &nodeList) override
Returns the ids of all elements, cut by a ray by using the perp-dot operator.
MBool m_communicateSegmentsSerial
Definition: geometry3d.h:133
void rebuildAdtTree() override
Rebuilds the ADT tree.
Definition: geometry3d.cpp:313
virtual Collector< element< 3 > > * readSegmentsSerial()
reads the segments in serial
Definition: geometry3d.cpp:855
MFloat GetBoundarySize(MInt segmentId) override
Returns the area of a segment.
virtual void countSegmentTrianglesBINARY(MString fileName, MInt *noElements)
counts the number of triangles in a BINARY STL file
Definition: geometry3d.cpp:457
void MoveAllMBElementVertex(MFloat *dx) override
virtual std::vector< std::pair< MFloat *, MFloat * > > GetUniqueSegmentEdges(MInt segmentId)
Returns unique edges of a given set segment id.
static constexpr const MInt nDim
Definition: geometry3d.h:131
MFloat ** GetBoundaryVertices(MInt segmentId, MFloat *tri_vx, MInt *keepOffsets, MInt size, MInt *num) override
This function gets all boundary vertices of an element<3> in a circular order.
void UpdateMBNormalVector(MInt e) override
Geometry3D(const MInt solverId_, const MPI_Comm comm)
MInt m_noAllTriangles
Definition: geometry3d.h:123
virtual MInt is_big_endian()
determines the CPU type big or little endian
Definition: geometry3d.cpp:608
void collectGlobalMemoryUsage() override
Definition: geometry3d.cpp:341
MInt getIETCallCounter
Definition: geometry3d.h:129
MBool edgeTriangleIntersection(MFloat *trianglePoint1, MFloat *trianglePoint2, MFloat *trianglePoint3, MFloat *edgePoint1, MFloat *edgePoint2) override
Determine intersection between an edge and a triangle.
void writeADTAndSTLToNetCDF(const char *fileName) override
MInt getIECallCounter
Definition: geometry3d.h:127
MInt m_t_geometryAll
Definition: geometry3d.h:138
MBool m_forceBoundingBox
Definition: geometry3d.h:117
virtual void correctVertexCoordinates()
MInt getLineIntersectionMBElements2(MFloat *targetRegion, MInt *spaceDirection, std::vector< MInt > &nodeList, MInt bcIc) override
MBool getLineTriangleIntersection(const MFloat *const p1, const MFloat *const p2, const MFloat radius, const MFloat *const v1, const MFloat *const v2, const MFloat *const v3, MFloat *intersection, MFloat *normal, MFloat *lambda2, MFloat *dist) override
This function determines if a line crosses a triangle.
void copyElement(MInt from, MInt to) override
Copies an element<3> from one poistion to another.
MBool getLineTriangleIntersectionSimple(MFloat *p1, MFloat *p2, MFloat *v1, MFloat *v2, MFloat *v3) override
This function determines if a line crosses a triangle.
void printMemoryUsage()
prints the current memory usage of this object
Definition: geometry3d.cpp:328
MInt getLineIntersectionElementsOld2(MFloat *targetRegion, MInt *spaceDirection, std::vector< MInt > &nodeList) override
Returns the ids of all elements, cut by a orthogonal line (or rectangular region)
MInt getIntersectionElements(MFloat *targetRegion, std::vector< MInt > &nodeList, MFloat cellHalfLength, const MFloat *const cell_coords) override
Determines all elements that are inside or intersect the target region with the separating axis theor...
virtual std::vector< std::pair< MFloat *, MFloat * > > GetUniqueSegmentEdgesParGeom(MFloat *tri_vx, MInt *keepOffsets, MInt size)
Returns unique edges of a given set segment id for parallel geometry.
MString m_gridFileName
Definition: geometry3d.h:122
MInt getSphereIntersectionMBElements(MFloat *P, MFloat radius, std::vector< MInt > &nodeList) override
MBool isEdgeAlreadyInCollection(std::vector< std::pair< MFloat *, MFloat * > > tmp_edges, MFloat *p1, MFloat *p2, MInt *pos) override
Checks if an edge given by two points is in a vector.
MInt getLIE2CommCounter
Definition: geometry3d.h:126
void addElement(MFloat *tri) override
Adds an element<3> to the collector.
void logStatistics() override
virtual void countSegmentTrianglesNETCDF(MString fileName, MInt *noElements, const MPI_Comm comm)
counts the number of triangles in a NETCDF STL file
Definition: geometry3d.cpp:485
virtual void countSegmentTrianglesASCII(MString fileName, MInt *noElements)
counts the number of triangles in an ASCII STL file
Definition: geometry3d.cpp:418
MInt m_getLIE2CallCounter
Definition: geometry3d.h:125
MInt m_levelSetIntfBndId
Definition: geometry3d.h:114
void resizeCollector(MInt new_size) override
deletes the current element<3> collector and reinitializes
virtual void readSegmentTrianglesNETCDF(MString fileName, Collector< element< 3 > > *elemCollector, MInt bndCndId, MInt segmentId, MInt *offset, const MPI_Comm comm)
reads triangles from a BINARY file
Definition: geometry3d.cpp:783
void readSTLNetCDF(const char *fileName) override
void writeParallelGeometryVTK(MString filename) override
Write the current geometry to a VTK file for parallel computation.
virtual void readSegmentTrianglesASCII(MString fileName, Collector< element< 3 > > *elemCollector, MInt bndCndId, MInt segmentId, MInt *offset)
reads triangles from an ASCII file
Definition: geometry3d.cpp:509
void calculateBoundingBox() override
Calculates the global bounding box of the geometry.
virtual MInt getIntersectionElementsTetraeder(MFloat *targetRegion, std::vector< MInt > &nodeList)
Determines all elements that are inside or intersect the target region.
void ReplaceMBElementVertex(MInt e, MInt v, MFloat *np) override
MInt m_noLevelSetIntfBndIds
Definition: geometry3d.h:116
void UpdateMBBoundingBox() override
MString m_geomFileType
Definition: geometry3d.h:121
MInt edgeTICallCounter
Definition: geometry3d.h:130
MBool getClosestLineIntersectionLength(MInt bndCndId, const std::vector< MInt > &nodeList, MFloat *targetRegion, MFloat *dist) override
MInt getIntersectionMBElements(MFloat *targetRegion, std::vector< MInt > &nodeList) override
MInt * m_levelSetIntfBndIds
Definition: geometry3d.h:115
MFloat getBndMaxRadius(MFloat **vertices, MInt num) override
This function gets the maximal radius for a boundary segment.
void UpdateADT() override
MInt getLineIntersectionMBElements(MFloat *targetRegion, std::vector< MInt > &nodeList) override
void readSegments() override
reads the STL segments from file
MBool getLineTriangleIntersectionSimpleDistance(MFloat *p1, MFloat *p2, MFloat *v1, MFloat *v2, MFloat *v3, MFloat *dist) override
This function determines if a line crosses a triangle.
virtual void swap4BytesToBE(char *buf)
swaps 4 bytes from little to big endian
Definition: geometry3d.cpp:592
MInt getIECommCounter
Definition: geometry3d.h:128
void MoveMBElementVertex(MInt e, MInt v, MFloat *dx) override
void determineSegmentOwnership(MInt segmentId, MInt *own, MInt *sumowners, MInt *firstOwner, MInt *owners) override
Determines the ownership of a segment.
MInt m_t_readGeometry
Definition: geometry3d.h:139
void writeSTL(const char *fileName) override
MInt otherCalls
Definition: geometry3d.h:111
MBool propertyExists(MString name, MInt solver)
GeometryProperty * getProperty(const MString &name, MInt segment)
MFloat ** m_vertices
MInt noDomains() const
Definition: geometry.h:47
const MFloat * boundingBox() const
Definition: geometry.h:50
MBool * m_ownSegmentId
Definition: geometry.h:222
MInt m_noAllBCs
Definition: geometry.h:199
MBool m_flowSolver
Definition: geometry.h:201
MString m_parallelGeomFileName
Definition: geometry.h:230
std::array< MFloat, 2 *nDim > m_minMax
Definition: geometry.h:187
std::vector< MInt > m_segmentOffsets
Definition: geometry.h:212
MInt m_noSegments
Definition: geometry.h:185
bodyMap m_bodyMap
Definition: geometry.h:192
Collector< element< nDim > > * m_elements
Definition: geometry.h:214
MPI_Comm mpiComm() const
Definition: geometry.h:45
element< nDim > * elements
Definition: geometry.h:215
element< nDim > * mbelements
Definition: geometry.h:218
std::vector< MInt > m_segmentOffsetsWithoutMB
Definition: geometry.h:213
MInt m_noMBElements
Definition: geometry.h:195
MInt domainId() const
Definition: geometry.h:46
void setHaloElementOffset(MInt off)
Definition: geometry.h:51
MInt * m_allBCs
Definition: geometry.h:198
bodyIterator m_bodyIt
Definition: geometry.h:193
MBool vectorsEqual(MFloat *a, MFloat *b)
Compares two vectors entry by entry.
Definition: geometry.cpp:114
GeometryContext & geometryContext()
Definition: geometry.h:48
MInt m_noElements
Definition: geometry.h:189
std::set< MInt > m_uniqueOriginalTriId
Definition: geometry.h:223
Collector< element< nDim > > * m_mbelements
Definition: geometry.h:217
std::array< MFloat, 2 *nDim > m_mbminMax
Definition: geometry.h:219
GeometryAdt< nDim > * m_adt
Definition: geometry.h:216
MBool m_parallelGeometry
Definition: geometry.h:228
MBool m_debugParGeom
Definition: geometry.h:229
MInt isRunning(const MInt timerId) const
Definition: timer.h:192
This class is a ScratchSpace.
Definition: scratch.h:758
T * getPointer() const
Deprecated: use begin() instead!
Definition: scratch.h:316
iterator begin()
Definition: scratch.h:273
MInt string2enum(MString theString)
This global function translates strings in their corresponding enum values (integer values)....
Definition: enums.cpp:20
@ NETCDF
Definition: enums.h:18
@ TOML
Definition: enums.h:18
@ BINARY
Definition: enums.h:18
@ ASCII
Definition: enums.h:18
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
constexpr Real POW2(const Real x)
Definition: functions.h:119
Real ABS(const Real x)
Definition: functions.h:85
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
constexpr T mMax(const T &x, const T &y)
Definition: functions.h:94
void tokenize(const std::string &str, ContainerT &tokens, const std::string &delimiters=" ", MBool trimEmpty=false)
Definition: functions.h:439
MInt g_t_readGeomFile
InfoOutFile m_log
std::vector< std::pair< MString, MInt > > g_tc_geometry
constexpr MLong IPOW2(MInt x)
constexpr MFloat FPOW2(MInt x)
int32_t MInt
Definition: maiatypes.h:62
std::basic_string< char > MString
Definition: maiatypes.h:55
double MFloat
Definition: maiatypes.h:52
bool MBool
Definition: maiatypes.h:58
uint_least16_t MUshort
Definition: maiatypes.h:61
uint64_t MUlong
Definition: maiatypes.h:65
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allreduce
int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm, const MString &name, const MString &varname)
same as MPI_Bcast
int MPI_Gather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Gather
int MPI_Allgather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allgather
const MInt PIO_REPLACE
Definition: parallelio.h:36
const MInt PIO_READ
Definition: parallelio.h:40
PARALLELIO_DEFAULT_BACKEND ParallelIo
Definition: parallelio.h:292
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Definition: pointbox.h:54
Definition: contexttypes.h:19
MTimers & timers()
Definition: timer.cpp:19