MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
FcBndryCnd< nDim > Class Template Reference

#include <fcbndrycnd.h>

Collaboration diagram for FcBndryCnd< nDim >:
[legend]

Public Types

using Cell = GridCell
 Types. More...
 
using SolverCell = FcCell
 
using Fd = FcDescriptor< nDim >
 

Public Member Functions

 FcBndryCnd (FcSolver< nDim > *solver)
 
virtual ~FcBndryCnd ()
 
void initBndryCnds ()
 Initializes boundary cells. More...
 
void setBndryCndHandler ()
 This function sets the BndryCndHandler objects at solver setup \adaptation 22.04.2021, Felix Wietbuescher. More...
 
void setBndryCndHandlerMb (MInt *bcTypeList)
 
void createBoundaryCells ()
 Creates boundary cells according to the geometry information. More...
 
void sortBoundaryCells ()
 This function sorts the boundary cells according to the BC id. More...
 
void updateSystemMatrix ()
 Execution of the displacement boundary conditions. More...
 
void updateForceVector ()
 Execution of the force boundary conditions. More...
 
void updateTrianglePosition ()
 Moves a triangle depending on the simulated displacment inside a cell. More...
 
void calcReactionForces ()
 Calculation of reaction forces. More...
 
void writeOutModifiedBoundaries ()
 Write out the boundary segments in stl-file format. More...
 
void calculateCutPoints ()
 Calculation of the cutpoints of each segment. More...
 
void calcAvgFaceNormal (MInt index)
 Calculation of the normal vector of the cut faces. More...
 
void setBoundaryStlElements (std::vector< std::vector< MFloat > > cutPointList, MFloat *normal, MInt segId, MInt i)
 Add cut faces to the collector of the boundary cell. More...
 
void writeOutSTLBoundaries (MInt index, MString prefix)
 Write out the boundary segments in stl-file format. More...
 
void subCellIntegration (const MInt subCellLvl, MFloat *subCellParentCoord, const MInt childPos, const MInt pCellId, MFloat **Ke)
 Execution of the subcell integration. More...
 
void findCellsRequireSubCellIntegration ()
 Set the subcell tree depth for cells requiring subcell integration. More...
 
std::vector< std::vector< MFloat > > createTrianglesFromCutPoints (std::vector< std::vector< MFloat > > cutPointList, MFloat *triangleNormal)
 Triangulation algorithm of the cut points. More...
 
std::vector< std::vector< MFloat > > createEdgesFromCutPoints (std::vector< std::vector< MFloat > > cutPointList)
 Calculation of the surface edges. More...
 
MFloat solveIntegrationOnTriangle (std::vector< MFloat > trianglePoints, MFloat *triangleNormal)
 Gauss quadrature on triangles. More...
 
MBool pointInTriangle (MFloat *A, MFloat *B, MFloat *C, std::vector< MFloat > P)
 Checks if a point is inside a triangle. More...
 
void refineTriangle (MInt index)
 Refines the triangles of a segment by deviding them in the middle. More...
 
void getStlNodeList (const MInt cellId, std::vector< MInt > &nodeList)
 Returns a list of all elements cutting the target cell. More...
 
virtual void bc0 (MInt index)
 Boundary condition for free surfaces. More...
 
void bc8010 (MInt index)
 This function applies the fixation boundary condition. More...
 
void bc8011 (MInt index)
 This function applies the fixation boundary condition. More...
 
void bc8012 (MInt index)
 This function applies the fixation boundary condition. More...
 
void bc8020 (MInt index)
 This function applies a non-zero displacement boundary condition. More...
 
void bc8030 (MInt index)
 This function applies the loads boundary condition. More...
 
void bc8031 (MInt index)
 This function applies the loads boundary condition. More...
 
void bc8032 (MInt index)
 This function applies the loads boundary condition. More...
 
void bc8035 (MInt index)
 This function applies the loads boundary condition. More...
 
void bc8040 (MInt index)
 

Public Attributes

List< MInt > * m_bndryCellIds = nullptr
 
List< MInt > * m_sortedBndryCells = nullptr
 
