MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
geometry2d.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 "geometry2d.h"
8
9#include <bitset>
10#include "geometryadt.h"
11#include "geometrycontext.h"
12#include "geometryelement.h"
13#include "globals.h"
14
15using namespace std;
16
17Geometry2D::Geometry2D(const MInt solverId_, const MPI_Comm comm) : Geometry<2>(solverId_, comm) {
18 TRACE();
19
20 m_adt = 0;
21 m_elements = 0;
22 m_noElements = 0;
23
24 // moving boundary
25 m_mbelements = 0;
30 m_GFieldInitFromSTL = Context::getSolverProperty<MBool>("GFieldInitFromSTL", solverId(), AT_, &m_GFieldInitFromSTL);
31
33 m_levelSetIntfBndId = Context::getSolverProperty<MInt>("levelSetIntfBndId", solverId(), AT_, &m_levelSetIntfBndId);
34 if(Context::propertyExists("bodyBndryCndIds", solverId())
35 || Context::propertyExists("GFieldInitFromSTLBndCndIds", solverId())) {
36 const MInt noBodyBndIds = Context::propertyLength("bodyBndryCndIds", solverId());
37 const MInt noBndIds = Context::propertyLength("GFieldInitFromSTLBndCndIds", solverId());
38
39 m_noLevelSetIntfBndIds = noBodyBndIds + noBndIds;
41
42 for(MInt i = 0; i < noBodyBndIds; i++) {
43 m_levelSetIntfBndIds[i] = Context::getSolverProperty<MInt>("bodyBndryCndIds", solverId(), AT_, i);
44 if(domainId() == 0) {
45 cerr << " levelSetIntfBndIds: " << m_levelSetIntfBndIds[i] << endl;
46 }
47 }
48
49 for(MInt i = noBodyBndIds; i < m_noLevelSetIntfBndIds; i++) {
51 Context::getSolverProperty<MInt>("GFieldInitFromSTLBndCndIds", solverId(), AT_, i - noBodyBndIds);
52 if(domainId() == 0) {
53 cerr << " levelSetIntfBndIds: " << m_levelSetIntfBndIds[i] << endl;
54 }
55 }
56
57 if(domainId() == 0) {
58 cerr << " noLevelSetIntfBndIds: " << m_noLevelSetIntfBndIds << endl;
59 }
60
61 } else {
62 m_levelSetIntfBndIds = nullptr;
63 // for(MInt i=0; i < m_noLevelSetIntfBndIds; i++){
64 // m_levelSetIntfBndIds[i] = m_levelSetIntfBndId;
65 // }
66 }
67 }
68
69 MString testcaseDir = "./";
70 testcaseDir = Context::getSolverProperty<MString>("testcaseDir", solverId(), AT_, &testcaseDir);
71 MString inputDir = "./";
72 inputDir = Context::getSolverProperty<MString>("inputDir", solverId(), AT_, &inputDir);
73
74 MString tmpFileName =
75 testcaseDir + inputDir + Context::getSolverProperty<MString>("geometryInputFileName", solverId(), AT_);
76
77 if(tmpFileName.find(".toml") == MString::npos) {
78 geometryContext().readPropertyFile(NETCDF, tmpFileName.c_str());
79 } else {
80 geometryContext().readPropertyFile(TOML, tmpFileName.c_str());
81 }
84 m_adt = new GeometryAdt<2>(this);
85 m_adt->buildTree();
86
87 // moving boundary
89 m_adt->buildTreeMB();
90 }
91}
92
93/*
94 * brief: generates an auxiliary geometry from an ASCII file that can be used for whatever
95 *
96 * Thomas Schilden, December 2016
97 */
98Geometry2D::Geometry2D(const MInt solverId_, const MString filename, const MPI_Comm comm) : Geometry(solverId_, comm) {
99 TRACE();
100
101 m_log << "reading the auxiliary stl " << filename << endl;
102
104
105 m_noElements = 0;
106 m_noMBElements = 0;
107
109
110 m_log << " number of Elements: " << m_noElements << endl;
111
113
114 MInt bla = 0;
115 readSegmentLinesASCII(filename, m_elements, 0, 0, &bla);
116
117 elements = &(m_elements->a[0]);
118
120
121 m_adt = new GeometryAdt<2>(this);
122 m_adt->buildTree();
123}
124
130 TRACE();
131
132 delete m_adt;
133 delete m_elements;
134
135 if(m_mbelements) delete m_mbelements;
136}
142 TRACE();
143
144 MInt counter = 0;
145 MInt segmentId = 0;
146 MString fileName;
147 // This loop only counts all elements of all segments
148 for(m_bodyIt = m_bodyMap.begin(); m_bodyIt != m_bodyMap.end(); m_bodyIt++) {
149 // Do not create default body!
150 if(m_bodyIt->second->name != "default") {
151 for(MInt i = 0; i < m_bodyIt->second->noSegments; i++) {
152 fileName = *geometryContext().getProperty("filename", segmentId)->asString();
153 if(geometryContext().noPropertySegments("filename") == 1
154 && (m_bodyIt->second->noSegments > 1 || m_bodyMap.size() > 2)) {
155 fileName += "." + to_string(segmentId);
156 }
157 countSegmentLinesASCII(fileName, &counter);
158 m_noElements += counter;
159 segmentId++;
160 }
161 }
162 }
163
164 auto* m_allelements = new Collector<element<nDim>>(m_noElements, nDim, 0);
165 element<nDim>* allelements = m_allelements->a;
166 vector<MInt> allBCs;
167
168 segmentId = 0;
169 counter = 0;
170 // This loop reads all elements from all segments
171 for(m_bodyIt = m_bodyMap.begin(); m_bodyIt != m_bodyMap.end(); m_bodyIt++) {
172 // Do not create default body!
173 if(m_bodyIt->second->name != "default") {
174 for(MInt i = 0; i < m_bodyIt->second->noSegments; i++) {
175 m_log << " Reading Ascii coordinates from file " << endl;
176 fileName = *geometryContext().getProperty("filename", segmentId)->asString();
177 if(geometryContext().noPropertySegments("filename") == 1
178 && (m_bodyIt->second->noSegments > 1 || m_bodyMap.size() > 2)) {
179 fileName += "." + to_string(segmentId);
180 }
181 MInt bndCndId = *geometryContext().getProperty("BC", segmentId)->asInt();
182 allBCs.push_back(bndCndId);
183 readSegmentLinesASCII(fileName, m_allelements, bndCndId, segmentId, &counter);
184 segmentId++;
185 }
186 }
187 }
188 m_log << m_noElements << " line elements read. " << endl;
189
194 }
195
197 elements = m_elements->a;
198
199 MInt mbelem_counter = 0, elem_counter = 0;
200 MBool mbElem = false;
201
202 for(MInt allelem_counter = 0; allelem_counter < m_allelements->size(); allelem_counter++) {
204 for(MInt id = 0; id < m_noLevelSetIntfBndIds; id++) {
205 if(allelements[allelem_counter].m_bndCndId == m_levelSetIntfBndIds[id]) {
206 mbElem = true;
207 break;
208 }
209 }
210 if(mbElem) {
211 // LevelSet Moving boundary elements
212 m_mbelements->append();
213 for(MInt j = 0; j < 2; j++) {
214 mbelements[mbelem_counter].m_normal[j] = allelements[allelem_counter].m_normal[j];
215 for(MInt i = 0; i < 2; i++) {
216 mbelements[mbelem_counter].m_vertices[j][i] = allelements[allelem_counter].m_vertices[j][i];
217 }
218 }
219 mbelements[mbelem_counter].boundingBox();
220 mbelements[mbelem_counter].m_bndCndId = allelements[allelem_counter].m_bndCndId;
221 mbelements[mbelem_counter].m_segmentId = allelements[allelem_counter].m_segmentId;
222 mbelem_counter++;
223 mbElem = false;
224 } else {
225 // Non movable elements
226 m_elements->append();
227 for(MInt j = 0; j < 2; j++) {
228 elements[elem_counter].m_normal[j] = allelements[allelem_counter].m_normal[j];
229 for(MInt i = 0; i < 2; i++) {
230 elements[elem_counter].m_vertices[j][i] = allelements[allelem_counter].m_vertices[j][i];
231 }
232 }
233 elements[elem_counter].boundingBox();
234 elements[elem_counter].m_bndCndId = allelements[allelem_counter].m_bndCndId;
235 elements[elem_counter].m_segmentId = allelements[allelem_counter].m_segmentId;
236 elem_counter++;
237 }
238 } else {
239 if(m_GFieldInitFromSTL && (m_levelSetIntfBndId == allelements[allelem_counter].m_bndCndId)) {
240 // LevelSet Moving boundary elements
241 m_mbelements->append();
242 for(MInt i = 0; i < 2; i++) {
243 mbelements[mbelem_counter].m_normal[i] = allelements[allelem_counter].m_normal[i];
244 }
245 for(MInt j = 0; j < 2; j++) {
246 for(MInt i = 0; i < 2; i++) {
247 mbelements[mbelem_counter].m_vertices[j][i] = allelements[allelem_counter].m_vertices[j][i];
248 }
249 }
250 mbelements[mbelem_counter].boundingBox();
251 mbelements[mbelem_counter].m_bndCndId = allelements[allelem_counter].m_bndCndId;
252 mbelements[mbelem_counter].m_segmentId = allelements[allelem_counter].m_segmentId;
253 mbelem_counter++;
254 } else {
255 // Non movable elements
256 m_elements->append();
257 for(MInt i = 0; i < 2; i++) {
258 elements[elem_counter].m_normal[i] = allelements[allelem_counter].m_normal[i];
259 }
260 for(MInt j = 0; j < 2; j++) {
261 for(MInt i = 0; i < 2; i++) {
262 elements[elem_counter].m_vertices[j][i] = allelements[allelem_counter].m_vertices[j][i];
263 }
264 }
265 elements[elem_counter].boundingBox();
266 elements[elem_counter].m_bndCndId = allelements[allelem_counter].m_bndCndId;
267 elements[elem_counter].m_segmentId = allelements[allelem_counter].m_segmentId;
268 elem_counter++;
269 }
270 }
271 }
272
273 delete m_allelements;
274
276
277 m_noAllBCs = allBCs.size();
278 mAlloc(m_allBCs, m_noAllBCs, "m_allBCs", 0, AT_);
279 for(MInt i = 0; i < m_noAllBCs; i++)
280 m_allBCs[i] = allBCs[i];
281}
282
310MInt Geometry2D::getIntersectionElements(MFloat* targetRegion, std::vector<MInt>& nodeList, MFloat /*cellHalfLength*/,
311 const MFloat* const /*cell_coords*/) {
312 // TRACE();
313
314
315 MInt noReallyIntersectingNodes = 0;
316 m_adt->retrieveNodes(targetRegion, nodeList);
317 const MInt noNodes = nodeList.size();
318
319 MFloat cos_alpha, sin_alpha, length_diff;
320 MFloat diff_vec[nDim];
321
322 for(MInt i = 0; i < nDim; i++) {
323 diff_vec[i] = numeric_limits<MFloat>::max(); // gcc 4.8.2 maybe uninitialized
324 }
325
326 MFloat rot_point;
327 MFloat rot_corners[nDim];
328
329 MBool overlap[2];
330 MBool parallel;
331 MInt parallel_dim;
332
333 for(MInt n = 0; n < noNodes; n++) {
334 length_diff = 0.0;
335 parallel = false;
336 overlap[0] = false;
337 overlap[1] = false;
338
339 parallel_dim = 0;
340
341 // coordinate-axis tests
342 for(MInt i = 0; i < nDim; i++) // run over dimensions (x and y)
343 {
344 // is first point in projection of quad?
345 if(elements[nodeList[n]].m_vertices[0][i] >= targetRegion[i]
346 && elements[nodeList[n]].m_vertices[0][i] <= targetRegion[i + nDim]) {
347 overlap[i] = true;
348 continue;
349 }
350
351 // is second point in projection of quad?
352 if(elements[nodeList[n]].m_vertices[1][i] >= targetRegion[i]
353 && elements[nodeList[n]].m_vertices[1][i] <= targetRegion[i + nDim]) {
354 overlap[i] = true;
355 continue;
356 }
357
358 // do both points clasp the projection of quad?
359 if(elements[nodeList[n]].m_vertices[0][i] <= targetRegion[i]
360 && elements[nodeList[n]].m_vertices[1][i] >= targetRegion[i + nDim]) {
361 overlap[i] = true;
362 continue;
363 }
364 if(elements[nodeList[n]].m_vertices[1][i] <= targetRegion[i]
365 && elements[nodeList[n]].m_vertices[0][i] >= targetRegion[i + nDim]) {
366 overlap[i] = true;
367 continue;
368 }
369 if(!overlap[i]) break;
370 }
371
372 if(!(overlap[0] && overlap[1])) continue;
373
374 // is the line parallel to axis? Then we are done if we don't
375 for(parallel_dim = 0; parallel_dim < nDim; parallel_dim++) {
376 parallel = parallel
377 || (approx(elements[nodeList[n]].m_vertices[0][parallel_dim],
378 elements[nodeList[n]].m_vertices[1][parallel_dim], MFloatEps));
379 if(parallel) break;
380 }
381
382 if(parallel) {
383 nodeList[noReallyIntersectingNodes] = nodeList[n];
384 noReallyIntersectingNodes++;
385 } else {
386 // For the sake of simplicity rotate everything so that line becomes parallel to x-axis. Check overlapping in
387 // y-direction.
388 for(MInt i = 0; i < nDim; i++) {
389 diff_vec[i] = elements[nodeList[n]].m_vertices[1][i] - elements[nodeList[n]].m_vertices[0][i];
390 length_diff += diff_vec[i] * diff_vec[i];
391 }
392 length_diff = sqrt(length_diff);
393
394 cos_alpha = fabs(diff_vec[0]) / length_diff;
395 sin_alpha = fabs(diff_vec[1]) / length_diff;
396
397 if((diff_vec[0] * diff_vec[1]) < 0) // negative slope
398 {
399 rot_point =
400 sin_alpha * elements[nodeList[n]].m_vertices[0][0] + cos_alpha * elements[nodeList[n]].m_vertices[0][1];
401 rot_corners[0] = sin_alpha * (targetRegion[2]) + cos_alpha * (targetRegion[3]);
402 rot_corners[1] = sin_alpha * (targetRegion[0]) + cos_alpha * (targetRegion[1]);
403 } else // positive slope
404 {
405 rot_point = -1 * sin_alpha * elements[nodeList[n]].m_vertices[0][0]
406 + cos_alpha * elements[nodeList[n]].m_vertices[0][1];
407 rot_corners[0] = -1 * sin_alpha * (targetRegion[0]) + cos_alpha * (targetRegion[3]);
408 rot_corners[1] = -1 * sin_alpha * (targetRegion[2]) + cos_alpha * (targetRegion[1]);
409 }
410
411 // final cut test
412 if(rot_corners[0] >= rot_point && rot_corners[1] <= rot_point) {
413 nodeList[noReallyIntersectingNodes] = nodeList[n];
414 noReallyIntersectingNodes++;
415 }
416 }
417 }
418 nodeList.resize(noReallyIntersectingNodes);
419
420 return noReallyIntersectingNodes;
421}
422
432MInt Geometry2D::getIntersectionElements(MFloat* targetRegion, std::vector<MInt>& nodeList) {
433 // TRACE();
434
435 MInt noReallyIntersectingNodes = 0;
436 // get all candidates for an intersection
437 // Check for intersection...
438 bitset<4> points[2];
439 bitset<4> faceCodes[4];
440 bitset<4> pCode;
441
442 // Edges of the targetRegion (using targetPoints)
443 MInt rejection;
444 MBool piercePointInside;
445 MBool triviallyAccepted;
446
447 // Each of the following arrays holds one different point for
448 // all of the 6 planes. Points are built with the targetRegion
449 // i.e. a = targetRegion[pointAInPlane[0]],
450 // targetRegion[pointAInPlane[1]],
451 // etc.
452 MInt pointAInPlane[4][2] = {{0, 1}, {2, 1}, {0, 1}, {0, 3}};
453
454 MInt pointBInPlane[4][2] = {{0, 3}, {2, 3}, {2, 1}, {2, 3}};
455
456 MFloat a[2] = {numeric_limits<MFloat>::max(),
457 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // point in plane
458 MFloat b[2] = {numeric_limits<MFloat>::max(),
459 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // point in plane
460 MFloat c[2] = {numeric_limits<MFloat>::max(),
461 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // start of piercing edge
462 MFloat d[2] = {numeric_limits<MFloat>::max(),
463 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // end of piercing edge
464 MFloat s1, s2, gamma; // For pierce point calculation
465 MFloat pP[2] = {numeric_limits<MFloat>::max(),
466 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // piercePoint
467 faceCodes[0] = IPOW2(0);
468 faceCodes[1] = IPOW2(1);
469 faceCodes[2] = IPOW2(2);
470 faceCodes[3] = IPOW2(3);
471 bitset<4> result;
472
473 m_adt->retrieveNodes(targetRegion, nodeList);
474 const MInt noNodes = nodeList.size();
475 // return noNodes;
476 noReallyIntersectingNodes = 0;
477
478 for(MInt n = 0; n < noNodes; n++) {
479 // create edges (in 3D) AB, AC, BC and point A B C
480 // Determine outcode (see Aftosmis, Solution Adaptive Cartesian Grid Methods for Aerodynamic flows ...)
481
482 // Loop over all points of an element<2>
483 for(MInt p = 0; p < nDim; p++) {
484 points[p] = 0;
485 // Calculate outcode for point
486 for(MInt j = 0; j < nDim; j++) {
487 if(elements[nodeList[n]].m_vertices[p][j] < targetRegion[j]) {
488 points[p] |= faceCodes[2 * j];
489 }
490 if(elements[nodeList[n]].m_vertices[p][j] > targetRegion[j + nDim]) {
491 points[p] |= faceCodes[2 * j + 1];
492 }
493 }
494 // m_log << points[p] << endl;
495 }
496 rejection = 0;
497 // check outcode combinations for edges for trivial rejection
498 for(MInt i = 0; i < nDim; i++) {
499 if((points[0] & points[1]) != 0) {
500 rejection++;
501 break;
502 } else {
503 // If one point is inside region the element<2> is trivially accepted
504 triviallyAccepted = false;
505 for(MInt k = 0; k < nDim; k++) {
506 if(points[k] == 0) {
507 triviallyAccepted = true;
508 rejection = 0;
509 break;
510 }
511 }
512 if(triviallyAccepted) {
513 break;
514 }
515 // No trivial rejection, check for rejection of subsegment:
516 // For all pierce points!
517 // 1. Calculate pierce point:
518 // a - determine plane for pierce point calculation
519 // b - calculate pierce point
520 // 2. Check for rejection of new segment
521 // a - calculate new outcode
522 // b - check for containment in pierce planes face
523 // 3. If all(!) pierce points are rejected -> reject edge
524 // TODO labels:GEOM This algorith might get a problem if a triangle lies completely on
525 // a face.
526
527 // 1.a
528 result = (points[0] | points[1]);
529 piercePointInside = false;
530 for(MInt j = 0; j < 2 * nDim; j++) {
531 if(result[j] == 1) {
532 // pierce plane found
533 for(MInt k = 0; k < nDim; k++) {
534 a[k] = targetRegion[pointAInPlane[j][k]];
535 b[k] = targetRegion[pointBInPlane[j][k]];
536 c[k] = elements[nodeList[n]].m_vertices[0][k];
537 d[k] = elements[nodeList[n]].m_vertices[1][k];
538 }
539 gamma = (b[0] - a[0]) * (c[1] - d[1]) - (c[0] - d[0]) * (b[1] - a[1]);
540
541 s1 = ((c[0] - d[0]) * (a[1] - c[1]) - (c[1] - d[1]) * (a[0] - c[0])) / gamma;
542
543
544 s2 = ((b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1])) / gamma;
545 // 1. b Pierce point pP in plane j:
546 for(MInt k = 0; k < nDim; k++) {
547 if(s1 * s1 < s2 * s2)
548 pP[k] = c[k] + s2 * (d[k] - c[k]);
549 else
550 pP[k] = a[k] + s1 * (b[k] - a[k]);
551 }
552 pCode = 0;
553 // 2. a Calculate outcode for pierce point
554 for(MInt k = 0; k < nDim; k++) {
555 if(pP[k] < targetRegion[k]) {
556 pCode |= faceCodes[2 * k];
557 }
558 if(pP[k] > targetRegion[k + nDim]) {
559 pCode |= faceCodes[2 * k + 1];
560 }
561 }
562
563 } else {
564 continue;
565 }
566 // 2. b
567 result = faceCodes[j];
568 result.flip();
569 result = (result & pCode);
570 if(result == 0) { // -> is contained
571 piercePointInside = true;
572 break;
573 }
574 }
575 // reject if all pierce points are off coresponding face
576 // else accept
577 if(!piercePointInside) {
578 rejection++;
579 } else {
580 rejection = 0;
581 break;
582 }
583 }
584 }
585 // If not all edges are rejected a cutting element<2> has been found
586 // m_log << rejection << endl;
587 if(!rejection) {
588 nodeList[noReallyIntersectingNodes] = nodeList[n];
589 noReallyIntersectingNodes++;
590 continue;
591 }
592
593 // write nodes in reallyIntersectingNodes
594 }
595 nodeList.resize(noReallyIntersectingNodes);
596
597 return noReallyIntersectingNodes;
598}
599
605 MFloat* trianglePoint2,
606 MFloat* /*trianglePoint3*/,
607 MFloat* edgePoint1,
608 MFloat* edgePoint2) {
609 // TRACE();
610
611 MFloat a[2]; // point in plane
612 MFloat b[2]; // point in plane
613 MFloat c[2]; // start of piercing edge
614 MFloat d[2]; // end of piercing edge
615 MFloat s1, s2, gamma;
616
617
618 // Calculate the intersection between edge and triangle and check if
619 // the intersection point lies on the edge.
620
621 // pierce plane found
622 // TODO labels:GEOM why is a,b,c,d used here?
623 for(MInt k = 0; k < nDim; k++) {
624 a[k] = edgePoint1[k];
625 b[k] = edgePoint2[k];
626 c[k] = trianglePoint1[k];
627 d[k] = trianglePoint2[k];
628 }
629
630 gamma = (b[0] - a[0]) * (c[1] - d[1]) - (c[0] - d[0]) * (b[1] - a[1]);
631
632 // TODO labels:GEOM,toenhance the small number should be replaced by an eps value defined in maia.h
633#ifdef IBM_BLUE_GENE
634 if(gamma < 0.00000000001) {
635 return false;
636 }
637#endif
638
639 s1 = ((c[0] - d[0]) * (a[1] - c[1]) - (c[1] - d[1]) * (a[0] - c[0])) / gamma;
640
641 s2 = ((b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1])) / gamma;
642
643 if(s2 < 0 || s2 > 1.0 || s1 < 0 || s1 > 1.0) {
644 return false;
645 } else {
646 return true;
647 }
648}
649
654MInt Geometry2D::getLineIntersectionElements(MFloat* targetRegion, std::vector<MInt>& nodeList) {
655 // TRACE();
656
657 MInt noReallyIntersectingNodes = 0;
658
659 m_adt->retrieveNodes(targetRegion, nodeList);
660 const MInt noNodes = nodeList.size();
661
662 MFloat e1[2], e2[2];
663 for(MInt i = 0; i < nDim; i++) {
664 e1[i] = targetRegion[i];
665 e2[i] = targetRegion[i + nDim];
666 }
667
668 for(MInt n = 0; n < noNodes; n++) {
669 if(edgeTriangleIntersection(elements[nodeList[n]].m_vertices[0], elements[nodeList[n]].m_vertices[1], 0, e1, e2)) {
670 nodeList[noReallyIntersectingNodes] = nodeList[n];
671 noReallyIntersectingNodes++;
672 }
673 }
674 nodeList.resize(noReallyIntersectingNodes);
675
676 return noReallyIntersectingNodes;
677}
678
679MInt Geometry2D::getLineIntersectionElementsOld1(MFloat* targetRegion, std::vector<MInt>& nodeList) {
680 return getLineIntersectionElements(targetRegion, nodeList);
681}
682
684 std::vector<MInt>& nodeList) {
685 return getLineIntersectionElements(targetRegion, nodeList);
686}
687
688MInt Geometry2D::getIntersectionMBElements(MFloat* targetRegion, std::vector<MInt>& nodeList) {
689 // TRACE();
690
691 MInt noReallyIntersectingNodes = 0;
692 // get all candidates for an intersection
693 // Check for intersection...
694 bitset<4> points[2];
695 bitset<4> faceCodes[4];
696 bitset<4> pCode;
697
698 // Edges of the targetRegion (using targetPoints)
699 MInt rejection;
700 MBool piercePointInside;
701 MBool triviallyAccepted;
702
703 // Each of the following arrays holds one different point for
704 // all of the 6 planes. Points are built with the targetRegion
705 // i.e. a = targetRegion[pointAInPlane[0]],
706 // targetRegion[pointAInPlane[1]],
707 // etc.
708 MInt pointAInPlane[4][2] = {{0, 1}, {2, 1}, {0, 1}, {0, 3}};
709
710 MInt pointBInPlane[4][2] = {{0, 3}, {2, 3}, {2, 1}, {2, 3}};
711
712 MFloat a[2] = {numeric_limits<MFloat>::max(),
713 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // point in plane
714 MFloat b[2] = {numeric_limits<MFloat>::max(),
715 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // point in plane
716 MFloat c[2] = {numeric_limits<MFloat>::max(),
717 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // start of piercing edge
718 MFloat d[2] = {numeric_limits<MFloat>::max(),
719 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // end of piercing edge
720 MFloat s1, s2, gamma; // For pierce point calculation
721 MFloat pP[2] = {numeric_limits<MFloat>::max(),
722 numeric_limits<MFloat>::max()}; // gcc 4.8.2 maybe uninitialized // piercePoint
723 faceCodes[0] = IPOW2(0);
724 faceCodes[1] = IPOW2(1);
725 faceCodes[2] = IPOW2(2);
726 faceCodes[3] = IPOW2(3);
727 bitset<4> result;
728
729 m_adt->retrieveNodesMBElements(targetRegion, nodeList);
730 const MInt noNodes = nodeList.size();
731 // return noNodes;
732 noReallyIntersectingNodes = 0;
733
734 for(MInt n = 0; n < noNodes; n++) {
735 // create edges (in 3D) AB, AC, BC and point A B C
736 // Determine outcode (see Aftosmis, Solution Adaptive Cartesian Grid Methods for Aerodynamic flows ...)
737
738 // Loop over all points of an element<2>
739 for(MInt p = 0; p < nDim; p++) {
740 points[p] = 0;
741 // Calculate outcode for point
742 for(MInt j = 0; j < nDim; j++) {
743 if(mbelements[nodeList[n]].m_vertices[p][j] < targetRegion[j]) {
744 points[p] |= faceCodes[2 * j];
745 }
746 if(mbelements[nodeList[n]].m_vertices[p][j] > targetRegion[j + nDim]) {
747 points[p] |= faceCodes[2 * j + 1];
748 }
749 }
750 // m_log << points[p] << endl;
751 }
752 rejection = 0;
753 // check outcode combinations for edges for trivial rejection
754 for(MInt i = 0; i < nDim; i++) {
755 if((points[0] & points[1]) != 0) {
756 rejection++;
757 break;
758 } else {
759 // If one point is inside region the element<2> is trivially accepted
760 triviallyAccepted = false;
761 for(MInt k = 0; k < nDim; k++) {
762 if(points[k] == 0) {
763 triviallyAccepted = true;
764 rejection = 0;
765 break;
766 }
767 }
768 if(triviallyAccepted) {
769 break;
770 }
771 // No trivial rejection, check for rejection of subsegment:
772 // For all pierce points!
773 // 1. Calculate pierce point:
774 // a - determine plane for pierce point calculation
775 // b - calculate pierce point
776 // 2. Check for rejection of new segment
777 // a - calculate new outcode
778 // b - check for containment in pierce planes face
779 // 3. If all(!) pierce points are rejected -> reject edge
780 // TODO labels:GEOM This algorith might get a problem if a triangle lies completely on
781 // a face.
782
783 // 1.a
784 result = (points[0] | points[1]);
785 piercePointInside = false;
786 for(MInt j = 0; j < 2 * nDim; j++) {
787 if(result[j] == 1) {
788 // pierce plane found
789 for(MInt k = 0; k < nDim; k++) {
790 a[k] = targetRegion[pointAInPlane[j][k]];
791 b[k] = targetRegion[pointBInPlane[j][k]];
792 c[k] = mbelements[nodeList[n]].m_vertices[0][k];
793 d[k] = mbelements[nodeList[n]].m_vertices[1][k];
794 }
795 gamma = (b[0] - a[0]) * (c[1] - d[1]) - (c[0] - d[0]) * (b[1] - a[1]);
796
797 s1 = ((c[0] - d[0]) * (a[1] - c[1]) - (c[1] - d[1]) * (a[0] - c[0])) / gamma;
798
799
800 s2 = ((b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1])) / gamma;
801 // 1. b Pierce point pP in plane j:
802 for(MInt k = 0; k < nDim; k++) {
803 if(s1 * s1 < s2 * s2)
804 pP[k] = c[k] + s2 * (d[k] - c[k]);
805 else
806 pP[k] = a[k] + s1 * (b[k] - a[k]);
807 }
808 pCode = 0;
809 // 2. a Calculate outcode for pierce point
810 for(MInt k = 0; k < nDim; k++) {
811 if(pP[k] < targetRegion[k]) {
812 pCode |= faceCodes[2 * k];
813 }
814 if(pP[k] > targetRegion[k + nDim]) {
815 pCode |= faceCodes[2 * k + 1];
816 }
817 }
818
819 } else {
820 continue;
821 }
822 // 2. b
823 result = faceCodes[j];
824 result.flip();
825 result = (result & pCode);
826 if(result == 0) { // -> is contained
827 piercePointInside = true;
828 break;
829 }
830 }
831 // reject if all pierce points are off coresponding face
832 // else accept
833 if(!piercePointInside) {
834 rejection++;
835 } else {
836 rejection = 0;
837 break;
838 }
839 }
840 }
841 // If not all edges are rejected a cutting element<2> has been found
842 // m_log << rejection << endl;
843 if(!rejection) {
844 nodeList[noReallyIntersectingNodes] = nodeList[n];
845 noReallyIntersectingNodes++;
846 continue;
847 }
848
849 // write nodes in reallyIntersectingNodes
850 }
851 nodeList.resize(noReallyIntersectingNodes);
852
853 return noReallyIntersectingNodes;
854}
855
856MInt Geometry2D::getLineIntersectionMBElements(MFloat* targetRegion, std::vector<MInt>& nodeList) {
857 // TRACE();
858
859 MInt noReallyIntersectingNodes = 0;
860
861 m_adt->retrieveNodesMBElements(targetRegion, nodeList);
862 const MInt noNodes = nodeList.size();
863
864 MFloat e1[2], e2[2];
865 for(MInt i = 0; i < nDim; i++) {
866 e1[i] = targetRegion[i];
867 e2[i] = targetRegion[i + nDim];
868 }
869
870 for(MInt n = 0; n < noNodes; n++) {
871 if(edgeTriangleIntersection(mbelements[nodeList[n]].m_vertices[0], mbelements[nodeList[n]].m_vertices[1], 0, e1,
872 e2)) {
873 nodeList[noReallyIntersectingNodes] = nodeList[n];
874 noReallyIntersectingNodes++;
875 }
876 }
877 nodeList.resize(noReallyIntersectingNodes);
878
879 return noReallyIntersectingNodes;
880}
881
882
883MInt Geometry2D::getSphereIntersectionMBElements(MFloat* P, MFloat radius, std::vector<MInt>& nodeList) {
884 // TRACE();
885
886 MInt noReallyIntersectingNodes = 0;
887
888 // compute minimum target region that contains the sphere:
889 MFloat target[4] = {0, 0, 0, 0};
890 MFloat enlargeFactor = 1.05;
891 for(MInt i = 0; i < nDim; i++) {
892 target[i] = P[i] - radius * enlargeFactor;
893 target[i + nDim] = P[i] + radius * enlargeFactor;
894 }
895
896 // fetch all possibly intersecting triangles in this region:
897 m_adt->retrieveNodesMBElements(target, nodeList);
898 const MInt noNodes = nodeList.size();
899
900 MFloat A[2], B[2], AB[2], Q1[2];
901
902 // loop over all elements
903 for(MInt n = 0; n < noNodes; n++) {
904 // store the vertices of the current element<2> in A, B, C:
905 for(MInt i = 0; i < nDim; i++) {
906 A[i] = mbelements[nodeList[n]].m_vertices[0][i];
907 B[i] = mbelements[nodeList[n]].m_vertices[1][i];
908 }
909
910 // compute separation algorithm from http://realtimecollisiondetection.net/blog/?p=103:
911 for(MInt i = 0; i < nDim; i++) {
912 A[i] = A[i] - P[i];
913 B[i] = B[i] - P[i];
914 AB[i] = B[i] - A[i];
915 }
916 MFloat rr = radius * radius;
917 MFloat aa = F0;
918 MFloat ab = F0;
919 MFloat bb = F0;
920 MFloat e1 = F0;
921 for(MInt i = 0; i < nDim; i++) {
922 aa += A[i] * A[i];
923 ab += A[i] * B[i];
924 bb += B[i] * B[i];
925 e1 += AB[i] * AB[i];
926 }
927 MBool sep2 = (aa > rr) && (ab > aa);
928 MBool sep3 = (bb > rr) && (ab > bb);
929 MFloat d1 = ab - aa;
930 MFloat qq1 = F0;
931 for(MInt i = 0; i < nDim; i++) {
932 Q1[i] = A[i] * e1 - d1 * AB[i];
933 qq1 += Q1[i] * Q1[i];
934 }
935 MBool sep5 = (qq1 > rr * e1 * e1);
936
937 MBool separated = sep2 || sep3 || sep5;
938
939 if(!separated) {
940 nodeList[noReallyIntersectingNodes] = nodeList[n];
941 noReallyIntersectingNodes++;
942 }
943 }
944 nodeList.resize(noReallyIntersectingNodes);
945
946 return noReallyIntersectingNodes;
947}
948
949
951 TRACE();
952
953 for(MInt e = 0; e < m_noMBElements; e++) {
954 for(MInt j = 0; j < nDim; j++) {
955 for(MInt i = 0; i < nDim; i++) {
956 mbelements[e].m_vertices[j][i] += dx[i];
957 }
958 }
959 }
960}
961
963 TRACE();
964
965 for(MInt i = 0; i < nDim; i++) {
966 mbelements[e].m_vertices[v][i] += dx[i];
967 }
968}
969
971 TRACE();
972
973 for(MInt i = 0; i < nDim; i++)
974 mbelements[e].m_vertices[v][i] = np[i];
975}
976
978 TRACE();
979
980 for(MInt e = 0; e < m_mbelements->size(); e++) {
981 mbelements[e].boundingBox();
982 }
983 for(MInt j = 0; j < nDim; j++) {
984 m_mbminMax[j] = mbelements[0].m_minMax[j];
985 m_mbminMax[j + nDim] = mbelements[0].m_minMax[j + nDim];
986 }
987 for(MInt i = 0; i < m_mbelements->size(); i++) {
988 for(MInt j = 0; j < nDim; j++) {
989 m_mbminMax[j + nDim] = (m_mbminMax[j + nDim] < mbelements[i].m_minMax[j + nDim])
990 ? mbelements[i].m_minMax[j + nDim]
991 : m_mbminMax[j + nDim];
992 m_mbminMax[j] = (m_mbminMax[j] > mbelements[i].m_minMax[j]) ? mbelements[i].m_minMax[j] : m_mbminMax[j];
993 }
994 }
995}
996
998 TRACE();
999
1000 m_adt->buildTreeMB();
1001}
1002
1012inline void Geometry2D::countSegmentLinesASCII(const MString& fileName, MInt* noElements) {
1013 TRACE();
1014
1015 *noElements = 0;
1016
1017 m_log << " Counting segment file: " << fileName << endl;
1018
1019 ifstream ifl(fileName);
1020 if(!ifl) {
1021 stringstream errorMessage;
1022 errorMessage << " ERROR in segment::readSegment (counting loop), couldn't find file : " << fileName << "!";
1023 mTerm(1, AT_, errorMessage.str());
1024 }
1025 // If number of elements unknown, count them...
1026 ifl >> (*noElements);
1027 ifl.close();
1028 (*noElements)--; // The ascii files contain the points(!) not the elements
1029 m_log << " number of vertices = " << *noElements << endl;
1030}
1031
1041inline void Geometry2D::readSegmentLinesASCII(MString fileName, Collector<element<2>>* elemCollector, MInt bndCndId,
1042 MInt segmentId, MInt* offset) {
1043 TRACE();
1044 m_log << " Reading segment file: " << fileName << endl;
1045 m_log << " BC : " << bndCndId << endl;
1046
1047
1048 ifstream ifl(fileName);
1049 if(!ifl) {
1050 stringstream errorMessage;
1051 errorMessage << " ERROR in segment::readSegment (reading loop), couldn't find file : " << fileName << "!";
1052 mTerm(1, AT_, errorMessage.str());
1053 }
1054
1055 element<2>* allelements = elemCollector->a;
1056
1057 // Read no of coordinates
1058 MInt tmp;
1059 ifl >> tmp;
1060 elemCollector->append();
1061 for(MInt j = 0; j < 2; j++) {
1062 ifl >> allelements[*offset].m_vertices[0][j];
1063 allelements[*offset].m_normal[j] = F0;
1064 }
1065 MInt fileElementCounter = 0;
1066 while(!ifl.eof()) {
1067 // Read coordinates
1068 for(MInt j = 0; j < 2; j++) {
1069 ifl >> allelements[*offset].m_vertices[1][j];
1070 allelements[*offset].m_normal[j] = F0;
1071 }
1072 allelements[*offset].boundingBox();
1073 allelements[*offset].m_bndCndId = bndCndId;
1074 allelements[*offset].m_segmentId = segmentId;
1076 for(MInt id = 0; id < m_noLevelSetIntfBndIds; id++) {
1077 if(bndCndId == m_levelSetIntfBndIds[id]) {
1079 }
1080 }
1081 }
1082
1083 if(m_noElements > 1000 && !((*offset) % (m_noElements / 10))) {
1084 m_log << (MInt)(((*offset) - 1) / ((MFloat)m_noElements / 100)) + 1 << " % read." << endl;
1085 }
1086 fileElementCounter++;
1087 (*offset)++;
1088 // Check if already all points read
1089 if(fileElementCounter < tmp - 1) { // set start point of next line
1090 elemCollector->append();
1091 for(MInt j = 0; j < 2; j++) {
1092 allelements[*offset].m_vertices[0][j] = allelements[(*offset) - 1].m_vertices[1][j];
1093 allelements[*offset].m_normal[j] = F0;
1094 }
1095 } else { // If all points read leave loop
1096 break;
1097 }
1098 }
1099 ifl.close();
1100}
1101
1109 TRACE();
1110
1111 // Calculate bounding box of segment
1112 for(MInt j = 0; j < nDim; j++) {
1113 m_minMax[j] = elements[0].m_minMax[j];
1114 m_minMax[j + nDim] = elements[0].m_minMax[j + nDim];
1115 }
1116 for(MInt i = 0; i < m_noElements; i++) {
1117 for(MInt j = 0; j < nDim; j++) {
1118 m_minMax[j + nDim] =
1119 (m_minMax[j + nDim] < elements[i].m_minMax[j + nDim]) ? elements[i].m_minMax[j + nDim] : m_minMax[j + nDim];
1120 m_minMax[j] = (m_minMax[j] > elements[i].m_minMax[j]) ? elements[i].m_minMax[j] : m_minMax[j];
1121 }
1122 }
1123 m_log << " Bounding box for segment :" << endl;
1124 m_log << " max = ";
1125 for(MInt i = 0; i < nDim; i++) {
1126 m_log << m_minMax[i + nDim] << " ";
1127 }
1128 m_log << endl;
1129
1130 m_log << " min = ";
1131 for(MInt i = 0; i < nDim; i++) {
1132 m_log << m_minMax[i] << " ";
1133 }
1134 m_log << endl;
1135
1137 // Calculate bounding box of Moving Boundary segment
1139 m_log << " Bounding box for Moving Boundary segment:" << endl;
1140 m_log << " max = ";
1141 for(MInt i = 0; i < nDim; i++) {
1142 m_log << m_mbminMax[i + nDim] << " ";
1143 }
1144 m_log << endl;
1145 m_log << " min = ";
1146 for(MInt i = 0; i < nDim; i++) {
1147 m_log << m_mbminMax[i] << " ";
1148 }
1149 m_log << endl;
1150 }
1151}
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
void readSegmentLinesASCII(MString fileName, Collector< element< 2 > > *elemCollector, MInt bndCndId, MInt segmentId, MInt *offset)
reads the lines in an ASCII file
virtual MBool edgeTriangleIntersection(MFloat *trianglePoint1, MFloat *trianglePoint2, MFloat *trianglePoint3, MFloat *edgePoint1, MFloat *edgePoint2)
Determine intersection between an edge and a triangle (in 2D between 2 edges)
Definition: geometry2d.cpp:604
MBool m_GFieldInitFromSTL
Definition: geometry2d.h:47
Geometry2D(const MInt solverId_, const MPI_Comm comm)
Definition: geometry2d.cpp:17
virtual MInt getLineIntersectionElementsOld1(MFloat *targetRegion, std::vector< MInt > &nodeList)
Definition: geometry2d.cpp:679
virtual MInt getIntersectionMBElements(MFloat *targetRegion, std::vector< MInt > &nodeList)
Definition: geometry2d.cpp:688
virtual void ReplaceMBElementVertex(MInt e, MInt v, MFloat *np)
Definition: geometry2d.cpp:970
void calculateBoundingBox()
Calculates the global bounding box of the geometry.
static constexpr const MInt nDim
Definition: geometry2d.h:52
MInt m_noLevelSetIntfBndIds
Definition: geometry2d.h:50
virtual void MoveAllMBElementVertex(MFloat *dx)
Definition: geometry2d.cpp:950
virtual MInt getSphereIntersectionMBElements(MFloat *P, MFloat radius, std::vector< MInt > &nodeList)
Definition: geometry2d.cpp:883
virtual MInt getLineIntersectionMBElements(MFloat *targetRegion, std::vector< MInt > &nodeList)
Definition: geometry2d.cpp:856
virtual void UpdateMBBoundingBox()
Definition: geometry2d.cpp:977
MInt m_levelSetIntfBndId
Definition: geometry2d.h:48
virtual void readSegments()
Definition: geometry2d.cpp:141
virtual void UpdateADT()
Definition: geometry2d.cpp:997
virtual MInt getLineIntersectionElementsOld2(MFloat *targetRegion, MInt *spaceDirection, std::vector< MInt > &nodeList)
Definition: geometry2d.cpp:683
virtual MInt getLineIntersectionElements(MFloat *targetRegion, std::vector< MInt > &nodeList)
Returns the ids of all elements, cut by a orthogonal line (or rectangular region)
Definition: geometry2d.cpp:654
virtual void MoveMBElementVertex(MInt e, MInt v, MFloat *dx)
Definition: geometry2d.cpp:962
void countSegmentLinesASCII(const MString &fileName, MInt *noElements)
counts the number of lines in an ASCII file, should be the in the first line
MInt * m_levelSetIntfBndIds
Definition: geometry2d.h:49
virtual MInt getIntersectionElements(MFloat *targetRegion, std::vector< MInt > &nodeList)
Determines all elements that are inside or intersect the target region.
Definition: geometry2d.cpp:432
GeometryProperty * getProperty(const MString &name, MInt segment)
void readPropertyFile(FileType, const MChar *fileName)
MFloat ** m_vertices
MInt solverId() const
Definition: geometry.h:44
MInt m_noAllBCs
Definition: geometry.h:199
std::array< MFloat, 2 *nDim > m_minMax
Definition: geometry.h:187
bodyMap m_bodyMap
Definition: geometry.h:192
Collector< element< nDim > > * m_elements
Definition: geometry.h:214
element< nDim > * elements
Definition: geometry.h:215
element< nDim > * mbelements
Definition: geometry.h:218
MInt m_noMBElements
Definition: geometry.h:195
MInt domainId() const
Definition: geometry.h:46
MInt * m_allBCs
Definition: geometry.h:198
bodyIterator m_bodyIt
Definition: geometry.h:193
GeometryContext & geometryContext()
Definition: geometry.h:48
MInt m_noElements
Definition: geometry.h:189
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
@ NETCDF
Definition: enums.h:18
@ TOML
Definition: enums.h:18
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
InfoOutFile m_log
constexpr MLong IPOW2(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
Definition: contexttypes.h:19