MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
fcbndrycnd.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 "fcbndrycnd.h"
8#include "fcsolver.h"
9
10#include <algorithm>
11#include <fstream>
12#include <iostream>
13#include <set>
14#include "COMM/mpioverride.h"
16#include "IO/context.h"
17#include "IO/infoout.h"
18#include "fcgridbndrycell.h"
19#include "property.h"
20
21using namespace std;
22
23template <MInt nDim>
25 : m_solverId(solver->m_solverId), m_noInternalCells(solver->grid().noInternalCells()) {
26 TRACE();
27
28 m_solver = solver;
29
30 // the number of all segments
31 m_noSegments = m_solver->m_geometry->geometryContext().getNoSegments();
32
40 m_kFactor = 1e+12;
41 m_kFactor = Context::getSolverProperty<MFloat>("kFactor", m_solverId, AT_, &m_kFactor);
42
50 if(Context::propertyExists("subCellLayerDepth", m_solverId)) {
51 mAlloc(m_subCellLayerDepth, m_noSegments, "m_subCellLayerDepth", 0, AT_);
52 for(MInt i = 0; i < m_noSegments; i++) {
53 m_subCellLayerDepth[i] = Context::getSolverProperty<MInt>("subCellLayerDepth", m_solverId, AT_, i);
54 }
55 }
56
57 // the number of cells that carry a certain boundary condition
58 mAlloc(m_noBndryCellsPerSegment, m_noSegments, "m_noBndryCellsPerSegment", 0, AT_);
59
71 m_multiBC = true;
72 m_multiBC = Context::getSolverProperty<MBool>("multiBC", m_solverId, AT_, &m_multiBC);
73 if(!m_multiBC) mTerm(1, AT_, "m_multiBC is set to false, bc functions are not adapted to this input.");
74
87 m_bndryNormalMethod = "read";
88 m_bndryNormalMethod = Context::getSolverProperty<MString>("bndryNormalMethod", m_solverId, AT_, &m_bndryNormalMethod);
89 if(m_bndryNormalMethod != "read")
90 mTerm(1, AT_, "m_bndryNormalMethod is not \"read\", bc functions are not adapted to this input.");
91
93 createBoundaryCells();
94 sortBoundaryCells();
95
96 setBndryCndHandler();
97
98 initBndryCnds();
99
100 findCellsRequireSubCellIntegration();
101
102 calculateCutPoints();
103
104 for(MInt i = 0; i < (MInt)m_bndryCndSegIds.size(); i++) {
105 if(m_solver->m_testRun) {
106 writeOutSTLBoundaries(i, "preSimulation");
107 }
108 calcAvgFaceNormal(i);
109 }
110}
111
112template <MInt nDim>
114 TRACE();
115
116 // Clean up allocated memory
117 mDeallocate(m_noBndryCellsPerSegment);
118}
119
132template <MInt nDim>
134 TRACE();
135
136 for(MInt i = 0; i < (MInt)(m_bndryCndSegIds.size()); i++) {
137 MInt seg_id = m_bndryCndSegIds[i];
138 MInt bc_id = m_bndryCndIds[i];
139
140 ostringstream ostrSegId;
141 ostrSegId << seg_id;
142 MString strSegId = ostrSegId.str();
143
144 MString name = "";
145 // Read bc specific properties
146 switch(bc_id) {
147 case 0: {
148 break;
149 }
150 case 8010: {
151 name = "segFixationDirs_";
152 name.append(strSegId);
153 MFloat dir[nDim] = {F0};
154 for(MInt d = 0; d < nDim; d++) {
155 dir[d] = Context::getSolverProperty<MFloat>(name, m_solverId, AT_, d);
156 }
157 for(MInt j = m_bndryCndOffsets[i]; j < m_bndryCndOffsets[i + 1]; j++) {
158 for(MInt d = 0; d < nDim; d++) {
159 m_bndryCells[j].m_directionOfAction[d] = dir[d];
160 }
161 }
162 break;
163 }
164 case 8011: {
165 name = "segFixationDirs_";
166 name.append(strSegId);
167 MFloat dir[nDim] = {F0};
168 for(MInt d = 0; d < nDim; d++) {
169 dir[d] = Context::getSolverProperty<MFloat>(name, m_solverId, AT_, d);
170 }
171 for(MInt j = m_bndryCndOffsets[i]; j < m_bndryCndOffsets[i + 1]; j++) {
172 for(MInt d = 0; d < nDim; d++) {
173 m_bndryCells[j].m_directionOfAction[d] = dir[d];
174 }
175 }
176 break;
177 }
178 case 8012: {
179 name = "segFixationDirs_";
180 name.append(strSegId);
181 MFloat dir[nDim] = {F0};
182 for(MInt d = 0; d < nDim; d++) {
183 dir[d] = Context::getSolverProperty<MFloat>(name, m_solverId, AT_, d);
184 }
185 for(MInt j = m_bndryCndOffsets[i]; j < m_bndryCndOffsets[i + 1]; j++) {
186 for(MInt d = 0; d < nDim; d++) {
187 m_bndryCells[j].m_directionOfAction[d] = dir[d];
188 }
189 }
190 break;
191 }
192 case 8020: {
193 break;
194 }
195 case 8030: {
196 name = "segLoadDirs_";
197 name.append(strSegId);
198 MFloat dir[nDim] = {F0};
199 for(MInt d = 0; d < nDim; d++) {
200 dir[d] = Context::getSolverProperty<MFloat>(name, m_solverId, AT_, d);
201 }
202 for(MInt j = m_bndryCndOffsets[i]; j < m_bndryCndOffsets[i + 1]; j++) {
203 for(MInt d = 0; d < nDim; d++) {
204 m_bndryCells[j].m_directionOfAction[d] = dir[d];
205 }
206 }
207 name = "segLoadValue_";
208 name.append(strSegId);
209 MFloat load[nDim] = {F0};
210 for(MInt d = 0; d < nDim; d++) {
211 load[d] = Context::getSolverProperty<MFloat>(name, m_solverId, AT_, d);
212 }
213 for(MInt j = m_bndryCndOffsets[i]; j < m_bndryCndOffsets[i + 1]; j++) {
214 for(MInt d = 0; d < nDim; d++) {
215 m_bndryCells[j].m_load[d] = load[d];
216 }
217 }
218 break;
219 }
220 case 8031: {
221 name = "segLoadDirs_";
222 name.append(strSegId);
223 MFloat dir[nDim] = {F0};
224 for(MInt d = 0; d < nDim; d++) {
225 dir[d] = Context::getSolverProperty<MFloat>(name, m_solverId, AT_, d);
226 }
227 for(MInt j = m_bndryCndOffsets[i]; j < m_bndryCndOffsets[i + 1]; j++) {
228 for(MInt d = 0; d < nDim; d++) {
229 m_bndryCells[j].m_directionOfAction[d] = dir[d];
230 }
231 }
232 name = "segLoadValue_";
233 name.append(strSegId);
234 MFloat load[nDim] = {F0};
235 for(MInt d = 0; d < nDim; d++) {
236 load[d] = Context::getSolverProperty<MFloat>(name, m_solverId, AT_, d);
237 }
238 for(MInt j = m_bndryCndOffsets[i]; j < m_bndryCndOffsets[i + 1]; j++) {
239 for(MInt d = 0; d < nDim; d++) {
240 m_bndryCells[j].m_load[d] = load[d];
241 }
242 }
243 break;
244 }
245 case 8032: {
246 name = "segLoadDirs_";
247 name.append(strSegId);
248 MFloat dir[nDim] = {F0};
249 for(MInt d = 0; d < nDim; d++) {
250 dir[d] = Context::getSolverProperty<MFloat>(name, m_solverId, AT_, d);
251 }
252 for(MInt j = m_bndryCndOffsets[i]; j < m_bndryCndOffsets[i + 1]; j++) {
253 for(MInt d = 0; d < nDim; d++) {
254 m_bndryCells[j].m_directionOfAction[d] = dir[d];
255 }
256 }
257 name = "segLoadValue_";
258 name.append(strSegId);
259 MFloat load[nDim] = {F0};
260 for(MInt d = 0; d < nDim; d++) {
261 load[d] = Context::getSolverProperty<MFloat>(name, m_solverId, AT_, d);
262 }
263 for(MInt j = m_bndryCndOffsets[i]; j < m_bndryCndOffsets[i + 1]; j++) {
264 for(MInt d = 0; d < nDim; d++) {
265 m_bndryCells[j].m_load[d] = load[d];
266 }
267 }
268 break;
269 }
270 case 8035: {
271 name = "segLoadDirs_";
272 name.append(strSegId);
273 MFloat dir[nDim] = {F0};
274 for(MInt d = 0; d < nDim; d++) {
275 dir[d] = Context::getSolverProperty<MFloat>(name, m_solverId, AT_, d);
276 }
277 for(MInt j = m_bndryCndOffsets[i]; j < m_bndryCndOffsets[i + 1]; j++) {
278 for(MInt d = 0; d < nDim; d++) {
279 m_bndryCells[j].m_directionOfAction[d] = dir[d];
280 }
281 }
282 name = "segLoadValue_";
283 name.append(strSegId);
284 MFloat load[nDim] = {F0};
285 for(MInt d = 0; d < nDim; d++) {
286 load[d] = Context::getSolverProperty<MFloat>(name, m_solverId, AT_, d);
287 }
288 for(MInt j = m_bndryCndOffsets[i]; j < m_bndryCndOffsets[i + 1]; j++) {
289 for(MInt d = 0; d < nDim; d++) {
290 m_bndryCells[j].m_load[d] = load[d];
291 }
292 }
293 break;
294 }
295 default: {
296 mTerm(1, AT_, "Unknown boundary condition id!");
297 }
298 }
299 }
300}
301
321template <MInt nDim>
323 TRACE();
324
325 MInt noMultiCells = 0; // Number of cells with multiple BCs
326
327 MInt bndryCellsIt = 0, bndryCellsIt2 = 0;
328
329 m_log << " + Creating boundary cells..." << endl;
330 m_log << " - Multiple BC usage: " << m_multiBC << endl;
331
332 for(MInt i = 0; i < m_solver->m_cells.size(); i++) {
333 if(!m_solver->c_isLeafCell(i)) continue;
334
335 std::vector<MInt> nodeList;
336 getStlNodeList(i, nodeList);
337
338 const MInt noNodes = (MInt)nodeList.size();
339 if(noNodes > 0) {
340 m_solver->a_isBndryCell(i) = true;
341
342 // Create a new boundary cell for our found cuts
343 m_bndryCells.emplace_back();
344
345 bndryCellsIt = m_bndryCells.size() - 1;
346 m_bndryCells[bndryCellsIt].m_cellId = i;
347
348 // Fill the segmentIds of the boundary cell
349 // and the associated bndryCndId
350 for(MInt j = 0; j < noNodes; j++) {
351 MBool already_in = false;
352 MInt segId = m_solver->m_geometry->elements[nodeList[j]].m_segmentId;
353 MInt bndId = m_solver->m_geometry->elements[nodeList[j]].m_bndCndId;
354 for(MInt k = 0; k < (MInt)(m_bndryCells[bndryCellsIt].m_segmentId.size()); k++) {
355 if(m_bndryCells[bndryCellsIt].m_segmentId[k] == segId) {
356 already_in = true;
357 break;
358 }
359 }
360 if(!already_in) {
361 m_bndryCells[bndryCellsIt].m_segmentId.push_back(segId);
362 m_bndryCells[bndryCellsIt].m_bndryCndId.push_back(bndId);
363 }
364 }
365
366 if(m_bndryCells[bndryCellsIt].m_segmentId.size() > 1) {
367 noMultiCells++;
368 if(m_multiBC) {
369 // Add the bndryCell n more times
371 // No sorting of segmentIds is applied.
372
373 bndryCellsIt2 = bndryCellsIt;
374 for(MInt j = 1; j < (MInt)(m_bndryCells[bndryCellsIt].m_segmentId.size()); j++) {
375 // make sure that bndryCells are only added if there is another bc
376 MInt bndId = m_bndryCells[bndryCellsIt].m_bndryCndId[j];
377 MInt segId = m_bndryCells[bndryCellsIt].m_segmentId[j];
378
379 bndryCellsIt2++;
380 m_bndryCells.emplace_back(); // add new bndryCell
381 m_bndryCells[bndryCellsIt2].m_cellId = i;
382
383 m_bndryCells[bndryCellsIt2].m_segmentId.push_back(segId);
384 m_bndryCells[bndryCellsIt2].m_bndryCndId.push_back(bndId);
385 }
386 }
387 }
388 }
389 }
390 m_log << " - noBndCells: " << m_bndryCells.size() << endl;
391 m_log << " - noMultiCells: " << noMultiCells << endl << endl;
392}
393
404template <MInt nDim>
406 TRACE();
407
408 // Sort the boundary cells
409 const MInt tmpCellSize = m_bndryCells.size();
410
411 m_log << " + Sorting boundary cells..." << endl;
412 m_log << " - no. boundary cells: " << tmpCellSize << endl;
413
414 // using stable_sort to preserve the order by cellId within segmentIds
415 stable_sort(m_bndryCells.begin(), m_bndryCells.end(), //
416 [](auto a, auto b) { return a.m_segmentId[0] < b.m_segmentId[0]; });
417
418 MInt tmpSegmentId = -1; // holds the current id
419 MInt tmpBndryCndId = -1; // holds the current boundary cells bndryCndId
420 MInt counter = 0; // Counts the boundary cells
421
422 m_mapBndryCndSegId2Index.resize(m_noSegments, -1);
423
424 for(MInt i = 0; i < tmpCellSize; i++) {
425 if(tmpSegmentId != m_bndryCells[i].m_segmentId[0]) {
426 // Since bndryCells has been sorted previously and new segmentid differs
427 // from tmpSegmentId, we sort now for a new tmpSegmentId and co
428 tmpSegmentId = m_bndryCells[i].m_segmentId[0];
429 tmpBndryCndId = m_bndryCells[i].m_bndryCndId[0];
430
431 m_bndryCndIds.push_back(tmpBndryCndId);
432 m_bndryCndOffsets.push_back(counter);
433 m_bndryCndSegIds.push_back(tmpSegmentId);
434 m_mapBndryCndSegId2Index[tmpSegmentId] = m_bndryCndSegIds.size() - 1;
435 }
436 m_noBndryCellsPerSegment[tmpSegmentId]++;
437 m_solver->a_isBndryCell(m_bndryCells[counter].m_cellId) = true;
438 m_solver->a_bndId(m_bndryCells[counter].m_cellId) = counter;
439
440 counter++;
441 }
442
443 m_bndryCndOffsets.push_back(counter);
444
445 for(MInt i = 0; i < (MInt)(m_bndryCndSegIds.size()); i++) {
446 MInt seg_id = m_bndryCndSegIds[i];
447
448 m_log << " - BC " << m_bndryCndIds[i] << endl;
449 m_log << " * index: " << i << endl;
450 m_log << " * segment id: " << seg_id << endl;
451 m_log << " * no cells: " << m_noBndryCellsPerSegment[seg_id] << endl;
452 m_log << " * offsets: " << m_bndryCndOffsets[i] << " - " << m_bndryCndOffsets[i + 1] - 1 << endl;
453 }
454 m_log << endl;
455}
456
463template <MInt nDim>
465 TRACE();
466
467 m_log << " + Setting the boundary condition handler..." << endl << endl;
468
469 // Allocate space for pointer lists which store the boundary functions
470 bndryCndHandlerSystemMatrix = new BndryCndHandler[m_bndryCndIds.size()];
471 bndryCndHandlerForce = new BndryCndHandler[m_bndryCndIds.size()];
472
473 // Fill the function pointer lists with correct bc functions
474 for(MInt i = 0; i < (MInt)(m_bndryCndIds.size()); i++) {
475 switch(m_bndryCndIds[i]) {
476 case 0:
477 bndryCndHandlerSystemMatrix[i] = &FcBndryCnd::bc0;
478 bndryCndHandlerForce[i] = &FcBndryCnd::bc0;
479 break;
480
481 //----------------------------------------------------
482 // fixation boundary conditions
483 case 8010:
484 bndryCndHandlerSystemMatrix[i] = &FcBndryCnd::bc8010;
485 bndryCndHandlerForce[i] = &FcBndryCnd::bc0;
486 break;
487
488 //----------------------------------------------------
489 // fixation boundary conditions
490 case 8011:
491 bndryCndHandlerSystemMatrix[i] = &FcBndryCnd::bc8011;
492 bndryCndHandlerForce[i] = &FcBndryCnd::bc0;
493 break;
494
495 //----------------------------------------------------
496 // fixation boundary conditions
497 case 8012:
498 bndryCndHandlerSystemMatrix[i] = &FcBndryCnd::bc8012;
499 bndryCndHandlerForce[i] = &FcBndryCnd::bc0;
500 break;
501
502 //----------------------------------------------------
503 // displacement boundary conditions
504 case 8020:
505 bndryCndHandlerSystemMatrix[i] = &FcBndryCnd::bc8020;
506 bndryCndHandlerForce[i] = &FcBndryCnd::bc0;
507 break;
508
509 //----------------------------------------------------
510 // imposed loads boundary conditions
511 case 8030:
512 bndryCndHandlerSystemMatrix[i] = &FcBndryCnd::bc0;
513 bndryCndHandlerForce[i] = &FcBndryCnd::bc8030;
514 break;
515
516 //----------------------------------------------------
517 // imposed loads boundary conditions
518 case 8031:
519 bndryCndHandlerSystemMatrix[i] = &FcBndryCnd::bc0;
520 bndryCndHandlerForce[i] = &FcBndryCnd::bc8031;
521 break;
522
523 //----------------------------------------------------
524 // imposed loads boundary conditions
525 case 8032:
526 bndryCndHandlerSystemMatrix[i] = &FcBndryCnd::bc0;
527 bndryCndHandlerForce[i] = &FcBndryCnd::bc8032;
528 break;
529
530 case 8035:
531 bndryCndHandlerSystemMatrix[i] = &FcBndryCnd::bc0;
532 bndryCndHandlerForce[i] = &FcBndryCnd::bc8035;
533 break;
534
535 default:
536 stringstream errorMessage;
537 errorMessage << " FcBndryCnd::setBndryCndHandler : Unknown boundary condition " << m_bndryCndIds[i]
538 << " exiting program.";
539 mTerm(1, AT_, errorMessage.str());
540 }
541 }
542}
543
553template <MInt nDim>
555 TRACE();
556
557 MInt segId = m_bndryCndSegIds[index];
558 cout << "bc8010(" << index << "), offset [" << m_bndryCndOffsets[index] << ", " << m_bndryCndOffsets[index + 1]
559 << "; diff = " << m_bndryCndOffsets[index + 1] - m_bndryCndOffsets[index] << "]" << endl;
560
561 // Run through all corresponding boundary cells and change the node displacements
562 for(MInt i = m_bndryCndOffsets[index]; i < m_bndryCndOffsets[index + 1]; i++) {
563 const MInt cellId = m_bndryCells[i].m_cellId;
564 const MFloat halfLength = m_solver->c_cellLengthAtCell(cellId) * F1B2;
565
566 const MInt noNodes = m_solver->a_noNodes(cellId);
567
568 MFloatScratchSpace penalty(nDim * m_solver->a_noNodes(cellId), nDim * m_solver->a_noNodes(cellId), AT_, "penalty");
569 penalty.fill(F0);
570 for(MInt node = 0; node < noNodes; node++) {
571 MFloat nodalCoord[nDim];
572 m_solver->getCoordinatesOfNode(node, cellId, nodalCoord);
573
574 for(MInt t = 0; t < (MInt)m_bndryCells[i].m_cutFaces.size(); t++) {
575 if(m_bndryCells[i].m_segmentIdOfCutFace[t] != segId) continue;
576
577 for(MInt d = F0; d < nDim; d++) {
578 MFloat dist = F0;
579 for(MInt dim = 0; dim < nDim; dim++) {
580 const MFloat normal = m_bndryCells[i].m_faceNormals[t][dim];
581 const MFloat diff = (nodalCoord[dim] - m_bndryCells[i].m_cutFaces[t][d * nDim + dim]);
582 dist += normal * normal * diff * diff;
583 }
584 const MFloat eps = halfLength * 1e-3;
585 if(dist < (eps * eps)) {
586 for(MInt dim = 0; dim < nDim; dim++) {
587 const MInt pos = node * nDim + dim;
588 if(m_bndryCells[i].m_directionOfAction[dim] > F0) {
589 penalty(pos, pos) = m_kFactor;
590 }
591 }
592 }
593 }
594 }
595 }
596 m_solver->computeAssembledBndryMatrix(penalty, cellId);
597 }
598}
599
609template <MInt nDim>
611 TRACE();
612
613 MInt segId = m_bndryCndSegIds[index];
614 cout << "bc8011(" << index << "), offset [" << m_bndryCndOffsets[index] << ", " << m_bndryCndOffsets[index + 1]
615 << "; diff = " << m_bndryCndOffsets[index + 1] - m_bndryCndOffsets[index] << "]" << endl;
616
617 // Run through all corresponding boundary cells and find the nodes lying on the boundary surface.
618 for(MInt i = m_bndryCndOffsets[index]; i < m_bndryCndOffsets[index + 1]; i++) {
619 const MInt cellId = m_bndryCells[i].m_cellId;
620 const MFloat halfLength = m_solver->c_cellLengthAtCell(cellId) * F1B2;
621 std::vector<MInt> nodeList;
622 getStlNodeList(cellId, nodeList);
623
624 MInt noNodes = m_solver->a_noNodes(cellId);
625 MIntScratchSpace nodeOnSurface(noNodes, AT_, "nodeOnSurface");
626 nodeOnSurface.fill(0);
627 // Calculate the distance of each node to the boundary surface.
628 // If it is below the eps, the node is located on the surface.
629 MFloat eps = 1e-6;
630 for(MInt node = 0; node < noNodes; node++) {
631 MFloat nodalCoord[nDim];
632 m_solver->getCoordinatesOfNode(node, cellId, nodalCoord);
633
634 MFloat d[nDim];
635 MFloat e[nDim];
636 MFloat radius = F0;
637 for(MInt dim = 0; dim < nDim; dim++) {
638 d[dim] = nodalCoord[dim] - m_bndryCells[i].m_avgFaceNormal[dim] * halfLength;
639 e[dim] = nodalCoord[dim] + m_bndryCells[i].m_avgFaceNormal[dim] * halfLength;
640 radius += (d[dim] - nodalCoord[dim]) * (d[dim] - nodalCoord[dim]);
641 }
642 radius = sqrt(radius);
643
644 MBool hasCut = false;
645 for(MInt n = 0; n < (signed)nodeList.size(); n++) {
646 if(m_solver->m_geometry->elements[nodeList[n]].m_segmentId != segId) continue;
647
648 MFloat distance = 0.0;
649 MFloat** const v = m_solver->m_geometry->elements[nodeList[n]].m_vertices;
650 hasCut = m_solver->m_geometry->getLineTriangleIntersectionSimpleDistance(d, e, v[0], v[1], v[2], &distance);
651 if(approx(distance, radius, eps)) {
652 hasCut = true;
653 break;
654 }
655 }
656 if(hasCut) {
657 nodeOnSurface(node) = 1;
658 }
659 }
660
661 // Since we have identified all nodes on the boundary surface,
662 // the penalty factor can now be added to the system matrix
663 MFloat z[nDim] = {F0};
664 MFloatScratchSpace penalty(nDim * m_solver->a_noNodes(cellId), nDim * m_solver->a_noNodes(cellId), AT_, "penalty");
665 penalty.fill(F0);
666
667 for(MInt j = 0; j < (m_solver->a_pRfnmnt(cellId) + 2); j++) {
668 for(MInt k = 0; k < (m_solver->a_pRfnmnt(cellId) + 2); k++) {
669 MInt loop = (nDim == 3) ? (m_solver->a_pRfnmnt(cellId) + 2) : 1;
670 for(MInt l = 0; l < loop; l++) {
671 MInt nodePos[nDim] = {0};
672 nodePos[0] = j;
673 nodePos[1] = k;
674 if(nDim == 3) nodePos[2] = l;
675
676 MBool wrongSide = false;
677 for(MInt d = 0; d < nDim; d++) {
678 z[d] = m_solver->m_gaussPoints[m_solver->a_pRfnmnt(cellId)][nodePos[d]];
679 if(!approx(m_bndryCells[i].m_avgFaceNormal[d], F0, 1e-6)) {
680 if(z[d] < F0) {
681 wrongSide = true;
682 }
683 }
684 }
685 if(wrongSide) continue;
686
687 // Calculate the lagrange interpolation factor
688 MFloatScratchSpace L_coef(nDim, m_solver->a_noNodes(cellId) * nDim, AT_, "L_coef");
689 L_coef.fill(F1);
690 m_solver->getDisplacementInterpolationMatrix(cellId, z, L_coef);
691
692 // Remove lagrange interpolation factor for points outside of the surface of interest.
693 for(MInt node = 0; node < m_solver->a_noNodes(cellId); node++) {
694 if(nodeOnSurface(node)) continue;
695 for(MInt d = 0; d < nDim; d++) {
696 L_coef(d, node * nDim + d) = F0;
697 }
698 }
699
700 // Calculate the integral penalty = int_A L_coef * k * L_coef^T dA
701 for(MInt n1 = 0; n1 < m_solver->a_noNodes(cellId); n1++) {
702 for(MInt n2 = 0; n2 < m_solver->a_noNodes(cellId); n2++) {
703 for(MInt d = 0; d < nDim; d++) {
704 MFloat k_factor = (fabs(m_bndryCells[i].m_directionOfAction[d]) > m_solver->m_eps) ? m_kFactor : F0;
705 MFloat L1 = F1;
706 MFloat L2 = F1;
707 for(MInt dim = 0; dim < nDim; dim++) {
708 if(fabs(m_bndryCells[i].m_avgFaceNormal[dim]) > F0) continue;
709 L1 *= L_coef(dim, n1);
710 L2 *= L_coef(dim, n2);
711 }
712 penalty(n1 * nDim + d, n2 * nDim + d) += (L1 * k_factor * L2);
713 }
714 }
715 }
716 }
717 }
718 }
719 m_solver->computeAssembledBndryMatrix(penalty, cellId);
720 }
721}
722
732template <MInt nDim>
734 TRACE();
735
736 MInt segId = m_bndryCndSegIds[index];
737 const MInt noTriEdges = (nDim == 3) ? 3 : 1;
738 cout << "bc8012(" << index << "), offset [" << m_bndryCndOffsets[index] << ", " << m_bndryCndOffsets[index + 1]
739 << "; diff = " << m_bndryCndOffsets[index + 1] - m_bndryCndOffsets[index] << "]" << endl;
740
741 // Run through all corresponding boundary cells and change the node displacements
742 for(MInt i = m_bndryCndOffsets[index]; i < m_bndryCndOffsets[index + 1]; i++) {
743 const MInt cellId = m_bndryCells[i].m_cellId;
744 // Now we can use the triangles for integration
745 const MInt dof = nDim * m_solver->a_noNodes(cellId);
746 for(MInt t = 0; t < (MInt)m_bndryCells[i].m_cutFaces.size(); t++) {
747 if(m_bndryCells[i].m_segmentIdOfCutFace[t] != segId) continue;
748 std::vector<MFloat> transformedTriangle;
749 MFloat normal[nDim] = {F0};
750 for(MInt d = 0; d < nDim; d++) {
751 MFloat x[nDim] = {F0};
752 MFloat z[nDim] = {F0};
753 for(MInt d1 = 0; d1 < nDim; d1++) {
754 x[d1] = m_bndryCells[i].m_cutFaces[t][d * nDim + d1];
755 }
756 m_solver->transformToLocal(cellId, x, z);
757 for(MInt d1 = 0; d1 < nDim; d1++) {
758 transformedTriangle.push_back(z[d1]);
759 }
760 normal[d] = m_bndryCells[i].m_faceNormals[t][d];
761 }
762 MFloat determinant = solveIntegrationOnTriangle(transformedTriangle, normal);
763 MFloatScratchSpace penalty(dof, dof, AT_, "penalty");
764
765 MFloat weight = F1B6;
766 for(MInt e = 0; e < noTriEdges; e++) {
767 MFloatScratchSpace L_coef(nDim, dof, AT_, "L_coef");
768 L_coef.fill(F1);
769 MFloat z[nDim] = {F0};
770 for(MInt d = 0; d < nDim; d++) {
771 MInt e1 = e;
772 MInt e2 = ((e + 1) < nDim) ? (e + 1) : 0;
773 z[d] = (transformedTriangle[e1 * nDim + d] + transformedTriangle[e2 * nDim + d]) * F1B2;
774 }
775 m_solver->getDisplacementInterpolationMatrix(cellId, z, L_coef);
776 if(m_solver->m_testRun && m_solver->m_polyDeg < 1) {
777 m_solver->getDisplacementInterpolationMatrixDebug(cellId, z, L_coef);
778 }
779 // Calculate the integral penalty = int_A L_coef * k * L_coef^T dA
780 for(MInt n1 = 0; n1 < dof; n1++) {
781 for(MInt n2 = 0; n2 < dof; n2++) {
782 MFloat product = F0;
783 for(MInt d = 0; d < nDim; d++) {
784 MFloat k_factor = (fabs(m_bndryCells[i].m_directionOfAction[d]) > m_solver->m_eps) ? m_kFactor : F0;
785 product += L_coef(d, n1) * k_factor * L_coef(d, n2);
786 }
787 penalty(n1, n2) += product * determinant * weight;
788 }
789 }
790 }
791 m_solver->computeAssembledBndryMatrix(penalty, cellId);
792 }
793 }
794}
795
800template <MInt nDim>
802 TRACE();
803
804 MInt segId = m_bndryCndSegIds[index];
805 cout << "bc8020(" << index << ", " << segId << "), offset [" << m_bndryCndOffsets[index] << ", "
806 << m_bndryCndOffsets[index + 1] << "; diff = " << m_bndryCndOffsets[index + 1] - m_bndryCndOffsets[index] << "]"
807 << endl;
808
809 MInt cellId = 0;
810 for(MInt i = m_bndryCndOffsets[index]; i < m_bndryCndOffsets[index + 1]; i++) {
811 cellId = m_bndryCells[i].m_cellId;
812 cout << "bndryId = " << i << ", cellId = " << cellId << ", primeBndryId = " << m_solver->a_bndId(cellId) << endl;
813 }
814}
815
826template <MInt nDim>
828 TRACE();
829
830 MInt segId = m_bndryCndSegIds[index];
831 cout << "bc8030(" << index << "), offset [" << m_bndryCndOffsets[index] << ", " << m_bndryCndOffsets[index + 1]
832 << "; diff = " << m_bndryCndOffsets[index + 1] - m_bndryCndOffsets[index] << "]" << endl;
833
834 for(MInt i = m_bndryCndOffsets[index]; i < m_bndryCndOffsets[index + 1]; i++) {
835 const MInt cellId = m_bndryCells[i].m_cellId;
836 const MFloat halfLength = m_solver->c_cellLengthAtCell(cellId) * F1B2;
837 std::vector<MInt> nodeList;
838 getStlNodeList(cellId, nodeList);
839
840 MInt noNodes = m_solver->a_noNodes(cellId);
841 for(MInt node = 0; node < noNodes; node++) {
842 MFloat nodalCoord[nDim];
843 m_solver->getCoordinatesOfNode(node, cellId, nodalCoord);
844
845 MFloat d[nDim];
846 MFloat e[nDim];
847 MFloat radius = F0;
848 for(MInt dim = 0; dim < nDim; dim++) {
849 d[dim] = nodalCoord[dim] - m_bndryCells[i].m_avgFaceNormal[dim] * halfLength;
850 e[dim] = nodalCoord[dim] + m_bndryCells[i].m_avgFaceNormal[dim] * halfLength;
851 radius += (d[dim] - nodalCoord[dim]) * (d[dim] - nodalCoord[dim]);
852 }
853 radius = sqrt(radius);
854
855 for(MInt n = 0; n < (signed)nodeList.size(); n++) {
856 if(m_solver->m_geometry->elements[nodeList[n]].m_segmentId != segId) continue;
857
858 MFloat distance = 0.0;
859 MFloat** const v = m_solver->m_geometry->elements[nodeList[n]].m_vertices;
860 const MBool hasCut =
861 m_solver->m_geometry->getLineTriangleIntersectionSimpleDistance(d, e, v[0], v[1], v[2], &distance);
862 std::ignore = hasCut;
863 MInt nodeId = m_solver->a_nodeIdsLocal(cellId, node);
864 if(approx(distance, radius, 1e-6)) {
865 for(MInt dim = 0; dim < nDim; dim++) {
866 m_solver->m_externalLoadVector[nodeId * nDim + dim] =
867 m_bndryCells[i].m_directionOfAction[dim] * m_bndryCells[i].m_load[dim];
868 }
869 }
870 }
871 }
872 }
873}
874
885template <MInt nDim>
887 TRACE();
888
889 MInt segId = m_bndryCndSegIds[index];
890 const MInt noTriEdges = (nDim == 3) ? 3 : 1;
891 cout << "bc8031(" << index << "), offset [" << m_bndryCndOffsets[index] << ", " << m_bndryCndOffsets[index + 1]
892 << "; diff = " << m_bndryCndOffsets[index + 1] - m_bndryCndOffsets[index] << "]" << endl;
893
894
895 // Run through all corresponding boundary cells and change the node displacements
896 for(MInt i = m_bndryCndOffsets[index]; i < m_bndryCndOffsets[index + 1]; i++) {
897 const MInt cellId = m_bndryCells[i].m_cellId;
898 const MFloat cellLength = m_solver->c_cellLengthAtCell(cellId);
899
900 // Now we can use the triangles for integration
901 for(MInt t = 0; t < (MInt)m_bndryCells[i].m_cutFaces.size(); t++) {
902 if(m_bndryCells[i].m_segmentIdOfCutFace[t] != segId) continue;
903 std::vector<MFloat> transformedTriangle;
904 MFloat normal[nDim] = {F0};
905 for(MInt d = 0; d < nDim; d++) {
906 MFloat x[nDim] = {F0};
907 MFloat z[nDim] = {F0};
908 for(MInt d1 = 0; d1 < nDim; d1++) {
909 x[d1] = m_bndryCells[i].m_cutFaces[t][d * nDim + d1];
910 }
911 m_solver->transformToLocal(cellId, x, z);
912 for(MInt d1 = 0; d1 < nDim; d1++) {
913 transformedTriangle.push_back(z[d1]);
914 normal[d1] = m_bndryCells[i].m_faceNormals[t][d];
915 }
916 }
917 MFloat determinant = solveIntegrationOnTriangle(transformedTriangle, normal);
918 MFloat weight = F1B6;
919 for(MInt e = 0; e < noTriEdges; e++) {
920 MFloatScratchSpace L_coef(nDim, m_solver->a_noNodes(cellId) * nDim, AT_, "L_coef");
921 L_coef.fill(F1);
922 MFloat z[nDim] = {F0};
923 for(MInt d = 0; d < nDim; d++) {
924 MInt e1 = e;
925 MInt e2 = ((e + 1) < nDim) ? (e + 1) : 0;
926 z[d] = (transformedTriangle[e1 * nDim + d] + transformedTriangle[e2 * nDim + d]) * F1B2;
927 }
928 m_solver->getDisplacementInterpolationMatrix(cellId, z, L_coef);
929 if(m_solver->m_testRun && m_solver->m_polyDeg < 1) {
930 m_solver->getDisplacementInterpolationMatrixDebug(cellId, z, L_coef);
931 }
932
933 for(MInt node = 0; node < m_solver->a_noNodes(cellId); node++) {
934 for(MInt dim = 0; dim < nDim; dim++) {
935 MInt nodeId = m_solver->a_nodeIdsLocal(cellId, node);
936 MFloat sigma[nDim] = {F0};
937 for(MInt d = 0; d < nDim; d++) {
938 sigma[d] = m_bndryCells[i].m_load[d];
939 }
940 MFloat load = F0;
941 for(MInt d = 0; d < nDim; d++) {
942 load += L_coef(d, node * nDim + dim) * sigma[d] * determinant * weight;
943 }
944 m_solver->m_externalLoadVector[nodeId * nDim + dim] += (F1B4 * cellLength * cellLength) * load;
945 }
946 }
947 }
948 }
949 }
950}
951
963template <MInt nDim>
965 TRACE();
966
967 MInt segId = m_bndryCndSegIds[index];
968 const MInt noTriEdges = (nDim == 3) ? 3 : 1;
969 cout << "bc8032(" << index << "), offset [" << m_bndryCndOffsets[index] << ", " << m_bndryCndOffsets[index + 1]
970 << "; diff = " << m_bndryCndOffsets[index + 1] - m_bndryCndOffsets[index] << "]" << endl;
971
972
973 // Run through all corresponding boundary cells and change the node displacements
974 for(MInt i = m_bndryCndOffsets[index]; i < m_bndryCndOffsets[index + 1]; i++) {
975 const MInt cellId = m_bndryCells[i].m_cellId;
976 const MFloat cellLength = m_solver->c_cellLengthAtCell(cellId);
977
978 // Now we can use the triangles for integration
979 for(MInt t = 0; t < (MInt)m_bndryCells[i].m_cutFaces.size(); t++) {
980 if(m_bndryCells[i].m_segmentIdOfCutFace[t] != segId) continue;
981 std::vector<MFloat> transformedTriangle;
982 MFloat normal[nDim] = {F0};
983 for(MInt d = 0; d < nDim; d++) {
984 MFloat x[nDim] = {F0};
985 MFloat z[nDim] = {F0};
986 for(MInt d1 = 0; d1 < nDim; d1++) {
987 x[d1] = m_bndryCells[i].m_cutFaces[t][d * nDim + d1];
988 }
989 m_solver->transformToLocal(cellId, x, z);
990 for(MInt d1 = 0; d1 < nDim; d1++) {
991 transformedTriangle.push_back(z[d1]);
992 normal[d1] = m_bndryCells[i].m_faceNormals[t][d];
993 }
994 }
995 MFloat determinant = solveIntegrationOnTriangle(transformedTriangle, normal);
996 MFloat weight = F1B6;
997 for(MInt e = 0; e < noTriEdges; e++) {
998 MFloatScratchSpace L_coef(nDim, m_solver->a_noNodes(cellId) * nDim, AT_, "L_coef");
999 L_coef.fill(F1);
1000 MFloat z[nDim] = {F0};
1001 MFloat coord[nDim] = {F0};
1002 for(MInt d = 0; d < nDim; d++) {
1003 MInt e1 = e;
1004 MInt e2 = ((e + 1) < nDim) ? (e + 1) : 0;
1005 z[d] = (transformedTriangle[e1 * nDim + d] + transformedTriangle[e2 * nDim + d]) * F1B2;
1006 coord[d] =
1007 (m_bndryCells[i].m_cutFaces[t][e1 * nDim + d] + m_bndryCells[i].m_cutFaces[t][e2 * nDim + d]) * F1B2;
1008 }
1009 m_solver->getDisplacementInterpolationMatrix(cellId, z, L_coef);
1010 if(m_solver->m_testRun && m_solver->m_polyDeg < 1) {
1011 m_solver->getDisplacementInterpolationMatrixDebug(cellId, z, L_coef);
1012 }
1013
1014 MFloat x = coord[0];
1015 MFloat y = coord[1];
1016 MFloat r_squared = x * x + y * y;
1017 MFloat cosTheta = x / sqrt(r_squared);
1018 MFloat sinTheta = y / sqrt(r_squared);
1019 MFloat cos2Theta = F2 * cosTheta * cosTheta - 1;
1020 MFloat sin2Theta = F2 * cosTheta * sinTheta;
1021 MFloat sigmaRR =
1022 m_bndryCells[i].m_load[0] * F1B2 * (F1 - F1 / r_squared)
1023 + m_bndryCells[i].m_load[0] * F1B2 * (F1 + F3 / (r_squared * r_squared) - F4 / r_squared) * cos2Theta;
1024 MFloat sigmaTT = m_bndryCells[i].m_load[1] * F1B2 * (F1 + F1 / r_squared)
1025 - m_bndryCells[i].m_load[1] * F1B2 * (F1 + F3 / (r_squared * r_squared)) * cos2Theta;
1026 MFloat sigmaRT =
1027 -m_bndryCells[i].m_load[0] * F1B2 * (F1 + F2 / r_squared - F3 / (r_squared * r_squared)) * sin2Theta;
1028 MFloat sigmaXX =
1029 sigmaRR * cosTheta * cosTheta + sigmaTT * sinTheta * sinTheta - F2 * sigmaRT * cosTheta * sinTheta;
1030 MFloat sigmaYY =
1031 sigmaTT * cosTheta * cosTheta + sigmaRR * sinTheta * sinTheta + F2 * sigmaRT * cosTheta * sinTheta;
1032 MFloat sigmaXY =
1033 (sigmaRR - sigmaTT) * cosTheta * sinTheta + sigmaRT * (cosTheta * cosTheta - sinTheta * sinTheta);
1034
1035 for(MInt node = 0; node < m_solver->a_noNodes(cellId); node++) {
1036 for(MInt dim = 0; dim < nDim; dim++) {
1037 MInt nodeId = m_solver->a_nodeIdsLocal(cellId, node);
1038 MFloat sigma[nDim] = {F0};
1039 if(approx(m_bndryCells[i].m_avgFaceNormal[0], F0, 1e-6)) {
1040 sigma[0] = sigmaXY;
1041 sigma[1] = sigmaYY;
1042 } else {
1043 sigma[0] = sigmaXX;
1044 sigma[1] = sigmaXY;
1045 }
1046 MFloat load = F0;
1047 for(MInt d = 0; d < nDim; d++) {
1048 load += L_coef(d, node * nDim + dim) * sigma[d] * determinant * weight;
1049 }
1050 m_solver->m_externalLoadVector[nodeId * nDim + dim] += (F1B4 * cellLength * cellLength) * load;
1051 }
1052 }
1053 }
1054 }
1055 }
1056}
1057
1064template <MInt nDim>
1066 TRACE();
1067
1068 MInt segId = m_bndryCndSegIds[index];
1069 const MInt noTriEdges = (nDim == 3) ? 3 : 1;
1070 cout << "bc8035(" << index << "), offset [" << m_bndryCndOffsets[index] << ", " << m_bndryCndOffsets[index + 1]
1071 << "; diff = " << m_bndryCndOffsets[index + 1] - m_bndryCndOffsets[index] << "]" << endl;
1072
1073
1074 // Run through all corresponding boundary cells and change the node displacements
1075 for(MInt i = m_bndryCndOffsets[index]; i < m_bndryCndOffsets[index + 1]; i++) {
1076 const MInt cellId = m_bndryCells[i].m_cellId;
1077 const MFloat cellLength = m_solver->c_cellLengthAtCell(cellId);
1078
1079 // Now we can use the triangles for integration
1080 for(MInt t = 0; t < (MInt)m_bndryCells[i].m_cutFaces.size(); t++) {
1081 if(m_bndryCells[i].m_segmentIdOfCutFace[t] != segId) continue;
1082 std::vector<MFloat> transformedTriangle;
1083 MFloat normal[nDim] = {F0};
1084 for(MInt d = 0; d < nDim; d++) {
1085 MFloat x[nDim] = {F0};
1086 MFloat z[nDim] = {F0};
1087 for(MInt d1 = 0; d1 < nDim; d1++) {
1088 x[d1] = m_bndryCells[i].m_cutFaces[t][d * nDim + d1];
1089 }
1090 m_solver->transformToLocal(cellId, x, z);
1091 for(MInt d1 = 0; d1 < nDim; d1++) {
1092 transformedTriangle.push_back(z[d1]);
1093 }
1094 normal[d] = m_bndryCells[i].m_faceNormals[t][d];
1095 }
1096 MFloat determinant = solveIntegrationOnTriangle(transformedTriangle, normal);
1097 MFloat weight = F1B6;
1098 for(MInt e = 0; e < noTriEdges; e++) {
1099 MFloatScratchSpace L_coef(nDim, m_solver->a_noNodes(cellId) * nDim, AT_, "L_coef");
1100 L_coef.fill(F1);
1101 MFloat z[nDim] = {F0};
1102 for(MInt d = 0; d < nDim; d++) {
1103 MInt e1 = e;
1104 MInt e2 = ((e + 1) < nDim) ? (e + 1) : 0;
1105 z[d] = (transformedTriangle[e1 * nDim + d] + transformedTriangle[e2 * nDim + d]) * F1B2;
1106 }
1107 m_solver->getDisplacementInterpolationMatrix(cellId, z, L_coef);
1108 if(m_solver->m_testRun && m_solver->m_polyDeg < 1) {
1109 m_solver->getDisplacementInterpolationMatrixDebug(cellId, z, L_coef);
1110 }
1111
1112 for(MInt node = 0; node < m_solver->a_noNodes(cellId); node++) {
1113 for(MInt dim = 0; dim < nDim; dim++) {
1114 MInt nodeId = m_solver->a_nodeIdsLocal(cellId, node);
1115 MFloat sigma[nDim] = {F0};
1116 for(MInt d = 0; d < nDim; d++) {
1117 sigma[d] = normal[d] * 1.0;
1118 }
1119 MFloat load = F0;
1120 for(MInt d = 0; d < nDim; d++) {
1121 load += L_coef(d, node * nDim + dim) * sigma[d] * determinant * weight;
1122 }
1123 m_solver->m_externalLoadVector[nodeId * nDim + dim] += (F1B4 * cellLength * cellLength) * load;
1124 }
1125 }
1126 }
1127 }
1128 }
1129}
1130
1136template <MInt nDim>
1138 TRACE();
1139 std::ignore = index;
1140}
1141
1146template <MInt nDim>
1148 TRACE();
1149
1150 for(MInt i = 0; i < (MInt)(m_bndryCndIds.size()); i++) {
1151 (this->*bndryCndHandlerSystemMatrix[i])(i);
1152 }
1153}
1154
1159template <MInt nDim>
1161 TRACE();
1162
1163 for(MInt i = 0; i < (MInt)(m_bndryCndIds.size()); i++) {
1164 (this->*bndryCndHandlerForce[i])(i);
1165 }
1166}
1167
1174template <MInt nDim>
1176 TRACE();
1177
1178 for(MInt index = 0; index < (MInt)(m_bndryCndSegIds.size()); index++) {
1179 const MInt bc_id = m_bndryCndIds[index];
1180 const MInt segId = m_bndryCndSegIds[index];
1181
1182 if(bc_id == 0) continue;
1183 if(bc_id > 8020) continue;
1184
1185 for(MInt i = m_bndryCndOffsets[index]; i < m_bndryCndOffsets[index + 1]; i++) {
1186 const MInt cellId = m_bndryCells[i].m_cellId;
1187 const MFloat halfLength = m_solver->c_cellLengthAtCell(cellId) * F1B2;
1188
1189 const MInt noNodes = m_solver->a_noNodes(cellId);
1190
1191 for(MInt node = 0; node < noNodes; node++) {
1192 std::array<MFloat, nDim> nodalCoord{};
1193 m_solver->getCoordinatesOfNode(node, cellId, nodalCoord.data());
1194
1195 for(MInt t = 0; t < (MInt)m_bndryCells[i].m_cutFaces.size(); t++) {
1196 if(m_bndryCells[i].m_segmentIdOfCutFace[t] != segId) continue;
1197
1198 for(MInt d = F0; d < nDim; d++) {
1199 MFloat dist = F0;
1200 for(MInt dim = 0; dim < nDim; dim++) {
1201 const MFloat normal = m_bndryCells[i].m_faceNormals[t][dim];
1202 const MFloat diff = (nodalCoord[dim] - m_bndryCells[i].m_cutFaces[t][d * nDim + dim]);
1203 dist += normal * normal * diff * diff;
1204 }
1205 const MFloat eps = halfLength * 1e-3;
1206 if(dist < (eps * eps)) {
1207 for(MInt dim = 0; dim < nDim; dim++) {
1208 const MInt pos = m_solver->a_nodeIdsLocal(cellId, node) * nDim + dim;
1209 if(m_bndryCells[i].m_directionOfAction[dim] > F0) {
1210 m_solver->m_reactionForceVector[pos] = m_solver->m_internalLoadVector[pos];
1211 }
1212 }
1213 }
1214 }
1215 }
1216 }
1217 }
1218 }
1219}
1220
1225template <MInt nDim>
1226void FcBndryCnd<nDim>::subCellIntegration(const MInt subCellLvl, MFloat* subCellParentCoord, const MInt subCellPos,
1227 const MInt pCellId, MFloat** Ke_final) {
1228 TRACE();
1229
1230 // do the subcell integration only until the max depth is reached
1231 if(subCellLvl > m_solver->a_maxSubCellLvl(pCellId)) return;
1232
1233 std::vector<MInt> nodeList;
1234
1235 // set the half cell length...
1236 const MFloat subCellHalfLength = m_solver->c_cellLengthAtCell(pCellId) * FFPOW2(subCellLvl + 1);
1237 // and the bounding box of the subcell and the center coordinates of the sub cell
1238 MFloat target[2 * nDim] = {F0};
1239 MFloat subCellCoord[nDim] = {F0};
1240 for(MInt d = 0; d < nDim; d++) {
1241 MFloat dir = Fd::vertexPosition(subCellPos, d);
1242 subCellCoord[d] = subCellParentCoord[d] + dir * subCellHalfLength;
1243 target[d] = subCellCoord[d] - subCellHalfLength;
1244 target[d + nDim] = subCellCoord[d] + subCellHalfLength;
1245 }
1246
1247 // increase the childLevel
1248 const MInt childLevel = subCellLvl + 1;
1249
1250 // check if the sub cell is intersected by the geometry
1251 m_solver->m_geometry->getIntersectionElements(target, nodeList, subCellHalfLength, subCellCoord);
1252
1253 // if the cell is intersected refine the cell further if the maxSubCellLevel is not reached
1254 // if it is intersected but the maximum depth is reached, calculate the stiffness matrix
1255 if(nodeList.size() > 0) {
1256 if(childLevel <= m_solver->a_maxSubCellLvl(pCellId)) {
1257 for(MInt child = 0; child < IPOW2(nDim); child++) {
1258 subCellIntegration(childLevel, subCellCoord, child, pCellId, Ke_final);
1259 }
1260 } else {
1261 // calculate the stiffness matrix for this subcell
1262 MFloatScratchSpace Ke(m_solver->a_noNodes(pCellId) * nDim, m_solver->a_noNodes(pCellId) * nDim, AT_, "Ke");
1263 // reset element stiffness matrix
1264 for(MInt m1 = 0; m1 < m_solver->a_noNodes(pCellId) * nDim; m1++) {
1265 for(MInt m2 = 0; m2 < m_solver->a_noNodes(pCellId) * nDim; m2++) {
1266 Ke(m1, m2) = F0;
1267 }
1268 }
1269
1270 // Calculate the Element Stiffness Matrix for the subcell
1271 // and add it to the element stiffness of the root element
1272 const MFloat alpha = (F1 - m_solver->m_alpha);
1273 m_solver->getElementMatrix(Ke, pCellId, alpha, subCellLvl, subCellCoord);
1274 for(MInt m1 = 0; m1 < m_solver->a_noNodes(pCellId) * nDim; m1++) {
1275 for(MInt m2 = 0; m2 < m_solver->a_noNodes(pCellId) * nDim; m2++) {
1276 Ke_final[m1][m2] += Ke(m1, m2);
1277 }
1278 }
1279 }
1280 } else {
1281 // Check if the subcell is outside or inside the geometry
1282 // if the subcell is outside nothing more is to be done
1283 // if the subcell is inside the element stiffness matrix of the subcell is calculated
1284 MBool outside = m_solver->m_geometry->pointIsInside2(subCellCoord);
1285 if(outside) {
1286 return;
1287 }
1288
1289 // calculate the stiffness matrix for this subcell
1290 MFloatScratchSpace Ke(m_solver->a_noNodes(pCellId) * nDim, m_solver->a_noNodes(pCellId) * nDim, AT_, "Ke");
1291 // reset element stiffness matrix
1292 for(MInt m1 = 0; m1 < m_solver->a_noNodes(pCellId) * nDim; m1++) {
1293 for(MInt m2 = 0; m2 < m_solver->a_noNodes(pCellId) * nDim; m2++) {
1294 Ke(m1, m2) = F0;
1295 }
1296 }
1297 // Calculate the Element Stiffness Matrix for the subcell
1298 // and add it to the element stiffness of the root element
1299 const MFloat alpha = (F1 - m_solver->m_alpha);
1300 m_solver->getElementMatrix(Ke, pCellId, alpha, subCellLvl, subCellCoord);
1301 for(MInt m1 = 0; m1 < m_solver->a_noNodes(pCellId) * nDim; m1++) {
1302 for(MInt m2 = 0; m2 < m_solver->a_noNodes(pCellId) * nDim; m2++) {
1303 Ke_final[m1][m2] += Ke(m1, m2);
1304 }
1305 }
1306 }
1307}
1308
1315template <MInt nDim>
1317 TRACE();
1318
1319 for(MInt cell = 0; cell < m_solver->a_noCells(); cell++) {
1320 m_solver->a_needsSubCells(cell) = false;
1321 m_solver->a_maxSubCellLvl(cell) = 0;
1322 }
1323 for(MInt cell = 0; cell < (MInt)m_bndryCells.size(); cell++) {
1324 MInt pCellId = m_bndryCells[cell].m_cellId;
1325 MInt depth = 0;
1326 for(MInt noSeg = 0; noSeg < (MInt)m_bndryCells[cell].m_segmentId.size(); noSeg++) {
1327 MInt segId = m_bndryCells[cell].m_segmentId[noSeg];
1328 if(m_subCellLayerDepth[segId] > depth) {
1329 depth = m_subCellLayerDepth[segId];
1330 }
1331 }
1332 if(depth > 0) {
1333 m_solver->a_needsSubCells(pCellId) = true;
1334 m_solver->a_maxSubCellLvl(pCellId) = depth;
1335 }
1336 }
1337}
1338
1344template <MInt nDim>
1345std::vector<std::vector<MFloat>>
1346FcBndryCnd<nDim>::createTrianglesFromCutPoints(std::vector<std::vector<MFloat>> cutPointList, MFloat* triangleNormal) {
1347 TRACE();
1348
1349 // Step 1:
1350 // Calculate the Center of gravity of the cut point list.
1351 MFloat COG[nDim] = {F0};
1352 for(MInt d = 0; d < nDim; d++) {
1353 for(MInt c1 = 0; c1 < (MInt)cutPointList.size(); c1++) {
1354 COG[d] += cutPointList[c1][d];
1355 }
1356 COG[d] /= (MInt)cutPointList.size();
1357 }
1358
1359 // Step 2:
1360 // Sort vector of cut points depending on their angle.
1361 // The line segment between COG and the first point in the cut point list is the reference.
1362 // The line segments between COG and the other points in the cut point list are calculated
1363 // consecutively. The angle between them and the reference line segment is calculated using
1364 // the scalar product. Since the cosinus in cpp is not defined for 2pi, the cross product
1365 // of the two vectors is also calculated. The sign of the scalar product of the resulting
1366 // vector and the triangle normal determines if the angle is <pi or >=pi.
1367 // Since the first point in the cut point list is the reference point, it is assigned the
1368 // angle 0.
1369 std::vector<MFloat> angles;
1370 angles.push_back(0);
1371 for(MInt c1 = 1; c1 < (MInt)cutPointList.size(); c1++) {
1372 MFloat crossProduct[nDim] = {F0};
1373 MFloat cosPhi = F0;
1374 MFloat l1 = F0;
1375 MFloat l2 = F0;
1376 MFloat lCross = F0;
1377 MFloat lNormal = F0;
1378
1379 // Step 2a: Calculate cross product and scalar product
1380 // Furthermore the length of the different vectors are calculated
1381 for(MInt d = 0; d < nDim; d++) {
1382 // Cross product
1383 crossProduct[d] = F0;
1384 MInt d1 = ((d + 1) < nDim) ? (d + 1) : 0;
1385 MInt d2 = ((d1 + 1) < nDim) ? (d1 + 1) : 0;
1386 crossProduct[d] = ((cutPointList[0][d1] - COG[d1]) * (cutPointList[c1][d2] - COG[d2]))
1387 - ((cutPointList[0][d2] - COG[d2]) * (cutPointList[c1][d1] - COG[d1]));
1388
1389 // Scalar product
1390 cosPhi += ((cutPointList[0][d] - COG[d]) * (cutPointList[c1][d] - COG[d]));
1391
1392 // Vector length
1393 l1 += ((cutPointList[0][d] - COG[d]) * (cutPointList[0][d] - COG[d]));
1394 l2 += ((cutPointList[c1][d] - COG[d]) * (cutPointList[c1][d] - COG[d]));
1395 lCross += (crossProduct[d] * crossProduct[d]);
1396 lNormal += (triangleNormal[d] * triangleNormal[d]);
1397 }
1398 cosPhi /= (sqrt(l1) * sqrt(l2));
1399
1400 // Step 2b: Calculate the angle
1401 MFloat oppDir = F0;
1402 for(MInt d = 0; d < nDim; d++) {
1403 oppDir += (triangleNormal[d] * crossProduct[d]);
1404 }
1405 oppDir /= (sqrt(lCross) * sqrt(lNormal));
1406
1407 // Step 2c: Calculate angle
1408 // Since it might occur that abs(cosPhi) is slightly larger than 1 due to numerical errors
1409 // it is rounded in this case. Afterwards, the angle is calculated. If oppDir is <0 the
1410 // opposite angle is used.
1411 if(cosPhi > F1 || cosPhi < -F1) {
1412 cosPhi = round(cosPhi);
1413 }
1414 if(oppDir >= F0) {
1415 angles.push_back(acos(cosPhi));
1416 } else {
1417 angles.push_back((2 * PI) - acos(cosPhi));
1418 }
1419 }
1420
1421 // Step 2d: Sort the cut point list from smallest to largest angles.
1422 for(MInt i = 0; i < (MInt)(angles.size() - 1); i++) {
1423 for(MInt j = 0; j < (MInt)(angles.size() - i - 1); j++) {
1424 if(angles.at(j) > angles.at(j + 1)) {
1425 std::swap(angles.at(j), angles.at(j + 1));
1426 std::swap(cutPointList.at(j), cutPointList.at(j + 1));
1427 }
1428 }
1429 }
1430
1431 // Step 3: Triangulate cut points. One triangles consists of 3 points with 3 coordinates.
1432 std::vector<std::vector<MFloat>> triangleList;
1433 for(MInt c = 1; c < (MInt)cutPointList.size() - 1; c++) {
1434 std::vector<MFloat> triangle;
1435 for(MInt d1 = 0; d1 < nDim; d1++) {
1436 for(MInt d2 = 0; d2 < nDim; d2++) {
1437 MInt point = (d1 == 0) ? d1 : (c + d1 - 1);
1438 triangle.push_back(cutPointList[point][d2]);
1439 }
1440 }
1441 triangleList.push_back(triangle);
1442 }
1443
1444 return triangleList;
1445}
1446
1453template <MInt nDim>
1454std::vector<std::vector<MFloat>>
1455FcBndryCnd<nDim>::createEdgesFromCutPoints(std::vector<std::vector<MFloat>> cutPointList) {
1456 TRACE();
1457
1458 ASSERT((MInt)cutPointList.size() == 2, "A line can only have two cut points with a cell");
1459 std::vector<std::vector<MFloat>> edgeList;
1460 std::vector<MFloat> edge;
1461
1462 for(MInt c = 0; c < (MInt)cutPointList.size(); c++) {
1463 for(MInt p = 0; p < (MInt)cutPointList[c].size(); p++) {
1464 edge.push_back(cutPointList[c][p]);
1465 }
1466 }
1467
1468 ASSERT((MInt)edge.size() == 4, "A edge must have only four coordinates");
1469 edgeList.push_back(edge);
1470
1471 return edgeList;
1472}
1473
1478template <MInt nDim>
1479MFloat FcBndryCnd<nDim>::solveIntegrationOnTriangle(std::vector<MFloat> trianglePoints, MFloat* triangleNormal) {
1480 TRACE();
1481
1482 std::vector<MFloat> transformedTriPoints;
1483
1484 MFloat edge1[nDim] = {F0};
1485 MFloat edge2[nDim] = {F0};
1486 MFloat result[nDim] = {F0};
1487 // Calculate the transformed points
1488 for(MInt d1 = 0; d1 < nDim; d1++) {
1489 for(MInt d2 = 0; d2 < nDim; d2++) {
1490 MFloat transformed = trianglePoints[d1 * nDim + d2] - trianglePoints[d2];
1491 if(d1 == nDim - 2) edge1[d2] = (trianglePoints[d1 * nDim + d2] - trianglePoints[d2]);
1492 if(d1 == nDim - 1) edge2[d2] = (trianglePoints[d1 * nDim + d2] - trianglePoints[d2]);
1493 transformedTriPoints.push_back(transformed);
1494 }
1495 }
1496
1497 if(nDim == 3) {
1498 maia::math::cross(edge1, edge2, result);
1499 }
1500
1501 MFloat determinant = F0;
1502 for(MInt d1 = 0; d1 < nDim; d1++) {
1503 determinant += (result[d1] * result[d1]);
1504 }
1505 determinant = sqrt(determinant);
1506
1507 // TODO: This is the mathematical correct way to calculate the determinant,
1508 // but so far, it is not working due to a bug.
1509 std::ignore = triangleNormal;
1510 /*
1511 MFloatScratchSpace transformationMatrix((nDim + 1), (nDim + 1), AT_, "transformationMatrix");
1512 transformationMatrix.fill(F0);
1513 // This is the inverse of the translation matrix.
1514 // The matrix moves one point of the triangle in the coordinate origin
1515 for(MInt d1 = 0; d1 < nDim + 1; d1++) {
1516 for(MInt d2 = 0; d2 < nDim; d2++) {
1517 if(d1 == d2) transformationMatrix(d2, d1) = F1;
1518 if(d1 == nDim) transformationMatrix(d2, d1) = trianglePoints[d2];
1519 }
1520 }
1521 transformationMatrix(nDim, nDim) = F1;
1522
1523 //Use Rodrigues rotation formula to rotate triangle in xy-plane
1524 //Normalize the normal of the triangle
1525 MFloat lengthN = F0;
1526 for(MInt d = 0; d < nDim; d++) {
1527 lengthN += (triangleNormal[d] * triangleNormal[d]);
1528 }
1529 for(MInt d = 0; d < nDim; d++) {
1530 triangleNormal[d] /= sqrt(lengthN);
1531 }
1532
1533 //Calculate the cross product of the x-axis and the triangle normal
1534 //and normalize the result
1535 MFloat xyPlaneNormal[nDim] = {F0};
1536 xyPlaneNormal[nDim - 1] = F1;
1537 MFloat k[nDim] = {F0};
1538 if(nDim == 3) {
1539 maia::math::cross(triangleNormal, xyPlaneNormal, k);
1540 }
1541 MFloat lengthK = F0;
1542 for(MInt d = 0; d < nDim; d++) {
1543 lengthK += (k[d] * k[d]);
1544 }
1545
1546 for(MInt d = 0; d < nDim; d++) {
1547 k[d] /= sqrt(lengthK);
1548 triangleNormal[d] /= sqrt(lengthN);
1549 }
1550
1551 //Calculate the rotation angle
1552 MFloat dotProduct = F0;
1553 for(MInt d = 0; d < nDim; d++) {
1554 dotProduct += triangleNormal[d] * xyPlaneNormal[d];
1555 }
1556 MFloat cosTheta = dotProduct;
1557 MFloat sinTheta = lengthK / (lengthN); //length of xyPlaneNormal is always one
1558
1559 //Calculate the rotation matrix using Rodrigues rotation formular
1560 MFloat identityMat[nDim][nDim] = {F0};;
1561 MFloat kMat[nDim][nDim] = {F0};
1562 MFloat kMat_square[nDim][nDim] = {F0};
1563 MFloatScratchSpace R1((nDim + 1), (nDim + 1), AT_, "R1");
1564 MFloatScratchSpace R2((nDim + 1), (nDim + 1), AT_, "R2");
1565 R1.fill(F0);
1566 R2.fill(F0);
1567
1568 for(MInt d1 = 0; d1 < nDim; d1++) {
1569 for(MInt d2 = 0; d2 < nDim; d2++) {
1570 identityMat[d1][d2] = F0;
1571 if(d1 == d2) identityMat[d1][d2] = F1;
1572 }
1573 }
1574
1575 for(MInt d1 = 0; d1 < nDim; d1++) {
1576 kMat[d1][d1] = F0;
1577 MInt d2 = ((d1 + 1) < nDim) ? (d1 + 1) : 0;
1578 MInt d3 = ((d2 + 1) < nDim) ? (d2 + 1) : 0;
1579 kMat[d1][d2] = k[d3];
1580 if(d1 == 1) kMat[d1][d2] *= -F1;
1581 kMat[d2][d1] = -k[d3];
1582 }
1583
1584 for(MInt d1 = 0; d1 < nDim; d1++) {
1585 for(MInt d2 = 0; d2 < nDim; d2++) {
1586 kMat_square[d1][d2] = F0;
1587 for(MInt d3 = 0; d3 < nDim; d3++) {
1588 kMat_square[d1][d2] += (kMat[d1][d3] * kMat[d3][d2]);
1589 }
1590 }
1591 }
1592
1593 for(MInt d1 = 0; d1 < nDim; d1++) {
1594 for(MInt d2 = 0; d2 < nDim; d2++) {
1595 R1(d1, d2) = identityMat[d1][d2] + (sinTheta * kMat[d1][d2]) + ((F1 + cosTheta) * kMat_square[d1][d2]);
1596 }
1597 }
1598
1599 //To transform the triangle into a unit triangle a third transformation is needed
1600 //The inverse of this matrix is given by the coordinates of the transformed
1601 for(MInt d1 = 0; d1 < nDim; d1++) {
1602 MFloat point[nDim] = {F0};
1603 for(MInt d2 = 0; d2 < nDim; d2++) {
1604 for(MInt d3 = 0; d3 < nDim; d3++) {
1605 point[d2] += transformedTriPoints[d1 * nDim + d3] * R1(d2, d3);
1606 }
1607 }
1608 for(MInt d = 0; d < nDim; d++) {
1609 transformedTriPoints[d1 * nDim + d] = point[d];
1610 }
1611 }
1612
1613 for(MInt d1 = 0; d1 < nDim; d1++) {
1614 for(MInt d2 = 0; d2 < nDim; d2++) {
1615 MInt d = ((d1 + 1) < nDim) ? (d1 + 1) : 0;
1616 R2(d2, d1) = transformedTriPoints[d * nDim + d2];
1617 }
1618 }
1619
1620 //The nDim + 1 dimension is required for the translation and to
1621 //allow to calculat the inverse of the matrix
1622 R2((nDim - 1), (nDim - 1)) = F1;
1623 R1(nDim, nDim) = F1;
1624 R2(nDim, nDim) = F1;
1625 //TODO: Write a inverse function in maiamath.h that can handle
1626 //2DScratchSpaces
1627 MFloatScratchSpace R1_inv((nDim + 1) * (nDim + 1), AT_, "R1_inv");
1628 for(MInt d1 = 0; d1 < nDim + 1; d1++) {
1629 for(MInt d2 = 0; d2 < nDim + 1; d2++) {
1630 R1_inv(d1 * (nDim + 1) + d2) = R1(d1, d2);
1631 }
1632 }
1633 maia::math::invert(R1_inv.getPointer(), (nDim + 1), (nDim + 1));
1634
1635 for(MInt d1 = 0; d1 < nDim + 1; d1++) {
1636 for(MInt d2 = 0; d2 < nDim + 1; d2++) {
1637 R1(d1, d2) = R1_inv(d1 * (nDim + 1) + d2);
1638 }
1639 }
1640
1641 //Now we have everything we need, so we calculate the product of the 3 inverse
1642 //matrices. The product is the transformation matrix that transforms the triangle
1643 //Gauss points into the cell coordinate system.
1644 MFloatScratchSpace helper((nDim + 1), (nDim + 1), AT_, "helper");
1645 maia::math::multiplyMatricesSq(transformationMatrix, R1, helper, nDim + 1);
1646 maia::math::multiplyMatricesSq(helper, R2, transformationMatrix, nDim + 1);
1647
1648 //Calculate the determinant of the resulting matrix
1649 MFloatScratchSpace subMat(nDim, nDim, AT_, "subMat");
1650 MFloat determinant = F0;
1651 MFloat sign = -F1;
1652 for(MInt d1 = 0; d1 < (nDim + 1); d1++) {
1653 sign *= (-F1);
1654 MInt cnt = 0;
1655 for(MInt d2 = 0; d2 < (nDim + 1); d2++) {
1656 if(d1 == d2) continue;
1657 for(MInt d3 = 1; d3 < (nDim + 1); d3++) {
1658 subMat(cnt, d3 - 1) = transformationMatrix(d2, d3);
1659 }
1660 cnt++;
1661 }
1662 MFloat det = maia::math::determinant(subMat, nDim);
1663 determinant += (sign * transformationMatrix(d1, 0) * det);
1664 }
1665 */
1666 return determinant;
1667}
1668
1673template <MInt nDim>
1675 TRACE();
1676
1677 // Returns the number of the opposite vertex of an edge
1678 // e1
1679 // 1 - - - - 3
1680 // | |
1681 // e0| |e3
1682 // | |
1683 // 0 - - - - 2
1684 // e2
1685 // For edge 2 the edgeStartPos is vertex number 2 and
1686 // the edgeEndPos is vertex number 0
1687 // This is valid in 2D and for the edges in the yz-plane in 3D
1688 const MInt edgeEndPos[4] = {1, 3, 0, 2};
1689
1690 // Stores the normals of the cell faces
1691 // the normal points in -x, x, -y, y, -z, z direction
1692 MFloat normals[2 * nDim][nDim];
1693 for(MInt d1 = 0; d1 < 2 * nDim; d1++) {
1694 for(MInt d2 = 0; d2 < nDim; d2++) {
1695 if(d1 >= (2 * d2) && d1 < (2 * (d2 + 1))) {
1696 MInt expo = d1 + 1;
1697 normals[d1][d2] = pow(-F1, expo);
1698 } else {
1699 normals[d1][d2] = F0;
1700 }
1701 }
1702 }
1703
1704 const MInt noStlElementEdges = (nDim == 3) ? 3 : 1;
1705 const MInt noElementEdges = (nDim == 3) ? 12 : 4;
1706 const MFloat eps = m_solver->m_eps;
1707
1708 struct stlElement {
1709 MFloat points[nDim][nDim];
1710 MFloat edges[noStlElementEdges][2 * nDim];
1711 std::array<MFloat, nDim> normal;
1712 std::array<MBool, nDim> pointInsideCell;
1713 MInt noInsidePoints;
1714 std::array<MInt, noStlElementEdges> noCutsPerEdge;
1715 MBool cutSurfPerEdge[noStlElementEdges][2 * nDim];
1716 MInt noCuttedSurfaces;
1717 std::array<MBool, noStlElementEdges> edgeNotCutted;
1718 std::array<MBool, noStlElementEdges> edgeOnSurface;
1719 };
1720
1721 struct element {
1722 MFloat edges[noElementEdges][2 * nDim];
1723 std::array<MBool, noElementEdges> edgeIsCut;
1724 MInt noCuts;
1725 std::array<MBool, noElementEdges> edgeOnSurface;
1726 };
1727
1728 // Loop over all boundary ids
1729 for(MInt index = 0; index < (MInt)(m_bndryCndIds.size()); index++) {
1730 MInt segId = m_bndryCndSegIds[index];
1731
1732 for(MInt i = m_bndryCndOffsets[index]; i < m_bndryCndOffsets[index + 1]; i++) {
1733 const MInt cellId = m_bndryCells[i].m_cellId;
1734 const MFloat cellLength = m_solver->c_cellLengthAtCell(cellId);
1735 const MFloat halfLength = cellLength * 0.5;
1736
1737 // 1. Calculate the edges of the cell,
1738 // i.e., for each edge, the start and end point is stored
1739 element ele;
1740 for(MInt e = 0; e < noElementEdges; e++) {
1741 if(nDim == 2) {
1742 for(MInt d = 0; d < nDim; d++) {
1743 MFloat coord = m_solver->c_coordinate(cellId, d);
1744 ele.edges[e][d] = coord + Fd::vertexPosition(e, d) * halfLength;
1745 ele.edges[e][d + nDim] = coord + Fd::vertexPosition(edgeEndPos[e], d) * halfLength;
1746 }
1747 } else {
1748 if(e < 4) { // For all edges in the yz-plane in negative x-direction
1749 for(MInt d = 0; d < nDim; d++) {
1750 MFloat coord = m_solver->c_coordinate(cellId, d);
1751 ele.edges[e][d] = coord + Fd::vertexPosition(e, d) * halfLength;
1752 ele.edges[e][d + nDim] = coord + Fd::vertexPosition(edgeEndPos[e], d) * halfLength;
1753 }
1754 } else if(e < 8) { // For all edges in the yz-plane in positive x-direction
1755 for(MInt d = 0; d < nDim; d++) {
1756 MFloat coord = m_solver->c_coordinate(cellId, d);
1757 ele.edges[e][d] = coord + Fd::vertexPosition(e - 4, d) * halfLength;
1758 ele.edges[e][d + nDim] = coord + Fd::vertexPosition(e, d) * halfLength;
1759 }
1760 } else {
1761 for(MInt d = 0; d < nDim; d++) { // For all edges, which are parallel to the x-axis
1762 MFloat coord = m_solver->c_coordinate(cellId, d);
1763 ele.edges[e][d] = coord + Fd::vertexPosition(e - 4, d) * halfLength;
1764 MInt h = edgeEndPos[e - 8] + 4;
1765 ele.edges[e][d + nDim] = coord + Fd::vertexPosition(h, d) * halfLength;
1766 }
1767 }
1768 }
1769 }
1770
1771 // 2. Find all stl elements that cut the element
1772 MFloat target[2 * nDim]; // bounding box of the currentId
1773 for(MInt j = 0; j < nDim; j++) {
1774 target[j] = m_solver->c_coordinate(cellId, j) - halfLength;
1775 target[j + nDim] = m_solver->c_coordinate(cellId, j) + halfLength;
1776 }
1777 std::vector<MInt> nodeList;
1778 getStlNodeList(cellId, nodeList);
1779 for(MInt n = 0; n < (MInt)nodeList.size(); n++) {
1780 std::vector<std::vector<MFloat>> cutPointList;
1781
1782 // If STL-element does not belong to the boundary, continue
1783 if(m_solver->m_geometry->elements[nodeList[n]].m_segmentId != segId) {
1784 continue;
1785 }
1786
1787 // a). create stl elements struct and calculate the edges of the STL-element, i.e.,
1788 // for each edge, the start and end point is stored
1789 stlElement stl;
1790 for(MInt e = 0; e < noStlElementEdges; e++) {
1791 for(MInt d = 0; d < nDim; d++) {
1792 stl.edges[e][d] = m_solver->m_geometry->elements[nodeList[n]].m_vertices[e][d];
1793 if(e + 1 < nDim) {
1794 stl.edges[e][d + nDim] = m_solver->m_geometry->elements[nodeList[n]].m_vertices[e + 1][d];
1795 } else {
1796 stl.edges[e][d + nDim] = m_solver->m_geometry->elements[nodeList[n]].m_vertices[0][d];
1797 }
1798 }
1799 }
1800 if(nDim == 3) {
1801 for(MInt d = 0; d < nDim; d++) {
1802 stl.normal[d] = m_solver->m_geometry->elements[nodeList[n]].m_normal[d];
1803 }
1804 } else {
1805 stl.normal[0] = stl.edges[0][1 + nDim] - stl.edges[0][1];
1806 stl.normal[1] = stl.edges[0][0 + nDim] - stl.edges[0][0];
1807 }
1808
1809 // b). Check if the corner points of the STL-element are inside or outside of the cell
1810 stl.noInsidePoints = 0;
1811 for(MInt point = 0; point < nDim; point++) {
1812 stl.pointInsideCell[point] = false;
1813 MBool isInside = true;
1814 for(MInt d = 0; d < nDim; d++) {
1815 stl.points[point][d] = m_solver->m_geometry->elements[nodeList[n]].m_vertices[point][d];
1816 if(stl.points[point][d] < (target[d]) || stl.points[point][d] > (target[d + nDim])) {
1817 isInside = false;
1818 }
1819 }
1820 stl.pointInsideCell[point] = isInside;
1821 // if a point is located inside the cell, it is added to the cut point list
1822 if(stl.pointInsideCell[point]) {
1823 stl.noInsidePoints++;
1824 std::vector<MFloat> cutPoint;
1825 for(MInt d = 0; d < nDim; d++) {
1826 cutPoint.push_back(stl.points[point][d]);
1827 }
1828 cutPointList.push_back(cutPoint);
1829 }
1830 }
1831
1832 // c). Check if edge is cutted
1833 // If start and end point are located inside of the cell, the edge is not cutted.
1834 // If start and end point are located outside of the cell, the edge might have two cuts.
1835 for(MInt e = 0; e < noStlElementEdges; e++) {
1836 MInt point1 = e;
1837 MInt point2 = (e + 1 < nDim) ? (e + 1) : 0;
1838 stl.edgeNotCutted[e] = (stl.pointInsideCell[point1] && stl.pointInsideCell[point2]);
1839 stl.noCutsPerEdge[e] = 0;
1840 stl.noCuttedSurfaces = 0;
1841 stl.edgeOnSurface[e] = false;
1842 for(MInt surface = 0; surface < 2 * nDim; surface++) {
1843 stl.cutSurfPerEdge[e][surface] = false;
1844 }
1845 }
1846
1847 // d). Check if the edges cut the cell surfaces and count the cuts per edge
1848 // An edge can cut the cell surfaces twice (if start and end point are
1849 // outside of the cell), once (if one of the edge corner points is inside
1850 // and the other is outside), or zero times (if start and end point are
1851 // outside or inside of the cell).
1852 // Furthermore, we need to check if the edge is located on the surface.
1853 // If all points of the stl element are located inside the cell, we dont need to
1854 // do the next steps
1855 if(stl.noInsidePoints < nDim) {
1856 switch(nDim) {
1857 case 2: {
1858 for(MInt e = 0; e < noStlElementEdges; e++) {
1859 // If the edge has no cut, continue
1860 if(stl.edgeNotCutted[e]) continue;
1861
1862 // If the edge has a cut, find the surface which is cutted by the edge
1863 // Line-line-intersection: if line cuts line, check if cutpoint is
1864 // inside of the cell surface
1865 for(MInt surface = 0; surface < 2 * nDim; surface++) {
1866 const MFloat numer = stl.edges[e][1 + nDim] - stl.edges[e][1];
1867 const MFloat denom = stl.edges[e][0 + nDim] - stl.edges[e][0];
1868 const MFloat coordX = m_solver->c_coordinate(cellId, 0);
1869 const MFloat coordY = m_solver->c_coordinate(cellId, 1);
1870 const MFloat minStlEdgeX = mMin(stl.edges[e][0], stl.edges[e][0 + nDim]);
1871 const MFloat minStlEdgeY = mMin(stl.edges[e][1], stl.edges[e][1 + nDim]);
1872 const MFloat maxStlEdgeX = mMax(stl.edges[e][0], stl.edges[e][0 + nDim]);
1873 const MFloat maxStlEdgeY = mMax(stl.edges[e][1], stl.edges[e][1 + nDim]);
1874
1875 // surface is parallel to x-axis
1876 if(approx(normals[surface][0], F0, eps)) {
1877 const MFloat y = coordY + normals[surface][1] * halfLength;
1878 const MFloat x1 = coordX - halfLength;
1879 const MFloat x2 = coordX + halfLength;
1880
1881 // STL element is parallel to x-axis.
1882 // We can skip this case as these cut points are already considered in
1883 // the other cases
1884 if(approx(numer, F0, eps)) {
1885 continue;
1886 }
1887 // stl element is parallel to y-axis
1888 // check if there is a cut by comparing the edge coordinates
1889 else if(approx(denom, F0, eps)) {
1890 // Check if the x-coord of the stl edge lies in between the corner
1891 // points of the surface
1892 if(x1 <= stl.edges[e][0 + nDim] && x2 >= stl.edges[e][0 + nDim]) {
1893 // Check if the y-coord of the surface lies in between the corner
1894 // points of the stl edge
1895 if(minStlEdgeY <= y && maxStlEdgeY >= y) {
1896 std::vector<MFloat> cutPoint;
1897 cutPoint.push_back(stl.edges[e][0 + nDim]);
1898 cutPoint.push_back(y);
1899 cutPointList.push_back(cutPoint);
1900 }
1901 }
1902 }
1903 // stl element is not parallel to an axis
1904 // Insert the y-coord of the surface in the equation of the stl edge to
1905 // calculate the x-coord of the cut.
1906 // Check if the cut point lies in between the corner points of the surface.
1907 else {
1908 const MFloat cutPointX = (denom / numer) * (y - stl.edges[e][1]) + stl.edges[e][0];
1909 const MFloat cutPointY = y;
1910 if(cutPointX >= x1 && cutPointX <= x2 && cutPointX >= minStlEdgeX && cutPointX <= maxStlEdgeX) {
1911 std::vector<MFloat> cutPoint;
1912 cutPoint.push_back(cutPointX);
1913 cutPoint.push_back(cutPointY);
1914 cutPointList.push_back(cutPoint);
1915 }
1916 }
1917 }
1918 // surface is parallel to y-axis
1919 if(approx(normals[surface][1], F0, eps)) {
1920 const MFloat x = coordX + normals[surface][0] * halfLength;
1921 const MFloat y1 = coordY - halfLength;
1922 const MFloat y2 = coordY + halfLength;
1923
1924 // STL element is parallel to y-axis.
1925 // We can skip this case as these cut points are already considered in
1926 // the other cases
1927 if(approx(denom, F0, eps)) {
1928 continue;
1929 }
1930 // stl element is parallel to x-axis
1931 // check if there is a cut by comparing the edge coordinates
1932 else if(approx(numer, F0, eps)) {
1933 // Check if the y-coord of the stl edge lies in between the corner
1934 // points of the surface
1935 if(y1 <= stl.edges[e][1 + nDim] && y2 >= stl.edges[e][1 + nDim]) {
1936 // Check if the x-coord of the surface lies in between the corner
1937 // points of the stl edge
1938 if(minStlEdgeX <= x && maxStlEdgeX >= x) {
1939 std::vector<MFloat> cutPoint;
1940 cutPoint.push_back(x);
1941 cutPoint.push_back(stl.edges[e][1 + nDim]);
1942 cutPointList.push_back(cutPoint);
1943 }
1944 }
1945 }
1946 // stl element is not parallel to an axis
1947 // Insert the x-coord of the surface in the equation of the stl edge to
1948 // calculate the y-coord of the cut.
1949 // Check if the cut point lies in between the corner points of the surface.
1950 else {
1951 const MFloat cutPointX = x;
1952 const MFloat cutPointY = (numer / denom) * (x - stl.edges[e][0]) + stl.edges[e][1];
1953
1954 if(cutPointY >= y1 && cutPointY <= y2 && cutPointY >= minStlEdgeY && cutPointY <= maxStlEdgeY) {
1955 std::vector<MFloat> cutPoint;
1956 cutPoint.push_back(cutPointX);
1957 cutPoint.push_back(cutPointY);
1958 cutPointList.push_back(cutPoint);
1959 }
1960 }
1961 }
1962 }
1963 }
1964 break;
1965 }
1966 case 3: {
1967 for(MInt e = 0; e < noStlElementEdges; e++) {
1968 // If the edge has no cut, continue
1969 if(stl.edgeNotCutted[e]) continue;
1970 // If the edge has a cut, find the surface which is cutted by the edge
1971 // Line-plane-intersection: if line cuts plane, check if cutpoint is inside of
1972 // the cell surface
1973 for(MInt surface = 0; surface < 2 * nDim; surface++) {
1974 MFloat numer = F0;
1975 MFloat denom = F0;
1976 for(MInt d = 0; d < nDim; d++) {
1977 MFloat locationVec = m_solver->c_coordinate(cellId, d) + normals[surface][d] * halfLength;
1978 denom += (normals[surface][d] * (stl.edges[e][d + nDim] - stl.edges[e][d]));
1979 numer += (normals[surface][d] * locationVec);
1980 }
1981 for(MInt d = 0; d < nDim; d++) {
1982 numer -= (normals[surface][d] * stl.edges[e][d]);
1983 }
1984 if(!approx(denom, F0, eps)) {
1985 // Check is cut point is inside cell surface
1986 MFloat lambda = numer / denom;
1987 if((lambda >= F0) && (lambda <= F1)) {
1988 MBool validIntersection = true;
1989 std::vector<MFloat> cutPoint;
1990 for(MInt d = 0; d < nDim; d++) {
1991 MFloat point = stl.edges[e][d] + lambda * (stl.edges[e][d + nDim] - stl.edges[e][d]);
1992 if(fabs(point - target[d]) < m_solver->m_eps) {
1993 point = target[d];
1994 } else if(fabs(point - target[d + nDim]) < m_solver->m_eps) {
1995 point = target[d + nDim];
1996 }
1997 cutPoint.push_back(point);
1998 if(point < (target[d]) || point > (target[d + nDim])) {
1999 validIntersection = false;
2000 }
2001 }
2002 if(validIntersection) {
2003 stl.cutSurfPerEdge[e][surface] = true;
2004 cutPointList.push_back(cutPoint);
2005 MBool surfCutBefore = false;
2006 for(MInt prevE = 0; prevE < e - 1; prevE++) {
2007 if(stl.cutSurfPerEdge[prevE][surface]) {
2008 surfCutBefore = true;
2009 break;
2010 }
2011 }
2012 if(!surfCutBefore) stl.noCuttedSurfaces++;
2013 stl.noCutsPerEdge[e]++;
2014 }
2015 }
2016 }
2017 }
2018 }
2019 break;
2020 }
2021 default: {
2022 mTerm(1, AT_, "ERROR: Wrong number of dimensions! Aborting.");
2023 break;
2024 }
2025 }
2026
2027 if(nDim == 3) {
2028 // e). Check if the edges of the element cut the stl element
2029 for(MInt e = 0; e < noElementEdges; e++) {
2030 ele.edgeOnSurface[e] = false;
2031 MFloat numer = F0;
2032 MFloat denom = F0;
2033 for(MInt d = 0; d < nDim; d++) {
2034 denom += (stl.normal[d] * (ele.edges[e][d + nDim] - ele.edges[e][d]));
2035 numer += (stl.normal[d] * stl.points[0][d]);
2036 }
2037 for(MInt d = 0; d < nDim; d++) {
2038 numer -= (stl.normal[d] * ele.edges[e][d]);
2039 }
2040 if(approx(denom, F0, eps)) {
2041 if(approx(numer, F0, eps)) {
2042 // Element edge lies on the stl element surface
2043 // We store the corner points of the edge as cut points for later
2044 ele.edgeOnSurface[e] = true;
2045 std::vector<MFloat> cutPoint1;
2046 std::vector<MFloat> cutPoint2;
2047 for(MInt d = 0; d < nDim; d++) {
2048 cutPoint1.push_back(ele.edges[e][d]);
2049 cutPoint2.push_back(ele.edges[e][d + nDim]);
2050 }
2051 MBool inside = pointInTriangle(stl.points[0], stl.points[1], stl.points[2], cutPoint1);
2052 if(inside) {
2053 cutPointList.push_back(cutPoint1);
2054 }
2055
2056 inside = pointInTriangle(stl.points[0], stl.points[1], stl.points[2], cutPoint2);
2057 if(inside) {
2058 cutPointList.push_back(cutPoint2);
2059 }
2060 break;
2061 } else {
2062 // Element edge is parallel to the stl element surface
2063 continue;
2064 }
2065 } else {
2066 MFloat lambda = numer / denom;
2067 MBool inside = false;
2068 std::vector<MFloat> cutPoint;
2069 if((lambda >= F0) && (lambda <= F1)) {
2070 for(MInt d = 0; d < nDim; d++) {
2071 MFloat point = ele.edges[e][d] + lambda * (ele.edges[e][d + nDim] - ele.edges[e][d]);
2072 cutPoint.push_back(point);
2073 }
2074 inside = pointInTriangle(stl.points[0], stl.points[1], stl.points[2], cutPoint);
2075 if(inside) {
2076 cutPointList.push_back(cutPoint);
2077 }
2078 }
2079 }
2080 }
2081 }
2082 }
2083
2084 for(MInt c1 = 0; c1 < (MInt)cutPointList.size(); c1++) {
2085 MInt c2 = c1 + 1;
2086 while(c2 < (MInt)cutPointList.size()) {
2087 MBool dublicated = true;
2088 for(MInt d = 0; d < nDim; d++) {
2089 if(!approx(cutPointList[c1][d], cutPointList[c2][d], eps)) {
2090 dublicated = false;
2091 break;
2092 }
2093 }
2094 if(dublicated) {
2095 cutPointList.erase(cutPointList.begin() + c2);
2096 } else {
2097 c2++;
2098 }
2099 }
2100 }
2101
2102 if((MInt)cutPointList.size() < nDim) continue;
2103 setBoundaryStlElements(cutPointList, stl.normal.data(), segId, i);
2104 }
2105 }
2106 }
2107}
2108
2113template <MInt nDim>
2114void FcBndryCnd<nDim>::setBoundaryStlElements(std::vector<std::vector<MFloat>> cutPointList, MFloat* normal, MInt segId,
2115 MInt i) {
2116 TRACE();
2117
2118 std::vector<std::vector<MFloat>> newStlElementList;
2119 if(nDim == 2) {
2120 newStlElementList = createEdgesFromCutPoints(cutPointList);
2121 } else {
2122 newStlElementList = createTrianglesFromCutPoints(cutPointList, normal);
2123 }
2124 MFloat normalLength = F0;
2125 for(MInt d = 0; d < nDim; d++) {
2126 normalLength += (normal[d] * normal[d]);
2127 }
2128 normalLength = sqrt(normalLength);
2129
2130 for(MInt t = 0; t < (MInt)newStlElementList.size(); t++) {
2131 std::vector<MFloat> vertices;
2132 std::vector<MFloat> elementNormal;
2133 for(MInt v = 0; v < nDim; v++) {
2134 for(MInt p = 0; p < nDim; p++) {
2135 vertices.push_back(newStlElementList[t][v * nDim + p]);
2136 }
2137 MFloat n = normal[v] / normalLength;
2138 elementNormal.push_back(n);
2139 }
2140 m_bndryCells[i].m_cutFaces.push_back(vertices);
2141 m_bndryCells[i].m_faceNormals.push_back(elementNormal);
2142 m_bndryCells[i].m_segmentIdOfCutFace.push_back(segId);
2143 }
2144}
2145
2151template <MInt nDim>
2153 TRACE();
2154
2155 MInt segId = m_bndryCndSegIds[index];
2156
2157 MString fileName = "Segment_" + std::to_string(segId) + prefix + ".stl";
2158 ofstream stlFile;
2159 stlFile.open(fileName);
2160
2161 stlFile << "solid Visualization Toolkit generated SLA File\n";
2162 for(MInt i = m_bndryCndOffsets[index]; i < m_bndryCndOffsets[index + 1]; i++) {
2163 for(MInt t = 0; t < (MInt)m_bndryCells[i].m_cutFaces.size(); t++) {
2164 if(m_bndryCells[i].m_segmentIdOfCutFace[t] != segId) continue;
2165 stlFile << " facet normal ";
2166 for(MInt d = 0; d < nDim; d++) {
2167 if(d < (nDim - 1)) {
2168 stlFile << m_bndryCells[i].m_faceNormals[t][d] << " ";
2169 } else {
2170 stlFile << m_bndryCells[i].m_faceNormals[t][d] << "\n";
2171 }
2172 }
2173 stlFile << " outer loop\n";
2174 for(MInt v = 0; v < nDim; v++) {
2175 stlFile << " vertex ";
2176 for(MInt p = 0; p < nDim; p++) {
2177 if(p < (nDim - 1)) {
2178 stlFile << m_bndryCells[i].m_cutFaces[t][v * nDim + p] << " ";
2179 } else {
2180 stlFile << m_bndryCells[i].m_cutFaces[t][v * nDim + p] << "\n";
2181 }
2182 }
2183 }
2184 stlFile << " endloop\n";
2185 stlFile << " endFacet\n";
2186 }
2187 }
2188 stlFile << "endsolid";
2189 stlFile.close();
2190}
2191
2196template <MInt nDim>
2198 TRACE();
2199
2200 MInt segId = m_bndryCndSegIds[index];
2201
2202 // Run through all corresponding boundary cells and change the node displacements
2203 for(MInt i = m_bndryCndOffsets[index]; i < m_bndryCndOffsets[index + 1]; i++) {
2204 MFloat avgNormal[nDim] = {F0};
2205 MInt cnt = 0;
2206 for(MInt t = 0; t < (MInt)m_bndryCells[i].m_cutFaces.size(); t++) {
2207 if(m_bndryCells[i].m_segmentIdOfCutFace[t] != segId) continue;
2208 for(MInt d = 0; d < nDim; d++) {
2209 avgNormal[d] += m_bndryCells[i].m_faceNormals[t][d];
2210 }
2211 cnt++;
2212 }
2213 MFloat normalLength = F0;
2214 for(MInt d = 0; d < nDim; d++) {
2215 m_bndryCells[i].m_avgFaceNormal[d] = avgNormal[d] / cnt;
2216 normalLength += (m_bndryCells[i].m_avgFaceNormal[d] * m_bndryCells[i].m_avgFaceNormal[d]);
2217 }
2218 normalLength = sqrt(normalLength);
2219 for(MInt d = 0; d < nDim; d++) {
2220 m_bndryCells[i].m_avgFaceNormal[d] = avgNormal[d] / normalLength;
2221 }
2222 }
2223}
2224
2229template <MInt nDim>
2231 TRACE();
2232
2233 for(MInt index = 0; index < (MInt)(m_bndryCndIds.size()); index++) {
2234 MInt segId = m_bndryCndSegIds[index];
2235
2236 if(!m_solver->m_testRun) {
2237 MString prefix = "preTimeStep_" + std::to_string(globalTimeStep);
2238 writeOutSTLBoundaries(index, prefix);
2239 }
2240 for(MInt i = m_bndryCndOffsets[index]; i < m_bndryCndOffsets[index + 1]; i++) {
2241 for(MInt t = 0; t < (MInt)m_bndryCells[i].m_cutFaces.size(); t++) {
2242 if(m_bndryCells[i].m_segmentIdOfCutFace[t] != segId) continue;
2243 for(MInt d1 = 0; d1 < nDim; d1++) {
2244 MFloat x[nDim] = {F0};
2245 MFloat z[nDim] = {F0};
2246 for(MInt d2 = 0; d2 < nDim; d2++) {
2247 x[d2] = m_bndryCells[i].m_cutFaces[t][d1 * nDim + d2];
2248 }
2249 const MInt pCellId = m_bndryCells[i].m_cellId;
2250 m_solver->transformToLocal(pCellId, x, z);
2251 MFloatScratchSpace L_coef(nDim, m_solver->a_noNodes(pCellId) * nDim, AT_, "L_coef");
2252 L_coef.fill(F1);
2253 m_solver->getDisplacementInterpolationMatrix(pCellId, z, L_coef);
2254
2255 for(MInt d2 = 0; d2 < nDim; d2++) {
2256 MFloat displacement = F0;
2257 for(MInt node = 0; node < m_solver->a_noNodes(pCellId); node++) {
2258 for(MInt d3 = 0; d3 < nDim; d3++) {
2259 MInt nodeId = m_solver->a_nodeIdsLocal(pCellId, node);
2260 displacement += L_coef(d2, node * nDim + d3) * m_solver->m_totalNodalDisplacements[nodeId * nDim + d3];
2261 }
2262 }
2263 m_bndryCells[i].m_cutFaces[t][d1 * nDim + d2] += displacement;
2264 }
2265 }
2266 }
2267 }
2268 if(!m_solver->m_testRun) {
2269 MString prefix = "postTimeStep_" + std::to_string(globalTimeStep);
2270 writeOutSTLBoundaries(index, prefix);
2271 }
2272 }
2273}
2274
2280template <MInt nDim>
2282 TRACE();
2283
2284 for(MInt index = 0; index < (MInt)(m_bndryCndIds.size()); index++) {
2285 MInt segId = m_bndryCndSegIds[index];
2286
2287 stringstream prefix;
2288 prefix << "_modified_iteration_" << globalTimeStep;
2289 MString fileName = "Segment_" + std::to_string(segId) + prefix.str() + ".stl";
2290 ofstream stlFile;
2291 stlFile.open(fileName);
2292
2293 stlFile << "solid Visualization Toolkit generated SLA File\n";
2294 for(MInt i = m_bndryCndOffsets[index]; i < m_bndryCndOffsets[index + 1]; i++) {
2295 for(MInt t = 0; t < (MInt)m_bndryCells[i].m_cutFaces.size(); t++) {
2296 if(m_bndryCells[i].m_segmentIdOfCutFace[t] != segId) continue;
2297 stlFile << " facet normal ";
2298 for(MInt d = 0; d < nDim; d++) {
2299 if(d < (nDim - 1)) {
2300 stlFile << m_bndryCells[i].m_faceNormals[t][d] << " ";
2301 } else {
2302 stlFile << m_bndryCells[i].m_faceNormals[t][d] << "\n";
2303 }
2304 }
2305 MFloatScratchSpace points(nDim, nDim, AT_, "points");
2306 points.fill(F0);
2307 for(MInt d1 = 0; d1 < nDim; d1++) {
2308 std::array<MFloat, nDim> x{};
2309 std::array<MFloat, nDim> z{};
2310 for(MInt d2 = 0; d2 < nDim; d2++) {
2311 x[d2] = m_bndryCells[i].m_cutFaces[t][d1 * nDim + d2];
2312 }
2313 const MInt pCellId = m_bndryCells[i].m_cellId;
2314 m_solver->transformToLocal(pCellId, x.data(), z.data());
2315 MFloatScratchSpace L_coef(nDim, m_solver->a_noNodes(pCellId) * nDim, AT_, "L_coef");
2316 L_coef.fill(F1);
2317 m_solver->getDisplacementInterpolationMatrix(pCellId, z.data(), L_coef);
2318
2319 for(MInt d2 = 0; d2 < nDim; d2++) {
2320 MFloat displacement = F0;
2321 for(MInt node = 0; node < m_solver->a_noNodes(pCellId); node++) {
2322 for(MInt d3 = 0; d3 < nDim; d3++) {
2323 MInt nodeId = m_solver->a_nodeIdsLocal(pCellId, node);
2324 displacement += L_coef(d2, node * nDim + d3) * m_solver->m_totalNodalDisplacements[nodeId * nDim + d3];
2325 }
2326 }
2327 points(d1, d2) = displacement + m_bndryCells[i].m_cutFaces[t][d1 * nDim + d2];
2328 }
2329 }
2330 stlFile << " outer loop\n";
2331 for(MInt v = 0; v < nDim; v++) {
2332 stlFile << " vertex ";
2333 for(MInt p = 0; p < nDim; p++) {
2334 if(p < (nDim - 1)) {
2335 stlFile << points(v, p) << " ";
2336 } else {
2337 stlFile << points(v, p) << "\n";
2338 }
2339 }
2340 }
2341 stlFile << " endloop\n";
2342 stlFile << " endFacet\n";
2343 }
2344 }
2345 stlFile << "endsolid";
2346 stlFile.close();
2347 }
2348}
2349
2354template <MInt nDim>
2355MBool FcBndryCnd<nDim>::pointInTriangle(MFloat* A, MFloat* B, MFloat* C, std::vector<MFloat> P) {
2356 TRACE();
2357 // Check if points are located inside the triangle
2358 MFloat u = F0;
2359 MFloat v = F0;
2360 MFloat dot[5] = {F0};
2361 // Check the start point
2362 for(MInt d = 0; d < nDim; d++) {
2363 dot[0] += (C[d] - A[d]) * (C[d] - A[d]);
2364 dot[1] += (C[d] - A[d]) * (B[d] - A[d]);
2365 dot[2] += (C[d] - A[d]) * (P[d] - A[d]);
2366 dot[3] += (B[d] - A[d]) * (B[d] - A[d]);
2367 dot[4] += (B[d] - A[d]) * (P[d] - A[d]);
2368 }
2369 u = (dot[3] * dot[2] - dot[1] * dot[4]) / (dot[0] * dot[3] - dot[1] * dot[1]);
2370 v = (dot[0] * dot[4] - dot[1] * dot[2]) / (dot[0] * dot[3] - dot[1] * dot[1]);
2371 if((u >= F0) && (v >= F0) && ((u + v) <= F1)) {
2372 return true;
2373 }
2374 return false;
2375}
2376
2381template <MInt nDim>
2383 TRACE();
2384
2385 MInt segId = m_bndryCndSegIds[index];
2386
2387 // Run through all corresponding boundary cells and change the node displacements
2388 for(MInt i = m_bndryCndOffsets[index]; i < m_bndryCndOffsets[index + 1]; i++) {
2389 MInt noCutFaces = (MInt)m_bndryCells[i].m_cutFaces.size();
2390 for(MInt t = 0; t < noCutFaces; t++) {
2391 if(m_bndryCells[i].m_segmentIdOfCutFace[t] != segId) continue;
2392 MFloat pointA[nDim];
2393 MFloat pointB[nDim];
2394 MFloat pointC[nDim];
2395 MFloat midPoint[nDim];
2396 std::vector<MFloat> triangleNormal;
2397 for(MInt d = 0; d < nDim; d++) {
2398 pointA[d] = m_bndryCells[i].m_cutFaces[t][0 * nDim + d];
2399 pointB[d] = m_bndryCells[i].m_cutFaces[t][1 * nDim + d];
2400 pointC[d] = m_bndryCells[i].m_cutFaces[t][2 * nDim + d];
2401 triangleNormal.push_back(m_bndryCells[i].m_faceNormals[t][d]);
2402 }
2403 MFloat lenAB = F0;
2404 MFloat lenAC = F0;
2405 MFloat lenBC = F0;
2406 for(MInt d = 0; d < nDim; d++) {
2407 lenAB += (pointA[d] - pointB[d]) * (pointA[d] - pointB[d]);
2408 lenAC += (pointA[d] - pointC[d]) * (pointA[d] - pointC[d]);
2409 lenBC += (pointB[d] * pointC[d]) * (pointB[d] * pointC[d]);
2410 }
2411 lenAB = sqrt(lenAB);
2412 lenAC = sqrt(lenAC);
2413 lenBC = sqrt(lenBC);
2414 std::vector<MFloat> newTriangle;
2415 if((lenAB > lenAC) && (lenAB > lenBC)) {
2416 for(MInt d = 0; d < nDim; d++) {
2417 midPoint[d] = F1B2 * (pointA[d] + pointB[d]);
2418 m_bndryCells[i].m_cutFaces[t][0 * nDim + d] = midPoint[d];
2419 }
2420 for(MInt d = 0; d < nDim; d++) {
2421 newTriangle.push_back(midPoint[d]);
2422 }
2423 for(MInt d = 0; d < nDim; d++) {
2424 newTriangle.push_back(pointA[d]);
2425 }
2426 for(MInt d = 0; d < nDim; d++) {
2427 newTriangle.push_back(pointC[d]);
2428 }
2429 } else if((lenAC > lenAB) && (lenAC > lenBC)) {
2430 for(MInt d = 0; d < nDim; d++) {
2431 midPoint[d] = F1B2 * (pointA[d] + pointC[d]);
2432 m_bndryCells[i].m_cutFaces[t][0 * nDim + d] = midPoint[d];
2433 }
2434 for(MInt d = 0; d < nDim; d++) {
2435 newTriangle.push_back(midPoint[d]);
2436 }
2437 for(MInt d = 0; d < nDim; d++) {
2438 newTriangle.push_back(pointA[d]);
2439 }
2440 for(MInt d = 0; d < nDim; d++) {
2441 newTriangle.push_back(pointB[d]);
2442 }
2443 } else if((lenBC > lenAB) && (lenBC > lenAC)) {
2444 for(MInt d = 0; d < nDim; d++) {
2445 midPoint[d] = F1B2 * (pointB[d] + pointC[d]);
2446 m_bndryCells[i].m_cutFaces[t][1 * nDim + d] = midPoint[d];
2447 }
2448 for(MInt d = 0; d < nDim; d++) {
2449 newTriangle.push_back(midPoint[d]);
2450 }
2451 for(MInt d = 0; d < nDim; d++) {
2452 newTriangle.push_back(pointA[d]);
2453 }
2454 for(MInt d = 0; d < nDim; d++) {
2455 newTriangle.push_back(pointB[d]);
2456 }
2457 }
2458 m_bndryCells[i].m_cutFaces.push_back(newTriangle);
2459 m_bndryCells[i].m_faceNormals.push_back(triangleNormal);
2460 m_bndryCells[i].m_segmentIdOfCutFace.push_back(segId);
2461 }
2462 }
2463}
2464
2469template <MInt nDim>
2470void FcBndryCnd<nDim>::getStlNodeList(const MInt cellId, std::vector<MInt>& nodeList) {
2471 TRACE();
2472
2473 MFloat target[2 * nDim];
2474 MFloat cellHalfLength;
2475
2476 // Define corners of current cell in target
2477 for(MInt d = 0; d < nDim; d++) {
2478 cellHalfLength = F1B2 * m_solver->c_cellLengthAtCell(cellId);
2479 target[d] = m_solver->c_coordinate(cellId, d) - cellHalfLength;
2480 target[d + nDim] = m_solver->c_coordinate(cellId, d) + cellHalfLength;
2481 }
2482
2483 // Check for intersection with geometry elements
2484 m_solver->m_geometry->getIntersectionElements(target, nodeList, cellHalfLength, &m_solver->c_coordinate(cellId, 0));
2485}
2486// Explicit instantiations for 2D and 3D
2487template class FcBndryCnd<2>;
2488template class FcBndryCnd<3>;
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
MBool mDeallocate(T *&a)
deallocates the memory previously allocated for element 'a'
Definition: alloc.h:544
static MBool propertyExists(const MString &name, MInt solver=m_noSolvers)
This function checks if a property exists in general.
Definition: context.cpp:494
void setBndryCndHandler()
This function sets the BndryCndHandler objects at solver setup \adaptation 22.04.2021,...
Definition: fcbndrycnd.cpp:464
void sortBoundaryCells()
This function sorts the boundary cells according to the BC id.
Definition: fcbndrycnd.cpp:405
void bc8030(MInt index)
This function applies the loads boundary condition.
Definition: fcbndrycnd.cpp:827
void createBoundaryCells()
Creates boundary cells according to the geometry information.
Definition: fcbndrycnd.cpp:322
void updateForceVector()
Execution of the force boundary conditions.
void initBndryCnds()
Initializes boundary cells.
Definition: fcbndrycnd.cpp:133
void writeOutSTLBoundaries(MInt index, MString prefix)
Write out the boundary segments in stl-file format.
void writeOutModifiedBoundaries()
Write out the boundary segments in stl-file format.
void bc8011(MInt index)
This function applies the fixation boundary condition.
Definition: fcbndrycnd.cpp:610
std::vector< std::vector< MFloat > > createEdgesFromCutPoints(std::vector< std::vector< MFloat > > cutPointList)
Calculation of the surface edges.
void bc8031(MInt index)
This function applies the loads boundary condition.
Definition: fcbndrycnd.cpp:886
void bc8032(MInt index)
This function applies the loads boundary condition.
Definition: fcbndrycnd.cpp:964
void bc8035(MInt index)
This function applies the loads boundary condition.
void bc8012(MInt index)
This function applies the fixation boundary condition.
Definition: fcbndrycnd.cpp:733
FcBndryCnd(FcSolver< nDim > *solver)
void refineTriangle(MInt index)
Refines the triangles of a segment by deviding them in the middle.
virtual ~FcBndryCnd()
Definition: fcbndrycnd.cpp:113
std::vector< std::vector< MFloat > > createTrianglesFromCutPoints(std::vector< std::vector< MFloat > > cutPointList, MFloat *triangleNormal)
Triangulation algorithm of the cut points.
void getStlNodeList(const MInt cellId, std::vector< MInt > &nodeList)
Returns a list of all elements cutting the target cell.
void findCellsRequireSubCellIntegration()
Set the subcell tree depth for cells requiring subcell integration.
void subCellIntegration(const MInt subCellLvl, MFloat *subCellParentCoord, const MInt childPos, const MInt pCellId, MFloat **Ke)
Execution of the subcell integration.
void updateSystemMatrix()
Execution of the displacement boundary conditions.
void setBoundaryStlElements(std::vector< std::vector< MFloat > > cutPointList, MFloat *normal, MInt segId, MInt i)
Add cut faces to the collector of the boundary cell.
virtual void bc0(MInt index)
Boundary condition for free surfaces.
void updateTrianglePosition()
Moves a triangle depending on the simulated displacment inside a cell.
void bc8010(MInt index)
This function applies the fixation boundary condition.
Definition: fcbndrycnd.cpp:554
void bc8020(MInt index)
This function applies a non-zero displacement boundary condition.
Definition: fcbndrycnd.cpp:801
void calculateCutPoints()
Calculation of the cutpoints of each segment.
MFloat solveIntegrationOnTriangle(std::vector< MFloat > trianglePoints, MFloat *triangleNormal)
Gauss quadrature on triangles.
void calcReactionForces()
Calculation of reaction forces.
void calcAvgFaceNormal(MInt index)
Calculation of the normal vector of the cut faces.
MBool pointInTriangle(MFloat *A, MFloat *B, MFloat *C, std::vector< MFloat > P)
Checks if a point is inside a triangle.
This class represents a structure solver using the Finite Cell Method.
Definition: fcsolver.h:27
Geometry< nDim > * m_geometry
Definition: fcsolver.h:484
This class is a ScratchSpace.
Definition: scratch.h:758
void fill(T val)
fill the scratch with a given value
Definition: scratch.h:311
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
constexpr T mMin(const T &x, const T &y)
Definition: functions.h:90
constexpr T mMax(const T &x, const T &y)
Definition: functions.h:94
MInt globalTimeStep
InfoOutFile m_log
constexpr MLong IPOW2(MInt x)
constexpr MFloat FFPOW2(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
void cross(const T *const u, const T *const v, T *const c)
Definition: maiamath.h:101
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Definition: pointbox.h:54
Definition: contexttypes.h:19
define array structures