MIntm_boundarySurfaces = nullptr
 

Protected Types

using FcCellCollector = maia::fc::collector::FcCellCollector< nDim >
 
typedef void(FcBndryCnd::* BndryCndHandler) (MInt set)
 

Protected Attributes

std::vector< FcGridBndryCell< nDim > > m_bndryCells
 
FcSolver< nDim > * m_solver
 pointer to a member function data type More...
 
FcGridBndryCell< nDim > * bndryCells
 
BndryCndHandlerbndryCndHandlerSystemMatrix
 
BndryCndHandlerbndryCndHandlerForce
 
MInt m_solverId
 
MInt m_noInternalCells
 
std::vector< MIntm_bndryCndIds
 
std::vector< MIntm_bndryCndOffsets
 
std::vector< MIntm_bndryCndSegIds
 
std::vector< MIntm_mapBndryCndSegId2Index
 
MIntm_mapBndryCndIdSegId {}
 
MInt m_noSegments {}
 
MIntm_noBndryCellsPerSegment = nullptr
 
MString m_bndryNormalMethod
 Read from property file. More...
 
MBool m_multiBC
 
MInt m_t_BCAll
 
MIntm_subCellLayerDepth = nullptr
 
MFloat m_kFactor = 1e+12
 

Friends

template<MInt nDim_>
class FcSolver
 

Detailed Description

template<MInt nDim>
class FcBndryCnd< nDim >

Definition at line 34 of file fcbndrycnd.h.

Member Typedef Documentation

◆ BndryCndHandler

template<MInt nDim>
typedef void(FcBndryCnd::* FcBndryCnd< nDim >::BndryCndHandler) (MInt set)
protected

Definition at line 52 of file fcbndrycnd.h.

◆ Cell

template<MInt nDim>
using FcBndryCnd< nDim >::Cell = GridCell

Definition at line 41 of file fcbndrycnd.h.

◆ FcCellCollector

template<MInt nDim>
using FcBndryCnd< nDim >::FcCellCollector = maia::fc::collector::FcCellCollector<nDim>
protected

Definition at line 46 of file fcbndrycnd.h.

◆ Fd

template<MInt nDim>
using FcBndryCnd< nDim >::Fd = FcDescriptor<nDim>

Definition at line 43 of file fcbndrycnd.h.

◆ SolverCell

template<MInt nDim>
using FcBndryCnd< nDim >::SolverCell = FcCell

Definition at line 42 of file fcbndrycnd.h.

Constructor & Destructor Documentation

◆ FcBndryCnd()

template<MInt nDim>
FcBndryCnd< nDim >::FcBndryCnd ( FcSolver< nDim > *  solver)

◆ ~FcBndryCnd()

template<MInt nDim>
FcBndryCnd< nDim >::~FcBndryCnd
virtual

Definition at line 113 of file fcbndrycnd.cpp.

113 {
114 TRACE();
115
116 // Clean up allocated memory
118}
MBool mDeallocate(T *&a)
deallocates the memory previously allocated for element 'a'
Definition: alloc.h:544
MInt * m_noBndryCellsPerSegment
Definition: fcbndrycnd.h:68

Member Function Documentation

◆ bc0()

template<MInt nDim>
void FcBndryCnd< nDim >::bc0 ( MInt  index)
virtual
Author
Moritz Waldmann

At these surfaces no computations are required.

Definition at line 1137 of file fcbndrycnd.cpp.

1137 {
1138 TRACE();
1139 std::ignore = index;
1140}
IdType index(const FloatType *const x, const IdType level)
Return Hilbert index for given location and level in 2D or 3D.
Definition: hilbert.h:165

◆ bc8010()

template<MInt nDim>
void FcBndryCnd< nDim >::bc8010 ( MInt  index)
Author
Moritz Waldmann

For every cell with bcId 8010 part of the displacements of the corresponding nodes in the assembly vector are set to zero. The nodes can be identified via the segment normal vector. The directions which have to be fixated are set in the segment fixaction direction vector (segFixationDirs).

Definition at line 554 of file fcbndrycnd.cpp.

554 {
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}
std::vector< MInt > m_bndryCndOffsets
Definition: fcbndrycnd.h:60
std::vector< FcGridBndryCell< nDim > > m_bndryCells
Definition: fcbndrycnd.h:47
MFloat m_kFactor
Definition: fcbndrycnd.h:79
std::vector< MInt > m_bndryCndSegIds
Definition: fcbndrycnd.h:62
FcSolver< nDim > * m_solver
pointer to a member function data type
Definition: fcbndrycnd.h:50
void getCoordinatesOfNode(MInt node, MInt cell, MFloat *coordinates)
void computeAssembledBndryMatrix(MFloatScratchSpace &Bndry, const MInt pCellId)
MInt & a_noNodes(const MInt cellId)
Returns number of elements of the cell cellId.
Definition: fcsolver.h:226
MFloat c_cellLengthAtCell(const MInt cellId) const
Definition: fcsolver.h:262
This class is a ScratchSpace.
Definition: scratch.h:758
int32_t MInt
Definition: maiatypes.h:62
double MFloat
Definition: maiatypes.h:52
void const MInt cellId
Definition: collector.h:239
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Definition: pointbox.h:54

◆ bc8011()

template<MInt nDim>
void FcBndryCnd< nDim >::bc8011 ( MInt  index)
Author
Moritz Waldmann

For every cell with bcId 8011 part of the displacements of the corresponding nodes in the assembly vector are set to zero. The nodes can be identified via the segment normal vector. The directions which have to be fixated are set in the segment fixaction direction vector (segFixationDirs).

Definition at line 610 of file fcbndrycnd.cpp.

610 {
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);
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}
void getStlNodeList(const MInt cellId, std::vector< MInt > &nodeList)
Returns a list of all elements cutting the target cell.
MFloat m_eps
Definition: fcsolver.h:511
MInt & a_pRfnmnt(const MInt cellId)
Returns pRfnmnt of the cell cellId.
Definition: fcsolver.h:238
void getDisplacementInterpolationMatrix(const MInt pCellId, const MFloat *z, MFloatScratchSpace &x)
Geometry< nDim > * m_geometry
Definition: fcsolver.h:484
MFloat ** m_gaussPoints
Definition: fcsolver.h:536
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
bool MBool
Definition: maiatypes.h:58
void loop(Functor &&fun, Class *object, const IdType begin, const IdType end, Args... args)
MFloat distance(const MFloat *a, const MFloat *b)
Definition: maiamath.h:249

◆ bc8012()

template<MInt nDim>
void FcBndryCnd< nDim >::bc8012 ( MInt  index)
Author
Moritz Waldmann

For every cell with bcId 8012 part of the displacements of the corresponding nodes in the assembly vector are set to zero. The nodes can be identified via the segment normal vector. The directions which have to be fixated are set in the segment fixaction direction vector (segFixationDirs).

Definition at line 733 of file fcbndrycnd.cpp.

733 {
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 }
776 if(m_solver->m_testRun && m_solver->m_polyDeg < 1) {
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}
MFloat solveIntegrationOnTriangle(std::vector< MFloat > trianglePoints, MFloat *triangleNormal)
Gauss quadrature on triangles.
MInt m_polyDeg
Definition: fcsolver.h:503
void transformToLocal(const MInt pCellId, const MFloat *z, MFloat *x)
MBool m_testRun
Definition: fcsolver.h:505
void getDisplacementInterpolationMatrixDebug(const MInt pCellId, const MFloat *z, MFloatScratchSpace &L_coef_lagrange)
MFloat determinant(std::array< T, N > &m)
Definition: maiamath.cpp:130

◆ bc8020()

template<MInt nDim>
void FcBndryCnd< nDim >::bc8020 ( MInt  index)
Author
Moritz Waldmann

Definition at line 801 of file fcbndrycnd.cpp.

801 {
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}
MInt & a_bndId(const MInt cellId)
Returns bndId of the cell cellId.
Definition: fcsolver.h:232

◆ bc8030()

template<MInt nDim>
void FcBndryCnd< nDim >::bc8030 ( MInt  index)
Author
Moritz Waldmann

For every cell with bcId 8030 a force is applied to corresponding nodes in the assembly vector. The nodes can be identified via the segment normal vector. The directions of the force are set in the segment load direction vector (segFixationDirs). An the strength of the load is set in the segment load value vector.

Definition at line 827 of file fcbndrycnd.cpp.

827 {
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}
MFloat * m_externalLoadVector
Definition: fcsolver.h:525
MInt & a_nodeIdsLocal(const MInt cellId, const MInt nodeDir)
Returns node ids of the cell cellId.
Definition: fcsolver.h:250

◆ bc8031()

template<MInt nDim>
void FcBndryCnd< nDim >::bc8031 ( MInt  index)
Author
Moritz Waldmann

For every cell with bcId 8031 a force is applied to corresponding nodes in the assembly vector. The nodes can be identified via the segment normal vector. The directions of the force are set in the segment load direction vector (segFixationDirs). An the strength of the load is set in the segment load value vector.

Definition at line 886 of file fcbndrycnd.cpp.

886 {
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 }
929 if(m_solver->m_testRun && m_solver->m_polyDeg < 1) {
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}

◆ bc8032()

template<MInt nDim>
void FcBndryCnd< nDim >::bc8032 ( MInt  index)
Author
Moritz Waldmann

For every cell with bcId 8032 a force is applied to corresponding nodes in the assembly vector. The nodes can be identified via the segment normal vector. The directions of the force are set in the segment load direction vector (segFixationDirs). An the strength of the load is set in the segment load value vector. The force is specific for a plate under uniaxial force.

Definition at line 964 of file fcbndrycnd.cpp.

964 {
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) {
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}
define array structures

◆ bc8035()

template<MInt nDim>
void FcBndryCnd< nDim >::bc8035 ( MInt  index)
Author
Moritz Waldmann

For every cell with bcId 8035 a force is applied to corresponding nodes in the assembly vector.

Definition at line 1065 of file fcbndrycnd.cpp.

1065 {
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) {
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}

◆ bc8040()

template<MInt nDim>
void FcBndryCnd< nDim >::bc8040 ( MInt  index)

◆ calcAvgFaceNormal()

template<MInt nDim>
void FcBndryCnd< nDim >::calcAvgFaceNormal ( MInt  index)
Author
Moritz Waldmann

Definition at line 2197 of file fcbndrycnd.cpp.

2197 {
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}

◆ calcReactionForces()

template<MInt nDim>
void FcBndryCnd< nDim >::calcReactionForces
Author
Moritz Waldmann

The Reaction forces are defined as the inner forces, which occur at the fixed boundaries, i.e., boundaries with id < 8020.

Definition at line 1175 of file fcbndrycnd.cpp.

1175 {
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) {
1211 }
1212 }
1213 }
1214 }
1215 }
1216 }
1217 }
1218 }
1219}
std::vector< MInt > m_bndryCndIds
Definition: fcbndrycnd.h:59
MFloat * m_reactionForceVector
Definition: fcsolver.h:527
MFloat * m_internalLoadVector
Definition: fcsolver.h:526

◆ calculateCutPoints()

template<MInt nDim>
void FcBndryCnd< nDim >::calculateCutPoints
Author
Moritz Waldmann

Definition at line 1674 of file fcbndrycnd.cpp.

1674 {
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}
void setBoundaryStlElements(std::vector< std::vector< MFloat > > cutPointList, MFloat *normal, MInt segId, MInt i)
Add cut faces to the collector of the boundary cell.
MBool pointInTriangle(MFloat *A, MFloat *B, MFloat *C, std::vector< MFloat > P)
Checks if a point is inside a triangle.
const MFloat & c_coordinate(const MInt gCellId, const MInt dim) const
Returns the coordinate of the cell cellId for direction dim.
Definition: fcsolver.h:274
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
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
static constexpr MFloat vertexPosition(MInt i, MInt j)
Definition: fcdescriptor.h:214

◆ createBoundaryCells()

template<MInt nDim>
void FcBndryCnd< nDim >::createBoundaryCells
Author
Andreas Lintermann
Date
29.01.2010 \adaptation 22.04.2021, Felix Wietbuescher

This function runs over all cells and makes an intersection test with the triangles of nearby segments. All candidates carry a segment id and a boundary condition. Hence, a corner cell can have multiple properties. Depending on the allowance of multiple BCs, only one single (no multiple BCs allowed) boundary cell is added to a temporary vector. Anyhow, the boundary cell can carry multiple information on segment id and boundary condition.

In this case the wall boundary condition is chosen by setting the first element of both the boundary condition array and the segment id to this wall condition.

In the other case of multiple BCs, the boundary cell is added multiple
times to the vector of temporary boundary cells, each time with its according different conditions. After that,
the collector of boundary cells is initialized. The size is now known by the size of the temporary vector. Finally,
the information in the vector is copied to the collector.

according to the number of different bc's.

Definition at line 322 of file fcbndrycnd.cpp.

322 {
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}
MBool m_multiBC
Definition: fcbndrycnd.h:73
MBool a_isBndryCell(const MInt cellId) const
Returns isBndryCell of the cell CellId.
Definition: fcsolver.h:81
maia::fc::collector::FcCellCollector< nDim > m_cells
Collector for Fc cells.
Definition: fcsolver.h:548
MBool c_isLeafCell(const MInt cellId) const
Definition: fcsolver.h:350
InfoOutFile m_log

◆ createEdgesFromCutPoints()

template<MInt nDim>
std::vector< std::vector< MFloat > > FcBndryCnd< nDim >::createEdgesFromCutPoints ( std::vector< std::vector< MFloat > >  cutPointList)
Author
Moritz Waldmann

2D version of the triangulation algorithm. Works only in 2D.

Definition at line 1455 of file fcbndrycnd.cpp.

1455 {
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}
constexpr std::underlying_type< FcCell >::type p(const FcCell property)
Converts property name to underlying integer value.

◆ createTrianglesFromCutPoints()

template<MInt nDim>
std::vector< std::vector< MFloat > > FcBndryCnd< nDim >::createTrianglesFromCutPoints ( std::vector< std::vector< MFloat > >  cutPointList,
MFloat triangleNormal 
)
Author
Moritz Waldmann

Works only in 3D

Definition at line 1346 of file fcbndrycnd.cpp.

1346 {
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}

◆ findCellsRequireSubCellIntegration()

template<MInt nDim>
void FcBndryCnd< nDim >::findCellsRequireSubCellIntegration
Author
Moritz Waldmann

The depth and the boundary segment, at which the subcell integration is required, is given in the properties file.

Definition at line 1316 of file fcbndrycnd.cpp.

1316 {
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}
MInt * m_subCellLayerDepth
Definition: fcbndrycnd.h:78
MInt a_noCells() const
Definition: fcsolver.h:544
MBool a_needsSubCells(const MInt cellId) const
Returns needsSubCells of the cell CellId.
Definition: fcsolver.h:218
MInt & a_maxSubCellLvl(const MInt cellId)
Returns pRfnmnt of the cell cellId.
Definition: fcsolver.h:244

◆ getStlNodeList()

template<MInt nDim>
void FcBndryCnd< nDim >::getStlNodeList ( const MInt  cellId,
std::vector< MInt > &  nodeList 
)
Author
Moritz Waldmann

Definition at line 2470 of file fcbndrycnd.cpp.

2470 {
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}

◆ initBndryCnds()

template<MInt nDim>
void FcBndryCnd< nDim >::initBndryCnds
Author
Moritz Waldmann
Date
29.05.2021

Sets the direction of fixation and the direction of loads at the boundaries.

That is, the property segFixationDirs_x is 0.0 or 1.0 for segment x in each direction. If it is 1.0 the displacement in that direction is set to 0. The same applies for the property segLoadDirs_x, which sets the direction in which a load is applied. The propterty segLoadValue_x contains the explicite load value in each Cartesian direction.

Definition at line 133 of file fcbndrycnd.cpp.

133 {
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}
MInt m_solverId
Definition: fcbndrycnd.h:56
std::basic_string< char > MString
Definition: maiatypes.h:55

◆ pointInTriangle()

template<MInt nDim>
MBool FcBndryCnd< nDim >::pointInTriangle ( MFloat A,
MFloat B,
MFloat C,
std::vector< MFloat P 
)
Author
Moritz Waldmann

Definition at line 2355 of file fcbndrycnd.cpp.

2355 {
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}

◆ refineTriangle()

template<MInt nDim>
void FcBndryCnd< nDim >::refineTriangle ( MInt  index)
Author
Moritz Waldmann

Definition at line 2382 of file fcbndrycnd.cpp.

2382 {
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}

◆ setBndryCndHandler()

template<MInt nDim>
void FcBndryCnd< nDim >::setBndryCndHandler

It needs the boundary condition to set the boundary condition handler. Each new boundary condition needs to be implemented here, too.

Definition at line 464 of file fcbndrycnd.cpp.

464 {
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
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:
479 break;
480
481 //----------------------------------------------------
482 // fixation boundary conditions
483 case 8010:
486 break;
487
488 //----------------------------------------------------
489 // fixation boundary conditions
490 case 8011:
493 break;
494
495 //----------------------------------------------------
496 // fixation boundary conditions
497 case 8012:
500 break;
501
502 //----------------------------------------------------
503 // displacement boundary conditions
504 case 8020:
507 break;
508
509 //----------------------------------------------------
510 // imposed loads boundary conditions
511 case 8030:
514 break;
515
516 //----------------------------------------------------
517 // imposed loads boundary conditions
518 case 8031:
521 break;
522
523 //----------------------------------------------------
524 // imposed loads boundary conditions
525 case 8032:
528 break;
529
530 case 8035:
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}
void bc8030(MInt index)
This function applies the loads boundary condition.
Definition: fcbndrycnd.cpp:827
void bc8011(MInt index)
This function applies the fixation boundary condition.
Definition: fcbndrycnd.cpp:610
BndryCndHandler * bndryCndHandlerForce
Definition: fcbndrycnd.h:54
BndryCndHandler * bndryCndHandlerSystemMatrix
Definition: fcbndrycnd.h:53
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
virtual void bc0(MInt index)
Boundary condition for free surfaces.
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(FcBndryCnd::* BndryCndHandler)(MInt set)
Definition: fcbndrycnd.h:52

◆ setBndryCndHandlerMb()

template<MInt nDim>
void FcBndryCnd< nDim >::setBndryCndHandlerMb ( MInt bcTypeList)

◆ setBoundaryStlElements()

template<MInt nDim>
void FcBndryCnd< nDim >::setBoundaryStlElements ( std::vector< std::vector< MFloat > >  cutPointList,
MFloat normal,
MInt  segId,
MInt  i 
)
Author
Moritz Waldmann

Definition at line 2114 of file fcbndrycnd.cpp.

2115 {
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}
std::vector< std::vector< MFloat > > createEdgesFromCutPoints(std::vector< std::vector< MFloat > > cutPointList)
Calculation of the surface edges.
std::vector< std::vector< MFloat > > createTrianglesFromCutPoints(std::vector< std::vector< MFloat > > cutPointList, MFloat *triangleNormal)
Triangulation algorithm of the cut points.

◆ solveIntegrationOnTriangle()

template<MInt nDim>
MFloat FcBndryCnd< nDim >::solveIntegrationOnTriangle ( std::vector< MFloat trianglePoints,
MFloat triangleNormal 
)
Author
Moritz Waldmann

Definition at line 1479 of file fcbndrycnd.cpp.

1479 {
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}
void cross(const T *const u, const T *const v, T *const c)
Definition: maiamath.h:101

◆ sortBoundaryCells()

template<MInt nDim>
void FcBndryCnd< nDim >::sortBoundaryCells
Author
Andreas Lintermann
Date
27.01.2010

The sorting of the boundary cells is necessary because all cells are stored in one single collector. The boundary condition functions get the position of a type of boundary cells in the collector (offset) and the number of boundary cells of equal type ( i.e. with the same boundary id) as parameter.

Definition at line 405 of file fcbndrycnd.cpp.

405 {
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
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}
std::vector< MInt > m_mapBndryCndSegId2Index
Definition: fcbndrycnd.h:63
MInt m_noSegments
Definition: fcbndrycnd.h:67
Definition: contexttypes.h:19

◆ subCellIntegration()

template<MInt nDim>
void FcBndryCnd< nDim >::subCellIntegration ( const MInt  subCellLvl,
MFloat subCellParentCoord,
const MInt  subCellPos,
const MInt  pCellId,
MFloat **  Ke_final 
)
Author
Moritz Waldmann

Definition at line 1226 of file fcbndrycnd.cpp.

1227 {
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}
void subCellIntegration(const MInt subCellLvl, MFloat *subCellParentCoord, const MInt childPos, const MInt pCellId, MFloat **Ke)
Execution of the subcell integration.
MFloat m_alpha
Definition: fcsolver.h:516
void getElementMatrix(MFloatScratchSpace &Ke, const MInt pCellId, const MFloat alpha, const MInt subCellLevel, const MFloat *subCellCoord=nullptr)
constexpr MLong IPOW2(MInt x)
constexpr MFloat FFPOW2(MInt x)

◆ updateForceVector()

template<MInt nDim>
void FcBndryCnd< nDim >::updateForceVector
Author
Moritz Waldmann

Definition at line 1160 of file fcbndrycnd.cpp.

1160 {
1161 TRACE();
1162
1163 for(MInt i = 0; i < (MInt)(m_bndryCndIds.size()); i++) {
1164 (this->*bndryCndHandlerForce[i])(i);
1165 }
1166}

◆ updateSystemMatrix()

template<MInt nDim>
void FcBndryCnd< nDim >::updateSystemMatrix
Author
Moritz Waldmann

Definition at line 1147 of file fcbndrycnd.cpp.

1147 {
1148 TRACE();
1149
1150 for(MInt i = 0; i < (MInt)(m_bndryCndIds.size()); i++) {
1151 (this->*bndryCndHandlerSystemMatrix[i])(i);
1152 }
1153}

◆ updateTrianglePosition()

template<MInt nDim>
void FcBndryCnd< nDim >::updateTrianglePosition
Author
Moritz Waldmann

Definition at line 2230 of file fcbndrycnd.cpp.

2230 {
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}
void writeOutSTLBoundaries(MInt index, MString prefix)
Write out the boundary segments in stl-file format.
MFloat * m_totalNodalDisplacements
Definition: fcsolver.h:523
MInt globalTimeStep

◆ writeOutModifiedBoundaries()

template<MInt nDim>
void FcBndryCnd< nDim >::writeOutModifiedBoundaries
Author
Moritz Waldmann

Debug function.

Definition at line 2281 of file fcbndrycnd.cpp.

2281 {
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}

◆ writeOutSTLBoundaries()

template<MInt nDim>
void FcBndryCnd< nDim >::writeOutSTLBoundaries ( MInt  index,
MString  prefix 
)
Author
Moritz Waldmann

Debug function.

Definition at line 2152 of file fcbndrycnd.cpp.

2152 {
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}

Friends And Related Function Documentation

◆ FcSolver

template<MInt nDim>
template<MInt nDim_>
friend class FcSolver
friend

Definition at line 37 of file fcbndrycnd.h.

Member Data Documentation

◆ bndryCells

template<MInt nDim>
FcGridBndryCell<nDim>* FcBndryCnd< nDim >::bndryCells
protected

Definition at line 51 of file fcbndrycnd.h.

◆ bndryCndHandlerForce

template<MInt nDim>
BndryCndHandler* FcBndryCnd< nDim >::bndryCndHandlerForce
protected

Definition at line 54 of file fcbndrycnd.h.

◆ bndryCndHandlerSystemMatrix

template<MInt nDim>
BndryCndHandler* FcBndryCnd< nDim >::bndryCndHandlerSystemMatrix
protected

Definition at line 53 of file fcbndrycnd.h.

◆ m_bndryCellIds

template<MInt nDim>
List<MInt>* FcBndryCnd< nDim >::m_bndryCellIds = nullptr

Definition at line 86 of file fcbndrycnd.h.

◆ m_bndryCells

template<MInt nDim>
std::vector<FcGridBndryCell<nDim> > FcBndryCnd< nDim >::m_bndryCells
protected

Definition at line 47 of file fcbndrycnd.h.

◆ m_bndryCndIds

template<MInt nDim>
std::vector<MInt> FcBndryCnd< nDim >::m_bndryCndIds
protected

Definition at line 59 of file fcbndrycnd.h.

◆ m_bndryCndOffsets

template<MInt nDim>
std::vector<MInt> FcBndryCnd< nDim >::m_bndryCndOffsets
protected

Definition at line 60 of file fcbndrycnd.h.

◆ m_bndryCndSegIds

template<MInt nDim>
std::vector<MInt> FcBndryCnd< nDim >::m_bndryCndSegIds
protected

Definition at line 62 of file fcbndrycnd.h.

◆ m_bndryNormalMethod

template<MInt nDim>
MString FcBndryCnd< nDim >::m_bndryNormalMethod
protected

Definition at line 72 of file fcbndrycnd.h.

◆ m_boundarySurfaces

template<MInt nDim>
MInt* FcBndryCnd< nDim >::m_boundarySurfaces = nullptr

Definition at line 88 of file fcbndrycnd.h.

◆ m_kFactor

template<MInt nDim>
MFloat FcBndryCnd< nDim >::m_kFactor = 1e+12
protected

Definition at line 79 of file fcbndrycnd.h.

◆ m_mapBndryCndIdSegId

template<MInt nDim>
MInt* FcBndryCnd< nDim >::m_mapBndryCndIdSegId {}
protected

Definition at line 65 of file fcbndrycnd.h.

◆ m_mapBndryCndSegId2Index

template<MInt nDim>
std::vector<MInt> FcBndryCnd< nDim >::m_mapBndryCndSegId2Index
protected

Definition at line 63 of file fcbndrycnd.h.

◆ m_multiBC

template<MInt nDim>
MBool FcBndryCnd< nDim >::m_multiBC
protected

Definition at line 73 of file fcbndrycnd.h.

◆ m_noBndryCellsPerSegment

template<MInt nDim>
MInt* FcBndryCnd< nDim >::m_noBndryCellsPerSegment = nullptr
protected

Definition at line 68 of file fcbndrycnd.h.

◆ m_noInternalCells

template<MInt nDim>
MInt FcBndryCnd< nDim >::m_noInternalCells
protected

Definition at line 57 of file fcbndrycnd.h.

◆ m_noSegments

template<MInt nDim>
MInt FcBndryCnd< nDim >::m_noSegments {}
protected

Definition at line 67 of file fcbndrycnd.h.

◆ m_solver

template<MInt nDim>
FcSolver<nDim>* FcBndryCnd< nDim >::m_solver
protected

Definition at line 50 of file fcbndrycnd.h.

◆ m_solverId

template<MInt nDim>
MInt FcBndryCnd< nDim >::m_solverId
protected

Definition at line 56 of file fcbndrycnd.h.

◆ m_sortedBndryCells

template<MInt nDim>
List<MInt>* FcBndryCnd< nDim >::m_sortedBndryCells = nullptr

Definition at line 87 of file fcbndrycnd.h.

◆ m_subCellLayerDepth

template<MInt nDim>
MInt* FcBndryCnd< nDim >::m_subCellLayerDepth = nullptr
protected

Definition at line 78 of file fcbndrycnd.h.

◆ m_t_BCAll

template<MInt nDim>
MInt FcBndryCnd< nDim >::m_t_BCAll
protected

Definition at line 76 of file fcbndrycnd.h.


The documentation for this class was generated from the following files: