#include // #include // for windows getcwd() #include "array.h" #include "densemat.h" #include "material.h" #include "tensor.h" #include "tetra.elemDG" #include "tetra.h" #include "tetra_MatNew.h" #include "vtr.h" #include #include #include #include #include #include // for linux getcwd() extern "C" { #include "mkl.h" } #include "Octree.h" // Added by qi jian using namespace std; using namespace ClipperLib; //library used to get the geometeries in nonConformal cases static int TetPolyOrderDim[4] = {6, 12, 30, 45}; static int FacePolyOrderDim[4] = {3, 6, 12, 18}; static int fac2tet[4][18] = { {5, 4, 3, 11, 10, 9, 12, 13, 25, 24, 23, 26, 30, 31, 32, 42, 43, 44}, {5, 2, 1, 11, 8, 7, 14, 15, 25, 22, 21, 27, 33, 34, 35, 42, 43, 44}, {4, 2, 0, 10, 8, 6, 16, 17, 24, 22, 20, 28, 36, 37, 38, 42, 43, 44}, {3, 1, 0, 9, 7, 6, 18, 19, 23, 21, 20, 29, 39, 40, 41, 42, 43, 44} // edge group 0, "", "",edge group 1, "", "",face group 2,"", edge group 3, "","",face group 4,face group 5,"","",tetra group 6 }; static int GAUSS_POINT_NUM[4] = {4,20,20,20}; // Number of points for volume order 0,1,2,3 const int TETRA_BASIS_IJK[45][4] ={ {0, 1, -1, -1}, // edge basis funcs {0, 2, -1, -1}, // group 0 {0, 3, -1, -1}, {1, 2, -1, -1}, {1, 3, -1, -1}, {2, 3, -1, -1}, // W6 (end of 0th order basis functions) {0, 1, -1, -1}, // edge basis funcs {0, 2, -1, -1}, // group 1 {0, 3, -1, -1}, {1, 2, -1, -1}, {1, 3, -1, -1}, {2, 3, -1, -1}, // W12 (end of 1st order basis functions) {1, 2, 3, -1}, // face basis funcs {1, 2, 3, -1}, // group 2 {0, 2, 3, -1}, {0, 2, 3, -1}, {0, 1, 3, -1}, {0, 1, 3, -1}, {0, 1, 2, -1}, {0, 1, 2, -1}, // W20 {0, 1, -1, -1}, // edge basis funcs {0, 2, -1, -1}, // group 3 {0, 3, -1, -1}, {1, 2, -1, -1}, {1, 3, -1, -1}, {2, 3, -1, -1}, // W26 {1, 2, 3, -1}, // face basis funcs {0, 2, 3, -1}, // group 4 {0, 1, 3, -1}, {0, 1, 2, -1}, // W30 (end of 2nd order basis functions) {1, 2, 3, -1}, // face basis funcs {1, 2, 3, -1}, // group 5 {1, 2, 3, -1}, {0, 2, 3, -1}, {0, 2, 3, -1}, {0, 2, 3, -1}, {0, 1, 3, -1}, {0, 1, 3, -1}, {0, 1, 3, -1}, {0, 1, 2, -1}, {0, 1, 2, -1}, {0, 1, 2, -1}, // W42 {0, 3, 2, 1}, // tetra basis funcs {0, 2, 3, 1}, // group 6 {0, 1, 3, 2} // W45 (end of 3rd order basis functions) }; static int DOFS_PER_EDGE[4] = {1, 2, 3, 3}; static int DOFS_PER_FACE_1[4] = {0, 0, 2, 2}; static int DOFS_PER_FACE_2[4] = {0, 0, 1, 1}; static int DOFS_PER_FACE_3[4] = {0, 0, 0, 3}; static int DOFS_PER_TET[4] = {0, 0, 0, 3}; tetra::tetra(int ob) { int i; objNum = ob; for (i = 0; i < 4; i++) nd[i] = nullptr; for (i = 0; i < 6; i++) eg[i] = nullptr; for (i = 0; i < 4; i++) fc[i] = nullptr; cnt = -1; mat = nullptr; nbc[0] = 0; nbc[1] = 0; nbc[2] = 0; nbc[3] = 0; LocalEDOF = 0; LocalHDOF = 0; edgeEDOF = 0; edgeHDOF = 0; faceEDOF = 0; faceHDOF = 0; TetrahedronFlag = -1; PolyOrderFlag = -1; LocalOffsetE = -1; LocalOffsetH = -1; ExcitationFlag = false; LTS_Flag = -1; isNonConformal = false; regularGroup = 0; nDipoles = 0; Conduct_Flag = -1; MassE = nullptr; MassH = nullptr; StiffE = nullptr; StiffH = nullptr; BiiE = nullptr; BiiH = nullptr; FiiE = nullptr; FiiH = nullptr; FijE = nullptr; FijH = nullptr; BijE = nullptr; BijH = nullptr; LHSInvE = nullptr; LHSInvH = nullptr; RHSLoc1E = nullptr; RHSLoc1H = nullptr; RHSLoc2E = nullptr; RHSLoc2H = nullptr; RHSCoup1E = nullptr; RHSCoup1H = nullptr; RHSCoup2E = nullptr; RHSCoup2H = nullptr; mapPEC = nullptr; mapPMC = nullptr; Class_dt = 0.0; Stability_dt = 0.0; NeighNum = 0; //-1 because it counts itself NeighNCNum = 0; //-1 because it counts itself vol_ = 0.0; for(int j = 0; j < 4; j ++){ gradZeta_[j].setvtr(0.0, 0.0, 0.0); } LocMapE = nullptr; LocMapH = nullptr; cntpec_ = 0; cntpmc_ = 0; EdofMap = nullptr; HdofMap = nullptr; } tetra::~tetra() { freeDofMap(); FreeNonExcitatonTetra(); } void tetra::FreeNonExcitatonTetra() { if (MassE != nullptr) delete MassE; MassE = nullptr; if (LHSInvE != nullptr) delete LHSInvE; LHSInvE = nullptr; if (MassH != nullptr) delete MassH; MassH = nullptr; if (LHSInvH != nullptr) delete LHSInvH; LHSInvH = nullptr; if (StiffE != nullptr) delete StiffE; StiffE = nullptr; if (StiffH != nullptr) delete StiffH; StiffH = nullptr; if (BiiE != nullptr) delete BiiE; BiiE = nullptr; if (BiiH != nullptr) delete BiiH; BiiH = nullptr; if (FiiE != nullptr) delete FiiE; FiiE = nullptr; if (FiiH != nullptr) delete FiiH; FiiH = nullptr; if (FijE != nullptr) delete FijE; FijE = nullptr; if (FijH != nullptr) delete FijH; FijH = nullptr; if (BijE != nullptr) delete BijE; BijE = nullptr; if (BijH != nullptr) delete BijH; BijH = nullptr; if (RHSLoc1E != nullptr) delete RHSLoc1E; RHSLoc1E = nullptr; if (RHSLoc1H != nullptr) delete RHSLoc1H; RHSLoc1H = nullptr; if (RHSLoc2E != nullptr) delete RHSLoc2E; RHSLoc2E = nullptr; if (RHSLoc2H != nullptr) delete RHSLoc2H; RHSLoc2H = nullptr; if (RHSCoup1E != nullptr) delete RHSCoup1E; RHSCoup1E = nullptr; if (RHSCoup1H != nullptr) delete RHSCoup1H; RHSCoup1H = nullptr; if (RHSCoup2E != nullptr) delete RHSCoup2E; RHSCoup2E = nullptr; if (RHSCoup2H != nullptr) delete RHSCoup2H; RHSCoup2H = nullptr; } void tetra::set_node(node* nd0, node* nd1, node* nd2, node* nd3) { nd[0] = nd0; nd[1] = nd1; nd[2] = nd2; nd[3] = nd3; } void tetra::reArrange() { int i, j; int tmpCNT; node* tmp; // make sure local and global numberings are consistent for (i = 0; i < 4; i++) { for (j = (i + 1); j < 4; j++) { if ((*nd[i]) > (*nd[j])) { tmp = nd[i]; nd[i] = nd[j]; nd[j] = tmp; tmpCNT = nbc[i]; nbc[i] = nbc[j]; nbc[j] = tmpCNT; } } } } void tetra::set_objNum(int ob) { objNum = ob; } void tetra::set_nbc(int bcd0, int bcd1, int bcd2, int bcd3) { nbc[0] = bcd0; nbc[1] = bcd1; nbc[2] = bcd2; nbc[3] = bcd3; } void tetra::setEdge(edge* egPtr, int n) { eg[n] = egPtr; } void tetra::setFace(face* fcPtr, int n) { fc[n] = fcPtr; } edge* tetra::getEdgePtr(int n) { return eg[n]; } face* tetra::getFacePtr(int n) { return fc[n]; } void tetra::TetraBasisW(fp_t *zeta, int p, vtr *W){ int i, j, k, l; vtr zeroVtr; zeroVtr.setvtr(0.,0.,0.); vtr* gradZeta = gradZeta_; i = TETRA_BASIS_IJK[p][0]; j = TETRA_BASIS_IJK[p][1]; k = TETRA_BASIS_IJK[p][2]; l = TETRA_BASIS_IJK[p][3]; switch(p){ case 0: case 1: case 2: case 3: case 4: case 5: // 6 edges *W = gradZeta[j] * zeta[i] - gradZeta[i] * zeta[j]; break; case 6: case 7: case 8: case 9: case 10: case 11: // 6 edges *W = (gradZeta[j] * zeta[i] + gradZeta[i] * zeta[j]) * 4.; break; case 12: case 14: case 16: case 18: // 4 faces // face{i,j,k}, group 2 *W = (gradZeta[k] * zeta[i] - gradZeta[i] * zeta[k]) * zeta[j] * 4.; break; case 13: case 15: case 17: case 19: // face{i,j,k}, group 2 *W = (gradZeta[j] * zeta[i] - gradZeta[i] * zeta[j]) * zeta[k] * 4.; break; case 20: case 21: case 22: case 23: case 24: case 25: // edge{i,j}, group 3 *W = (gradZeta[j] * zeta[i] * zeta[i] + gradZeta[i] * zeta[i] * zeta[j] * 2. - gradZeta[i] * zeta[j] * zeta[j] - gradZeta[j] * zeta[i] * zeta[j] * 2.) * 4.; break; case 26: case 27: case 28: case 29: // face{i,j,k}, group 4 *W = (gradZeta[k] * zeta[i] * zeta[j] + gradZeta[j] * zeta[i] * zeta[k] + gradZeta[i] * zeta[j] * zeta[k]) * 8.; break; case 30: case 33: case 36: case 39: *W = (gradZeta[k] * zeta[j] - gradZeta[j] * zeta[k]) * zeta[i] * zeta[i] * 4.; break; case 31: case 34: case 37: case 40: *W = (gradZeta[k] * zeta[i] - gradZeta[i] * zeta[k]) * zeta[j] * zeta[j] * 4.; break; case 32: case 35: case 38: case 41: *W = (gradZeta[j] * zeta[i] - gradZeta[i] * zeta[j]) * zeta[k] * zeta[k] * 4.; break; case 42: case 43: case 44: *W = (gradZeta[j] * zeta[i] - gradZeta[i] * zeta[j]) * zeta[k] * zeta[l] * 8.; break; default: *W = zeroVtr; break; } *W = *W / 3. / vol_; } void tetra::TetraBasisCurlW(fp_t *zeta, int p, vtr *W){ int i, j, k, l; vtr zeroVtr; zeroVtr.setvtr(0.,0.,0.); vtr* gradZeta = gradZeta_; i = TETRA_BASIS_IJK[p][0]; j = TETRA_BASIS_IJK[p][1]; k = TETRA_BASIS_IJK[p][2]; l = TETRA_BASIS_IJK[p][3]; switch(p){ case 0: case 1: case 2: case 3: case 4: case 5: // 6 edges *W = gradZeta[i] * gradZeta[j] - gradZeta[j] * gradZeta[i]; break; case 6: case 7: case 8: case 9: case 10: case 11: // 6 edges *W = zeroVtr; break; case 12: case 14: case 16: case 18: // 4 faces // face{i,j,k}, group 2 *W = ( gradZeta[j] * (gradZeta[k] * zeta[i] - gradZeta[i] * zeta[k]) + (gradZeta[i] * gradZeta[k] - gradZeta[k] * gradZeta[i]) * zeta[j] )* 4.; break; case 13: case 15: case 17: case 19: // face{i,j,k}, group 2 *W = (gradZeta[k] * (gradZeta[j] * zeta[i] - gradZeta[i] * zeta[j]) + (gradZeta[i] * gradZeta[j] - gradZeta[j] * gradZeta[i]) * zeta[k] )* 4.; break; case 20: case 21: case 22: case 23: case 24: case 25: // edge{i,j}, group 3 *W = zeroVtr; break; case 26: case 27: case 28: case 29: // face{i,j,k}, group 4 *W = zeroVtr; break; case 30: case 33: case 36: case 39: *W = ( (gradZeta[j] * gradZeta[k] - gradZeta[k] * gradZeta[j])*zeta[i]*zeta[i] + (gradZeta[i] * zeta[i] * 2.)*(gradZeta[k] * zeta[j] - gradZeta[j] * zeta[k]) ) * 4.; break; case 31: case 34: case 37: case 40: *W = ( (gradZeta[i] * gradZeta[k] - gradZeta[k] * gradZeta[i])*zeta[j]*zeta[j] + (gradZeta[j] * zeta[j] * 2.)*(gradZeta[k] * zeta[i] - gradZeta[i] * zeta[k]) ) * 4.; break; case 32: case 35: case 38: case 41: *W = ( (gradZeta[i] * gradZeta[j] - gradZeta[j] * gradZeta[i])*zeta[k]*zeta[k] + (gradZeta[k] * zeta[k] * 2.)*(gradZeta[j] * zeta[i] - gradZeta[i] * zeta[j]) ) * 4.; break; case 42: case 43: case 44: *W = ( (gradZeta[i] * gradZeta[j] - gradZeta[j] * gradZeta[i]) * zeta[k] * zeta[l] + (gradZeta[l]*zeta[k] + gradZeta[k]*zeta[l])*(gradZeta[j] * zeta[i] - gradZeta[i] * zeta[j])) * 8.; break; default: *W = zeroVtr; break; } *W = *W / 3. / 3. / vol_ / vol_; } void tetra::CountDOF_E() { int i, j; int cntpec = 0; int tetEDOF = 0; edgeEDOF = 0; faceEDOF = 0; for (i = 0; i < NumOfFaces; i++) { if (fc[i]->getbType() == pecType) for (j = 0; j < NumOfEdgesPerFace; j++) eg[fac2tet[i][j]]->setbType(pecType); else faceEDOF++; } // as long as one face is non-pec, then add tetrahedral basis functions for third order case if (faceEDOF > 0) tetEDOF = 1; for (i = 0; i < NumOfEdges; i++) { if (eg[i]->getbType() == pecType || eg[i]->IsPecPmc()) cntpec++; else edgeEDOF++; ; } LocalEDOF = DOFS_PER_EDGE[PolyOrderFlag] * edgeEDOF + DOFS_PER_FACE_1[PolyOrderFlag] * faceEDOF + DOFS_PER_FACE_2[PolyOrderFlag] * faceEDOF + DOFS_PER_FACE_3[PolyOrderFlag] * faceEDOF + DOFS_PER_TET[PolyOrderFlag] * tetEDOF; } void tetra::CountDOF_H() { int i, j; int cntpmc = 0; int tetHDOF = 0; edgeHDOF = 0; faceHDOF = 0; for (i = 0; i < NumOfFaces; i++) { if (fc[i]->getbType() == pmcType) { for (j = 0; j < NumOfEdgesPerFace; j++) eg[fac2tet[i][j]]->setbType(pmcType); } else faceHDOF++; } // as long as one face is non-pmc, then add tetrahedral basis functions for third order case if (faceHDOF > 0) tetHDOF = 1; for (i = 0; i < NumOfEdges; i++) { if (eg[i]->getbType() == pmcType || eg[i]->IsPecPmc()) cntpmc++; else edgeHDOF++; } LocalHDOF = DOFS_PER_EDGE[PolyOrderFlag] * edgeHDOF + DOFS_PER_FACE_1[PolyOrderFlag] * faceHDOF + DOFS_PER_FACE_2[PolyOrderFlag] * faceHDOF + DOFS_PER_FACE_3[PolyOrderFlag] * faceHDOF + DOFS_PER_TET[PolyOrderFlag] * tetHDOF; } void tetra::Local_DG_mapE(int* mapID, int offset) { // dofcount=12+8+6+4=30 -> P2 complete int i, j; // edges and faces !PEC or !PMC if (PolyOrderFlag > 3) { cout << "Be careful with DOFS_PER_EDGE length" << endl; exit(-1); } int counter = offset; int index = 0; for (i = 0; i < TetPolyOrderDim[PolyOrderFlag]; i++) { mapID[i] = NOT_NUMBERED; } // 0 and 1st order edge functions (6 or 12) for (int k = 0; k < DOFS_PER_EDGE[PolyOrderFlag] && k < 2; k++) { for (int i = 0; i < NumOfEdges; i++) { if (eg[i]->getbType() != pecType && !eg[i]->IsPecPmc()) { mapID[index] = counter; counter++; } index++; } } // Functions for the first 8 face functions (2 per face) for the 2 order // basis if (DOFS_PER_FACE_1[PolyOrderFlag] > 0) { for (i = 0; i < NumOfFaces; i++) { if (fc[i]->getbType() != pecType) { for (j = 0; j < DOFS_PER_FACE_1[PolyOrderFlag]; j++) { mapID[index] = counter; counter++; index++; } } else { index += DOFS_PER_FACE_1[PolyOrderFlag]; } } } // Second order edge functions (8) if (DOFS_PER_EDGE[PolyOrderFlag] > 2) { for (int i = 0; i < NumOfEdges; i++) { if (eg[i]->getbType() != pecType && !eg[i]->IsPecPmc()) { mapID[index] = counter; counter++; } index++; } } // Functions for the next 4 face functions (1 per face) for the 2 order // basis if (DOFS_PER_FACE_2[PolyOrderFlag] > 0) { for (i = 0; i < NumOfFaces; i++) { if (fc[i]->getbType() != pecType) { for (j = 0; j < DOFS_PER_FACE_2[PolyOrderFlag]; j++) { mapID[index] = counter; counter++; index++; } } else { index += DOFS_PER_FACE_2[PolyOrderFlag]; } } } // dofcount=12+8+6+4=30 -> P2 complete // Functions for the next 12 face functions (3 per face) for the 3rd order basis if (DOFS_PER_FACE_3[PolyOrderFlag] > 0){ for (i = 0; i < NumOfFaces; i++){ if (fc[i]->getbType() != pecType){ for (j = 0; j < DOFS_PER_FACE_3[PolyOrderFlag]; j++){ mapID[index] = counter; counter++; index++; } } else { index += DOFS_PER_FACE_3[PolyOrderFlag]; } } } // Functions for the next 3 tetra functions (3 per tetra) for the 3rd order basis int pecFaceCounter = 0; if (DOFS_PER_TET[PolyOrderFlag] > 0){ for (i = 0; i < NumOfFaces; i++){ if (fc[i]->getbType() == pecType) pecFaceCounter += 1; } if (pecFaceCounter != 4) { for (j = 0; j < DOFS_PER_TET[PolyOrderFlag]; j++){ mapID[index] = counter; counter++; index++; } } else { index += DOFS_PER_TET[PolyOrderFlag]; } } // dofcount = 12+8+6+4+12+3 = 45 -> P3 complete } void tetra::Local_DG_mapH(int* mapID, int offset) { // dofcount = 0 int i, j; // edges and faces !PEC or !PMC if (PolyOrderFlag > 3) { cout << "Be careful with DOFS_PER_EDGE length" << endl; exit(-1); } int counter = offset; int index = 0; for (i = 0; i < TetPolyOrderDim[PolyOrderFlag]; i++) { mapID[i] = NOT_NUMBERED; } // 0 and 1st order edge functions (6 or 12) for (int k = 0; k < DOFS_PER_EDGE[PolyOrderFlag] && k < 2; k++) { for (int i = 0; i < NumOfEdges; i++) { if (eg[i]->getbType() != pmcType && !eg[i]->IsPecPmc()) { mapID[index] = counter; counter++; } index++; } } // Functions for the first 8 face functions (2 per face) for the 2 order // basis if (DOFS_PER_FACE_1[PolyOrderFlag] > 0) { for (i = 0; i < NumOfFaces; i++) { if (fc[i]->getbType() != pmcType) { for (j = 0; j < DOFS_PER_FACE_1[PolyOrderFlag]; j++) { mapID[index] = counter; counter++; index++; } } else { index += DOFS_PER_FACE_1[PolyOrderFlag]; } } } // Second order edge functions (8) if (DOFS_PER_EDGE[PolyOrderFlag] > 2) { for (int i = 0; i < NumOfEdges; i++) { if (eg[i]->getbType() != pmcType && !eg[i]->IsPecPmc()) { mapID[index] = counter; counter++; } index++; } } // Functions for the next 4 face functions (1 per face) for the 2 order // basis if (DOFS_PER_FACE_2[PolyOrderFlag] > 0) { for (i = 0; i < NumOfFaces; i++) { if (fc[i]->getbType() != pmcType) { for (j = 0; j < DOFS_PER_FACE_2[PolyOrderFlag]; j++) { mapID[index] = counter; counter++; index++; } } else { index += DOFS_PER_FACE_2[PolyOrderFlag]; } } } // dofcount=12+8+6+4=30 -> P2 complete // Functions for the next 12 face functions (3 per face) for the 3rd order basis if (DOFS_PER_FACE_3[PolyOrderFlag] > 0){ for (i = 0; i < NumOfFaces; i++){ if (fc[i]->getbType() != pmcType){ for (j = 0; j < DOFS_PER_FACE_3[PolyOrderFlag]; j++){ mapID[index] = counter; counter++; index++; } } else { index += DOFS_PER_FACE_3[PolyOrderFlag]; } } } // Functions for the next 3 tetra functions (3 per tetra) for the 3rd order basis int pmcFaceCounter = 0; if (DOFS_PER_TET[PolyOrderFlag] > 0){ for (i = 0; i < NumOfFaces; i++){ if (fc[i]->getbType() == pmcType) pmcFaceCounter += 1; } if (pmcFaceCounter != 4) { for (j = 0; j < DOFS_PER_TET[PolyOrderFlag]; j++){ mapID[index] = counter; counter++; index++; } } else { index += DOFS_PER_TET[PolyOrderFlag]; } } // dofcount = 12+8+6+4+12+3 = 45 -> P3 complete } void tetra::set_TetrahedronFlag() { int i; int DG_FaceFlag; int InterFaceCounter = 0; int ABCFaceCounter = 0; // loop through 4 faces to see if this tetra is on any BC for (i = 0; i < NumOfFaces; i++) { DG_FaceFlag = fc[i]->bcPtr->getbType(); if (DG_FaceFlag == 0 || DG_FaceFlag == outputSurfType) { // || DG_FaceFlag == fieldPlaneType InterFaceCounter++; } else if (DG_FaceFlag == abcType) { ABCFaceCounter++; } else if (DG_FaceFlag == pmlType) { // Add PML type ExcitationFlag = true; } else if (DG_FaceFlag == planeWaveType) { ABCFaceCounter++; ExcitationFlag = true; } else if (DG_FaceFlag >= portType && DG_FaceFlag < pecType) { ABCFaceCounter++; ExcitationFlag = true; } } // TODO: review InterFaceCounter <= 4 if (InterFaceCounter <= 4 && ABCFaceCounter == 0) TetrahedronFlag = 0; // not ABC tetra etc else if (ABCFaceCounter >= 1) TetrahedronFlag = 1; // is ABC tetra else TetrahedronFlag = 0; // not ABC tetra etc if (TetrahedronFlag == -1) { cout << "ERROR: TetrahedronFlag not set (" << TetrahedronFlag << ")" << endl; return; } } void tetra::set_PolyOrderFlagDebug(int n) { PolyOrderFlag = n; if (PolyOrderFlag == NOT_NUMBERED) { cout << "ERROR: PolyOrderFlag not set (" << PolyOrderFlag << ")" << endl; return; } } // Modified by qi jian void tetra::set_NeighborTetra(tetra* tetARRAY, int* ncARRAY, int nonConformalCNT, Octree* octree_ptr, double min_AABB_size) { int i, j; tetra* neigh; std::vector myNeighset; // Stores cnt() indices of neighboring tetrahedra std::vector myNeighsetFaceMap; // Maps each face[i] to neighbor[i] // ------------------------------------------------------------------------------------------ // Procedure for tetrahedral with all conformal faces if (!isNonConformal) { // Standard conformal neighbor assignment for (i = 0; i < NumOfFaces; i++) { neigh = fc[i]->neighborTETRA(this); // Lookup neighbor through shared face if (neigh != NULL) { myNeighset.push_back(neigh->getcnt()); myNeighsetFaceMap.push_back(i); NeighNum++; } } } // ------------------------------------------------------------------------------------------ // Procedure for tetrehedral with nonconformal faces else { // Nonconformal case: use octree to find spatially overlapping tets std::vector NC_NeighSet; face* neighface; for (i = 0; i < NumOfFaces; i++) { if (fc[i]->getbType() == nonConformal) { // Step 1: Extract node coordinates for the face std::array, 3> probe_xyz = fc[i]->getNodeCoordinates(); // Step 2: Define triangle's AABB AABB face_box; face_box.xmin = std::min({probe_xyz[0][0], probe_xyz[1][0], probe_xyz[2][0]}); face_box.xmax = std::max({probe_xyz[0][0], probe_xyz[1][0], probe_xyz[2][0]}); face_box.ymin = std::min({probe_xyz[0][1], probe_xyz[1][1], probe_xyz[2][1]}); face_box.ymax = std::max({probe_xyz[0][1], probe_xyz[1][1], probe_xyz[2][1]}); face_box.zmin = std::min({probe_xyz[0][2], probe_xyz[1][2], probe_xyz[2][2]}); face_box.zmax = std::max({probe_xyz[0][2], probe_xyz[1][2], probe_xyz[2][2]}); auto enforce_min_extent = [&](double& min_val, double& max_val) { double extent = max_val - min_val; if (extent < min_AABB_size) { double center = 0.5 * (min_val + max_val); min_val = center - 0.5 * min_AABB_size; max_val = center + 0.5 * min_AABB_size; } }; enforce_min_extent(face_box.xmin, face_box.xmax); enforce_min_extent(face_box.ymin, face_box.ymax); enforce_min_extent(face_box.zmin, face_box.zmax); // Step 3: Use Octree to find candidate tets std::vector found_tets; bool success = octree_ptr->findNCTetraInOctree(face_box, found_tets); if (!success) { std::cout << "No candidate tetrahedron found for nonconformal face " << i << " in tetra " << cnt << ".\n"; } // Step 4: Refine candidates by checking face-level geometric overlap for (int tet_id : found_tets) { neigh = &(tetARRAY[tet_id]); // Candidate neighbor if (neigh->getcnt() != cnt) // Skip self { for (j = 0; j < NumOfFaces; j++) { neighface = neigh->fc[j]; if (neighface->getbType() == nonConformal) { if (triangle_overlaps_triangle(fc[i], neighface) && CheckIntersection(fc[i], neighface)) { // Record neighbor indices and mapping NC_NeighSet.push_back(neigh->getcnt()); myNeighset.push_back(neigh->getcnt()); myNeighsetFaceMap.push_back(i); NeighNum++; NeighNCNum++; } } } } } /* for(int idx = 0; idx < nonConformalCNT; idx++) { neigh = &(tetARRAY[ncARRAY[idx]]); if(neigh->getcnt() != cnt) { for(j = 0; j < NumOfFaces; j++) { neighface = neigh->fc[j]; if(neighface->getbType() == nonConformal) { if (triangle_overlaps_triangle(fc[i], neighface)) { if(CheckIntersection(fc[i], neighface)) { NC_NeighSet.push_back(neigh->getcnt()); myNeighset.push_back(neigh->getcnt()); myNeighsetFaceMap.push_back(i); NeighNum++; NeighNCNum++; } } } } } } */ } else { // Fallback for conformal faces in mixed mesh neigh = fc[i]->neighborTETRA(this); if (neigh != NULL) { myNeighset.push_back(neigh->getcnt()); myNeighsetFaceMap.push_back(i); NeighNum++; } } } // Step 4: Store nonconformal neighbor tetrahedra NeighNCTetra = new tetra*[NeighNCNum]; for (i = 0; i < NeighNCNum; i++) { NeighNCTetra[i] = &(tetARRAY[NC_NeighSet[i]]); } } // Step 5: Store all neighbors (conformal or mixed) NeighTetra = new tetra*[NeighNum]; NeighTetraFaceMap = new int[NeighNum]; for (i = 0; i < NeighNum; i++) { NeighTetra[i] = &(tetARRAY[myNeighset[i]]); NeighTetraFaceMap[i] = myNeighsetFaceMap[i]; } } bool tetra::triangle_overlaps_triangle(face* LocalFace, face* NeighFace){ bool SamePlaneX = false; bool SamePlaneY = false; bool SamePlaneZ = false; bool SamePlane = false; bool Overlap = false; double tri1Coords[6]; double tri2Coords[6]; int PlaneID = 0; double thridCoord = 0.0; vtr triangle1[3]; vtr triangle2[3]; for (int i = 0; i < 3; i++){ triangle1[i].setvtr(LocalFace->nd[i]->getCoord().getx(), LocalFace->nd[i]->getCoord().gety(), LocalFace->nd[i]->getCoord().getz()); triangle2[i].setvtr(NeighFace->nd[i]->getCoord().getx(), NeighFace->nd[i]->getCoord().gety(), NeighFace->nd[i]->getCoord().getz()); } // Check which Plane is the source if( (essentiallyEqual(triangle1[0].getx(), triangle1[1].getx(), Tolerance)) && (essentiallyEqual(triangle1[0].getx(), triangle1[2].getx(), Tolerance)) && (essentiallyEqual(triangle1[1].getx(), triangle1[2].getx(), Tolerance))){ SamePlaneX = true; } if( (essentiallyEqual(triangle1[0].gety(), triangle1[1].gety(), Tolerance)) && (essentiallyEqual(triangle1[0].gety(), triangle1[2].gety(), Tolerance)) && (essentiallyEqual(triangle1[1].gety(), triangle1[2].gety(), Tolerance))){ SamePlaneY = true; } if( (essentiallyEqual(triangle1[0].getz(), triangle1[1].getz(), Tolerance)) && (essentiallyEqual(triangle1[0].getz(), triangle1[2].getz(), Tolerance)) && (essentiallyEqual(triangle1[1].getz(), triangle1[2].getz(), Tolerance))){ SamePlaneZ = true; } // Check if source and target are Coplanar if(SamePlaneX){ if( (essentiallyEqual(triangle1[0].getx(), triangle2[0].getx(), Tolerance)) && (essentiallyEqual(triangle1[1].getx(), triangle2[1].getx(), Tolerance)) && (essentiallyEqual(triangle1[2].getx(), triangle2[2].getx(), Tolerance))){ SamePlane = true; PlaneID = 0; } }else if(SamePlaneY){ if( (essentiallyEqual(triangle1[0].gety(), triangle2[0].gety(), Tolerance)) && (essentiallyEqual(triangle1[1].gety(), triangle2[1].gety(), Tolerance)) && (essentiallyEqual(triangle1[2].gety(), triangle2[2].gety(), Tolerance))){ SamePlane = true; PlaneID = 1; } }else if(SamePlaneZ){ if( (essentiallyEqual(triangle1[0].getz(), triangle2[0].getz(), Tolerance)) && (essentiallyEqual(triangle1[1].getz(), triangle2[1].getz(), Tolerance)) && (essentiallyEqual(triangle1[2].getz(), triangle2[2].getz(), Tolerance))){ SamePlane = true; PlaneID = 2; } } if(SamePlane){ LocalFace->ReturnIntferfacePlaneCoord(tri1Coords, thridCoord, PlaneID); NeighFace->ReturnIntferfacePlaneCoord(tri2Coords, thridCoord, PlaneID); ///// new version Paths subj(1), clip(1), solution; subj[0]<< IntPoint(cInt(tri1Coords[0] * scaleFact),cInt(tri1Coords[1] * scaleFact)) << IntPoint(cInt(tri1Coords[2] * scaleFact),cInt(tri1Coords[3] * scaleFact)) << IntPoint(cInt(tri1Coords[4] * scaleFact),cInt(tri1Coords[5] * scaleFact)); clip[0]<< IntPoint(cInt(tri2Coords[0] * scaleFact),cInt(tri2Coords[1] * scaleFact)) << IntPoint(cInt(tri2Coords[2] * scaleFact),cInt(tri2Coords[3] * scaleFact)) << IntPoint(cInt(tri2Coords[4] * scaleFact),cInt(tri2Coords[5] * scaleFact)); Clipper c; c.AddPaths(subj, ptSubject, true); c.AddPaths(clip, ptClip, true); if(c.Execute(ctIntersection, solution, pftNonZero, pftNonZero)){ if(solution.size() > 0){ if(solution[0].size() >= 3) Overlap = true; else Overlap = false; }else Overlap = false; }else Overlap = false; } return (Overlap || triangle_overlaps_triangleCO(LocalFace, NeighFace)); } bool tetra::triangle_overlaps_triangleCO(face* LocalFace, face* NeighFace){ vtr triangle1[3]; vtr triangle2[3]; for(int i = 0; i < 3; i++){ triangle1[i].setvtr(LocalFace->nd[i]->getCoord().getx(), LocalFace->nd[i]->getCoord().gety(), LocalFace->nd[i]->getCoord().getz()); triangle2[i].setvtr(NeighFace->nd[i]->getCoord().getx(), NeighFace->nd[i]->getCoord().gety(), NeighFace->nd[i]->getCoord().getz()); } vector PointsDiff; vtr tmpvtr; // conformal but not planar triangles bool Check1 = false; bool Check2 = false; bool Check3 = false; for (int i = 0 ; i < 3 ; i++){ for (int j = 0; j < 3 ; j++){ tmpvtr = triangle1[i] - triangle2[j]; PointsDiff.push_back(tmpvtr); } } Check1 = ((PointsDiff[0].magnitude() < Tolerance) || (PointsDiff[1].magnitude() < Tolerance) || (PointsDiff[2].magnitude() < Tolerance)); Check2 = ((PointsDiff[3].magnitude() < Tolerance) || (PointsDiff[4].magnitude() < Tolerance) || (PointsDiff[5].magnitude() < Tolerance)); Check3 = ((PointsDiff[6].magnitude() < Tolerance) || (PointsDiff[7].magnitude() < Tolerance) || (PointsDiff[8].magnitude() < Tolerance)); bool OverlapCon = (Check1 && Check2 && Check3); return OverlapCon; } bool tetra::essentiallyEqual(double a, double b, double epsilon){ return fabs(a - b) <= ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon); } void tetra::set_ConductivityFlag() { if (mat->sigma.getEntry(0, 0) == 0.0) Conduct_Flag = 0; else Conduct_Flag = 1; if (Conduct_Flag == NOT_NUMBERED) { cout << "ERROR: Conduct_Flag not set (" << Conduct_Flag << ")" << endl; return; } } void tetra::SetFacePEC() { int i, j; for (i = 0; i < NumOfFaces; i++) { if (fc[i]->getbType() == pecType) { for (j = 0; j < NumOfEdgesPerFace; j++) eg[fac2tet[i][j]]->setbType(pecType); } } } void tetra::SetFacePMC() { int i, j; for (i = 0; i < NumOfFaces; i++) { if (fc[i]->getbType() == pmcType) { for (j = 0; j < NumOfEdgesPerFace; j++) eg[fac2tet[i][j]]->setbType(pmcType); } } } tetra& tetra::operator=(const tetra& right) { int i; for (i = 0; i < NumOfNodes; i++) { nd[i] = right.nd[i]; fc[i] = right.fc[i]; nbc[i] = right.nbc[i]; } for (i = 0; i < NumOfEdges; i++) eg[i] = right.eg[i]; objNum = right.objNum; return *this; } int tetra::operator==(const tetra& right) const { for (int i = 0; i < NumOfNodes; i++) { if (nd[i] != (right.nd[i])) return NO; } return YES; } void tetra::geometry(vtr* lvtr, vtr* avtr, fp_t* vol) { int i, i1, i2, i3; vtr vv, tt; // Just needed 3 vectors because the fourth one is the addition of the others for (i = 0; i < 3; i++) { lvtr[i] = nd[i + 1]->coord - nd[0]->coord; } for (i = 0; i < 3; i++) { i1 = (i + 1) % NumOfNodes; i2 = (i + 2) % NumOfNodes; i3 = (i + 3) % NumOfNodes; tt = nd[i2]->coord - nd[i1]->coord; vv = nd[i3]->coord - nd[i1]->coord; avtr[i] = tt * vv; avtr[i] = avtr[i] * 0.5; tt = nd[i]->coord - nd[i1]->coord; if (dotP(avtr[i], tt) < 0.0) avtr[i] = avtr[i] * (-1.0); } avtr[3].reset(); avtr[3] = avtr[3] - (avtr[0] + avtr[1] + avtr[2]); (*vol) = dotP(avtr[2], lvtr[1]) / 3.0; } void tetra::makeCoeff(vtr avtr[], tensor epsr, fp_t coeffA[][3]) { int i, j; for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) coeffA[i][j] = dotP((epsr * avtr[j]), avtr[i]); } } void tetra::makeCoeff_curl(vtr avtr[], fp_t coeffCurl[][3], fp_t& scale) { coeffCurl[0][0] = scale * dotP(avtr[0], (avtr[1] * avtr[2])); coeffCurl[0][1] = scale * dotP(avtr[0], (avtr[2] * avtr[0])); coeffCurl[0][2] = scale * dotP(avtr[0], (avtr[0] * avtr[1])); coeffCurl[1][0] = scale * dotP(avtr[1], (avtr[1] * avtr[2])); coeffCurl[1][1] = scale * dotP(avtr[1], (avtr[2] * avtr[0])); coeffCurl[1][2] = scale * dotP(avtr[1], (avtr[0] * avtr[1])); coeffCurl[2][0] = scale * dotP(avtr[2], (avtr[1] * avtr[2])); coeffCurl[2][1] = scale * dotP(avtr[2], (avtr[2] * avtr[0])); coeffCurl[2][2] = scale * dotP(avtr[2], (avtr[0] * avtr[1])); } void tetra::set_einc(fp_t t, ArrayFP* nxh_inc, ArrayFP* nxnxe_inc) { int i, j; Coordinate coord; int LocalFaceDim; ArrayFP* nxh; ArrayFP* nxnxe; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; nxh = new ArrayFP(LocalFaceDim); nxnxe = new ArrayFP(LocalFaceDim); for (i = 0; i < 4; i++) { if (fc[i]->getbType() == planeWaveType || (fc[i]->getbType() >= portType && fc[i]->getbType() < pecType)) { fc[i]->make_upd_Einc(coord, nxh, nxnxe, t, this, PolyOrderFlag); for (j = 0; j < LocalFaceDim; j++) { nxh_inc->addentry(fac2tet[i][j], nxh->getentry(j)); nxnxe_inc->addentry(fac2tet[i][j], nxnxe->getentry(j)); } } } delete nxh; delete nxnxe; } void tetra::set_hinc(fp_t t, ArrayFP* nxe_inc, ArrayFP* nxnxh_inc) { int i, j; Coordinate coord; int LocalFaceDim; ArrayFP* nxe; ArrayFP* nxnxh; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; nxe = new ArrayFP(LocalFaceDim); nxnxh = new ArrayFP(LocalFaceDim); for (i = 0; i < 4; i++) { if (fc[i]->getbType() == planeWaveType || (fc[i]->getbType() >= portType && fc[i]->getbType() < pecType)) { fc[i]->make_upd_Hinc(coord, nxe, nxnxh, t, this, PolyOrderFlag); for (j = 0; j < LocalFaceDim; j++) { nxe_inc->addentry(fac2tet[i][j], nxe->getentry(j)); nxnxh_inc->addentry(fac2tet[i][j], nxnxh->getentry(j)); } } } delete nxe; delete nxnxh; } /** Apply PEC PMC boundary conditions */ void tetra::MapPEC() { // TODO: make it dynamic if (PolyOrderFlag > 3) { cout << "Be careful with MapPEC" << endl; exit(-1); } int index = 0; int face_pec_cnt = 0; int tet_pec_cnt = 0; int cntpec_aux = 0; int counter = 0; for (int i = 0; i < NumOfEdges; i++) if (eg[i]->getbType() == pecType || eg[i]->IsPecPmc()) cntpec_aux++; if (DOFS_PER_FACE_1[PolyOrderFlag] > 0 || DOFS_PER_FACE_2[PolyOrderFlag] > 0) for (int j = 0; j < 4; j++) if (fc[j]->getbType() == pecType) face_pec_cnt++; if (face_pec_cnt == 4) tet_pec_cnt = 1; cntpec_ += DOFS_PER_EDGE[PolyOrderFlag] * cntpec_aux + (DOFS_PER_FACE_1[PolyOrderFlag] + DOFS_PER_FACE_2[PolyOrderFlag] + DOFS_PER_FACE_3[PolyOrderFlag]) * face_pec_cnt + DOFS_PER_TET[PolyOrderFlag] * tet_pec_cnt; if (cntpec_ != 0) { mapPEC = new int[cntpec_]; for (int i = 0; i < NumOfEdges; i++) { if (eg[i]->getbType() == pecType && eg[i]->IsPecPmc()) { mapPEC[index] = i; if (DOFS_PER_EDGE[PolyOrderFlag] > 1) mapPEC[index + cntpec_aux] = i + NumOfEdges; index++; } } if (DOFS_PER_EDGE[PolyOrderFlag] > 1) { index += cntpec_aux; counter = 2 * NumOfEdges; // If this statement is achieved it mean that we // have checked all the values of the 12 previous // basis functions (edges order 0 & edges order 1) } if (DOFS_PER_FACE_1[PolyOrderFlag] > 0) { for (int i = 0; i < NumOfFaces; i++) { if (fc[i]->getbType() == pecType) { mapPEC[index++] = counter; mapPEC[index++] = counter + 1; } counter += 2; } } if (DOFS_PER_EDGE[PolyOrderFlag] > 2) for (int i = 0; i < NumOfEdges; i++) { if (eg[i]->getbType() == pecType && eg[i]->IsPecPmc()) mapPEC[index++] = counter; counter++; } if (DOFS_PER_FACE_2[PolyOrderFlag] > 0) for (int i = 0; i < NumOfFaces; i++) { if (fc[i]->getbType() == pecType) mapPEC[index++] = counter; counter++; } if (DOFS_PER_FACE_3[PolyOrderFlag] > 0) for (int i = 0; i < NumOfFaces; i++) { if (fc[i]->getbType() == pecType){ mapPEC[index++] = counter; mapPEC[index++] = counter+1; mapPEC[index++] = counter+2; } counter += 3; } if (DOFS_PER_TET[PolyOrderFlag] > 0){ if (tet_pec_cnt == 1){ mapPEC[index++] = counter; mapPEC[index++] = counter+1; mapPEC[index++] = counter+2; } counter += 3; } } } void tetra::MapPMC() { if (PolyOrderFlag > 3) { cout << "Be careful with MapPMC" << endl; exit(-1); } int index = 0; int face_pmc_cnt = 0; int tet_pmc_cnt = 0; int cntpmc_aux = 0; int counter = 0; for (int i = 0; i < NumOfEdges; i++) if (eg[i]->getbType() == pmcType || eg[i]->IsPecPmc()) cntpmc_aux++; if (DOFS_PER_FACE_1[PolyOrderFlag] > 0 || DOFS_PER_FACE_2[PolyOrderFlag] > 0) for (int j = 0; j < 4; j++) if (fc[j]->getbType() == pmcType) face_pmc_cnt++; cntpmc_ += DOFS_PER_EDGE[PolyOrderFlag] * cntpmc_aux + (DOFS_PER_FACE_1[PolyOrderFlag] + DOFS_PER_FACE_2[PolyOrderFlag] + DOFS_PER_FACE_3[PolyOrderFlag]) * face_pmc_cnt + DOFS_PER_TET[PolyOrderFlag] * tet_pmc_cnt; if (cntpmc_ != 0) { mapPMC = new int[cntpmc_]; for (int i = 0; i < NumOfEdges; i++) { if (eg[i]->getbType() == pmcType && eg[i]->IsPecPmc()) { mapPMC[index] = i; if (DOFS_PER_EDGE[PolyOrderFlag] > 1) mapPMC[index + cntpmc_aux] = i + NumOfEdges; index++; } } if (DOFS_PER_EDGE[PolyOrderFlag] > 1) { index += cntpmc_aux; counter = 2 * NumOfEdges; // If this statement is achieved it mean that we // have checked all the values of the 12 previous // basis functions (edges order 0 & edges order 1) } if (DOFS_PER_FACE_1[PolyOrderFlag] > 0) { for (int i = 0; i < NumOfFaces; i++) { if (fc[i]->getbType() == pmcType) { mapPMC[index++] = counter; mapPMC[index++] = counter + 1; } counter += 2; } } if (DOFS_PER_EDGE[PolyOrderFlag] > 2) for (int i = 0; i < NumOfEdges; i++) { if (eg[i]->getbType() == pmcType && eg[i]->IsPecPmc()) mapPMC[index++] = counter; counter++; } if (DOFS_PER_FACE_2[PolyOrderFlag] > 0) for (int i = 0; i < NumOfFaces; i++) { if (fc[i]->getbType() == pmcType) mapPMC[index++] = counter; counter++; } if (DOFS_PER_FACE_3[PolyOrderFlag] > 0) for (int i = 0; i < NumOfFaces; i++) { if (fc[i]->getbType() == pmcType){ mapPMC[index++] = counter; mapPMC[index++] = counter + 1; mapPMC[index++] = counter + 2; } counter += 3; } if (DOFS_PER_TET[PolyOrderFlag] > 0){ if (tet_pmc_cnt == 1){ mapPMC[index++] = counter; mapPMC[index++] = counter + 1; mapPMC[index++] = counter + 2; } counter += 3; } } } void tetra::ApplyPEC_Vector(ArrayFP* b, int LocalDim) { if (cntpec_ != 0) { for (int i = 0; i < LocalDim; i++) if (LocMapE[i] == -1) b->setentry(i, 0.0); } } void tetra::ApplyPEC(denseMat* A, int LocalDim) { if (cntpec_ != 0) { for (int i = 0; i < LocalDim; i++) { if (LocMapE[i] == -1) { for (int j = 0; j < LocalDim; j++) { A->setEntry(i, j, 0.0); A->setEntry(j, i, 0.0); } } } } } void tetra::ApplyPEC_E(denseMat* A, int LocalDim) { if (cntpec_ != 0) { for (int i = 0; i < LocalDim; i++) { if (LocMapE[i] == -1) { for (int j = 0; j < LocalDim; j++) A->setEntry(i, j, 0.0); } } } } void tetra::ApplyPEC_H(denseMat* A, int LocalDim) { if (cntpec_ != 0) { for (int i = 0; i < LocalDim; i++) { if (LocMapE[i] == -1) { for (int j = 0; j < LocalDim; j++) A->setEntry(j, i, 0.0); } } } } void tetra::ApplyPEC_Neigh_H(denseMat* A, tetra* neigh, int NeighDim) { if (neigh->cntpec_ != 0) { for (int i = 0; i < neigh->cntpec_; i++) { for (int j = 0; j < NeighDim; j++) { A->setEntry(j, neigh->mapPEC[i], 0.0); } } } } void tetra::ApplyPMC_Vector(ArrayFP* b, int LocalDim) { if (cntpmc_ != 0) { for (int i = 0; i < LocalDim; i++) if (LocMapH[i] == -1) b->setentry(i, 0.0); } } void tetra::ApplyPMC_E(denseMat* A, int LocalDim) { if (cntpmc_ != 0) { for (int i = 0; i < LocalDim; i++) { if (LocMapH[i] == -1) { for (int j = 0; j < LocalDim; j++) A->setEntry(j, i, 0.0); } } } } void tetra::ApplyPMC_Neigh_E(denseMat* A, tetra* neigh, int NeighDim) { if (neigh->cntpmc_ != 0) { for (int i = 0; i < neigh->cntpmc_; i++) { for (int j = 0; j < NeighDim; j++) { A->setEntry(j, neigh->mapPMC[i], 0.0); } } } } void tetra::ApplyPMC(denseMat* A, int LocalDim) { if (cntpmc_ != 0) { for (int i = 0; i < LocalDim; i++) { if (LocMapH[i] == -1) { for (int j = 0; j < LocalDim; j++) { A->setEntry(i, j, 0.0); A->setEntry(j, i, 0.0); } } } } } void tetra::ApplyPMC_H(denseMat* A, int LocalDim) { if (cntpmc_ != 0) { for (int i = 0; i < LocalDim; i++) { if (LocMapH[i] == -1) { for (int j = 0; j < LocalDim; j++) A->setEntry(i, j, 0.0); } } } } void tetra::Calculate_S_Matrix( denseMat* Curl_Sc) { // Se or Sh in the formulation int i, j, dim; fp_t vol; fp_t coeffC[3][3]; fp_t cval; vtr lvtr[4]; vtr avtr[4]; fp_t scale = 1.0; Curl_Sc->reset(); dim = Curl_Sc->getRowDim(); geometry(lvtr, avtr, &vol); makeCoeff_curl(avtr, coeffC, scale); // dotP(u, \nabla x u) dV // dotP(u, u x u) dV // u = avtr for (i = 0; i < dim; i++) { for (j = 0; j < dim; j++) { cval = (coeffC[0][0] * C00_P2[i][j]) + (coeffC[0][1] * C01_P2[i][j]) + (coeffC[1][0] * C10_P2[i][j]) + (coeffC[0][2] * C02_P2[i][j]) + (coeffC[2][0] * C20_P2[i][j]) + (coeffC[1][1] * C11_P2[i][j]) + (coeffC[1][2] * C12_P2[i][j]) + (coeffC[2][1] * C21_P2[i][j]) + (coeffC[2][2] * C22_P2[i][j]); cval = (2.0 * cval) / (9.0 * vol * vol * (fp_t)(C_DNUM)); Curl_Sc->addEntry(i, j, cval); } } } void tetra::Calculate_S_Matrix_Numeric(denseMat* Curl_Sc) { // Se or Sh in the formulation int i, j, k, dim; fp_t vol; fp_t* z; fp_t wgt = 0.; fp_t cval; vtr lvtr[4]; vtr avtr[4]; Curl_Sc->reset(); dim = Curl_Sc->getRowDim(); vtr w1, w2; geometry(lvtr, avtr, &vol); fp_t (*gaussQuadPoints)[5]; GetFormula3dPtr(GAUSS_POINT_NUM[PolyOrderFlag], gaussQuadPoints); vtr* gaussBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; vtr* gaussBasisCurlVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; for (i = 0; i < dim; i++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { z = &gaussQuadPoints[k][0]; TetraBasisW(z, i, &w1); TetraBasisCurlW(z, i, &w2); gaussBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = w1; // Removed epsr gaussBasisCurlVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = w2; } } for (i = 0; i < dim; i++){ for (j = 0; j < dim; j++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { wgt = gaussQuadPoints[k][4]; w1 = gaussBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k]; w2 = gaussBasisCurlVtrs[j * GAUSS_POINT_NUM[PolyOrderFlag] + k]; cval += wgt * dotP(w1, w2); } Curl_Sc->addEntry(i, j, cval * vol); cval = 0.0; } } delete[] gaussBasisVtrs; delete[] gaussBasisCurlVtrs; } /** E matrices */ void tetra::Calculate_M_Matrix_E() { int i, j, dim; fp_t cval = 0.0; fp_t vol; fp_t coeffA[3][3]; vtr lvtr[4]; // the 3 first positions are the vectors from the node 0 to the // others [{0,1}, {0,2}, {0,3}] vtr avtr[4]; // array of vectors normal to the faces and with a magnitude // equal to the area of them [f0, f1, f2, f3] int* map = new int[TetPolyOrderDim[PolyOrderFlag]]; Local_DG_mapE(map, 0); if (LocalEDOF == 0) { MassE = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); MassE->reset(); return; } MassE = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); dim = MassE->getRowDim(); if (dim != MassE->getColDim()) { cerr << "MassE: Non-square matrix passed." << endl; } MassE->reset(); geometry(lvtr, avtr, &vol); makeCoeff(avtr, mat->epsr, coeffA); // dotP(u, [t]*u) dV // u = avtr, [t]*u = [t] * avtr for (i = 0; i < dim; i++) { for (j = 0; j < dim; j++) { cval = (coeffA[0][0] * T00_P2[i][j]) + (coeffA[0][1] * T01_P2[i][j]) + (coeffA[1][0] * T10_P2[i][j]) + (coeffA[0][2] * T02_P2[i][j]) + (coeffA[2][0] * T20_P2[i][j]) + (coeffA[1][1] * T11_P2[i][j]) + (coeffA[1][2] * T12_P2[i][j]) + (coeffA[2][1] * T21_P2[i][j]) + (coeffA[2][2] * T22_P2[i][j]); cval = cval / (vol * (fp_t)T_DNUM); MassE->addEntry(i, j, cval); } } // If it's PEC, set a 1 if it's in the diagonal, 0 if not for (i = 0; i < TetPolyOrderDim[PolyOrderFlag]; i++) { for (j = 0; j < TetPolyOrderDim[PolyOrderFlag]; j++) { if (map[i] < 0 || map[j] < 0) { if (i == j) { MassE->setEntry(i, j, 1.0); // need to be inversed } else { MassE->setEntry(i, j, 0); // need to be inversed } } } } if (map != nullptr) delete[] map; } void tetra::Calculate_R_Matrix_E(denseMat* R_Matrix_E, fp_t dt) { if (LocalEDOF == 0) return; int LocalDim, LocalFaceDim; int DGface_bc; int AbcFlag = 0; fp_t eps_o = Eo; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); int i, j, dim; int k = 0; fp_t cval = 0.0; fp_t vol; fp_t coeffA[3][3]; vtr lvtr[4]; vtr avtr[4]; int* map = new int[TetPolyOrderDim[PolyOrderFlag]]; Local_DG_mapE(map, 0); dim = R_Matrix_E->getRowDim(); if (dim != R_Matrix_E->getColDim()) { cerr << "MassE: Non-square matrix passed." << endl; } R_Matrix_E->reset(); geometry(lvtr, avtr, &vol); makeCoeff(avtr, mat->sigma, coeffA); for (i = 0; i < dim; i++) { for (j = 0; j < dim; j++) { cval = (coeffA[0][0] * T00_P2[i][j]) + (coeffA[0][1] * T01_P2[i][j]) + (coeffA[1][0] * T10_P2[i][j]) + (coeffA[0][2] * T02_P2[i][j]) + (coeffA[2][0] * T20_P2[i][j]) + (coeffA[1][1] * T11_P2[i][j]) + (coeffA[1][2] * T12_P2[i][j]) + (coeffA[2][1] * T21_P2[i][j]) + (coeffA[2][2] * T22_P2[i][j]); cval = cval / (vol * (fp_t)T_DNUM); R_Matrix_E->addEntry(i, j, cval); } } if (map != nullptr) delete[] map; (*R_Matrix_E).scale(0.5 * (dt / eps_o)); LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; denseMat tetBe(LocalDim, LocalDim); // Matrices On the Faces denseMat Be(LocalFaceDim, LocalFaceDim); for (i = 0; i < 4; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { AbcFlag = 1; fc[i]->Calculate_Be_Matrix(&Be); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { tetBe.addEntry(fac2tet[i][j], fac2tet[i][k], Be.getEntry(j, k)); } } } } // ABC Boundary if (AbcFlag == 1) { for (i = 0; i < 4; i++) { // the same if (fc[i]->bcPtr->getbType() == abcType) { Y = 1.0 / fc[i]->bcPtr->get_ABCImpVal(); } else if (fc[i]->bcPtr->getbType() == planeWaveType) { Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); } else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) { Y = 1.0 / fc[i]->bcPtr->get_PortImpVal(); } } tetBe.scale(-0.25 * Y * (dt / eps_o)); *R_Matrix_E = *R_Matrix_E + tetBe; } } void tetra::Calculate_Bii_Matrix_E() { if (LocalEDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); fp_t Zneigh = 0.0; fp_t Yt = 0.0; tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; BiiE = new denseMat(LocalDim, LocalDim); denseMat Be(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == pmlType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr){ printf("ERROR: Null pointer at bType = 0 in tetra %d in face %d = [(%.8f, %.8f, %.8f), (%.8f, %.8f, %.8f), (%.8f, %.8f, %.8f)]", cnt, i, fc[i]->nd[0]->getCoord().getx(), fc[i]->nd[0]->getCoord().gety(), fc[i]->nd[0]->getCoord().getz(), fc[i]->nd[1]->getCoord().getx(), fc[i]->nd[1]->getCoord().gety(), fc[i]->nd[1]->getCoord().getz(), fc[i]->nd[2]->getCoord().getx(), fc[i]->nd[2]->getCoord().gety(), fc[i]->nd[2]->getCoord().getz()); cout << endl; } Zneigh = No * sqrt(neigh->mat->mur.getEntry(0, 0) / neigh->mat->epsr.getEntry(0, 0)); Yt = 1.0 / (0.5 * (Zneigh + Z)); fc[i]->Calculate_Be_Matrix(&Be); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { BiiE->addEntry(fac2tet[i][j], fac2tet[i][k], 0.5 * Yt * Be.getEntry(j, k) * GAMMA); } } } else if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { fc[i]->Calculate_Be_Matrix(&Be); if (fc[i]->bcPtr->getbType() == abcType) Y = 1.0 / fc[i]->bcPtr->get_ABCImpVal(); else if (fc[i]->bcPtr->getbType() == planeWaveType) Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) Y = 1.0 / fc[i]->bcPtr->get_PortImpVal(); for (j = 0; j < LocalFaceDim; j++) for (k = 0; k < LocalFaceDim; k++) BiiE->addEntry(fac2tet[i][j], fac2tet[i][k], 0.5 * Y * Be.getEntry(j, k)); } else if (DGface_bc == pecType) { } else if (DGface_bc == pmcType) { } else if (DGface_bc == nonConformal){ for(int idx = 0; idx < NeighNCNum; idx++){ if (OverlapMapVec[i].find(idx)->second){ if(IntersectionMapVec[i].find(idx)->second){ Zneigh = No * sqrt(NeighNCTetra[idx]->mat->mur.getEntry(0, 0) / NeighNCTetra[idx]->mat->epsr.getEntry(0, 0)); Yt = 1.0 / (0.5 * (Zneigh + Z)); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { BiiE->addEntry(fac2tet[i][j], fac2tet[i][k], 0.5 * Yt * NC_CouplingMatArray[idx * NumCouplingMatrices].getEntry(j, k) * GAMMA); } } } } } } } } void tetra::Calculate_Bij_Matrix_E() { if (LocalEDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); fp_t Zneigh = 0.0; fp_t Yt = 0.0; tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; BijE = new denseMat(LocalDim, 4 * LocalFaceDim); denseMat Be(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == pmlType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr) cout << "ERROR: Null pointer at bType = 0" << endl; fc[i]->Calculate_Be_Matrix(&Be); Zneigh = No * sqrt(neigh->mat->mur.getEntry(0, 0) / neigh->mat->epsr.getEntry(0, 0)); Yt = 1.0 / (0.5 * (Zneigh + Z)); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { if (LocMapE[fac2tet[i][j]] >= 0) { BijE->addEntry(fac2tet[i][j], i * LocalFaceDim + k, -0.5 * Yt * Be.getEntry(j, k) * GAMMA); } } } } else if (DGface_bc == abcType || DGface_bc == planeWaveType) {} else if (DGface_bc == pecType) {} else if (DGface_bc == pmcType) {} } } void tetra::Calculate_S_Matrix_E() { if (LocalEDOF == 0) return; int LocalDim; LocalDim = TetPolyOrderDim[PolyOrderFlag]; StiffE = new denseMat(LocalDim, LocalDim); Calculate_S_Matrix(StiffE); // [S] } void tetra::Calculate_Fii_Matrix_E() { if (LocalEDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; FiiE = new denseMat(LocalDim, LocalDim); denseMat Fii(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == nonConformal || DGface_bc == pmlType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr && DGface_bc != nonConformal) cout << "ERROR: Null pointer at bType = 0" << endl; else if (DGface_bc == nonConformal && NeighNCNum == 0) cout << "ERROR: Null pointer at bType = nonConformal no neighNC" << endl; fc[i]->Calculate_Fii_Matrix(this, &Fii); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { FiiE->addEntry(fac2tet[i][j], fac2tet[i][k], Fii.getEntry(j, k)); // 1 } } } else if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { fc[i]->Calculate_Fii_Matrix(this, &Fii); if (fc[i]->bcPtr->getbType() == abcType) Y = 1.0 / fc[i]->bcPtr->get_ABCImpVal(); else if (fc[i]->bcPtr->getbType() == planeWaveType) Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) Y = 1.0 / fc[i]->bcPtr->get_PortImpVal(); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { FiiE->addEntry(fac2tet[i][j], fac2tet[i][k], 2.0 * Fii.getEntry(j, k)); // 2 } } } else if (DGface_bc == pecType) { } else if (DGface_bc == pmcType) { } } } void tetra::Calculate_Fij_Matrix_E() { if (LocalEDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; FijE = new denseMat(LocalDim, 4 * LocalFaceDim); denseMat Fii(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == pmlType) { // not ABC and not PEC neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr) cout << "ERROR: Null pointer at bType = 0" << endl; fc[i]->Calculate_Fii_Matrix(this, &Fii); fc[i]->ApplyPEC_PMC(&Fii); for (j = 0; j < LocalFaceDim; j++){ for (k = 0; k < LocalFaceDim; k++) { if (LocMapE[fac2tet[i][j]] >= 0) FijE->addEntry(fac2tet[i][j], i * LocalFaceDim + k, Fii.getEntry(j, k)); // 1 } } } else if (DGface_bc == abcType || DGface_bc == planeWaveType) {} else if (DGface_bc == pecType) {} else if (DGface_bc == pmcType) {} } } /** E matrices numerically by quadrature */ void tetra::Calculate_M_Matrix_E_Numeric() { int i, j, k, dim; fp_t cval = 0.0; fp_t vol; fp_t* z; fp_t wgt = 0.; vtr lvtr[4]; // the 3 first positions are the vectors from the node 0 to the // others [{0,1}, {0,2}, {0,3}] vtr avtr[4]; // array of vectors normal to the faces and with a magnitude // equal to the area of them [f0, f1, f2, f3] vtr w1, w2; int* map = new int[TetPolyOrderDim[PolyOrderFlag]]; Local_DG_mapE(map, 0); if (LocalEDOF == 0) { cout << "RESET\n"; MassE = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); MassE->reset(); return; } MassE = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); dim = MassE->getRowDim(); if (dim != MassE->getColDim()) { cerr << "MassE: Non-square matrix passed." << endl; } MassE->reset(); geometry(lvtr, avtr, &vol); fp_t (*gaussQuadPoints)[5]; GetFormula3dPtr(GAUSS_POINT_NUM[PolyOrderFlag], gaussQuadPoints); vtr* gaussBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; vtr* gaussMatBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; for (i = 0; i < dim; i++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { z = &gaussQuadPoints[k][0]; TetraBasisW(z, i, &w1); gaussBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = w1; gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = mat->epsr * w1; } } for (i = 0; i < dim; i++){ for (j = 0; j < dim; j++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { wgt = gaussQuadPoints[k][4]; w1 = gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k]; w2 = gaussBasisVtrs[j * GAUSS_POINT_NUM[PolyOrderFlag] + k]; cval += wgt * dotP(w1, w2); } MassE->addEntry(i, j, cval * vol); cval = 0.0; } } delete[] gaussBasisVtrs; delete[] gaussMatBasisVtrs; // If it's PEC, set a 1 if it's in the diagonal, 0 if not for (i = 0; i < TetPolyOrderDim[PolyOrderFlag]; i++) { for (j = 0; j < TetPolyOrderDim[PolyOrderFlag]; j++) { if (map[i] < 0 || map[j] < 0) { if (i == j) { MassE->setEntry(i, j, 1.0); // need to be inversed } else { MassE->setEntry(i, j, 0); // need to be inversed } } } } if (map != nullptr) delete[] map; } void tetra::Calculate_R_Matrix_E_Numeric(denseMat* R_Matrix_E, fp_t dt) { if (LocalEDOF == 0) return; int LocalDim, LocalFaceDim; int DGface_bc; int AbcFlag = 0; fp_t eps_o = Eo; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); int i, j, k, dim; fp_t cval = 0.0; fp_t vol; fp_t wgt; fp_t* z; vtr lvtr[4]; vtr avtr[4]; vtr w1, w2; int* map = new int[TetPolyOrderDim[PolyOrderFlag]]; Local_DG_mapE(map, 0); dim = R_Matrix_E->getRowDim(); if (dim != R_Matrix_E->getColDim()) { cerr << "MassE: Non-square matrix passed." << endl; } R_Matrix_E->reset(); geometry(lvtr, avtr, &vol); fp_t (*gaussQuadPoints)[5]; GetFormula3dPtr(GAUSS_POINT_NUM[PolyOrderFlag], gaussQuadPoints); vtr* gaussBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; vtr* gaussMatBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; for (i = 0; i < dim; i++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { z = &gaussQuadPoints[k][0]; TetraBasisW(z, i, &w1); gaussBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = w1; gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = mat->sigma * w1; } } for (i = 0; i < dim; i++){ for (j = 0; j < dim; j++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { wgt = gaussQuadPoints[k][4]; w1 = gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k]; w2 = gaussBasisVtrs[j * GAUSS_POINT_NUM[PolyOrderFlag] + k]; cval += wgt * dotP(w1, w2); } R_Matrix_E->addEntry(i, j, cval * vol); cval = 0.0; } } delete[] gaussBasisVtrs; delete[] gaussMatBasisVtrs; if (map != nullptr) delete[] map; (*R_Matrix_E).scale(0.5 * (dt / eps_o)); LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; denseMat tetBe(LocalDim, LocalDim); // Matrices On the Faces denseMat Be(LocalFaceDim, LocalFaceDim); for (i = 0; i < 4; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { AbcFlag = 1; fc[i]->Calculate_Be_Matrix_Numeric(&Be,PolyOrderFlag); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { tetBe.addEntry(fac2tet[i][j], fac2tet[i][k], Be.getEntry(j, k)); } } } } // ABC Boundary if (AbcFlag == 1) { for (i = 0; i < 4; i++) { // the same if (fc[i]->bcPtr->getbType() == abcType) { Y = 1.0 / fc[i]->bcPtr->get_ABCImpVal(); } else if (fc[i]->bcPtr->getbType() == planeWaveType) { Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); } else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) { Y = 1.0 / fc[i]->bcPtr->get_PortImpVal(); } } tetBe.scale(-0.25 * Y * (dt / eps_o)); *R_Matrix_E = *R_Matrix_E + tetBe; } } void tetra::Calculate_Bii_Matrix_E_Numeric() { if (LocalEDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); fp_t Zneigh = 0.0; fp_t Yt = 0.0; tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; BiiE = new denseMat(LocalDim, LocalDim); denseMat Be(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == pmlType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr){ printf("ERROR: Null pointer at bType = 0 in tetra %d in face %d = [(%.8f, %.8f, %.8f), (%.8f, %.8f, %.8f), (%.8f, %.8f, %.8f)]", cnt, i, fc[i]->nd[0]->getCoord().getx(), fc[i]->nd[0]->getCoord().gety(), fc[i]->nd[0]->getCoord().getz(), fc[i]->nd[1]->getCoord().getx(), fc[i]->nd[1]->getCoord().gety(), fc[i]->nd[1]->getCoord().getz(), fc[i]->nd[2]->getCoord().getx(), fc[i]->nd[2]->getCoord().gety(), fc[i]->nd[2]->getCoord().getz()); cout << endl; } Zneigh = No * sqrt(neigh->mat->mur.getEntry(0, 0) / neigh->mat->epsr.getEntry(0, 0)); Yt = 1.0 / (0.5 * (Zneigh + Z)); fc[i]->Calculate_Be_Matrix_Numeric(&Be,PolyOrderFlag); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { BiiE->addEntry(fac2tet[i][j], fac2tet[i][k], 0.5 * Yt * Be.getEntry(j, k) * GAMMA); } } } else if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { fc[i]->Calculate_Be_Matrix_Numeric(&Be,PolyOrderFlag); if (fc[i]->bcPtr->getbType() == abcType) Y = 1.0 / fc[i]->bcPtr->get_ABCImpVal(); else if (fc[i]->bcPtr->getbType() == planeWaveType) Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) Y = 1.0 / fc[i]->bcPtr->get_PortImpVal(); for (j = 0; j < LocalFaceDim; j++) for (k = 0; k < LocalFaceDim; k++) BiiE->addEntry(fac2tet[i][j], fac2tet[i][k], 0.5 * Y * Be.getEntry(j, k)); } else if (DGface_bc == pecType) { } else if (DGface_bc == pmcType) { } else if (DGface_bc == nonConformal){ for(int idx = 0; idx < NeighNCNum; idx++){ if (OverlapMapVec[i].find(idx)->second){ if(IntersectionMapVec[i].find(idx)->second){ Zneigh = No * sqrt(NeighNCTetra[idx]->mat->mur.getEntry(0, 0) / NeighNCTetra[idx]->mat->epsr.getEntry(0, 0)); Yt = 1.0 / (0.5 * (Zneigh + Z)); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { BiiE->addEntry(fac2tet[i][j], fac2tet[i][k], 0.5 * Yt * NC_CouplingMatArray[idx * NumCouplingMatrices].getEntry(j, k) * GAMMA); } } } } } } } } void tetra::Calculate_Bij_Matrix_E_Numeric() { if (LocalEDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); fp_t Zneigh = 0.0; fp_t Yt = 0.0; tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; BijE = new denseMat(LocalDim, 4 * LocalFaceDim); denseMat Be(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == pmlType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr) cout << "ERROR: Null pointer at bType = 0" << endl; fc[i]->Calculate_Be_Matrix_Numeric(&Be,PolyOrderFlag); Zneigh = No * sqrt(neigh->mat->mur.getEntry(0, 0) / neigh->mat->epsr.getEntry(0, 0)); Yt = 1.0 / (0.5 * (Zneigh + Z)); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { if (LocMapE[fac2tet[i][j]] >= 0) { BijE->addEntry(fac2tet[i][j], i * LocalFaceDim + k, -0.5 * Yt * Be.getEntry(j, k) * GAMMA); } } } } else if (DGface_bc == abcType || DGface_bc == planeWaveType) {} else if (DGface_bc == pecType) {} else if (DGface_bc == pmcType) {} } } void tetra::Calculate_S_Matrix_E_Numeric() { if (LocalEDOF == 0) return; int LocalDim; LocalDim = TetPolyOrderDim[PolyOrderFlag]; StiffE = new denseMat(LocalDim, LocalDim); Calculate_S_Matrix_Numeric(StiffE); // [S] } void tetra::Calculate_Fii_Matrix_E_Numeric() { if (LocalEDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; FiiE = new denseMat(LocalDim, LocalDim); denseMat Fii(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == nonConformal || DGface_bc == pmlType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr && DGface_bc != nonConformal) cout << "ERROR: Null pointer at bType = 0" << endl; else if (DGface_bc == nonConformal && NeighNCNum == 0) cout << "ERROR: Null pointer at bType = nonConformal no neighNC" << endl; fc[i]->Calculate_Fii_Matrix_Numeric(this, &Fii,PolyOrderFlag); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { FiiE->addEntry(fac2tet[i][j], fac2tet[i][k], Fii.getEntry(j, k)); // 1 } } } else if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { fc[i]->Calculate_Fii_Matrix_Numeric(this, &Fii,PolyOrderFlag); if (fc[i]->bcPtr->getbType() == abcType) Y = 1.0 / fc[i]->bcPtr->get_ABCImpVal(); else if (fc[i]->bcPtr->getbType() == planeWaveType) Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) Y = 1.0 / fc[i]->bcPtr->get_PortImpVal(); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { FiiE->addEntry(fac2tet[i][j], fac2tet[i][k], 2.0 * Fii.getEntry(j, k)); // 2 } } } else if (DGface_bc == pecType) { } else if (DGface_bc == pmcType) { } } } void tetra::Calculate_Fij_Matrix_E_Numeric() { if (LocalEDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; FijE = new denseMat(LocalDim, 4 * LocalFaceDim); denseMat Fii(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == pmlType) { // not ABC and not PEC neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr) cout << "ERROR: Null pointer at bType = 0" << endl; fc[i]->Calculate_Fii_Matrix_Numeric(this, &Fii, PolyOrderFlag); fc[i]->ApplyPEC_PMC(&Fii); for (j = 0; j < LocalFaceDim; j++){ for (k = 0; k < LocalFaceDim; k++) { if (LocMapE[fac2tet[i][j]] >= 0) FijE->addEntry(fac2tet[i][j], i * LocalFaceDim + k, Fii.getEntry(j, k)); // 1 } } } else if (DGface_bc == abcType || DGface_bc == planeWaveType) {} else if (DGface_bc == pecType) {} else if (DGface_bc == pmcType) {} } } /** H matrices */ void tetra::Calculate_M_Matrix_H() { int i, j, dim; fp_t vol; fp_t coeffA[3][3]; fp_t cval = 0.0; vtr lvtr[4]; vtr avtr[4]; int* map = new int[TetPolyOrderDim[PolyOrderFlag]]; Local_DG_mapH(map, 0); if (LocalHDOF == 0) { MassH = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); MassH->reset(); return; } MassH = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); dim = MassH->getRowDim(); if (dim != MassH->getColDim()) { cerr << "MassH: Non-square matrix passed." << endl; } MassH->reset(); geometry(lvtr, avtr, &vol); makeCoeff(avtr, mat->mur, coeffA); // dotP(u, [t]*u) dV // u = avtr, [t]*u = [t] * avtr for (i = 0; i < dim; i++) { for (j = 0; j < dim; j++) { cval = (coeffA[0][0] * T00_P2[i][j]) + (coeffA[0][1] * T01_P2[i][j]) + (coeffA[1][0] * T10_P2[i][j]) + (coeffA[0][2] * T02_P2[i][j]) + (coeffA[2][0] * T20_P2[i][j]) + (coeffA[1][1] * T11_P2[i][j]) + (coeffA[1][2] * T12_P2[i][j]) + (coeffA[2][1] * T21_P2[i][j]) + (coeffA[2][2] * T22_P2[i][j]); cval = cval / (vol * (fp_t)T_DNUM); MassH->addEntry(i, j, cval); } } // If it's PMC, set a 1 if it's in the diagonal, 0 if not for (i = 0; i < TetPolyOrderDim[PolyOrderFlag]; i++) { for (j = 0; j < TetPolyOrderDim[PolyOrderFlag]; j++) { if (map[i] < 0 || map[j] < 0) { if (i == j) { MassH->setEntry(i, j, 1.0); // need to be inversed } else { MassH->setEntry(i, j, 0); // need to be inversed } } } } if (map != nullptr) delete[] map; } void tetra::Calculate_R_Matrix_H(denseMat* CondMatrixH, fp_t dt) { if (LocalHDOF == 0) return; int LocalDim, LocalFaceDim; int DGface_bc; int AbcFlag = 0; fp_t mu_o = Uo; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); int i, j, dim; int k = 0; fp_t vol; fp_t coeffA[3][3]; fp_t cval = 0.0; vtr lvtr[4]; vtr avtr[4]; int* map = new int[TetPolyOrderDim[PolyOrderFlag]]; Local_DG_mapH(map, 0); dim = CondMatrixH->getRowDim(); if (dim != CondMatrixH->getColDim()) { cerr << "MassH: Non-square matrix passed." << endl; } CondMatrixH->reset(); geometry(lvtr, avtr, &vol); makeCoeff(avtr, mat->sigma, coeffA); for (i = 0; i < dim; i++) { for (j = 0; j < dim; j++) { cval = (coeffA[0][0] * T00_P2[i][j]) + (coeffA[0][1] * T01_P2[i][j]) + (coeffA[1][0] * T10_P2[i][j]) + (coeffA[0][2] * T02_P2[i][j]) + (coeffA[2][0] * T20_P2[i][j]) + (coeffA[1][1] * T11_P2[i][j]) + (coeffA[1][2] * T12_P2[i][j]) + (coeffA[2][1] * T21_P2[i][j]) + (coeffA[2][2] * T22_P2[i][j]); cval = cval / (vol * (fp_t)T_DNUM); CondMatrixH->addEntry(i, j, cval); } } if (map != nullptr) delete[] map; fp_t sigma_m = 0.0; (*CondMatrixH).scale(0.5 * (dt / mu_o) * sigma_m); LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; denseMat tetBh(LocalDim, LocalDim); // Matrices On the Faces denseMat Bh(LocalFaceDim, LocalFaceDim); for (i = 0; i < 4; i++) { DGface_bc = getFacePtr(i)->bcPtr->getbType(); if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { AbcFlag = 1; fc[i]->Calculate_Bh_Matrix(&Bh); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { tetBh.addEntry(fac2tet[i][j], fac2tet[i][k], Bh.getEntry(j, k)); } } } } // ABC Boundary if (AbcFlag == 1) { for (i = 0; i < 4; i++) { if (fc[i]->bcPtr->getbType() == abcType) { Z = fc[i]->bcPtr->get_ABCImpVal(); } else if (fc[i]->bcPtr->getbType() == planeWaveType) { Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); } else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) { Z = fc[i]->bcPtr->get_PortImpVal(); } } tetBh.scale(-0.25 * Z * (dt / mu_o)); *CondMatrixH = *CondMatrixH + tetBh; } } void tetra::Calculate_Bii_Matrix_H() { if (LocalHDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); fp_t Yneigh = 0.0; fp_t Zt = 0.0; tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; BiiH = new denseMat(LocalDim, LocalDim); denseMat Bh(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == pmlType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr) cout << "ERROR: Null pointer at bType = 0" << endl; Yneigh = 1.0 / (No * sqrt(neigh->mat->mur.getEntry(0, 0) / neigh->mat->epsr.getEntry(0, 0))); Zt = 1.0 / (0.5 * (Y + Yneigh)); fc[i]->Calculate_Bh_Matrix(&Bh); for (j = 0; j < LocalFaceDim; j++) for (k = 0; k < LocalFaceDim; k++) BiiH->addEntry(fac2tet[i][j], fac2tet[i][k], 0.5 * Zt * Bh.getEntry(j, k) * GAMMA); // 0.5 } else if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { fc[i]->Calculate_Bh_Matrix(&Bh); if (fc[i]->bcPtr->getbType() == abcType) Z = fc[i]->bcPtr->get_ABCImpVal(); else if (fc[i]->bcPtr->getbType() == planeWaveType) Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) Z = fc[i]->bcPtr->get_PortImpVal(); for (j = 0; j < LocalFaceDim; j++) for (k = 0; k < LocalFaceDim; k++) BiiH->addEntry(fac2tet[i][j], fac2tet[i][k], 0.5 * Z * Bh.getEntry(j, k)); } else if (DGface_bc == pecType) { } else if (DGface_bc == pmcType) { } else if (DGface_bc == nonConformal){ for(int idx = 0; idx < NeighNCNum; idx++){ if (OverlapMapVec[i].find(idx)->second){ if(IntersectionMapVec[i].find(idx)->second){ Yneigh = 1.0 / (No * sqrt(NeighNCTetra[idx]->mat->mur.getEntry(0, 0) / NeighNCTetra[idx]->mat->epsr.getEntry(0, 0))); Zt = 1.0 / (0.5 * (Y + Yneigh)); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { BiiH->addEntry(fac2tet[i][j], fac2tet[i][k], 0.5 * Zt * NC_CouplingMatArray[idx * NumCouplingMatrices].getEntry(j, k) * GAMMA); } } } } } } } } void tetra::Calculate_Bij_Matrix_H() { if (LocalHDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); fp_t Yneigh = 0.0; fp_t Zt = 0.0; tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; BijH = new denseMat(LocalDim, 4 * LocalFaceDim); denseMat Bh(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == pmlType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr) cout << "ERROR: Null pointer at bType = 0" << endl; fc[i]->Calculate_Bh_Matrix(&Bh); Yneigh = 1.0 / (No * sqrt(neigh->mat->mur.getEntry(0, 0) / neigh->mat->epsr.getEntry(0, 0))); Zt = 1.0 / (0.5 * (Y + Yneigh)); for (j = 0; j < LocalFaceDim; j++) for (k = 0; k < LocalFaceDim; k++) { if (LocMapH[fac2tet[i][j]] >= 0) BijH->addEntry(fac2tet[i][j], i * LocalFaceDim + k, -0.5 * Zt * Bh.getEntry(j, k) * GAMMA); } } else if (DGface_bc == abcType || DGface_bc == planeWaveType) {} else if (DGface_bc == pecType) {} else if (DGface_bc == pmcType) {} } } void tetra::Calculate_S_Matrix_H() { if (LocalHDOF == 0) return; int LocalDim; LocalDim = TetPolyOrderDim[PolyOrderFlag]; StiffH = new denseMat(LocalDim, LocalDim); Calculate_S_Matrix(StiffH); // [S] } void tetra::Calculate_Fii_Matrix_H() { if (LocalHDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; FiiH = new denseMat(LocalDim, LocalDim); denseMat Fii(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == nonConformal || DGface_bc == pmlType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr && DGface_bc != nonConformal) cout << "ERROR: Null pointer at bType = 0" << endl; else if (DGface_bc == nonConformal && NeighNCNum == 0) cout << "ERROR: Null pointer at bType = nonConformal no neighNC" << endl; fc[i]->Calculate_Fii_Matrix(this, &Fii); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { FiiH->addEntry(fac2tet[i][j], fac2tet[i][k], Fii.getEntry(j, k)); } } } else if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { fc[i]->Calculate_Fii_Matrix(this, &Fii); if (fc[i]->bcPtr->getbType() == abcType) Z = fc[i]->bcPtr->get_ABCImpVal(); else if (fc[i]->bcPtr->getbType() == planeWaveType) Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) Z = fc[i]->bcPtr->get_PortImpVal(); for (j = 0; j < LocalFaceDim; j++) for (k = 0; k < LocalFaceDim; k++) FiiH->addEntry(fac2tet[i][j], fac2tet[i][k], 2.0 * Fii.getEntry(j, k)); } else if (DGface_bc == pecType) {} else if (DGface_bc == pmcType) {} } } void tetra::Calculate_Fij_Matrix_H() { if (LocalHDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; FijH = new denseMat(LocalDim, 4 * LocalFaceDim); denseMat Fii(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == pmlType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr) cout << "ERROR: Null pointer at bType = 0" << endl; fc[i]->Calculate_Fii_Matrix(this, &Fii); fc[i]->ApplyPMC_PEC(&Fii); for (j = 0; j < LocalFaceDim; j++) for (k = 0; k < LocalFaceDim; k++) if (LocMapH[fac2tet[i][j]] >= 0) FijH->addEntry(fac2tet[i][j], i * LocalFaceDim + k, -Fii.getEntry(j, k)); } else if (DGface_bc == abcType || DGface_bc == planeWaveType) {} else if (DGface_bc == pecType) {} else if (DGface_bc == pmcType) {} } } void tetra::Calculate_M_Matrix_H_Numeric() { int i, j, k, dim; fp_t cval = 0.0; fp_t vol; fp_t* z; fp_t wgt = 0.; vtr lvtr[4]; // the 3 first positions are the vectors from the node 0 to the // others [{0,1}, {0,2}, {0,3}] vtr avtr[4]; // array of vectors normal to the faces and with a magnitude // equal to the area of them [f0, f1, f2, f3] vtr w1, w2; int* map = new int[TetPolyOrderDim[PolyOrderFlag]]; Local_DG_mapH(map, 0); if (LocalHDOF == 0) { MassH = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); MassH->reset(); return; } MassH = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); dim = MassH->getRowDim(); if (dim != MassH->getColDim()) { cerr << "MassH: Non-square matrix passed." << endl; } MassH->reset(); geometry(lvtr, avtr, &vol); fp_t (*gaussQuadPoints)[5]; GetFormula3dPtr(GAUSS_POINT_NUM[PolyOrderFlag], gaussQuadPoints); vtr* gaussBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; vtr* gaussMatBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; for (i = 0; i < dim; i++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { z = &gaussQuadPoints[k][0]; TetraBasisW(z, i, &w1); gaussBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = w1; gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = mat->mur * w1; } } for (i = 0; i < dim; i++){ for (j = 0; j < dim; j++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { wgt = gaussQuadPoints[k][4]; w1 = gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k]; w2 = gaussBasisVtrs[j * GAUSS_POINT_NUM[PolyOrderFlag] + k]; cval += wgt * dotP(w1, w2); } MassH->addEntry(i, j, cval * vol); cval = 0.0; } } delete[] gaussBasisVtrs; delete[] gaussMatBasisVtrs; // If it's PMC, set a 1 if it's in the diagonal, 0 if not for (i = 0; i < TetPolyOrderDim[PolyOrderFlag]; i++) { for (j = 0; j < TetPolyOrderDim[PolyOrderFlag]; j++) { if (map[i] < 0 || map[j] < 0) { if (i == j) { MassH->setEntry(i, j, 1.0); // need to be inversed } else { MassH->setEntry(i, j, 0); // need to be inversed } } } } if (map != nullptr) delete[] map; } void tetra::Calculate_R_Matrix_H_Numeric(denseMat* CondMatrixH, fp_t dt) { if (LocalHDOF == 0) return; int LocalDim, LocalFaceDim; int DGface_bc; int AbcFlag = 0; fp_t mu_o = Uo; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); int i, j, k, dim; fp_t vol; fp_t cval = 0.0; fp_t wgt; fp_t* z; vtr lvtr[4]; vtr avtr[4]; vtr w1, w2; int* map = new int[TetPolyOrderDim[PolyOrderFlag]]; Local_DG_mapH(map, 0); dim = CondMatrixH->getRowDim(); if (dim != CondMatrixH->getColDim()) { cerr << "MassH: Non-square matrix passed." << endl; } CondMatrixH->reset(); geometry(lvtr, avtr, &vol); fp_t (*gaussQuadPoints)[5]; GetFormula3dPtr(GAUSS_POINT_NUM[PolyOrderFlag], gaussQuadPoints); vtr* gaussBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; vtr* gaussMatBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; for (i = 0; i < dim; i++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { z = &gaussQuadPoints[k][0]; TetraBasisW(z, i, &w1); gaussBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = w1; gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = mat->sigma * w1; } } for (i = 0; i < dim; i++){ for (j = 0; j < dim; j++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { wgt = gaussQuadPoints[k][4]; w1 = gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k]; w2 = gaussBasisVtrs[j * GAUSS_POINT_NUM[PolyOrderFlag] + k]; cval += wgt * dotP(w1, w2); } CondMatrixH->addEntry(i, j, cval * vol); cval = 0.0; } } delete[] gaussBasisVtrs; delete[] gaussMatBasisVtrs; if (map != nullptr) delete[] map; fp_t sigma_m = 0.0; (*CondMatrixH).scale(0.5 * (dt / mu_o) * sigma_m); LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; denseMat tetBh(LocalDim, LocalDim); // Matrices On the Faces denseMat Bh(LocalFaceDim, LocalFaceDim); for (i = 0; i < 4; i++) { DGface_bc = getFacePtr(i)->bcPtr->getbType(); if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { AbcFlag = 1; fc[i]->Calculate_Bh_Matrix_Numeric(&Bh, PolyOrderFlag); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { tetBh.addEntry(fac2tet[i][j], fac2tet[i][k], Bh.getEntry(j, k)); } } } } // ABC Boundary if (AbcFlag == 1) { for (i = 0; i < 4; i++) { if (fc[i]->bcPtr->getbType() == abcType) { Z = fc[i]->bcPtr->get_ABCImpVal(); } else if (fc[i]->bcPtr->getbType() == planeWaveType) { Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); } else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) { Z = fc[i]->bcPtr->get_PortImpVal(); } } tetBh.scale(-0.25 * Z * (dt / mu_o)); *CondMatrixH = *CondMatrixH + tetBh; } } void tetra::Calculate_Bii_Matrix_H_Numeric() { if (LocalHDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); fp_t Yneigh = 0.0; fp_t Zt = 0.0; tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; BiiH = new denseMat(LocalDim, LocalDim); denseMat Bh(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == pmlType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr) cout << "ERROR: Null pointer at bType = 0" << endl; Yneigh = 1.0 / (No * sqrt(neigh->mat->mur.getEntry(0, 0) / neigh->mat->epsr.getEntry(0, 0))); Zt = 1.0 / (0.5 * (Y + Yneigh)); fc[i]->Calculate_Bh_Matrix_Numeric(&Bh,PolyOrderFlag); for (j = 0; j < LocalFaceDim; j++) for (k = 0; k < LocalFaceDim; k++) BiiH->addEntry(fac2tet[i][j], fac2tet[i][k], 0.5 * Zt * Bh.getEntry(j, k) * GAMMA); // 0.5 } else if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { fc[i]->Calculate_Bh_Matrix_Numeric(&Bh,PolyOrderFlag); if (fc[i]->bcPtr->getbType() == abcType) Z = fc[i]->bcPtr->get_ABCImpVal(); else if (fc[i]->bcPtr->getbType() == planeWaveType) Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) Z = fc[i]->bcPtr->get_PortImpVal(); for (j = 0; j < LocalFaceDim; j++) for (k = 0; k < LocalFaceDim; k++) BiiH->addEntry(fac2tet[i][j], fac2tet[i][k], 0.5 * Z * Bh.getEntry(j, k)); } else if (DGface_bc == pecType) { } else if (DGface_bc == pmcType) { } else if (DGface_bc == nonConformal){ for(int idx = 0; idx < NeighNCNum; idx++){ if (OverlapMapVec[i].find(idx)->second){ if(IntersectionMapVec[i].find(idx)->second){ Yneigh = 1.0 / (No * sqrt(NeighNCTetra[idx]->mat->mur.getEntry(0, 0) / NeighNCTetra[idx]->mat->epsr.getEntry(0, 0))); Zt = 1.0 / (0.5 * (Y + Yneigh)); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { BiiH->addEntry(fac2tet[i][j], fac2tet[i][k], 0.5 * Zt * NC_CouplingMatArray[idx * NumCouplingMatrices].getEntry(j, k) * GAMMA); } } } } } } } } void tetra::Calculate_Bij_Matrix_H_Numeric() { if (LocalHDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); fp_t Yneigh = 0.0; fp_t Zt = 0.0; tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; BijH = new denseMat(LocalDim, 4 * LocalFaceDim); denseMat Bh(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == pmlType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr) cout << "ERROR: Null pointer at bType = 0" << endl; fc[i]->Calculate_Bh_Matrix_Numeric(&Bh,PolyOrderFlag); Yneigh = 1.0 / (No * sqrt(neigh->mat->mur.getEntry(0, 0) / neigh->mat->epsr.getEntry(0, 0))); Zt = 1.0 / (0.5 * (Y + Yneigh)); for (j = 0; j < LocalFaceDim; j++) for (k = 0; k < LocalFaceDim; k++) { if (LocMapH[fac2tet[i][j]] >= 0) BijH->addEntry(fac2tet[i][j], i * LocalFaceDim + k, -0.5 * Zt * Bh.getEntry(j, k) * GAMMA); } } else if (DGface_bc == abcType || DGface_bc == planeWaveType) {} else if (DGface_bc == pecType) {} else if (DGface_bc == pmcType) {} } } void tetra::Calculate_S_Matrix_H_Numeric() { if (LocalHDOF == 0) return; int LocalDim; LocalDim = TetPolyOrderDim[PolyOrderFlag]; StiffH = new denseMat(LocalDim, LocalDim); Calculate_S_Matrix_Numeric(StiffH); // [S] } void tetra::Calculate_Fii_Matrix_H_Numeric() { if (LocalHDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; FiiH = new denseMat(LocalDim, LocalDim); denseMat Fii(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == nonConformal || DGface_bc == pmlType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr && DGface_bc != nonConformal) cout << "ERROR: Null pointer at bType = 0" << endl; else if (DGface_bc == nonConformal && NeighNCNum == 0) cout << "ERROR: Null pointer at bType = nonConformal no neighNC" << endl; fc[i]->Calculate_Fii_Matrix_Numeric(this, &Fii, PolyOrderFlag); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { FiiH->addEntry(fac2tet[i][j], fac2tet[i][k], Fii.getEntry(j, k)); } } } else if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { fc[i]->Calculate_Fii_Matrix_Numeric(this, &Fii, PolyOrderFlag); if (fc[i]->bcPtr->getbType() == abcType) Z = fc[i]->bcPtr->get_ABCImpVal(); else if (fc[i]->bcPtr->getbType() == planeWaveType) Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) Z = fc[i]->bcPtr->get_PortImpVal(); for (j = 0; j < LocalFaceDim; j++) for (k = 0; k < LocalFaceDim; k++) FiiH->addEntry(fac2tet[i][j], fac2tet[i][k], 2.0 * Fii.getEntry(j, k)); } else if (DGface_bc == pecType) {} else if (DGface_bc == pmcType) {} } } void tetra::Calculate_Fij_Matrix_H_Numeric() { if (LocalHDOF == 0) return; int i, j, k; int LocalDim, LocalFaceDim; int DGface_bc; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; FijH = new denseMat(LocalDim, 4 * LocalFaceDim); denseMat Fii(LocalFaceDim, LocalFaceDim); // Loop through Faces for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType || DGface_bc == pmlType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr) cout << "ERROR: Null pointer at bType = 0" << endl; fc[i]->Calculate_Fii_Matrix_Numeric(this, &Fii, PolyOrderFlag); fc[i]->ApplyPMC_PEC(&Fii); for (j = 0; j < LocalFaceDim; j++) for (k = 0; k < LocalFaceDim; k++) if (LocMapH[fac2tet[i][j]] >= 0) FijH->addEntry(fac2tet[i][j], i * LocalFaceDim + k, -Fii.getEntry(j, k)); } else if (DGface_bc == abcType || DGface_bc == planeWaveType) {} else if (DGface_bc == pecType) {} else if (DGface_bc == pmcType) {} } } // Here, the time step is calculated based on the new formula // This, can handle both ocnformal and non-conformal for // non uniform polynomial ordes as well //*************************** // From experience we found that the stabilty conditions are sufficient // but not necessary. In example, the upwind flux results in a slightly more // restrictive time step compared to central flux. // However, in practise we found one can use the central flux timestep for both // upwing and central flux // without any instability occuring. Here we use the central flux timestep to be // more effecient. //*************************** //******************************** // Simplified stability for conformal meshes only and with uniform p=0,1 only. // This way of getting the dt is much faster since you dont compute the local // eigenvalues so for p=0,1 and conformal this maybe prefered since it is much // faster. void tetra::TimeStepEstimate(fp_t& dtEstim, fp_t& V_P) { vtr lvtr[4]; vtr avtr[4]; fp_t Vol_i; fp_t Per_i = 0.0; fp_t area = 0.0; fp_t eps_i; fp_t tmp_eps_k; fp_t eps_k_min = 10000.0; fp_t mu_i; fp_t tmp_mu_k; fp_t mu_k_min = 10000.0; vtr Normal; geometry(lvtr, avtr, &Vol_i); for (int i = 0; i < 4; i++) { fc[i]->getAreaNormal(&area, &Normal); Per_i = Per_i + area; } eps_i = mat->epsr.getEntry(0, 0); mu_i = mat->mur.getEntry(0, 0); eps_k_min = eps_i; mu_k_min = mu_i; for (int k = 0; k < NeighNum; k++) { if (NeighTetra[k] != nullptr) { tmp_eps_k = NeighTetra[k]->mat->epsr.getEntry(0, 0); tmp_mu_k = NeighTetra[k]->mat->mur.getEntry(0, 0); if (tmp_eps_k < eps_k_min) eps_k_min = tmp_eps_k; if (tmp_mu_k < mu_k_min) mu_k_min = tmp_mu_k; } } V_P = Vol_i / Per_i; if (sqrt(mu_i / mu_k_min) != 1.0) { cout << "tetra::TimeStepEstimate::ERROR" << endl; } fp_t Maxe_ie_k; if (sqrt(eps_i / eps_k_min) < sqrt(mu_i / mu_k_min)) { Maxe_ie_k = sqrt(mu_i / mu_k_min); } else { Maxe_ie_k = sqrt(eps_i / eps_k_min); } fp_t Denom; fp_t Numer = 4.0 * (Vol_i / Per_i); fp_t MatProp = sqrt(mat->mur.getEntry(0, 0) * mat->epsr.getEntry(0, 0)); fp_t StabilityScale; StabilityScale = 2.0; if (PolyOrderFlag == 0) { Denom = StabilityScale * (Vo / MatProp) * (Maxe_ie_k); } else if (PolyOrderFlag == 1) { // Luis Diaz Angulo, Discontinuous Galerkin Time Domain // Methods in Computational Electrodynamics: // State of the Art, EQ(47) Denom = (1.0) * (Vo / MatProp) * (8.0 * Maxe_ie_k + sqrt(20.0)) * (1. / 3.); // 40 -> 20 } else if (PolyOrderFlag == 2) { Denom = (1.0) * (Vo / MatProp) * (8.0 * Maxe_ie_k + sqrt(20.0)) * (1. / 3.); // 40 -> 20 Denom *= 2.0; //1.5 provokes an error in lambda/8. The value is empirically obtained from the analytical formula } else if (PolyOrderFlag == 3) { Denom = (1.0) * (Vo / MatProp) * (8.0 * Maxe_ie_k + sqrt(20.0)) * (1. / 3.); // 40 -> 20 Denom *= 3.0; //1.5 provokes an error in lambda/8. The value is empirically obtained from the analytical formula } dtEstim = 0.8 * (Numer / Denom); if (PML_Flag) { fp_t h = V_P; // Characteristic length fp_t sigma = mat->sigma.getEntry(0, 0); // Assume sigma_z dominates (adjust for anisotropy) fp_t c = Vo; // Speed of light in the medium fp_t factor = 1.0 + (sigma * sigma * h * h) / (8.0 * c * c); fp_t dt_pml = h / (c * sqrt(2.0 * factor)); // Final conservative dt for this tetra if (PolyOrderFlag == 2) { dtEstim = std::min(dtEstim, dt_pml * 0.8 / 2.0); // 0.8 safety factor } else if (PolyOrderFlag == 3) { dtEstim = std::min(dtEstim, dt_pml * 0.8 / 3.0); // 0.8 safety factor } } // Reduce the time step if the PML is used with high conducitivty /* if (PML_Flag) { vtr rc = Center(); // This is the polynomial order of the conductivity profile of the PML int m = mat->get_PML_m_ord(); // (Cartesian-Aligned) PML // Obtain the the thickness of the PML fp_t pml_thick = mat->get_PML_thick(); fp_t reflection_coeff = mat->sigma.getEntry(0, 0); // This is the reflection coefficient fp_t eps_o = 8.854187817e-12; fp_t sigma_base = - (m + 1.0) / (240.0 * Pi * pml_thick) * log(reflection_coeff); sigma_base = sigma_base; fp_t Rx = 0.2; fp_t Ry = 0.2; fp_t Rz = 0.2; // Compute radial distance from object surface into PML fp_t distance = rc.magnitude() - std::max({Rx, Ry, Rz}); fp_t D = pml_thick; // Gaussian profile settings fp_t dc = 0.6 * D; // Peak at 60% of PML thickness fp_t w = 0.3 * D; // Width of Gaussian // Clamp distance into [0, D] distance = std::max(0.0, std::min(D, distance)); // Compute Gaussian conductivity profile fp_t s3 = sigma_base * std::exp(-std::pow((distance - dc) / w, 2)); if (s3 > 1.0) { cout << "s3: " << s3 << endl; dtEstim = dtEstim / (s3) / 2.0; } } */ /* In order to fulfill the LTS requirement for stability the dt must be multiplied by 0.8 "Dissipative terms and local time-stepping improvements in a spatial high order Discontinuous Galerkin scheme for the time-domain Maxwell’s equations" , E. Montseny */ } void tetra::SetUpMatrixFree() { vtr lvtr[NumOfFaces]; // vectors of the edges from node 0 to the others (the fourth value is not used) vtr avtr[NumOfFaces]; // inward normal vectors to the faces with the magnitude equal to the area of the faces geometry(lvtr, gradZeta_, &vol_); LocMapE = new int[TetPolyOrderDim[PolyOrderFlag]]; LocMapH = new int[TetPolyOrderDim[PolyOrderFlag]]; Local_DG_mapE(LocMapE, LocalOffsetE); Local_DG_mapH(LocMapH, LocalOffsetH); MapPMC(); MapPEC(); if(isNonConformal){ SetUpInterfaceMatrices_NC(); SetUpInterfaceMaps_NC(); } } // MF Set-up, pre-compute and store the inverse of the LHS matrices to be use // at every time iteration. These inverses along with the massmatrix are the // only ones stored in the matrix-free implementation // NMF Set-up, Here we precompute the update matrices before the time step is // started. This part is only used when the non-matrix free option is choosen, // i.e. when memory resources are suffecient. This implementation is 2-3 time // faster compared to matrix-free but also consumes about 3x more memory as // well. /* E setup */ void tetra::SetUp_LocalFaceToTetraMapE_NMF1(fp_t dt) { if (LocalEDOF == 0) return; int LocalDim, LocalFaceDim; fp_t eps_o = Eo; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; // sigma and abc denseMat RMatrixE(LocalDim, LocalDim); Calculate_R_Matrix_E(&RMatrixE, dt); RHSLoc1E = new denseMat(LocalDim, LocalDim); RHSLoc2E = new denseMat(LocalDim, LocalDim); RHSCoup1E = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); RHSCoup2E = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); BiiE->scale(dt / eps_o); *RHSLoc1E = *MassE + *BiiE - RMatrixE; ApplyPEC(RHSLoc1E, LocalDim); *RHSLoc2E = *StiffE - *FiiE; RHSLoc2E->scale(dt / eps_o); ApplyPEC_E(RHSLoc2E, LocalDim); ApplyPMC_E(RHSLoc2E, LocalDim); *RHSCoup1E = *FijE; RHSCoup1E->scale(dt / eps_o); *RHSCoup2E = *BijE; RHSCoup2E->scale(dt / eps_o); // Inv LHSInvE = new denseMat(LocalDim, LocalDim); *LHSInvE = *MassE + RMatrixE; *LHSInvE = LHSInvE->inverse(); MassE->Clear(); StiffE->Clear(); BiiE->Clear(); FiiE->Clear(); BijE->Clear(); FijE->Clear(); } /* E setup */ void tetra::SetUp_LocalFaceToTetraMapE_NMF1_Numeric(fp_t dt) { if (LocalEDOF == 0) return; int LocalDim, LocalFaceDim; fp_t eps_o = Eo; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; // sigma and abc denseMat RMatrixE(LocalDim, LocalDim); Calculate_R_Matrix_E_Numeric(&RMatrixE, dt); RHSLoc1E = new denseMat(LocalDim, LocalDim); RHSLoc2E = new denseMat(LocalDim, LocalDim); RHSCoup1E = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); RHSCoup2E = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); BiiE->scale(dt / eps_o); *RHSLoc1E = *MassE + *BiiE - (RMatrixE) ; ApplyPEC(RHSLoc1E, LocalDim); *RHSLoc2E = *StiffE - *FiiE; RHSLoc2E->scale(dt / eps_o); ApplyPEC_E(RHSLoc2E, LocalDim); ApplyPMC_E(RHSLoc2E, LocalDim); *RHSCoup1E = *FijE; RHSCoup1E->scale(dt / eps_o); *RHSCoup2E = *BijE; RHSCoup2E->scale(dt / eps_o); // Inv LHSInvE = new denseMat(LocalDim, LocalDim); *LHSInvE = *MassE + RMatrixE; *LHSInvE = LHSInvE->inverse(); MassE->Clear(); StiffE->Clear(); BiiE->Clear(); FiiE->Clear(); BijE->Clear(); FijE->Clear(); } /* H setup */ void tetra::SetUp_LocalFaceToTetraMapH_NMF1(fp_t dt) { if (LocalHDOF == 0) return; int LocalDim, LocalFaceDim; fp_t mu_o = Uo; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; // sigma and abc denseMat RMatrixH(LocalDim, LocalDim); Calculate_R_Matrix_H(&RMatrixH, dt); RHSLoc1H = new denseMat(LocalDim, LocalDim); RHSLoc2H = new denseMat(LocalDim, LocalDim); RHSCoup1H = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); RHSCoup2H = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); BiiH->scale(dt / mu_o); *RHSLoc1H = *MassH + *BiiH - RMatrixH; ApplyPMC(RHSLoc1H, LocalDim); *RHSLoc2H = *FiiH - *StiffH; RHSLoc2H->scale(dt / mu_o); ApplyPEC_H(RHSLoc2H, LocalDim); ApplyPMC_H(RHSLoc2H, LocalDim); *RHSCoup1H = *FijH; RHSCoup1H->scale(dt / mu_o); *RHSCoup2H = *BijH; RHSCoup2H->scale(dt / mu_o); // Inv LHSInvH = new denseMat(LocalDim, LocalDim); *LHSInvH = *MassH + RMatrixH; *LHSInvH = LHSInvH->inverse(); // cout.precision(7); // if(cnt == 37 || cnt == 114){ // cout << "Node 0 = (" << nd[0]->getCoord().getx() << ", " << nd[0]->getCoord().gety() << ", " << nd[0]->getCoord().getz() << ") " << endl; // cout << "Node 1 = (" << nd[1]->getCoord().getx() << ", " << nd[1]->getCoord().gety() << ", " << nd[1]->getCoord().getz() << ") " << endl; // cout << "Node 2 = (" << nd[2]->getCoord().getx() << ", " << nd[2]->getCoord().gety() << ", " << nd[2]->getCoord().getz() << ") " << endl; // cout << "Node 3 = (" << nd[3]->getCoord().getx() << ", " << nd[3]->getCoord().gety() << ", " << nd[3]->getCoord().getz() << ") " << endl; // cout << "cnt = " << cnt << endl; // for(int i1 = 0; i1 < TetPolyOrderDim[PolyOrderFlag]; i1++){ // for(int i2 = 0; i2 < TetPolyOrderDim[PolyOrderFlag]; i2++){ // cout << LHSInvH->getEntry(i1, i2) << " "; // } // cout << endl; // }cout << endl; // } MassH->Clear(); StiffH->Clear(); BiiH->Clear(); FiiH->Clear(); BijH->Clear(); FijH->Clear(); } /* H setup Numeric */ void tetra::SetUp_LocalFaceToTetraMapH_NMF1_Numeric(fp_t dt) { if (LocalHDOF == 0) return; int LocalDim, LocalFaceDim; fp_t mu_o = Uo; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; // sigma and abc denseMat RMatrixH(LocalDim, LocalDim); Calculate_R_Matrix_H_Numeric(&RMatrixH, dt); RHSLoc1H = new denseMat(LocalDim, LocalDim); RHSLoc2H = new denseMat(LocalDim, LocalDim); RHSCoup1H = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); RHSCoup2H = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); BiiH->scale(dt / mu_o); *RHSLoc1H = *MassH + *BiiH - RMatrixH; ApplyPMC(RHSLoc1H, LocalDim); *RHSLoc2H = *FiiH - *StiffH; RHSLoc2H->scale(dt / mu_o); ApplyPEC_H(RHSLoc2H, LocalDim); ApplyPMC_H(RHSLoc2H, LocalDim); *RHSCoup1H = *FijH; RHSCoup1H->scale(dt / mu_o); *RHSCoup2H = *BijH; RHSCoup2H->scale(dt / mu_o); // Inv LHSInvH = new denseMat(LocalDim, LocalDim); *LHSInvH = *MassH + RMatrixH; *LHSInvH = LHSInvH->inverse(); // cout.precision(7); // if(cnt == 37 || cnt == 114){ // cout << "Node 0 = (" << nd[0]->getCoord().getx() << ", " << nd[0]->getCoord().gety() << ", " << nd[0]->getCoord().getz() << ") " << endl; // cout << "Node 1 = (" << nd[1]->getCoord().getx() << ", " << nd[1]->getCoord().gety() << ", " << nd[1]->getCoord().getz() << ") " << endl; // cout << "Node 2 = (" << nd[2]->getCoord().getx() << ", " << nd[2]->getCoord().gety() << ", " << nd[2]->getCoord().getz() << ") " << endl; // cout << "Node 3 = (" << nd[3]->getCoord().getx() << ", " << nd[3]->getCoord().gety() << ", " << nd[3]->getCoord().getz() << ") " << endl; // cout << "cnt = " << cnt << endl; // for(int i1 = 0; i1 < TetPolyOrderDim[PolyOrderFlag]; i1++){ // for(int i2 = 0; i2 < TetPolyOrderDim[PolyOrderFlag]; i2++){ // cout << LHSInvH->getEntry(i1, i2) << " "; // } // cout << endl; // }cout << endl; // } MassH->Clear(); StiffH->Clear(); BiiH->Clear(); FiiH->Clear(); BijH->Clear(); FijH->Clear(); } // The functions following are mainly all the update functions. // The ones named _NMF correspond to the non matrix free implementation option. // The ones named _BLAS are for the matrix-free option. void tetra::LocalFaceToTetraMapE_NMF1(ArrayFP& En_1, ArrayFP& En, ArrayFP& Hn_12, fp_t dt, fp_t t) { if (LocalEDOF == 0) return; int i; int LocalDim, LocalFaceDim, NeighFaceDim; int DGface_bc; tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; ArrayFP work(LocalDim); for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr) cout << "ERROR: Null pointer at bType = 0" << endl; int neFac; if (neigh != nullptr && (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType)) { NeighFaceDim = FacePolyOrderDim[neigh->PolyOrderFlag]; ArrayFP nei_e(NeighFaceDim); ArrayFP nei_h(NeighFaceDim); assert(NeighFaceDim == LocalFaceDim); for (int m = 0; m < NumOfFaces; m++) { if (neigh->getFacePtr(m) == fc[i]) neFac = m; } for (int l = 0; l < NeighFaceDim; l++) { if (neigh->LocMapE[fac2tet[neFac][l]] >= 0) nei_e[l] = En[neigh->LocMapE[fac2tet[neFac][l]]]; else nei_e[l] = 0.0; if (neigh->LocMapH[fac2tet[neFac][l]] >= 0) nei_h[l] = Hn_12[neigh->LocMapH[fac2tet[neFac][l]]]; else nei_h[l] = 0.0; } denseMat RHSCoup1E_aux(LocalDim, NeighFaceDim); denseMat RHSCoup2E_aux(LocalDim, NeighFaceDim); for(int l = 0; l < LocalDim; l++){ for(int k = 0; k < NeighFaceDim; k++){ RHSCoup1E_aux.setEntry(l, k, RHSCoup1E->getEntry(l, i * NeighFaceDim + k)); RHSCoup2E_aux.setEntry(l, k, RHSCoup2E->getEntry(l, i * NeighFaceDim + k)); } } ArrayFP work_aux(LocalDim); Ax(RHSCoup2E_aux, nei_e, work_aux); Axpy(RHSCoup1E_aux, nei_h, work_aux); for (int l = 0; l < LocalDim; l++) work[l] += work_aux[l]; } } else if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) {} else if (DGface_bc == pecType) {} else if (DGface_bc == pmcType) {} else if (DGface_bc == nonConformal){ int neighFaceIdx = 0; fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); fp_t Y = 1.0 / Z; fp_t Zneigh = 0.0; fp_t Yt = 0.0; for (int idx = 0 ; idx < NeighNCNum ; idx++){ if (OverlapMapVec[i].find(idx)->second){ if(IntersectionMapVec[i].find(idx)->second){ neigh = NeighNCTetra[idx]; NeighFaceDim = FacePolyOrderDim[neigh->PolyOrderFlag]; neighFaceIdx = IntersectionFaceMapVec[i].find(idx)->second; Zneigh = (No * sqrt(neigh->mat->mur.getEntry(0, 0) / neigh->mat->epsr.getEntry(0, 0))); Yt = 1.0 / (0.5 * (Z + Zneigh)); ArrayFP nei_e(NeighFaceDim); ArrayFP nei_h(NeighFaceDim); for (int l = 0; l < NeighFaceDim; l++) { if (neigh->LocMapE[fac2tet[neighFaceIdx][l]] >= 0) nei_e[l] = En[neigh->LocMapE[fac2tet[neighFaceIdx][l]]]; else nei_e[l] = 0.0; if (neigh->LocMapH[fac2tet[neighFaceIdx][l]] >= 0) nei_h[l] = Hn_12[neigh->LocMapH[fac2tet[neighFaceIdx][l]]]; else nei_h[l] = 0.0; } denseMat RHSCoup1E_aux(LocalDim, NeighFaceDim); denseMat RHSCoup2E_aux(LocalDim, NeighFaceDim); for (int l = 0; l < LocalFaceDim; l++){ for (int k = 0; k < NeighFaceDim; k++){ RHSCoup1E_aux.setEntry(l, k, (dt / Eo) * NC_CouplingMatArray[idx * NumCouplingMatrices + 1].getEntry(l, k)); RHSCoup2E_aux.setEntry (l, k, -(dt / Eo) * 0.5 * Yt * NC_CouplingMatArray[idx * NumCouplingMatrices + 2].getEntry(l, k) * GAMMA); } } ArrayFP work_aux(LocalFaceDim); Ax(RHSCoup2E_aux, nei_e, work_aux); Axpy(RHSCoup1E_aux, nei_h, work_aux); for (int l = 0; l < LocalFaceDim; l++) if (LocMapE[fac2tet[i][l]] >=0) work[fac2tet[i][l]] += work_aux[l]; } } } } } ArrayFP loc_e(LocalDim); ArrayFP loc_h(LocalDim); // get vector entries for (i = 0; i < LocalDim; i++) { if (LocMapE[i] >= 0) loc_e[i] = En[LocMapE[i]]; else loc_e[i] = 0.0; if (LocMapH[i] >= 0) loc_h[i] = Hn_12[LocMapH[i]]; else loc_h[i] = 0.0; } Axpy(*RHSLoc1E, loc_e, work); // 1st local term Axpy(*RHSLoc2E, loc_h, work); // 2nd local term if (ExcitationFlag) Excitation_E_BLAS(En_1, t, dt, work); // excitation (PW or port) Ax(*LHSInvE, work, loc_e); // add back into y with mapping for (i = 0; i < LocalDim; i++) { if (LocMapE[i] >= 0) En_1[LocMapE[i]] = loc_e[i]; } } void tetra::LocalFaceToTetraMapH_NMF1(ArrayFP& Hn_32, ArrayFP& En_1, ArrayFP& Hn_12, fp_t dt, fp_t t) { if (LocalHDOF == 0) return; int i; int LocalDim, LocalFaceDim, NeighFaceDim; int DGface_bc; tetra* neigh; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; ArrayFP work(LocalDim); for (i = 0; i < NumOfFaces; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType) { neigh = fc[i]->neighborTETRA(this); if (neigh == nullptr) cout << "ERROR: Null pointer at bType = 0" << endl; int neFac; if (neigh != nullptr && (DGface_bc == 0 || DGface_bc == outputSurfType || DGface_bc == fieldPlaneType)) { NeighFaceDim = FacePolyOrderDim[neigh->PolyOrderFlag]; ArrayFP nei_e(NeighFaceDim); ArrayFP nei_h(NeighFaceDim); assert(NeighFaceDim == LocalFaceDim); for (int m = 0; m < NumOfFaces; m++) { if (neigh->getFacePtr(m) == fc[i]) neFac = m; } for (int l = 0; l < NeighFaceDim; l++) { if (neigh->LocMapE[fac2tet[neFac][l]] >= 0) nei_e[l] = En_1[neigh->LocMapE[fac2tet[neFac][l]]]; else nei_e[l] = 0.0; if (neigh->LocMapH[fac2tet[neFac][l]] >= 0) nei_h[l] = Hn_12[neigh->LocMapH[fac2tet[neFac][l]]]; else nei_h[l] = 0.0; } denseMat RHSCoup1H_aux(LocalDim, NeighFaceDim); denseMat RHSCoup2H_aux(LocalDim, NeighFaceDim); for(int l = 0; l < LocalDim; l++){ for(int k = 0; k < NeighFaceDim; k++){ RHSCoup1H_aux.setEntry(l, k, RHSCoup1H->getEntry(l, i * NeighFaceDim + k)); RHSCoup2H_aux.setEntry(l, k, RHSCoup2H->getEntry(l, i * NeighFaceDim + k)); } } ArrayFP work_aux(LocalDim); Ax(RHSCoup2H_aux, nei_h, work_aux); Axpy(RHSCoup1H_aux, nei_e, work_aux); for (int l = 0; l < LocalDim; l++) work[l] += work_aux[l]; } } else if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { } else if (DGface_bc == pecType) { } else if (DGface_bc == pmcType) { } else if (DGface_bc == nonConformal){ int neighFaceIdx = 0; fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); fp_t Y = 1.0 / Z; fp_t Yneigh = 0.0; fp_t Zt = 0.0; for (int idx = 0 ; idx < NeighNCNum ; idx++){ if (OverlapMapVec[i].find(idx)->second){ if(IntersectionMapVec[i].find(idx)->second){ neigh = NeighNCTetra[idx]; NeighFaceDim = FacePolyOrderDim[neigh->PolyOrderFlag]; neighFaceIdx = IntersectionFaceMapVec[i].find(idx)->second; Yneigh = 1.0 / (No * sqrt(neigh->mat->mur.getEntry(0, 0) / neigh->mat->epsr.getEntry(0, 0))); Zt = 1.0 / (0.5 * (Y + Yneigh)); ArrayFP nei_e(NeighFaceDim); ArrayFP nei_h(NeighFaceDim); for (int l = 0; l < NeighFaceDim; l++) { if (neigh->LocMapE[fac2tet[neighFaceIdx][l]] >= 0) nei_e[l] = En_1[neigh->LocMapE[fac2tet[neighFaceIdx][l]]]; else nei_e[l] = 0.0; if (neigh->LocMapH[fac2tet[neighFaceIdx][l]] >= 0) nei_h[l] = Hn_12[neigh->LocMapH[fac2tet[neighFaceIdx][l]]]; else nei_h[l] = 0.0; } denseMat RHSCoup1H_aux(LocalDim, NeighFaceDim); denseMat RHSCoup2H_aux(LocalDim, NeighFaceDim); for (int l = 0; l < LocalFaceDim; l++){ for (int k = 0; k < NeighFaceDim; k++){ RHSCoup1H_aux.setEntry(l, k, -(dt / Uo) * NC_CouplingMatArray[idx * NumCouplingMatrices + 1].getEntry(l, k)); RHSCoup2H_aux.setEntry (l, k, -(dt / Uo) * 0.5 * Zt * NC_CouplingMatArray[idx * NumCouplingMatrices + 2].getEntry(l, k) * GAMMA); } } ArrayFP work_aux(LocalFaceDim); Ax(RHSCoup2H_aux, nei_h, work_aux); Axpy(RHSCoup1H_aux, nei_e, work_aux); for (int l = 0; l < LocalFaceDim; l++) if (LocMapH[fac2tet[i][l]] >=0) work[fac2tet[i][l]] += work_aux[l]; } } } } } ArrayFP loc_e(LocalDim); ArrayFP loc_h(LocalDim); // get vector entries for (i = 0; i < LocalDim; i++) { if (LocMapE[i] >= 0) loc_e[i] = En_1[LocMapE[i]]; else loc_e[i] = 0.0; if (LocMapH[i] >= 0) loc_h[i] = Hn_12[LocMapH[i]]; else loc_h[i] = 0.0; } Axpy(*RHSLoc1H, loc_h, work); Axpy(*RHSLoc2H, loc_e, work); if (ExcitationFlag) Excitation_H_BLAS(Hn_32, t, dt, work); Ax(*LHSInvH, work, loc_h); // add back to Hn_32 for (i = 0; i < LocalDim; i++) { if (LocMapH[i] >= 0) Hn_32[LocMapH[i]] = loc_h[i]; } } /* Excitations */ void tetra::Excitation_E_BLAS(ArrayFP& En_1, fp_t t, fp_t dt, ArrayFP& work2) { if (LocalEDOF == 0) return; if (t < 0.) return; int i; int LocalDim; fp_t Y; fp_t eps_o = Eo; ArrayFP* nxh; ArrayFP* nxnxe; // excitation LocalDim = TetPolyOrderDim[PolyOrderFlag]; nxh = new ArrayFP(LocalDim); nxnxe = new ArrayFP(LocalDim); // Check for excitation face for (i = 0; i < NumOfFaces; i++) { if (fc[i]->bcPtr->getbType() == planeWaveType) { Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); } else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) { Y = 1.0 / fc[i]->bcPtr->get_PortImpVal(); } } nxh->reset(); nxnxe->reset(); /* since the calling already has if(excitationflag==1), what is the purpose * of this if ? for PML ? */ if (ExcitationFlag) { set_einc(t, nxh, nxnxe); nxh->scale(dt / eps_o); nxh->axpy(-Y * (dt / eps_o), *nxnxe); ApplyPEC_Vector(nxh, LocalDim); } for (int l = 0; l < LocalDim; l++) if (LocMapE[l] >= 0) work2[l] += nxh->getentry(l); // add PML part delete nxh; delete nxnxe; } void tetra::Excitation_H_BLAS(ArrayFP& Hn_32, fp_t t, fp_t dt, ArrayFP& work2) { if (LocalHDOF == 0) return; if (t < 0.) return; int i; int LocalDim; fp_t Z; fp_t mu_o = Uo; ArrayFP* nxe; ArrayFP* nxnxh; // excitation LocalDim = TetPolyOrderDim[PolyOrderFlag]; nxe = new ArrayFP(LocalDim); nxnxh = new ArrayFP(LocalDim); // Check for excitation face for (i = 0; i < NumOfFaces; i++) { if (fc[i]->bcPtr->getbType() == planeWaveType) Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) Z = fc[i]->bcPtr->get_PortImpVal(); } nxe->reset(); nxnxh->reset(); if (ExcitationFlag) { set_hinc(t, nxe, nxnxh); nxe->scale(-(dt / mu_o)); nxe->axpy(-Z * (dt / mu_o), *nxnxh); ApplyPMC_Vector(nxe, LocalDim); } for (int l = 0; l < LocalDim; l++) if (LocMapH[l] >= 0) work2[l] += nxe->getentry(l); // add PML part delete nxe; delete nxnxh; } void tetra::setEHGlobalMap(int i, int ide, int idh) { EdofMap[i] = ide; HdofMap[i] = idh; } void tetra::allocDofMap() { EdofMap = new int[TetPolyOrderDim[PolyOrderFlag]]; HdofMap = new int[TetPolyOrderDim[PolyOrderFlag]]; for (int i = 0; i < TetPolyOrderDim[PolyOrderFlag]; i++) { EdofMap[i] = NOT_NUMBERED; HdofMap[i] = NOT_NUMBERED; } } void tetra::freeDofMap() { // cout<<"Calling freeDofMap"<neighborTETRA(this); if (fc[i]->getbType() == 0 || fc[i]->getbType()) { if (neigh != nullptr) { for (int m = 0; m < FaceNum; m++) { if (neigh->getFacePtr(m) == fc[i]) { NeighFace = m; } } for (int j = 0; j < FacePolyOrderDim[PolyOrderFlag]; j++) { NeighMaps[i * Offset + j] = neigh->LocMapH[fac2tet[NeighFace][j]]; NeighMaps[i * Offset + FacePolyOrderDim[PolyOrderFlag] + j] = neigh->LocMapE[fac2tet[NeighFace][j]]; } } } } return NeighMaps; } int* tetra::get_NeighMapsH() { int FaceNum = 4; int NeighFace = 0; int MapCol = FacePolyOrderDim[PolyOrderFlag] * 2; int MapDim = MapCol * 4; int Offset = FacePolyOrderDim[PolyOrderFlag] * 2; int* NeighMaps = (int*)malloc(sizeof(int) * (MapDim)); tetra* neigh; for (int i = 0; i < FaceNum; i++) for (int j = 0; j < MapCol; j++) NeighMaps[i * MapCol + j] = -1; for (int i = 0; i < FaceNum; i++) { neigh = fc[i]->neighborTETRA(this); if (fc[i]->getbType() == 0 || fc[i]->getbType()) { if (neigh != nullptr) { for (int m = 0; m < FaceNum; m++) { if (neigh->getFacePtr(m) == fc[i]) { NeighFace = m; } } for (int j = 0; j < FacePolyOrderDim[PolyOrderFlag]; j++) { NeighMaps[i * Offset + j] = neigh->LocMapE[fac2tet[NeighFace][j]]; NeighMaps[i * Offset + FacePolyOrderDim[PolyOrderFlag] + j] = neigh->LocMapH[fac2tet[NeighFace][j]]; } } } } return NeighMaps; } void tetra::SetUpInterfaceMatrices_NC(){ if(NeighNCNum <= 0) return; int neighFaceIdx = -1; int tcount = 0; bool Overlap = false; int LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; face* IntersectionFaceArray; face* neighborFace; // Allocate memory to pre-compute and store // the non-conformal coupling matrices NC_CouplingMatArray = new denseMat[NumCouplingMatrices * NeighNCNum]; for (int i = 0 ; i < NeighNCNum ; i++){ NC_CouplingMatArray[i * NumCouplingMatrices + 0].setDim(LocalFaceDim, FacePolyOrderDim[PolyOrderFlag]); NC_CouplingMatArray[i * NumCouplingMatrices + 1].setDim(LocalFaceDim, FacePolyOrderDim[NeighNCTetra[i]->PolyOrderFlag]); NC_CouplingMatArray[i * NumCouplingMatrices + 2].setDim(LocalFaceDim, FacePolyOrderDim[NeighNCTetra[i]->PolyOrderFlag]); } denseMat Beii_aux(LocalFaceDim, LocalFaceDim); for(int i = 0 ; i < NumOfFaces; i++){ // non-conformal face if (fc[i]->getbType() == nonConformal){ // get local non-conformal face for (int idx = 0 ; idx < NeighNCNum ; idx++){ Overlap = false; // Find the face of the neigh tet that couples to the localFace for(int faceIdx = 0; faceIdx < NumOfFaces; faceIdx++){ neighborFace = NeighNCTetra[idx]->fc[faceIdx]; if (neighborFace->getbType() == nonConformal){ if(triangle_overlaps_triangle(fc[i], neighborFace)){ if(CheckIntersection(fc[i], NeighNCTetra[idx]->fc[faceIdx])){ neighFaceIdx = faceIdx; Overlap = true; } } } } if(Overlap){ IntersectionFaceArray = CreateInterSectionMesh(fc[i], NeighNCTetra[idx]->fc[neighFaceIdx], tcount); if(IntersectionFaceArray != NULL){ // local Beii and Feii fc[i]->Calculate_w_w_Matrix_NC(IntersectionFaceArray, tcount, fc[i], fc[i], &Beii_aux, PolyOrderFlag); for (int row = 0; row < Beii_aux.getRowDim(); row++){ for (int col = 0; col < Beii_aux.getColDim(); col++){ NC_CouplingMatArray[idx * NumCouplingMatrices + 0].setEntry(row, col, Beii_aux.getEntry(row, col)); } } // Coupling Feij, Beij denseMat Feij_aux, Beij_aux; Feij_aux.setDim(LocalFaceDim, FacePolyOrderDim[NeighNCTetra[idx]->PolyOrderFlag]); Beij_aux.setDim(LocalFaceDim, FacePolyOrderDim[NeighNCTetra[idx]->PolyOrderFlag]); int auxPoly = (PolyOrderFlag > NeighNCTetra[idx]->PolyOrderFlag) ? PolyOrderFlag : NeighNCTetra[idx]->PolyOrderFlag; fc[i]->Calculate_w_nxw_Matrix_NC(IntersectionFaceArray, tcount, fc[i], NeighNCTetra[idx]->fc[neighFaceIdx], &Feij_aux, this, auxPoly); fc[i]->Calculate_w_w_Matrix_NC(IntersectionFaceArray, tcount, fc[i], NeighNCTetra[idx]->fc[neighFaceIdx] , &Beij_aux, auxPoly); for (int row = 0; row < Beij_aux.getRowDim(); row++){ for (int col = 0; col < Beij_aux.getColDim(); col++){ NC_CouplingMatArray[idx * NumCouplingMatrices + 1].setEntry(row, col, Feij_aux.getEntry(row, col)); NC_CouplingMatArray[idx * NumCouplingMatrices + 2].setEntry(row, col, Beij_aux.getEntry(row, col)); } } } // free the memory if(IntersectionFaceArray != NULL) delete [] IntersectionFaceArray; } } } } } void tetra::SetUpInterfaceMaps_NC(){ if (NeighNCNum <= 0) return; int neighFaceIdx = -1; int tcount = 0; bool Overlap = false; face* IntersectionFaceArray; face* neighborFace; map OverlapMap; map IntersectionMap; map IntersectionFaceMap; vector>::iterator it2; vector>::iterator it3; for(int i = 0; i < 4; i++){ OverlapMap.clear(); IntersectionMap.clear(); IntersectionFaceMap.clear(); // non-conformal face if(fc[i]->getbType() == nonConformal){ // get local non-conformal face for(int idx = 0 ; idx < NeighNCNum; idx++){ Overlap = false; // Find the face of the neigh tet that couples to the localFace for(int faceIdx = 0; faceIdx < 4; faceIdx++){ neighborFace = NeighNCTetra[idx]->fc[faceIdx]; if (neighborFace->getbType() == nonConformal){ if(triangle_overlaps_triangle(fc[i], neighborFace)){ if (CheckIntersection(fc[i], NeighNCTetra[idx]->fc[faceIdx])){ neighFaceIdx = faceIdx; Overlap = true; } } } } OverlapMap[idx] = Overlap; IntersectionMap[idx] = false; if(Overlap){ IntersectionFaceArray = CreateInterSectionMesh(fc[i], NeighNCTetra[idx]->fc[neighFaceIdx], tcount); if(IntersectionFaceArray != NULL){ IntersectionMap[idx] = true; IntersectionFaceMap[idx] = neighFaceIdx; } if(IntersectionFaceArray != NULL) delete [] IntersectionFaceArray; } } } // Add the maps to a vector it2 = OverlapMapVec.begin(); OverlapMapVec.insert(it2 + i, OverlapMap); it2 = IntersectionMapVec.begin(); IntersectionMapVec.insert(it2 + i, IntersectionMap); it3 = IntersectionFaceMapVec.begin(); IntersectionFaceMapVec.insert(it3 + i, IntersectionFaceMap); } } bool tetra::CheckIntersection(face* LocalFace, face* NeighFace){ double tri2Coords[6],tri1Coords[6]; char* plane; int tcount = 0; double thridCoord = 0.; // Non-Planar conformal case for (int i = 0 ; i < 4; i++){ if (triangle_overlaps_triangleCO(fc[i], NeighFace)){ return true; } } plane = NeighFace->ReturnIntferfacePlaneCoord(tri2Coords, thridCoord); int PlaneID; if(0 == strcmp(plane, "yz")) PlaneID = 0; if(0 == strcmp(plane, "xz")) PlaneID = 1; if(0 == strcmp(plane, "xy")) PlaneID = 2; LocalFace->ReturnIntferfacePlaneCoord(tri1Coords, thridCoord, PlaneID); NeighFace->ReturnIntferfacePlaneCoord(tri2Coords, thridCoord, PlaneID); Paths subj(1),clip(1), solution; subj[0]<< IntPoint(cInt(tri1Coords[0] * scaleFact),cInt(tri1Coords[1] * scaleFact)) << IntPoint(cInt(tri1Coords[2] * scaleFact),cInt(tri1Coords[3] * scaleFact)) << IntPoint(cInt(tri1Coords[4] * scaleFact),cInt(tri1Coords[5] * scaleFact)); clip[0]<< IntPoint(cInt(tri2Coords[0] * scaleFact),cInt(tri2Coords[1] * scaleFact)) << IntPoint(cInt(tri2Coords[2] * scaleFact),cInt(tri2Coords[3] * scaleFact)) << IntPoint(cInt(tri2Coords[4] * scaleFact),cInt(tri2Coords[5] * scaleFact)); Clipper c; c.AddPaths(subj, ptSubject, true); c.AddPaths(clip, ptClip, true); Vector2dVector TriangulatedPolygon; if(c.Execute(ctIntersection, solution, pftNonZero, pftNonZero)){ if(solution.size() > 0){ if(solution[0].size() >= 3){ Path& path = solution[0]; for (int t = 0 ; t < path.size() - 2;t++){ TriangulatedPolygon.push_back(Vector2d(double(path[0].X) * scaleFactinv, double(path[0].Y) * scaleFactinv)); TriangulatedPolygon.push_back(Vector2d(double(path[t + 1].X) * scaleFactinv, double(path[t + 1].Y) * scaleFactinv)); TriangulatedPolygon.push_back(Vector2d(double(path[t + 2].X) * scaleFactinv, double(path[t + 2].Y) * scaleFactinv)); } } } }else{ return false; } tcount = TriangulatedPolygon.size() / 3; if(tcount == 0) return false; vtr nd0, nd1, nd2; face IntersecFace; fp_t sik = 0.0; fp_t area = 0.0; for (int tri = 0; tri < tcount; tri++){ if (strcmp(plane, "yz") == 0){ nd0.setvtr(thridCoord, TriangulatedPolygon[tri * 3 + 0].GetX(), TriangulatedPolygon[tri * 3 + 0].GetY()); nd1.setvtr(thridCoord, TriangulatedPolygon[tri * 3 + 1].GetX(), TriangulatedPolygon[tri * 3 + 1].GetY()); nd2.setvtr(thridCoord, TriangulatedPolygon[tri * 3 + 2].GetX(), TriangulatedPolygon[tri * 3 + 2].GetY()); } else if (strcmp(plane, "xz") == 0){ nd0.setvtr(TriangulatedPolygon[tri * 3 + 0].GetX(), thridCoord, TriangulatedPolygon[tri * 3 + 0].GetY()); nd1.setvtr(TriangulatedPolygon[tri * 3 + 1].GetX(), thridCoord, TriangulatedPolygon[tri * 3 + 1].GetY()); nd2.setvtr(TriangulatedPolygon[tri * 3 + 2].GetX(), thridCoord, TriangulatedPolygon[tri * 3 + 2].GetY()); } else if (strcmp(plane, "xy") == 0){ nd0.setvtr(TriangulatedPolygon[tri * 3 + 0].GetX(), TriangulatedPolygon[tri * 3 + 0].GetY(), thridCoord); nd1.setvtr(TriangulatedPolygon[tri * 3 + 1].GetX(), TriangulatedPolygon[tri * 3 + 1].GetY(), thridCoord); nd2.setvtr(TriangulatedPolygon[tri * 3 + 2].GetX(), TriangulatedPolygon[tri * 3 + 2].GetY(), thridCoord); } IntersecFace.setCoordOfFaceNodes(nd0, nd1, nd2); IntersecFace.getFaceArea(&area); sik += area; } TriangulatedPolygon.clear(); if(sik == 0.0) return false; return true; } face* tetra::CreateInterSectionMesh(face* LocalFace, face* NeighFace, int& tcount){ double tri1Coords[6]; double tri2Coords[6]; char* plane; double thridCoord = 0.0; // Non-Planar conformal case for (int i = 0 ; i < 4; i++){ if (triangle_overlaps_triangleCO(fc[i], NeighFace)){ tcount = 1; face* IntersectionFaceArray = new face[tcount]; IntersectionFaceArray[0].setCoordOfFaceNodes(fc[i]->getNodePtr(0)->getCoord(), fc[i]->getNodePtr(1)->getCoord(), fc[i]->getNodePtr(2)->getCoord()); return IntersectionFaceArray; } } plane = NeighFace->ReturnIntferfacePlaneCoord(tri2Coords, thridCoord); ///// new version int PlaneID; if(0 == strcmp(plane, "yz")) PlaneID = 0; if(0 == strcmp(plane, "xz")) PlaneID = 1; if(0 == strcmp(plane, "xy")) PlaneID = 2; LocalFace->ReturnIntferfacePlaneCoord(tri1Coords, thridCoord, PlaneID); NeighFace->ReturnIntferfacePlaneCoord(tri2Coords, thridCoord, PlaneID); Paths subj(1),clip(1), solution; subj[0]<< IntPoint(cInt(tri1Coords[0] * scaleFact),cInt(tri1Coords[1] * scaleFact)) << IntPoint(cInt(tri1Coords[2] * scaleFact),cInt(tri1Coords[3] * scaleFact)) << IntPoint(cInt(tri1Coords[4] * scaleFact),cInt(tri1Coords[5] * scaleFact)); clip[0]<< IntPoint(cInt(tri2Coords[0] * scaleFact),cInt(tri2Coords[1] * scaleFact)) << IntPoint(cInt(tri2Coords[2] * scaleFact),cInt(tri2Coords[3] * scaleFact)) << IntPoint(cInt(tri2Coords[4] * scaleFact),cInt(tri2Coords[5] * scaleFact)); Clipper c; c.AddPaths(subj, ptSubject, true); c.AddPaths(clip, ptClip, true); Vector2dVector TriangulatedPolygon; if(c.Execute(ctIntersection, solution, pftNonZero, pftNonZero)){ if(solution.size() > 0){ if(solution[0].size() >= 3){ Path& path = solution[0]; for (int t = 0 ; t < path.size() - 2; t++){ TriangulatedPolygon.push_back(Vector2d(double(path[0].X) * scaleFactinv, double(path[0].Y) * scaleFactinv)); TriangulatedPolygon.push_back(Vector2d(double(path[t + 1].X) * scaleFactinv, double(path[t + 1].Y) * scaleFactinv)); TriangulatedPolygon.push_back(Vector2d(double(path[t + 2].X) * scaleFactinv, double(path[t + 2].Y) * scaleFactinv)); } } } }else{ return NULL; } tcount = TriangulatedPolygon.size() / 3; if(tcount == 0) return NULL; face* IntersectionFaceArray = new face[tcount]; vtr nd0, nd1, nd2; for(int tri = 0; tri < tcount; tri++){ if (strcmp(plane, "yz") == 0){ nd0.setvtr(thridCoord, TriangulatedPolygon[tri * 3 + 0].GetX(), TriangulatedPolygon[tri * 3 + 0].GetY()); nd1.setvtr(thridCoord, TriangulatedPolygon[tri * 3 + 1].GetX(), TriangulatedPolygon[tri * 3 + 1].GetY()); nd2.setvtr(thridCoord, TriangulatedPolygon[tri * 3 + 2].GetX(), TriangulatedPolygon[tri * 3 + 2].GetY()); } else if (strcmp(plane, "xz") == 0){ nd0.setvtr(TriangulatedPolygon[tri * 3 + 0].GetX(), thridCoord, TriangulatedPolygon[tri * 3 + 0].GetY()); nd1.setvtr(TriangulatedPolygon[tri * 3 + 1].GetX(), thridCoord, TriangulatedPolygon[tri * 3 + 1].GetY()); nd2.setvtr(TriangulatedPolygon[tri * 3 + 2].GetX(), thridCoord, TriangulatedPolygon[tri * 3 + 2].GetY()); } else if (strcmp(plane, "xy") == 0){ nd0.setvtr(TriangulatedPolygon[tri * 3 + 0].GetX(), TriangulatedPolygon[tri * 3 + 0].GetY(), thridCoord); nd1.setvtr(TriangulatedPolygon[tri * 3 + 1].GetX(), TriangulatedPolygon[tri * 3 + 1].GetY(), thridCoord); nd2.setvtr(TriangulatedPolygon[tri * 3 + 2].GetX(), TriangulatedPolygon[tri * 3 + 2].GetY(), thridCoord); } IntersectionFaceArray[tri].setCoordOfFaceNodes(nd0, nd1, nd2); } TriangulatedPolygon.clear(); return IntersectionFaceArray; } int tetra::getNeighFace(tetra* neigh){ tetra* neigh_aux; int DGface_bc; if(!isNonConformal){ for (int i = 0; i < NumOfFaces; i++){ neigh_aux = fc[i]->neighborTETRA(this); if (neigh_aux != nullptr && neigh_aux == neigh){ for (int m = 0; m < NumOfFaces; m++) { if (neigh->getFacePtr(m) == fc[i]) { return m; } } } } }else{ for (int i = 0; i < NumOfFaces; i++){ DGface_bc = fc[i]->bcPtr->getbType(); if(DGface_bc == nonConformal){ for (int idx = 0 ; idx < NeighNCNum ; idx++){ if (neigh != nullptr && NeighNCTetra[idx] == neigh){ if (OverlapMapVec[i].find(idx)->second){ if(IntersectionMapVec[i].find(idx)->second){ return IntersectionFaceMapVec[i].find(idx)->second; } } // cout << "NEIGH Node 0 = (" << neigh->getNode(0)->getCoord().getx() << ", " << neigh->getNode(0)->getCoord().gety() << ", " << neigh->getNode(0)->getCoord().getz() << ") " << endl; // cout << "NEIGH Node 1 = (" << neigh->getNode(1)->getCoord().getx() << ", " << neigh->getNode(1)->getCoord().gety() << ", " << neigh->getNode(1)->getCoord().getz() << ") " << endl; // cout << "NEIGH Node 2 = (" << neigh->getNode(2)->getCoord().getx() << ", " << neigh->getNode(2)->getCoord().gety() << ", " << neigh->getNode(2)->getCoord().getz() << ") " << endl; // cout << "NEIGH Node 3 = (" << neigh->getNode(3)->getCoord().getx() << ", " << neigh->getNode(3)->getCoord().gety() << ", " << neigh->getNode(3)->getCoord().getz() << ") " << endl; // cout << "NEIGH cnt = " << neigh->getcnt() << endl; } // return 0; // cout << "Node 0 = (" << nd[0]->getCoord().getx() << ", " << nd[0]->getCoord().gety() << ", " << nd[0]->getCoord().getz() << ") " << endl; // cout << "Node 1 = (" << nd[1]->getCoord().getx() << ", " << nd[1]->getCoord().gety() << ", " << nd[1]->getCoord().getz() << ") " << endl; // cout << "Node 2 = (" << nd[2]->getCoord().getx() << ", " << nd[2]->getCoord().gety() << ", " << nd[2]->getCoord().getz() << ") " << endl; // cout << "Node 3 = (" << nd[3]->getCoord().getx() << ", " << nd[3]->getCoord().gety() << ", " << nd[3]->getCoord().getz() << ") " << endl; // cout << "cnt = " << cnt << endl; // cout << i << endl; } }else{ neigh_aux = fc[i]->neighborTETRA(this); if (neigh_aux != nullptr && neigh_aux == neigh){ for (int m = 0; m < NumOfFaces; m++) { if (neigh->getFacePtr(m) == fc[i]) { return m; } } } } } } cout << "Return -1 " << NeighNCNum << " " << cnt << endl; return -1; } void tetra::prepare_GPU(fp_t_ts* LHS_InvE_init, fp_t_ts* LHS_InvH_init, fp_t_ts* LE_Matrices_init, fp_t_ts* LH_Matrices_init, bool needInverse){ int LocalDim = TetPolyOrderDim[PolyOrderFlag]; int LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; denseMat* RHSCoup1E_aux; denseMat* RHSCoup2E_aux; denseMat* RHSLoc1E_aux; denseMat* RHSLoc2E_aux; if(LocalEDOF != 0){ RHSCoup1E_aux = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); AB(*LHSInvE, *RHSCoup1E, *RHSCoup1E_aux); RHSCoup1E->Clear(); RHSCoup2E_aux = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); AB(*LHSInvE, *RHSCoup2E, *RHSCoup2E_aux); RHSCoup2E->Clear(); RHSLoc1E_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvE, *RHSLoc1E, *RHSLoc1E_aux); RHSLoc1E->Clear(); RHSLoc2E_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvE, *RHSLoc2E, *RHSLoc2E_aux); RHSLoc2E->Clear(); } denseMat* RHSCoup1H_aux; denseMat* RHSCoup2H_aux; denseMat* RHSLoc1H_aux; denseMat* RHSLoc2H_aux; if(LocalHDOF != 0){ RHSCoup1H_aux = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); AB(*LHSInvH, *RHSCoup1H, *RHSCoup1H_aux); RHSCoup1H->Clear(); RHSCoup2H_aux = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); AB(*LHSInvH, *RHSCoup2H, *RHSCoup2H_aux); RHSCoup2H->Clear(); RHSLoc1H_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvH, *RHSLoc1H, *RHSLoc1H_aux); RHSLoc1H->Clear(); RHSLoc2H_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvH, *RHSLoc2H, *RHSLoc2H_aux); RHSLoc2H->Clear(); } int DGface_bc; tetra* neigh; int rowDim = TypeOfFields * LocalDim + TypeOfFields * NeighNum * LocalFaceDim; for(int i = 0; i < LocalDim; i++){ for(int j = 0; j < LocalDim; j++){ if(LocalEDOF != 0){ if(needInverse) LHS_InvE_init[i * LocalDim + j] = LHSInvE->getEntry(i, j); LE_Matrices_init[i * rowDim + j] = RHSLoc1E_aux->getEntry(i, j); LE_Matrices_init[i * rowDim + LocalDim + j] = RHSLoc2E_aux->getEntry(i, j); }else{ if(needInverse) LHS_InvE_init[i * LocalDim + j] = 0; LE_Matrices_init[i * rowDim + j] = 0; LE_Matrices_init[i * rowDim + LocalDim + j] = 0; } if(LocalHDOF != 0){ if(needInverse) LHS_InvH_init[i * LocalDim + j] = LHSInvH->getEntry(i, j); LH_Matrices_init[i * rowDim + j] = RHSLoc1H_aux->getEntry(i, j); LH_Matrices_init[i * rowDim + LocalDim + j] = RHSLoc2H_aux->getEntry(i, j); }else{ if(needInverse) LHS_InvH_init[i * LocalDim + j] = 0; LH_Matrices_init[i * rowDim + j] = 0; LH_Matrices_init[i * rowDim + LocalDim + j] = 0; } } } if(LocalEDOF != 0){ RHSLoc1E_aux->Clear(); RHSLoc2E_aux->Clear(); } if(LocalHDOF != 0){ RHSLoc1H_aux->Clear(); RHSLoc2H_aux->Clear(); } int offset = 2 * LocalDim; fp_t dt = Class_dt; fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); fp_t Y = 1.0 / Z; fp_t Zneigh = 0.0; fp_t Yt = 0.0; fp_t Yneigh = 0.0; fp_t Zt = 0.0; for(int i = 0; i < NeighNum; i++){ DGface_bc = fc[NeighTetraFaceMap[i]]->bcPtr->getbType(); if(DGface_bc != nonConformal){ for(int j = 0; j < LocalDim; j++){ for(int k = 0; k < LocalFaceDim; k++){ if(LocalEDOF != 0){ LE_Matrices_init[j * rowDim + offset + i * LocalFaceDim * 2 + k] = RHSCoup1E_aux->getEntry(j, NeighTetraFaceMap[i] * LocalFaceDim + k); LE_Matrices_init[j * rowDim + offset + i * LocalFaceDim * 2 + LocalFaceDim + k] = RHSCoup2E_aux->getEntry(j, NeighTetraFaceMap[i] * LocalFaceDim + k); }else{ LE_Matrices_init[j * rowDim + offset + i * LocalFaceDim * 2 + k] = 0.0; LE_Matrices_init[j * rowDim + offset + i * LocalFaceDim * 2 + LocalFaceDim + k] = 0.0; } if(LocalHDOF != 0){ LH_Matrices_init[j * rowDim + offset + i * LocalFaceDim * 2 + k] = RHSCoup1H_aux->getEntry(j, NeighTetraFaceMap[i] * LocalFaceDim + k); LH_Matrices_init[j * rowDim + offset + i * LocalFaceDim * 2 + LocalFaceDim + k] = RHSCoup2H_aux->getEntry(j, NeighTetraFaceMap[i] * LocalFaceDim + k); }else{ LH_Matrices_init[j * rowDim + offset + i * LocalFaceDim * 2 + k] = 0; LH_Matrices_init[j * rowDim + offset + i * LocalFaceDim * 2 + LocalFaceDim + k] = 0; } } } }else{ for (int idx = 0 ; idx < NeighNCNum; idx++){ if (OverlapMapVec[NeighTetraFaceMap[i]].find(idx)->second){ if(IntersectionMapVec[NeighTetraFaceMap[i]].find(idx)->second){ neigh = NeighNCTetra[idx]; if(neigh->getcnt() == NeighTetra[i]->getcnt()){ denseMat* RHSCoup1E_NC = new denseMat(LocalDim, LocalFaceDim); denseMat* RHSCoup2E_NC = new denseMat(LocalDim, LocalFaceDim); denseMat* RHSCoup1H_NC = new denseMat(LocalDim, LocalFaceDim); denseMat* RHSCoup2H_NC = new denseMat(LocalDim, LocalFaceDim); Zneigh = (No * sqrt(neigh->mat->mur.getEntry(0, 0) / neigh->mat->epsr.getEntry(0, 0))); Yt = 1.0 / (0.5 * (Z + Zneigh)); Yneigh = 1.0 / (No * sqrt(neigh->mat->mur.getEntry(0, 0) / neigh->mat->epsr.getEntry(0, 0))); Zt = 1.0 / (0.5 * (Y + Yneigh)); for (int l = 0; l < LocalFaceDim; l++){ for (int k = 0; k < LocalFaceDim; k++){ RHSCoup1E_NC->setEntry(fac2tet[NeighTetraFaceMap[i]][l], k, (dt / Eo) * NC_CouplingMatArray[idx * NumCouplingMatrices + 1].getEntry(l, k)); RHSCoup2E_NC->setEntry (fac2tet[NeighTetraFaceMap[i]][l], k, -(dt / Eo) * 0.5 * Yt * NC_CouplingMatArray[idx * NumCouplingMatrices + 2].getEntry(l, k) * GAMMA); RHSCoup1H_NC->setEntry(fac2tet[NeighTetraFaceMap[i]][l], k, -(dt / Uo) * NC_CouplingMatArray[idx * NumCouplingMatrices + 1].getEntry(l, k)); RHSCoup2H_NC->setEntry (fac2tet[NeighTetraFaceMap[i]][l], k, -(dt / Uo) * 0.5 * Zt * NC_CouplingMatArray[idx * NumCouplingMatrices + 2].getEntry(l, k) * GAMMA); } } NC_CouplingMatArray[idx * NumCouplingMatrices + 1].Clear(); NC_CouplingMatArray[idx * NumCouplingMatrices + 2].Clear(); denseMat* RHSCoup1E_NC_aux = new denseMat(LocalDim, LocalFaceDim); AB(*LHSInvE, *RHSCoup1E_NC, *RHSCoup1E_NC_aux); RHSCoup1E_NC->Clear(); denseMat* RHSCoup2E_NC_aux = new denseMat(LocalDim, LocalFaceDim); AB(*LHSInvE, *RHSCoup2E_NC, *RHSCoup2E_NC_aux); RHSCoup2E_NC->Clear(); denseMat* RHSCoup1H_NC_aux = new denseMat(LocalDim, LocalFaceDim); AB(*LHSInvH, *RHSCoup1H_NC, *RHSCoup1H_NC_aux); RHSCoup1H_NC->Clear(); denseMat* RHSCoup2H_NC_aux = new denseMat(LocalDim, LocalFaceDim); AB(*LHSInvH, *RHSCoup2H_NC, *RHSCoup2H_NC_aux); RHSCoup2H_NC->Clear(); for(int j = 0; j < LocalDim; j++){ for(int k = 0; k < LocalFaceDim; k++){ LE_Matrices_init[j * rowDim + offset + i * LocalFaceDim * 2 + k] = RHSCoup1E_NC_aux->getEntry(j, k); LE_Matrices_init[j * rowDim + offset + i * LocalFaceDim * 2 + LocalFaceDim + k] = RHSCoup2E_NC_aux->getEntry(j, k); LH_Matrices_init[j * rowDim + offset + i * LocalFaceDim * 2 + k] = RHSCoup1H_NC_aux->getEntry(j, k); LH_Matrices_init[j * rowDim + offset + i * LocalFaceDim * 2 + LocalFaceDim + k] = RHSCoup2H_NC_aux->getEntry(j, k); } } RHSCoup1E_NC_aux->Clear(); RHSCoup2E_NC_aux->Clear(); RHSCoup1H_NC_aux->Clear(); RHSCoup2H_NC_aux->Clear(); break; } } } } } } if(LocalEDOF != 0){ LHSInvE->Clear(); RHSCoup1E_aux->Clear(); RHSCoup2E_aux->Clear(); } if(LocalHDOF != 0){ LHSInvH->Clear(); RHSCoup1H_aux->Clear(); RHSCoup2H_aux->Clear(); } } void tetra::invxCol(fp_t* col, bool Efield){ if(Efield){ if(LHSInvE == nullptr){ cerr << "ERROR LHSInvE null" << endl; return; } ArrayFP x(TetPolyOrderDim[PolyOrderFlag]); ArrayFP y(TetPolyOrderDim[PolyOrderFlag]); for(int i = 0; i < TetPolyOrderDim[PolyOrderFlag]; i++){ x[i] = col[i]; } Ax(*LHSInvE, x, y); for(int i = 0; i < TetPolyOrderDim[PolyOrderFlag]; i++){ col[i] = y[i]; } }else{ if(LHSInvH == nullptr){ cerr << "ERROR LHSInvE null" << endl; return; } ArrayFP x(TetPolyOrderDim[PolyOrderFlag]); ArrayFP y(TetPolyOrderDim[PolyOrderFlag]); for(int i = 0; i < TetPolyOrderDim[PolyOrderFlag]; i++){ x[i] = col[i]; } Ax(*LHSInvH, x, y); for(int i = 0; i < TetPolyOrderDim[PolyOrderFlag]; i++){ col[i] = y[i]; } } } void tetra::prepareCuBLAS(fp_t_ts* Loc1E_h, fp_t_ts* Loc2E_h, fp_t_ts* Neigh1E_h, fp_t_ts* Neigh2E_h, fp_t_ts* InvE_h, fp_t_ts* Loc1H_h, fp_t_ts* Loc2H_h, fp_t_ts* Neigh1H_h, fp_t_ts* Neigh2H_h, fp_t_ts* InvH_h){ int LocalDim = TetPolyOrderDim[PolyOrderFlag]; int LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; denseMat* RHSCoup1E_aux; denseMat* RHSCoup2E_aux; denseMat* RHSLoc1E_aux; denseMat* RHSLoc2E_aux; if(LocalEDOF != 0){ RHSCoup1E_aux = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); AB(*LHSInvE, *RHSCoup1E, *RHSCoup1E_aux); RHSCoup1E->Clear(); RHSCoup2E_aux = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); AB(*LHSInvE, *RHSCoup2E, *RHSCoup2E_aux); RHSCoup2E->Clear(); RHSLoc1E_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvE, *RHSLoc1E, *RHSLoc1E_aux); RHSLoc1E->Clear(); RHSLoc2E_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvE, *RHSLoc2E, *RHSLoc2E_aux); RHSLoc2E->Clear(); } denseMat* RHSCoup1H_aux; denseMat* RHSCoup2H_aux; denseMat* RHSLoc1H_aux; denseMat* RHSLoc2H_aux; if(LocalHDOF != 0){ RHSCoup1H_aux = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); AB(*LHSInvH, *RHSCoup1H, *RHSCoup1H_aux); RHSCoup1H->Clear(); RHSCoup2H_aux = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); AB(*LHSInvH, *RHSCoup2H, *RHSCoup2H_aux); RHSCoup2H->Clear(); RHSLoc1H_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvH, *RHSLoc1H, *RHSLoc1H_aux); RHSLoc1H->Clear(); RHSLoc2H_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvH, *RHSLoc2H, *RHSLoc2H_aux); RHSLoc2H->Clear(); } //Complete local matrices (they must be saved column-wise) for(int i = 0; i < LocalDim; i++){ for(int j = 0; j < LocalDim; j++){ //E-field matrices if(LocalEDOF != 0){ Loc1E_h[i * LocalDim + j] = RHSLoc1E_aux->getEntry(j, i); Loc2E_h[i * LocalDim + j] = RHSLoc2E_aux->getEntry(j, i); if(InvE_h != nullptr){ // cout << "here" << endl; InvE_h[i * LocalDim + j] = LHSInvE->getEntry(j, i); } }else{ Loc1E_h[i * LocalDim + j] = 0.0; Loc2E_h[i * LocalDim + j] = 0.0; if(InvE_h != nullptr){ InvE_h[i * LocalDim + j] = 0.0; } } //H-field matrices if(LocalHDOF != 0){ Loc1H_h[i * LocalDim + j] = RHSLoc1H_aux->getEntry(j, i); Loc2H_h[i * LocalDim + j] = RHSLoc2H_aux->getEntry(j, i); if(InvH_h != nullptr){ InvH_h[i * LocalDim + j] = LHSInvH->getEntry(j, i); } }else{ Loc1H_h[i * LocalDim + j] = 0.0; Loc2H_h[i * LocalDim + j] = 0.0; if(InvH_h != nullptr){ InvH_h[i * LocalDim + j] = 0.0; } } } } if(LocalEDOF != 0){ RHSLoc1E_aux->Clear(); RHSLoc2E_aux->Clear(); } if(LocalHDOF != 0){ RHSLoc1H_aux->Clear(); RHSLoc2H_aux->Clear(); } //Complete coupling matrices (they must be saved column-wise) for(int neigh = 0; neigh < NeighNum; neigh++){ int DGface_bc = fc[NeighTetraFaceMap[neigh]]->bcPtr->getbType(); int block = LocalDim * LocalFaceDim * neigh; if(DGface_bc != nonConformal){ //Conformal faces (already stored in the RHS coupling terms) for(int i = 0; i < LocalFaceDim; i++){ for(int j = 0; j < LocalDim; j++){ //E-field matrices if(LocalEDOF != 0){ Neigh1E_h[block + i * LocalDim + j] = RHSCoup1E_aux->getEntry(j, NeighTetraFaceMap[neigh] * LocalFaceDim + i); Neigh2E_h[block + i * LocalDim + j] = RHSCoup2E_aux->getEntry(j, NeighTetraFaceMap[neigh] * LocalFaceDim + i); }else{ Neigh1E_h[block + i * LocalDim + j] = 0.0; Neigh2E_h[block + i * LocalDim + j] = 0.0; } //H-field matrices if(LocalHDOF != 0){ Neigh1H_h[block + i * LocalDim + j] = RHSCoup1H_aux->getEntry(j, NeighTetraFaceMap[neigh] * LocalFaceDim + i); Neigh2H_h[block + i * LocalDim + j] = RHSCoup2H_aux->getEntry(j, NeighTetraFaceMap[neigh] * LocalFaceDim + i); }else{ Neigh1H_h[block + i * LocalDim + j] = 0.0; Neigh2H_h[block + i * LocalDim + j] = 0.0; } } } }else{ //Non-conformal faces (Not stored in the aux matrices so they need to be calculated) fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); fp_t Y = 1.0 / Z; for (int idx = 0 ; idx < NeighNCNum; idx++){ if (OverlapMapVec[NeighTetraFaceMap[neigh]].find(idx)->second){ if(IntersectionMapVec[NeighTetraFaceMap[neigh]].find(idx)->second){ tetra* neighbor = NeighNCTetra[idx]; if(neighbor->getcnt() == NeighTetra[neigh]->getcnt()){ denseMat* RHSCoup1E_NC = new denseMat(LocalDim, LocalFaceDim); denseMat* RHSCoup2E_NC = new denseMat(LocalDim, LocalFaceDim); denseMat* RHSCoup1H_NC = new denseMat(LocalDim, LocalFaceDim); denseMat* RHSCoup2H_NC = new denseMat(LocalDim, LocalFaceDim); fp_t Zneigh = (No * sqrt(neighbor->mat->mur.getEntry(0, 0) / neighbor->mat->epsr.getEntry(0, 0))); fp_t Yt = 1.0 / (0.5 * (Z + Zneigh)); fp_t Yneigh = 1.0 / (No * sqrt(neighbor->mat->mur.getEntry(0, 0) / neighbor->mat->epsr.getEntry(0, 0))); fp_t Zt = 1.0 / (0.5 * (Y + Yneigh)); for(int i = 0; i < LocalFaceDim; i++){ for(int j = 0; j < LocalFaceDim; j++){ RHSCoup1E_NC->setEntry(fac2tet[NeighTetraFaceMap[neigh]][i], j, (Class_dt / Eo) * NC_CouplingMatArray[idx * NumCouplingMatrices + 1].getEntry(i, j)); RHSCoup2E_NC->setEntry (fac2tet[NeighTetraFaceMap[neigh]][i], j, -(Class_dt / Eo) * 0.5 * Yt * NC_CouplingMatArray[idx * NumCouplingMatrices + 2].getEntry(i, j) * GAMMA); RHSCoup1H_NC->setEntry(fac2tet[NeighTetraFaceMap[neigh]][i], j, -(Class_dt / Uo) * NC_CouplingMatArray[idx * NumCouplingMatrices + 1].getEntry(i, j)); RHSCoup2H_NC->setEntry (fac2tet[NeighTetraFaceMap[neigh]][i], j, -(Class_dt / Uo) * 0.5 * Zt * NC_CouplingMatArray[idx * NumCouplingMatrices + 2].getEntry(i, j) * GAMMA); } } NC_CouplingMatArray[idx * NumCouplingMatrices + 1].Clear(); NC_CouplingMatArray[idx * NumCouplingMatrices + 2].Clear(); denseMat* RHSCoup1E_NC_aux = new denseMat(LocalDim, LocalFaceDim); AB(*LHSInvE, *RHSCoup1E_NC, *RHSCoup1E_NC_aux); RHSCoup1E_NC->Clear(); denseMat* RHSCoup2E_NC_aux = new denseMat(LocalDim, LocalFaceDim); AB(*LHSInvE, *RHSCoup2E_NC, *RHSCoup2E_NC_aux); RHSCoup2E_NC->Clear(); denseMat* RHSCoup1H_NC_aux = new denseMat(LocalDim, LocalFaceDim); AB(*LHSInvH, *RHSCoup1H_NC, *RHSCoup1H_NC_aux); RHSCoup1H_NC->Clear(); denseMat* RHSCoup2H_NC_aux = new denseMat(LocalDim, LocalFaceDim); AB(*LHSInvH, *RHSCoup2H_NC, *RHSCoup2H_NC_aux); RHSCoup2H_NC->Clear(); for(int i = 0; i < LocalFaceDim; i++){ for(int j = 0; j < LocalDim; j++){ Neigh1E_h[block + i * LocalDim + j] = RHSCoup1E_NC_aux->getEntry(j, i); Neigh2E_h[block + i * LocalDim + j] = RHSCoup2E_NC_aux->getEntry(j, i); Neigh1H_h[block + i * LocalDim + j] = RHSCoup1H_NC_aux->getEntry(j, i); Neigh2H_h[block + i * LocalDim + j] = RHSCoup2H_NC_aux->getEntry(j, i); } } RHSCoup1E_NC_aux->Clear(); RHSCoup2E_NC_aux->Clear(); RHSCoup1H_NC_aux->Clear(); RHSCoup2H_NC_aux->Clear(); break; } } } } } } if(LocalEDOF != 0){ LHSInvE->Clear(); RHSCoup1E_aux->Clear(); RHSCoup2E_aux->Clear(); } if(LocalHDOF != 0){ LHSInvH->Clear(); RHSCoup1H_aux->Clear(); RHSCoup2H_aux->Clear(); } } void tetra::prepareCuBLAS_PML(fp_t_ts* Loc1E_h, fp_t_ts* Loc2E_h, fp_t_ts* Neigh1E_h, fp_t_ts* Neigh2E_h, fp_t_ts* Loc1H_h, fp_t_ts* Loc2H_h, fp_t_ts* Neigh1H_h, fp_t_ts* Neigh2H_h, fp_t_ts* AuxE_h, fp_t_ts* AuxH_h, fp_t_ts* AuxM1_h, fp_t_ts* AuxM2_h, fp_t_ts* AuxJ1_h, fp_t_ts* AuxJ2_h) { int LocalDim = TetPolyOrderDim[PolyOrderFlag]; int LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; denseMat* RHSCoup1E_aux; denseMat* RHSCoup2E_aux; denseMat* RHSLoc1E_aux; denseMat* RHSLoc2E_aux; denseMat* AuxE_aux; denseMat* AuxJ1_aux; denseMat* AuxJ2_aux; if(LocalEDOF != 0){ RHSCoup1E_aux = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); AB(*LHSInvE, *RHSCoup1E, *RHSCoup1E_aux); RHSCoup1E->Clear(); RHSCoup2E_aux = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); AB(*LHSInvE, *RHSCoup2E, *RHSCoup2E_aux); RHSCoup2E->Clear(); RHSLoc1E_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvE, *RHSLoc1E, *RHSLoc1E_aux); RHSLoc1E->Clear(); RHSLoc2E_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvE, *RHSLoc2E, *RHSLoc2E_aux); RHSLoc2E->Clear(); AuxE_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvE, *RHSAuxE, *AuxE_aux); RHSAuxE->Clear(); AuxJ1_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvAuxJ, *RHSLocAuxJ1, *AuxJ1_aux); RHSLocAuxJ1->Clear(); AuxJ2_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvAuxJ, *RHSLocAuxJ2, *AuxJ2_aux); RHSLocAuxJ2->Clear(); } denseMat* RHSCoup1H_aux; denseMat* RHSCoup2H_aux; denseMat* RHSLoc1H_aux; denseMat* RHSLoc2H_aux; denseMat* AuxH_aux; denseMat* AuxM1_aux; denseMat* AuxM2_aux; if(LocalHDOF != 0){ RHSCoup1H_aux = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); AB(*LHSInvH, *RHSCoup1H, *RHSCoup1H_aux); RHSCoup1H->Clear(); RHSCoup2H_aux = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); AB(*LHSInvH, *RHSCoup2H, *RHSCoup2H_aux); RHSCoup2H->Clear(); RHSLoc1H_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvH, *RHSLoc1H, *RHSLoc1H_aux); RHSLoc1H->Clear(); RHSLoc2H_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvH, *RHSLoc2H, *RHSLoc2H_aux); RHSLoc2H->Clear(); AuxH_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvH, *RHSAuxH, *AuxH_aux); RHSAuxH->Clear(); AuxM1_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvAuxM, *RHSLocAuxM1, *AuxM1_aux); RHSLocAuxM1->Clear(); AuxM2_aux = new denseMat(LocalDim, LocalDim); AB(*LHSInvAuxM, *RHSLocAuxM2, *AuxM2_aux); RHSLocAuxM2->Clear(); } //Complete local matrices (they must be saved column-wise) for(int i = 0; i < LocalDim; i++){ for(int j = 0; j < LocalDim; j++){ //E-field matrices if(LocalEDOF != 0){ Loc1E_h[i * LocalDim + j] = RHSLoc1E_aux->getEntry(j, i); Loc2E_h[i * LocalDim + j] = RHSLoc2E_aux->getEntry(j, i); AuxE_h[i * LocalDim + j] = AuxE_aux->getEntry(j, i); AuxJ1_h[i * LocalDim + j] = AuxJ1_aux->getEntry(j, i); AuxJ2_h[i * LocalDim + j] = AuxJ2_aux->getEntry(j, i); }else{ Loc1E_h[i * LocalDim + j] = 0.0; Loc2E_h[i * LocalDim + j] = 0.0; AuxE_h[i * LocalDim + j] = 0.0; AuxJ1_h[i * LocalDim + j] = 0.0; AuxJ2_h[i * LocalDim + j] = 0.0; } //H-field matrices if(LocalHDOF != 0){ Loc1H_h[i * LocalDim + j] = RHSLoc1H_aux->getEntry(j, i); Loc2H_h[i * LocalDim + j] = RHSLoc2H_aux->getEntry(j, i); AuxH_h[i * LocalDim + j] = AuxH_aux->getEntry(j, i); AuxM1_h[i * LocalDim + j] = AuxM1_aux->getEntry(j, i); AuxM2_h[i * LocalDim + j] = AuxM2_aux->getEntry(j, i); }else{ Loc1H_h[i * LocalDim + j] = 0.0; Loc2H_h[i * LocalDim + j] = 0.0; AuxH_h[i * LocalDim + j] = 0.0; AuxM1_h[i * LocalDim + j] = 0.0; AuxM2_h[i * LocalDim + j] = 0.0; } } } if(LocalEDOF != 0){ RHSLoc1E_aux->Clear(); RHSLoc2E_aux->Clear(); } if(LocalHDOF != 0){ RHSLoc1H_aux->Clear(); RHSLoc2H_aux->Clear(); } //Complete coupling matrices (they must be saved column-wise) for(int neigh = 0; neigh < NeighNum; neigh++){ int DGface_bc = fc[NeighTetraFaceMap[neigh]]->bcPtr->getbType(); int block = LocalDim * LocalFaceDim * neigh; if(DGface_bc != nonConformal){ //Conformal faces (already stored in the RHS coupling terms) for(int i = 0; i < LocalFaceDim; i++){ for(int j = 0; j < LocalDim; j++){ //E-field matrices if(LocalEDOF != 0){ Neigh1E_h[block + i * LocalDim + j] = RHSCoup1E_aux->getEntry(j, NeighTetraFaceMap[neigh] * LocalFaceDim + i); Neigh2E_h[block + i * LocalDim + j] = RHSCoup2E_aux->getEntry(j, NeighTetraFaceMap[neigh] * LocalFaceDim + i); }else{ Neigh1E_h[block + i * LocalDim + j] = 0.0; Neigh2E_h[block + i * LocalDim + j] = 0.0; } //H-field matrices if(LocalHDOF != 0){ Neigh1H_h[block + i * LocalDim + j] = RHSCoup1H_aux->getEntry(j, NeighTetraFaceMap[neigh] * LocalFaceDim + i); Neigh2H_h[block + i * LocalDim + j] = RHSCoup2H_aux->getEntry(j, NeighTetraFaceMap[neigh] * LocalFaceDim + i); }else{ Neigh1H_h[block + i * LocalDim + j] = 0.0; Neigh2H_h[block + i * LocalDim + j] = 0.0; } } } }else{ //Non-conformal faces (Not stored in the aux matrices so they need to be calculated) fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); fp_t Y = 1.0 / Z; for (int idx = 0 ; idx < NeighNCNum; idx++){ if (OverlapMapVec[NeighTetraFaceMap[neigh]].find(idx)->second){ if(IntersectionMapVec[NeighTetraFaceMap[neigh]].find(idx)->second){ tetra* neighbor = NeighNCTetra[idx]; if(neighbor->getcnt() == NeighTetra[neigh]->getcnt()){ denseMat* RHSCoup1E_NC = new denseMat(LocalDim, LocalFaceDim); denseMat* RHSCoup2E_NC = new denseMat(LocalDim, LocalFaceDim); denseMat* RHSCoup1H_NC = new denseMat(LocalDim, LocalFaceDim); denseMat* RHSCoup2H_NC = new denseMat(LocalDim, LocalFaceDim); fp_t Zneigh = (No * sqrt(neighbor->mat->mur.getEntry(0, 0) / neighbor->mat->epsr.getEntry(0, 0))); fp_t Yt = 1.0 / (0.5 * (Z + Zneigh)); fp_t Yneigh = 1.0 / (No * sqrt(neighbor->mat->mur.getEntry(0, 0) / neighbor->mat->epsr.getEntry(0, 0))); fp_t Zt = 1.0 / (0.5 * (Y + Yneigh)); for(int i = 0; i < LocalFaceDim; i++){ for(int j = 0; j < LocalFaceDim; j++){ RHSCoup1E_NC->setEntry(fac2tet[NeighTetraFaceMap[neigh]][i], j, (Class_dt / Eo) * NC_CouplingMatArray[idx * NumCouplingMatrices + 1].getEntry(i, j)); RHSCoup2E_NC->setEntry (fac2tet[NeighTetraFaceMap[neigh]][i], j, -(Class_dt / Eo) * 0.5 * Yt * NC_CouplingMatArray[idx * NumCouplingMatrices + 2].getEntry(i, j) * GAMMA); RHSCoup1H_NC->setEntry(fac2tet[NeighTetraFaceMap[neigh]][i], j, -(Class_dt / Uo) * NC_CouplingMatArray[idx * NumCouplingMatrices + 1].getEntry(i, j)); RHSCoup2H_NC->setEntry (fac2tet[NeighTetraFaceMap[neigh]][i], j, -(Class_dt / Uo) * 0.5 * Zt * NC_CouplingMatArray[idx * NumCouplingMatrices + 2].getEntry(i, j) * GAMMA); } } NC_CouplingMatArray[idx * NumCouplingMatrices + 1].Clear(); NC_CouplingMatArray[idx * NumCouplingMatrices + 2].Clear(); denseMat* RHSCoup1E_NC_aux = new denseMat(LocalDim, LocalFaceDim); AB(*LHSInvE, *RHSCoup1E_NC, *RHSCoup1E_NC_aux); RHSCoup1E_NC->Clear(); denseMat* RHSCoup2E_NC_aux = new denseMat(LocalDim, LocalFaceDim); AB(*LHSInvE, *RHSCoup2E_NC, *RHSCoup2E_NC_aux); RHSCoup2E_NC->Clear(); denseMat* RHSCoup1H_NC_aux = new denseMat(LocalDim, LocalFaceDim); AB(*LHSInvH, *RHSCoup1H_NC, *RHSCoup1H_NC_aux); RHSCoup1H_NC->Clear(); denseMat* RHSCoup2H_NC_aux = new denseMat(LocalDim, LocalFaceDim); AB(*LHSInvH, *RHSCoup2H_NC, *RHSCoup2H_NC_aux); RHSCoup2H_NC->Clear(); for(int i = 0; i < LocalFaceDim; i++){ for(int j = 0; j < LocalDim; j++){ Neigh1E_h[block + i * LocalDim + j] = RHSCoup1E_NC_aux->getEntry(j, i); Neigh2E_h[block + i * LocalDim + j] = RHSCoup2E_NC_aux->getEntry(j, i); Neigh1H_h[block + i * LocalDim + j] = RHSCoup1H_NC_aux->getEntry(j, i); Neigh2H_h[block + i * LocalDim + j] = RHSCoup2H_NC_aux->getEntry(j, i); } } RHSCoup1E_NC_aux->Clear(); RHSCoup2E_NC_aux->Clear(); RHSCoup1H_NC_aux->Clear(); RHSCoup2H_NC_aux->Clear(); break; } } } } } } if(LocalEDOF != 0){ LHSInvE->Clear(); RHSCoup1E_aux->Clear(); RHSCoup2E_aux->Clear(); } if(LocalHDOF != 0){ LHSInvH->Clear(); RHSCoup1H_aux->Clear(); RHSCoup2H_aux->Clear(); } } void tetra::Calculate_M_Matrix_I_H_Numeric() { int i, j, k, dim; fp_t cval = 0.0; fp_t vol; fp_t* z; fp_t wgt = 0.; vtr lvtr[4]; // the 3 first positions are the vectors from the node 0 to the // others [{0,1}, {0,2}, {0,3}] vtr avtr[4]; // array of vectors normal to the faces and with a magnitude // equal to the area of them [f0, f1, f2, f3] vtr w1, w2; int* map = new int[TetPolyOrderDim[PolyOrderFlag]]; Local_DG_mapH(map, 0); if (LocalHDOF == 0) { MassI_H = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); MassI_H->reset(); return; } MassI_H = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); dim = MassI_H->getRowDim(); if (dim != MassI_H->getColDim()) { cerr << "MassI_H: Non-square matrix passed." << endl; } MassI_H->reset(); geometry(lvtr, avtr, &vol); dim = MassI_H->getRowDim(); fp_t (*gaussQuadPoints)[5]; GetFormula3dPtr(GAUSS_POINT_NUM[PolyOrderFlag], gaussQuadPoints); vtr* gaussBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; vtr* gaussMatBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; for (i = 0; i < dim; i++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { z = &gaussQuadPoints[k][0]; TetraBasisW(z, i, &w1); gaussBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = w1; gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = mat->mur * w1; } } for (i = 0; i < dim; i++){ for (j = 0; j < dim; j++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { wgt = gaussQuadPoints[k][4]; w1 = gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k]; w2 = gaussBasisVtrs[j * GAUSS_POINT_NUM[PolyOrderFlag] + k]; cval += wgt * dotP(w1, w2); } MassI_H->addEntry(i, j, cval * vol); cval = 0.0; } } delete[] gaussBasisVtrs; delete[] gaussMatBasisVtrs; // If it's PMC, set a 1 if it's in the diagonal, 0 if not for (i = 0; i < TetPolyOrderDim[PolyOrderFlag]; i++) { for (j = 0; j < TetPolyOrderDim[PolyOrderFlag]; j++) { if (map[i] < 0 || map[j] < 0) { if (i == j) { MassI_H->setEntry(i, j, 1.0); // need to be inversed } else { MassI_H->setEntry(i, j, 0); // need to be inversed } } } } if (map != nullptr) delete[] map; } void tetra::Calculate_ABC_H_Numeric() { if (LocalHDOF == 0) return; int LocalDim, LocalFaceDim; int DGface_bc; int AbcFlag = 0; fp_t mu_o = Uo; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); int i, j, k, dim; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; denseMat tetBh(LocalDim, LocalDim); // Matrices On the Faces denseMat Bh(LocalFaceDim, LocalFaceDim); for (i = 0; i < 4; i++) { DGface_bc = getFacePtr(i)->bcPtr->getbType(); if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { AbcFlag = 1; fc[i]->Calculate_Bh_Matrix_Numeric(&Bh, PolyOrderFlag); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { tetBh.addEntry(fac2tet[i][j], fac2tet[i][k], Bh.getEntry(j, k)); } } } } // ABC Boundary if (AbcFlag == 1) { for (i = 0; i < 4; i++) { if (fc[i]->bcPtr->getbType() == abcType) { Z = fc[i]->bcPtr->get_ABCImpVal(); } else if (fc[i]->bcPtr->getbType() == planeWaveType) { Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); } else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) { Z = fc[i]->bcPtr->get_PortImpVal(); } } tetBh.scale(-0.5 * Z); } ABC_tetBh = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); *ABC_tetBh = tetBh; } void tetra::Calculate_M_Matrix_I_E_Numeric() { int i, j, k, dim; fp_t cval = 0.0; fp_t vol; fp_t* z; fp_t wgt = 0.; vtr lvtr[4]; // the 3 first positions are the vectors from the node 0 to the // others [{0,1}, {0,2}, {0,3}] vtr avtr[4]; // array of vectors normal to the faces and with a magnitude // equal to the area of them [f0, f1, f2, f3] vtr w1, w2; int* map = new int[TetPolyOrderDim[PolyOrderFlag]]; Local_DG_mapE(map, 0); if (LocalEDOF == 0) { cout << "RESET\n"; MassI_E = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); MassI_E->reset(); return; } MassI_E = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); dim = MassI_E->getRowDim(); if (dim != MassE->getColDim()) { cerr << "MassI_E: Non-square matrix passed." << endl; } MassI_E->reset(); geometry(lvtr, avtr, &vol); dim = MassI_E->getRowDim(); fp_t (*gaussQuadPoints)[5]; GetFormula3dPtr(GAUSS_POINT_NUM[PolyOrderFlag], gaussQuadPoints); vtr* gaussBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; vtr* gaussMatBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; for (i = 0; i < dim; i++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { z = &gaussQuadPoints[k][0]; TetraBasisW(z, i, &w1); gaussBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = w1; gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = mat->epsr * w1; } } for (i = 0; i < dim; i++){ for (j = 0; j < dim; j++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { wgt = gaussQuadPoints[k][4]; w1 = gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k]; w2 = gaussBasisVtrs[j * GAUSS_POINT_NUM[PolyOrderFlag] + k]; cval += wgt * dotP(w1, w2); } MassI_E->addEntry(i, j, cval * vol); cval = 0.0; } } delete[] gaussBasisVtrs; delete[] gaussMatBasisVtrs; // If it's PEC, set a 1 if it's in the diagonal, 0 if not for (i = 0; i < TetPolyOrderDim[PolyOrderFlag]; i++) { for (j = 0; j < TetPolyOrderDim[PolyOrderFlag]; j++) { if (map[i] < 0 || map[j] < 0) { if (i == j) { MassI_E->setEntry(i, j, 1.0); // need to be inversed } else { MassI_E->setEntry(i, j, 0); // need to be inversed } } } } if (map != nullptr) delete[] map; } void tetra::Calculate_ABC_E_Numeric() { if (LocalEDOF == 0) return; int LocalDim, LocalFaceDim; int DGface_bc; int AbcFlag = 0; fp_t eps_o = Eo; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); int i, j, k, dim; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; denseMat tetBe(LocalDim, LocalDim); // Matrices On the Faces denseMat Be(LocalFaceDim, LocalFaceDim); for (i = 0; i < 4; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { AbcFlag = 1; fc[i]->Calculate_Be_Matrix_Numeric(&Be,PolyOrderFlag); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { tetBe.addEntry(fac2tet[i][j], fac2tet[i][k], Be.getEntry(j, k)); } } } } // ABC Boundary if (AbcFlag == 1) { for (i = 0; i < 4; i++) { // the same if (fc[i]->bcPtr->getbType() == abcType) { Y = 1.0 / fc[i]->bcPtr->get_ABCImpVal(); } else if (fc[i]->bcPtr->getbType() == planeWaveType) { Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); } else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) { Y = 1.0 / fc[i]->bcPtr->get_PortImpVal(); } } tetBe.scale(-0.5 * Y); } ABC_tetBe = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); *ABC_tetBe = tetBe; } void tetra::SetUp_LocalFaceToTetraMapE_NMF1_PML(fp_t dt) { if (LocalEDOF == 0) return; int LocalDim, LocalFaceDim; fp_t eps_o = Eo; bool has_null = false; if (!BiiE) { std::cerr << "❌ BiiE is null.\n"; has_null = true; } if (!Mass_epA_E) { std::cerr << "❌ Mass_epA_E is null.\n"; has_null = true; } if (!Mass_epB_E) { std::cerr << "❌ Mass_epB_E is null.\n"; has_null = true; } if (!ABC_tetBe) { std::cerr << "❌ ABC_tetBe is null.\n"; has_null = true; } if (!StiffE) { std::cerr << "❌ StiffE is null.\n"; has_null = true; } if (!FiiE) { std::cerr << "❌ FiiE is null.\n"; has_null = true; } if (!FijE) { std::cerr << "❌ FijE is null.\n"; has_null = true; } if (!BijE) { std::cerr << "❌ BijE is null.\n"; has_null = true; } if (!Mass_epC_E) { std::cerr << "❌ Mass_epC_E is null.\n"; has_null = true; } if (!MassI_E) { std::cerr << "❌ MassI_E is null.\n"; has_null = true; } if (!Mass_D_E) { std::cerr << "❌ Mass_D_E is null.\n"; has_null = true; } if (!Mass_F_E) { std::cerr << "❌ Mass_F_E is null.\n"; has_null = true; } if (!MassE) { std::cerr << "❌ MassE is null.\n"; has_null = true; } LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; RHSLoc1E = new denseMat(LocalDim, LocalDim); RHSLoc2E = new denseMat(LocalDim, LocalDim); RHSCoup1E = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); RHSCoup2E = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); BiiE->scale(dt / eps_o); Mass_epB_E->scale(0.5 * dt); ABC_tetBe->scale(0.5 * dt / eps_o); *RHSLoc1E = *Mass_epA_E + *BiiE - (*Mass_epB_E + *ABC_tetBe) ; ApplyPEC(RHSLoc1E, LocalDim); *RHSLoc2E = *StiffE - *FiiE; RHSLoc2E->scale(dt / eps_o); ApplyPEC_E(RHSLoc2E, LocalDim); ApplyPMC_E(RHSLoc2E, LocalDim); *RHSCoup1E = *FijE; RHSCoup1E->scale(dt / eps_o); *RHSCoup2E = *BijE; RHSCoup2E->scale(dt / eps_o); // Inv LHSInvE = new denseMat(LocalDim, LocalDim); *LHSInvE = *Mass_epA_E + (*Mass_epB_E + *ABC_tetBe); *LHSInvE = LHSInvE->inverse(); RHSAuxE = new denseMat(LocalDim, LocalDim); *RHSAuxE = *Mass_epC_E; RHSAuxE->scale(-1.0 * dt); ApplyPEC(RHSAuxE, LocalDim); // ------------------------------ // PML LHSInvAuxJ = new denseMat(LocalDim, LocalDim); RHSLocAuxJ1 = new denseMat(LocalDim, LocalDim); RHSLocAuxJ2 = new denseMat(LocalDim, LocalDim); MassI_E->scale(1.0 / dt); Mass_D_E->scale(0.5); *LHSInvAuxJ = (*MassI_E + *Mass_D_E); *LHSInvAuxJ = LHSInvAuxJ->inverse(); *RHSLocAuxJ1 = (*MassI_E - *Mass_D_E); *RHSLocAuxJ2 = *Mass_F_E; MassE->Clear(); StiffE->Clear(); BiiE->Clear(); FiiE->Clear(); BijE->Clear(); FijE->Clear(); ABC_tetBe->Clear(); Mass_epA_E->Clear(); Mass_epB_E->Clear(); Mass_epC_E->Clear(); Mass_D_E->Clear(); Mass_F_E->Clear(); MassI_E->Clear(); } void tetra::SetUp_LocalFaceToTetraMapH_NMF1_PML(fp_t dt) { if (LocalHDOF == 0) return; int LocalDim, LocalFaceDim; fp_t mu_o = Uo; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; bool has_null = false; if (!BiiH) { std::cerr << "❌ BiiH is null.\n"; has_null = true; } if (!Mass_muA_H) { std::cerr << "❌ Mass_muA_H is null.\n"; has_null = true; } if (!Mass_muB_H) { std::cerr << "❌ Mass_muB_H is null.\n"; has_null = true; } if (!ABC_tetBh) { std::cerr << "❌ ABC_tetBh is null.\n"; has_null = true; } if (!StiffH) { std::cerr << "❌ StiffH is null.\n"; has_null = true; } if (!FiiH) { std::cerr << "❌ FiiH is null.\n"; has_null = true; } if (!FijH) { std::cerr << "❌ FijH is null.\n"; has_null = true; } if (!BijH) { std::cerr << "❌ BijH is null.\n"; has_null = true; } if (!Mass_muC_H) { std::cerr << "❌ Mass_muC_H is null.\n"; has_null = true; } if (!MassI_H) { std::cerr << "❌ MassI_H is null.\n"; has_null = true; } if (!Mass_D_H) { std::cerr << "❌ Mass_D_H is null.\n"; has_null = true; } if (!Mass_F_H) { std::cerr << "❌ Mass_F_H is null.\n"; has_null = true; } if (!MassH) { std::cerr << "❌ MassH is null.\n"; has_null = true; } RHSLoc1H = new denseMat(LocalDim, LocalDim); RHSLoc2H = new denseMat(LocalDim, LocalDim); RHSCoup1H = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); RHSCoup2H = new denseMat(LocalDim, NumOfFaces * LocalFaceDim); BiiH->scale(dt / mu_o); Mass_muB_H->scale(0.5 * dt); ABC_tetBh->scale(0.5 * dt / mu_o); *RHSLoc1H = *Mass_muA_H + *BiiH - (*Mass_muB_H + *ABC_tetBh); ApplyPMC(RHSLoc1H, LocalDim); *RHSLoc2H = *FiiH - *StiffH; RHSLoc2H->scale(dt / mu_o); ApplyPEC_H(RHSLoc2H, LocalDim); ApplyPMC_H(RHSLoc2H, LocalDim); *RHSCoup1H = *FijH; RHSCoup1H->scale(dt / mu_o); *RHSCoup2H = *BijH; RHSCoup2H->scale(dt / mu_o); // Inv LHSInvH = new denseMat(LocalDim, LocalDim); *LHSInvH = *Mass_muA_H + (*Mass_muB_H + *ABC_tetBh); *LHSInvH = LHSInvH->inverse(); RHSAuxH = new denseMat(LocalDim, LocalDim); *RHSAuxH = *Mass_muC_H; RHSAuxH->scale(-1.0 * dt); ApplyPMC(RHSAuxH, LocalDim); // ------------------------------ // PML LHSInvAuxM = new denseMat(LocalDim, LocalDim); RHSLocAuxM1 = new denseMat(LocalDim, LocalDim); RHSLocAuxM2 = new denseMat(LocalDim, LocalDim); MassI_H->scale(1.0 / dt); Mass_D_H->scale(0.5); *LHSInvAuxM = (*MassI_H + *Mass_D_H); *LHSInvAuxM = LHSInvAuxM->inverse(); *RHSLocAuxM1 = (*MassI_H - *Mass_D_H); *RHSLocAuxM2 = *Mass_F_H; MassH->Clear(); StiffH->Clear(); BiiH->Clear(); FiiH->Clear(); BijH->Clear(); FijH->Clear(); ABC_tetBh->Clear(); Mass_muA_H->Clear(); Mass_muB_H->Clear(); Mass_muC_H->Clear(); Mass_D_H->Clear(); Mass_F_H->Clear(); MassI_H->Clear(); } // ------------------------------------------------------------------------ // Function for Ellipsoid system of equations void computeF(fp_t x[3], fp_t F[3], fp_t a, fp_t b, fp_t c, fp_t x1, fp_t y1, fp_t z1) { fp_t x0 = x[0], y0 = x[1], z0 = x[2]; F[0] = (x0 * x0) / (a * a) + (y0 * y0) / (b * b) + (z0 * z0) / (c * c) - 1.0; F[1] = z1 * (2 * y0 / (b * b)) - y1 * (2 * z0 / (c * c)) + (2.0 / (c * c) - 2.0 / (b * b)) * y0 * z0; F[2] = y1 * (2 * x0 / (a * a)) - x1 * (2 * y0 / (b * b)) + (2.0 / (b * b) - 2.0 / (a * a)) * x0 * y0; } // Jacobian to solve the Ellipsoidal System of Equations void computeJacobian(fp_t x[3], fp_t J[3][3], fp_t a, fp_t b, fp_t c, fp_t x1, fp_t y1, fp_t z1) { fp_t x0 = x[0], y0 = x[1], z0 = x[2]; // Row 1: ∂F0/∂x0, ∂F0/∂y0, ∂F0/∂z0 J[0][0] = 2 * x0 / (a * a); J[0][1] = 2 * y0 / (b * b); J[0][2] = 2 * z0 / (c * c); // Row 2: ∂F1/∂x0, ∂F1/∂y0, ∂F1/∂z0 J[1][0] = 0; J[1][1] = z1 * (2.0 / (b * b)) + (2.0 / (c * c) - 2.0 / (b * b)) * z0; J[1][2] = -y1 * (2.0 / (c * c)) + (2.0 / (c * c) - 2.0 / (b * b)) * y0; // Row 3: ∂F2/∂x0, ∂F2/∂y0, ∂F2/∂z0 J[2][0] = y1 * (2.0 / (a * a)) + (2.0 / (b * b) - 2.0 / (a * a)) * y0; J[2][1] = -x1 * (2.0 / (b * b)) + (2.0 / (b * b) - 2.0 / (a * a)) * x0; J[2][2] = 0; } // Solve 3x3 linear system A x = b using Cramer's Rule bool solveLinearSystem(double A[3][3], double b[3], double x[3]) { double detA = A[0][0] * (A[1][1] * A[2][2] - A[1][2] * A[2][1]) - A[0][1] * (A[1][0] * A[2][2] - A[1][2] * A[2][0]) + A[0][2] * (A[1][0] * A[2][1] - A[1][1] * A[2][0]); if (fabs(detA) < 1e-12) return false; for (int i = 0; i < 3; ++i) { double Ai[3][3]; for (int row = 0; row < 3; ++row) for (int col = 0; col < 3; ++col) Ai[row][col] = (col == i) ? b[row] : A[row][col]; double detAi = Ai[0][0] * (Ai[1][1] * Ai[2][2] - Ai[1][2] * Ai[2][1]) - Ai[0][1] * (Ai[1][0] * Ai[2][2] - Ai[1][2] * Ai[2][0]) + Ai[0][2] * (Ai[1][0] * Ai[2][1] - Ai[1][1] * Ai[2][0]); x[i] = detAi / detA; } return true; } auto printMatrix = [](const std::string& name, denseMat* M) { if (!M) { std::cout << name << " is null.\n"; return; } int rows = M->getRowDim(); int cols = M->getColDim(); std::cout << "---- " << name << " (" << rows << "x" << cols << ") ----\n"; for (int i = 0; i < rows; ++i) { for (int j = 0; j < cols; ++j) { std::cout << M->getEntry(i, j) << " "; } std::cout << "\n"; } std::cout << "\n"; }; void tetra::set_Conductivity_Profile_Spherical(fp_t Rx, fp_t Ry, fp_t Rz) { // This is the polynomial order of the conductivity profile of the PML fp_t m = mat->get_PML_m_ord(); // Obtain the the thickness of the PML fp_t pml_thick = mat->get_PML_thick(); fp_t eps_o = 8.854187817e-12; fp_t sigma_max = mat->sigma.getEntry(0, 0); // Center of the tetrahedron // Point P1 vtr rc = Center(); fp_t x1 = rc.getx(); fp_t y1 = rc.gety(); fp_t z1 = rc.getz(); // ------------------------------------------------------------- // Step 1: Solve for Point P0 on PML surface fp_t x[3] = {x1, y1, z1}; // Initial guess int MAX_ITER = 100; fp_t TOL = 1e-8; for (int iter = 0; iter < MAX_ITER; ++iter) { fp_t F[3], J[3][3]; computeF(x, F, Rx, Ry, Rz, x1, y1, z1); computeJacobian(x, J, Rx, Ry, Rz, x1, y1, z1); // Solve J * delta = -F fp_t minusF[3] = {-F[0], -F[1], -F[2]}; fp_t delta[3]; if (!solveLinearSystem(J, minusF, delta)) { cout << "Jacobian is singular!" << endl; break; } // Update x fp_t norm_delta = 0.0; for (int i = 0; i < 3; ++i) { x[i] += delta[i]; norm_delta += delta[i] * delta[i]; } if (sqrt(norm_delta) < TOL) { //cout << "Converged in " << iter + 1 << " iterations." << endl; break; } } // Points of P0 fp_t x0 = x[0]; fp_t y0 = x[1]; fp_t z0 = x[2]; vtr r0 (x0,y0,z0); // ------------------------------------------------------------- fp_t r0_mag = r0.magnitude(); fp_t r1_mag = rc.magnitude(); fp_t distance = r1_mag - r0_mag; fp_t growth_factor = std::abs(std::pow(distance / (pml_thick), m)); fp_t growth_factor2 = std::abs(std::pow(distance / (pml_thick), m + 1.0)); fp_t K_max = 2.0; fp_t K = 1.0 + (K_max - 1.0) * growth_factor; fp_t s_r = sigma_max * growth_factor; fp_t s_theta = s_r / (m + 1.0); fp_t s_phi = s_theta; fp_t s3 = s_theta * s_phi / s_r; fp_t s2 = s_r; fp_t s1 = s_r; matA = new denseMat(3, 3); matB = new denseMat(3, 3); matC = new denseMat(3, 3); matD = new denseMat(3, 3); matF = new denseMat(3, 3); matA->reset(); matB->reset(); matC->reset(); matD->reset(); matF->reset(); matA->setEntry(0, 0, K); matA->setEntry(1, 1, K); matA->setEntry(2, 2, K); fp_t A11 = matA->getEntry(0, 0); fp_t A22 = matA->getEntry(1, 1); fp_t A33 = matA->getEntry(2, 2); matB->setEntry(0, 0, (s2*K + s3*K - A11*s1) / eps_o); matB->setEntry(1, 1, (s1*K + s3*K - A22*s2) / eps_o); matB->setEntry(2, 2, (s1*K + s2*K - A33*s3) / eps_o); fp_t B11 = matB->getEntry(0, 0); fp_t B22 = matB->getEntry(1, 1); fp_t B33 = matB->getEntry(2, 2); matC->setEntry(0, 0, s2*s3/(eps_o * eps_o) - B11 * s1 / eps_o); matC->setEntry(1, 1, s1*s3/(eps_o * eps_o) - B22 * s2 / eps_o); matC->setEntry(2, 2, s1*s2/(eps_o * eps_o) - B33 * s3 / eps_o); matD->setEntry(0, 0, s1/(K * eps_o)); matD->setEntry(1, 1, s2/(K * eps_o)); matD->setEntry(2, 2, s3/(K * eps_o)); matF->setEntry(0, 0, 1.0/K); matF->setEntry(1, 1, 1.0/K); matF->setEntry(2, 2, 1.0/K); // ----- Rotation ---------- // fp_t xx = rc.getx(); fp_t yy = rc.gety(); fp_t zz = rc.getz(); fp_t rr = std::sqrt(xx*xx + yy*yy + zz*zz); fp_t theta = std::acos(zz / rr); // θ ∈ [0, π] fp_t phi = std::atan2(yy, zz); // φ ∈ [−π, π] vtr ur( std::sin(theta)*std::cos(phi), std::sin(theta)*std::sin(phi), std::cos(theta) ); vtr utheta( std::cos(theta)*std::cos(phi), std::cos(theta)*std::sin(phi), -std::sin(theta) ); vtr uphi( -std::sin(phi), std::cos(phi), 0.0 ); denseMat R(3, 3); R.setEntry(0, 0, ur.getx()); R.setEntry(0, 1, ur.gety()); R.setEntry(0, 2, ur.getz()); R.setEntry(1, 0, utheta.getx()); R.setEntry(1, 1, utheta.gety()); R.setEntry(1, 2, utheta.getz()); R.setEntry(2, 0, uphi.getx()); R.setEntry(2, 1, uphi.gety()); R.setEntry(2, 2, uphi.getz()); denseMat RT = R.transpose(); // Needed for tensor rotation denseMat A_cart(3,3); denseMat tmp(3,3); AB(*matA, R, tmp); AB(RT, tmp, *matA); AB(*matB, R, tmp); AB(RT, tmp, *matA); AB(*matC, R, tmp); AB(RT, tmp, *matC); AB(*matD, R, tmp); AB(RT, tmp, *matD); AB(*matF, R, tmp); AB(RT, tmp, *matF); } void tetra::set_Conductivity_Profile_Conformal(fp_t Rx, fp_t Ry, fp_t Rz) { if (!mat) { std::cerr << "Error: mat pointer is NULL!" << std::endl; return; } // This is the polynomial order of the conductivity profile of the PML fp_t m = mat->get_PML_m_ord(); // (Cartesian-Aligned) PML // Obtain the the thickness of the PML fp_t pml_thick = mat->get_PML_thick(); if (std::abs(pml_thick) < 1e-10) { std::cerr << "Error: PML thickness is zero or too small." << std::endl; return; } // Max loss fp_t eps_o = 8.854187817e-12; fp_t sigma_max = mat->sigma.getEntry(0, 0); // Center of the tetrahedron // Point P1 vtr rc = Center(); fp_t x1 = rc.getx(); fp_t y1 = rc.gety(); fp_t z1 = rc.getz(); // ------------------------------------------------------------- // Step 1: Solve for Point P0 on PML surface fp_t x[3] = {x1, y1, z1}; // Initial guess int MAX_ITER = 100; fp_t TOL = 1e-8; for (int iter = 0; iter < MAX_ITER; ++iter) { fp_t F[3], J[3][3]; computeF(x, F, Rx, Ry, Rz, x1, y1, z1); computeJacobian(x, J, Rx, Ry, Rz, x1, y1, z1); // Solve J * delta = -F fp_t minusF[3] = {-F[0], -F[1], -F[2]}; fp_t delta[3]; if (!solveLinearSystem(J, minusF, delta)) { cout << "Jacobian is singular!" << endl; break; } // Update x fp_t norm_delta = 0.0; for (int i = 0; i < 3; ++i) { x[i] += delta[i]; norm_delta += delta[i] * delta[i]; } if (sqrt(norm_delta) < TOL) { //cout << "Converged in " << iter + 1 << " iterations." << endl; break; } } // Points of P0 fp_t x0 = x[0]; fp_t y0 = x[1]; fp_t z0 = x[2]; vtr r0 (x0,y0,z0); // ------------------------------------------------------------- // Step 2: Calculate the principal curvature radii // We use the Analytical solutions from Analytical Derivation of Ellipsoid Conformal Perfectly Matched Layers for // Electromagnetic Simulations, Qian Yang , Bing Wei , Linqian Li , and Debiao Ge // Precompute powers fp_t a = Rx; fp_t b = Ry; fp_t c = Rz; fp_t a2 = a * a, b2 = b * b, c2 = c * c; fp_t a4 = a2 * a2, b4 = b2 * b2, c4 = c2 * c2; fp_t abc2 = (a * b * c) * (a * b * c); // (abc)^2 // Z denominator fp_t Z = x0 * x0 / a4 + y0 * y0 / b4 + z0 * z0 / c4; // Gauss curvature fp_t kG = 1.0 / (abc2 * Z * Z); // Mean curvature fp_t numerator = x0 * x0 + y0 * y0 + z0 * z0 - (a2 + b2 + c2); fp_t denominator = 2.0 * abc2 * pow(Z, 1.5); fp_t kM = numerator / denominator; // Principal curvatures fp_t delta = kM * kM - kG; if (delta < 0) { //std::cerr << "Warning: negative discriminant in curvature, clamping.\n"; delta = 0.0; } fp_t sqrt_term = sqrt(delta); fp_t k1 = kM + sqrt_term; fp_t k2 = kM - sqrt_term; // Principal curvature radii fp_t R01 = abs(1.0 / k1); fp_t R02 = abs(1.0 / k2); // ------------------------------------------------------------- // Step 3: Calculate Orthonormal basis u1, u2, u3 // U3 vtr u3 = rc - r0; // Normal vector at P0 fp_t u3_mag = u3.magnitude(); u3.unitvtr(); // If Sphere, All directions in the tangent plane are principal. // u1 and u2 are not uniquely defined — they are ambiguous but still orthogonal. vtr u1 , u2; u1.reset(); u2.reset(); fp_t EPS = 1e-6; // Sphere case — choose arbitrary orthonormal tangent vectors if (fabs(a - b) < EPS && fabs(b - c) < EPS) { // Pick arbitrary direction not colinear with normal if (fabs(u3.getx()) < fabs(u3.gety())) { u1 = vtr(0, -u3.getz(), u3.gety()); } else { u1 = vtr(-u3.getz(), 0, u3.getx()); } u1.unitvtr(); // Perpendicular u2 = crossP(u3, u1); u2.unitvtr(); } else { fp_t theta = acos(z0 / c); // theta ∈ [0, π] fp_t phi = atan2(y0 / b, x0 / a); // phi ∈ [-π, π] vtr r_theta( a * cos(theta) * cos(phi), b * cos(theta) * sin(phi), -c * sin(theta) ); vtr r_phi( -a * sin(theta) * sin(phi), b * sin(theta) * cos(phi), 0.0 ); // Compute coefficients fp_t E = pow(cos(theta),2) * (a*a * pow(cos(phi),2) + b*b * pow(sin(phi),2)) + c*c * pow(sin(theta),2); fp_t F = (b*b - a*a) * sin(theta) * cos(theta) * sin(phi) * cos(phi); fp_t G = pow(sin(theta),2) * (a*a * pow(sin(phi),2) + b*b * pow(cos(phi),2)); fp_t denomL = sqrt(c*c * pow(sin(theta),2) * (a*a * pow(sin(phi),2) + b*b * pow(cos(phi),2)) + a*a * b*b * pow(cos(theta),2)); fp_t L = -a * b * c / denomL; fp_t M = 0; fp_t N = L * pow(sin(theta), 2); // Quadratic coefficients fp_t A = E * M - F * L; fp_t B = -(L * G - E * N); fp_t C = F * N - G * M; // Solve quadratic fp_t discrim = B*B - 4*A*C; fp_t dtheta_dphi1 = (-B + sqrt(discrim)) / (2*A); fp_t dtheta_dphi2 = (-B - sqrt(discrim)) / (2*A); // Compute principal direction vectors u1 = r_theta * dtheta_dphi1 + r_phi; u2 = r_theta * dtheta_dphi2 + r_phi; u1.unitvtr(); // Normalize u2.unitvtr(); } if (std::abs(dotP(u1, u2)) > 1e-5 || std::abs(dotP(u1, u3)) > 1e-5) std::cerr << "Warning: u1/u2/u3 may not be orthonormal!\n"; // ------------------------------------------------------------- // Step 4: Calculate the Rotation Matrix denseMat R(3, 3); R.reset(); R.setEntry(0, 0, u1.getx()); R.setEntry(0, 1, u1.gety()); R.setEntry(0, 2, u1.getz()); R.setEntry(1, 0, u2.getx()); R.setEntry(1, 1, u2.gety()); R.setEntry(1, 2, u2.getz()); R.setEntry(2, 0, u3.getx()); R.setEntry(2, 1, u3.gety()); R.setEntry(2, 2, u3.getz()); denseMat RT = R.transpose(); // ------------------------------------------------------------- // Step 5: Update R1 and R2 fp_t R1 = R01 + u3_mag; fp_t R2 = R02 + u3_mag; // ------------------------------------------------------------- // Step 6: Calculate the Loss Parameters in local coordinates u1, u2, u3 sigma_1 = 0.0; sigma_2 = 0.0; sigma_3 = 0.0; fp_t rc_ro = dotP(rc - r0, u3); fp_t growth_factor = std::abs(std::pow(rc_ro / (pml_thick), m)); fp_t K_max = 2.0; fp_t K3 = 1.0 + (K_max - 1.0) * growth_factor; fp_t s3 = sigma_max * growth_factor; fp_t K2 = K3; fp_t K1 = K3; fp_t s1 = s3 / (m + 1.0); fp_t s2 = s3 / (m + 1.0); matA = new denseMat(3, 3); matB = new denseMat(3, 3); matC = new denseMat(3, 3); matD = new denseMat(3, 3); matF = new denseMat(3, 3); matA->reset(); matB->reset(); matC->reset(); matD->reset(); matF->reset(); matA->setEntry(0, 0, K2*K3/K1); matA->setEntry(1, 1, K1*K3/K2); matA->setEntry(2, 2, K1*K2/K3); fp_t A11 = matA->getEntry(0, 0); fp_t A22 = matA->getEntry(1, 1); fp_t A33 = matA->getEntry(2, 2); matB->setEntry(0, 0, (s2*K3 + s3*K2 - A11*s1) / eps_o); matB->setEntry(1, 1, (s1*K3 + s3*K1 - A22*s2) / eps_o); matB->setEntry(2, 2, (s1*K2 + s2*K1 - A33*s3) / eps_o); fp_t B11 = matB->getEntry(0, 0); fp_t B22 = matB->getEntry(1, 1); fp_t B33 = matB->getEntry(2, 2); matC->setEntry(0, 0, s2*s3/(eps_o * eps_o) - B11 * s1 / eps_o); matC->setEntry(1, 1, s1*s3/(eps_o * eps_o) - B22 * s2 / eps_o); matC->setEntry(2, 2, s1*s2/(eps_o * eps_o) - B33 * s3 / eps_o); matD->setEntry(0, 0, s1/(K1 * eps_o)); matD->setEntry(1, 1, s2/(K2 * eps_o)); matD->setEntry(2, 2, s3/(K3 * eps_o)); matF->setEntry(0, 0, 1.0/K1); matF->setEntry(1, 1, 1.0/K2); matF->setEntry(2, 2, 1.0/K3); // ------------------------------------------------------------- // Step 7: Rotate the Loss Parameters to global Euclidean space x,y,z denseMat tmp(3, 3); AB(*matA, R, tmp); AB(RT, tmp, *matA); AB(*matB, R, tmp); AB(RT, tmp, *matB); AB(*matC, R, tmp); AB(RT, tmp, *matC); AB(*matD, R, tmp); AB(RT, tmp, *matD); AB(*matF, R, tmp); AB(RT, tmp, *matF); } void tetra::set_Conductivity_Profile_Planar(fp_t planewave_xmin, fp_t planewave_ymin, fp_t planewave_zmin, fp_t planewave_xmax, fp_t planewave_ymax, fp_t planewave_zmax) { // Polynomial order of the PML conductivity profile fp_t m = static_cast(mat->get_PML_m_ord()); // PML thickness fp_t pml_thick = mat->get_PML_thick(); if (std::abs(pml_thick) < 1e-10) { std::cerr << "Error: PML thickness is zero or too small." << std::endl; return; } // Permittivity of free space fp_t eps_o = 8.854187817e-12; fp_t sigma_base = mat->sigma.getEntry(0, 0); // Assumed max σ // Get center of tetrahedron vtr rc = Center(); fp_t x1 = rc.getx(); fp_t y1 = rc.gety(); fp_t z1 = rc.getz(); // Distance to PML boundaries and conductivities fp_t dx = 0.0, dy = 0.0, dz = 0.0; fp_t s1 = 0.0, s2 = 0.0, s3 = 0.0; if (x1 < planewave_xmin) dx = planewave_xmin - x1; else if (x1 > planewave_xmax) dx = x1 - planewave_xmax; if (y1 < planewave_ymin) dy = planewave_ymin - y1; else if (y1 > planewave_ymax) dy = y1 - planewave_ymax; if (z1 < planewave_zmin) dz = planewave_zmin - z1; else if (z1 > planewave_zmax) dz = z1 - planewave_zmax; // Compute directional conductivity σi(x) if (dx > 0.0) s1 = sigma_base * std::pow(dx / pml_thick, m); if (dy > 0.0) s2 = sigma_base * std::pow(dy / pml_thick, m); if (dz > 0.0) s3 = sigma_base * std::pow(dz / pml_thick, m); // Use Euclidean distance for growth profile fp_t distance = std::sqrt(dx * dx + dy * dy + dz * dz); fp_t growth_factor = std::pow(distance / pml_thick, m); // K scaling (Jacobians) fp_t K_max = 2.0; fp_t K1 = 1.0 + (K_max - 1.0) * growth_factor; fp_t K2 = K1; fp_t K3 = K1; matA = new denseMat(3, 3); matB = new denseMat(3, 3); matC = new denseMat(3, 3); matD = new denseMat(3, 3); matF = new denseMat(3, 3); matA->reset(); matB->reset(); matC->reset(); matD->reset(); matF->reset(); matA->setEntry(0, 0, K2*K3/K1); matA->setEntry(1, 1, K1*K3/K2); matA->setEntry(2, 2, K1*K2/K3); fp_t A11 = matA->getEntry(0, 0); fp_t A22 = matA->getEntry(1, 1); fp_t A33 = matA->getEntry(2, 2); matB->setEntry(0, 0, (s2*K3 + s3*K2 - A11*s1) / eps_o); matB->setEntry(1, 1, (s1*K3 + s3*K1 - A22*s2) / eps_o); matB->setEntry(2, 2, (s1*K2 + s2*K1 - A33*s3) / eps_o); fp_t B11 = matB->getEntry(0, 0); fp_t B22 = matB->getEntry(1, 1); fp_t B33 = matB->getEntry(2, 2); matC->setEntry(0, 0, s2*s3/(eps_o * eps_o) - B11 * s1 / eps_o); matC->setEntry(1, 1, s1*s3/(eps_o * eps_o) - B22 * s2 / eps_o); matC->setEntry(2, 2, s1*s2/(eps_o * eps_o) - B33 * s3 / eps_o); matD->setEntry(0, 0, s1/(K1 * eps_o)); matD->setEntry(1, 1, s2/(K2 * eps_o)); matD->setEntry(2, 2, s3/(K3 * eps_o)); matF->setEntry(0, 0, 1.0/K1); matF->setEntry(1, 1, 1.0/K2); matF->setEntry(2, 2, 1.0/K3); } void tetra::Calculate_M_Matrix_I_H() { int i, j, k, dim; fp_t cval = 0.0; fp_t vol; fp_t* z; fp_t wgt = 0.; vtr lvtr[4]; // the 3 first positions are the vectors from the node 0 to the // others [{0,1}, {0,2}, {0,3}] vtr avtr[4]; // array of vectors normal to the faces and with a magnitude // equal to the area of them [f0, f1, f2, f3] vtr w1, w2; fp_t coeffA[3][3]; int* map = new int[TetPolyOrderDim[PolyOrderFlag]]; Local_DG_mapH(map, 0); if (LocalHDOF == 0) { MassI_H = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); MassI_H->reset(); return; } MassI_H = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); dim = MassI_H->getRowDim(); if (dim != MassI_H->getColDim()) { cerr << "MassI_H: Non-square matrix passed." << endl; } MassI_H->reset(); geometry(lvtr, avtr, &vol); dim = MassI_H->getRowDim(); tensor matrix_I(1.0,0.0,0.0, 0.0,1.0,0.0, 0.0,0.0,1.0); makeCoeff(avtr, matrix_I, coeffA); // dotP(u, [t]*u) dV // u = avtr, [t]*u = [t] * avtr for (i = 0; i < dim; i++) { for (j = 0; j < dim; j++) { cval = (coeffA[0][0] * T00_P2[i][j]) + (coeffA[0][1] * T01_P2[i][j]) + (coeffA[1][0] * T10_P2[i][j]) + (coeffA[0][2] * T02_P2[i][j]) + (coeffA[2][0] * T20_P2[i][j]) + (coeffA[1][1] * T11_P2[i][j]) + (coeffA[1][2] * T12_P2[i][j]) + (coeffA[2][1] * T21_P2[i][j]) + (coeffA[2][2] * T22_P2[i][j]); cval = cval / (vol * (fp_t)T_DNUM); MassI_H->addEntry(i, j, cval); } } // If it's PMC, set a 1 if it's in the diagonal, 0 if not for (i = 0; i < TetPolyOrderDim[PolyOrderFlag]; i++) { for (j = 0; j < TetPolyOrderDim[PolyOrderFlag]; j++) { if (map[i] < 0 || map[j] < 0) { if (i == j) { MassI_H->setEntry(i, j, 1.0); // need to be inversed } else { MassI_H->setEntry(i, j, 0); // need to be inversed } } } } if (map != nullptr) delete[] map; } void tetra::Calculate_ABC_H() { if (LocalHDOF == 0) return; int LocalDim, LocalFaceDim; int DGface_bc; int AbcFlag = 0; fp_t mu_o = Uo; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); int i, j, k, dim; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; denseMat tetBh(LocalDim, LocalDim); // Matrices On the Faces denseMat Bh(LocalFaceDim, LocalFaceDim); for (i = 0; i < 4; i++) { DGface_bc = getFacePtr(i)->bcPtr->getbType(); if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { AbcFlag = 1; fc[i]->Calculate_Bh_Matrix(&Bh); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { tetBh.addEntry(fac2tet[i][j], fac2tet[i][k], Bh.getEntry(j, k)); } } } } // ABC Boundary if (AbcFlag == 1) { for (i = 0; i < 4; i++) { if (fc[i]->bcPtr->getbType() == abcType) { Z = fc[i]->bcPtr->get_ABCImpVal(); } else if (fc[i]->bcPtr->getbType() == planeWaveType) { Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); } else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) { Z = fc[i]->bcPtr->get_PortImpVal(); } } tetBh.scale(-0.5 * Z); } ABC_tetBh = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); *ABC_tetBh = tetBh; } void tetra::Calculate_M_Matrix_I_E() { int i, j, k, dim; fp_t cval = 0.0; fp_t vol; fp_t* z; fp_t wgt = 0.; vtr lvtr[4]; // the 3 first positions are the vectors from the node 0 to the // others [{0,1}, {0,2}, {0,3}] vtr avtr[4]; // array of vectors normal to the faces and with a magnitude // equal to the area of them [f0, f1, f2, f3] vtr w1, w2; fp_t coeffA[3][3]; int* map = new int[TetPolyOrderDim[PolyOrderFlag]]; Local_DG_mapE(map, 0); if (LocalEDOF == 0) { cout << "RESET\n"; MassI_E = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); MassI_E->reset(); return; } MassI_E = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); dim = MassI_E->getRowDim(); if (dim != MassE->getColDim()) { cerr << "MassI_E: Non-square matrix passed." << endl; } MassI_E->reset(); geometry(lvtr, avtr, &vol); dim = MassI_E->getRowDim(); tensor matrix_I(1.0,0.0,0.0, 0.0,1.0,0.0, 0.0,0.0,1.0); makeCoeff(avtr, matrix_I, coeffA); // dotP(u, [t]*u) dV // u = avtr, [t]*u = [t] * avtr for (i = 0; i < dim; i++) { for (j = 0; j < dim; j++) { cval = (coeffA[0][0] * T00_P2[i][j]) + (coeffA[0][1] * T01_P2[i][j]) + (coeffA[1][0] * T10_P2[i][j]) + (coeffA[0][2] * T02_P2[i][j]) + (coeffA[2][0] * T20_P2[i][j]) + (coeffA[1][1] * T11_P2[i][j]) + (coeffA[1][2] * T12_P2[i][j]) + (coeffA[2][1] * T21_P2[i][j]) + (coeffA[2][2] * T22_P2[i][j]); cval = cval / (vol * (fp_t)T_DNUM); MassI_E->addEntry(i, j, cval); } } // If it's PEC, set a 1 if it's in the diagonal, 0 if not for (i = 0; i < TetPolyOrderDim[PolyOrderFlag]; i++) { for (j = 0; j < TetPolyOrderDim[PolyOrderFlag]; j++) { if (map[i] < 0 || map[j] < 0) { if (i == j) { MassI_E->setEntry(i, j, 1.0); // need to be inversed } else { MassI_E->setEntry(i, j, 0); // need to be inversed } } } } if (map != nullptr) delete[] map; } void tetra::Calculate_ABC_E() { if (LocalEDOF == 0) return; int LocalDim, LocalFaceDim; int DGface_bc; int AbcFlag = 0; fp_t eps_o = Eo; fp_t Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); fp_t Z = No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0)); int i, j, k, dim; LocalDim = TetPolyOrderDim[PolyOrderFlag]; LocalFaceDim = FacePolyOrderDim[PolyOrderFlag]; denseMat tetBe(LocalDim, LocalDim); // Matrices On the Faces denseMat Be(LocalFaceDim, LocalFaceDim); for (i = 0; i < 4; i++) { DGface_bc = fc[i]->bcPtr->getbType(); if (DGface_bc == abcType || DGface_bc == planeWaveType || (DGface_bc >= portType && DGface_bc < pecType)) { AbcFlag = 1; fc[i]->Calculate_Be_Matrix(&Be); for (j = 0; j < LocalFaceDim; j++) { for (k = 0; k < LocalFaceDim; k++) { tetBe.addEntry(fac2tet[i][j], fac2tet[i][k], Be.getEntry(j, k)); } } } } // ABC Boundary if (AbcFlag == 1) { for (i = 0; i < 4; i++) { // the same if (fc[i]->bcPtr->getbType() == abcType) { Y = 1.0 / fc[i]->bcPtr->get_ABCImpVal(); } else if (fc[i]->bcPtr->getbType() == planeWaveType) { Y = 1.0 / (No * sqrt(mat->mur.getEntry(0, 0) / mat->epsr.getEntry(0, 0))); } else if (fc[i]->bcPtr->getbType() >= portType && fc[i]->bcPtr->getbType() < pecType) { Y = 1.0 / fc[i]->bcPtr->get_PortImpVal(); } } tetBe.scale(-0.5 * Y); } ABC_tetBe = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); *ABC_tetBe = tetBe; } void tetra::Calculate_Mass_Material_Matrix( denseMat*& outputMassMat, // Output mass matrix to fill const denseMat* inputTensorMat, // Input tensor like A1, A3 const tensor& materialTensor, // Material tensor (e.g., epsr, mur) bool isElectricField // true → use E-field space, false → H-field space ) { if ((isElectricField && LocalEDOF == 0) || (!isElectricField && LocalHDOF == 0)) { outputMassMat = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); outputMassMat->reset(); return; } outputMassMat = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); int i, j, dim; fp_t vol, cval = 0.0; fp_t coeffA[3][3]; vtr lvtr[4], avtr[4]; int* map = new int[TetPolyOrderDim[PolyOrderFlag]]; if (isElectricField) Local_DG_mapE(map, 0); else Local_DG_mapH(map, 0); outputMassMat->reset(); geometry(lvtr, avtr, &vol); dim = outputMassMat->getRowDim(); // Form tensor from input matrix tensor Atensor( inputTensorMat->getEntry(0, 0), inputTensorMat->getEntry(0, 1), inputTensorMat->getEntry(0, 2), inputTensorMat->getEntry(1, 0), inputTensorMat->getEntry(1, 1), inputTensorMat->getEntry(1, 2), inputTensorMat->getEntry(2, 0), inputTensorMat->getEntry(2, 1), inputTensorMat->getEntry(2, 2) ); tensor scaledTensor = materialTensor * Atensor; makeCoeff(avtr, scaledTensor, coeffA); for (i = 0; i < dim; ++i) { for (j = 0; j < dim; ++j) { cval = coeffA[0][0] * T00_P2[i][j] + coeffA[0][1] * T01_P2[i][j] + coeffA[1][0] * T10_P2[i][j] + coeffA[0][2] * T02_P2[i][j] + coeffA[2][0] * T20_P2[i][j] + coeffA[1][1] * T11_P2[i][j] + coeffA[1][2] * T12_P2[i][j] + coeffA[2][1] * T21_P2[i][j] + coeffA[2][2] * T22_P2[i][j]; cval /= (vol * (fp_t)T_DNUM); outputMassMat->addEntry(i, j, cval); } } delete[] map; } void tetra::Calculate_Mass_Material_Matrix_Numeric( denseMat*& outputMassMat, // Output mass matrix to fill const denseMat* inputTensorMat, // Input tensor like A1, A3 const tensor& materialTensor, // Material tensor (e.g., epsr, mur) bool isElectricField // true → use E-field space, false → H-field space ) { if ((isElectricField && LocalEDOF == 0) || (!isElectricField && LocalHDOF == 0)) { outputMassMat = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); outputMassMat->reset(); return; } outputMassMat = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); int i, j, k, dim; fp_t cval = 0.0; fp_t vol; fp_t* z; fp_t wgt = 0.; vtr lvtr[4]; // the 3 first positions are the vectors from the node 0 to the // others [{0,1}, {0,2}, {0,3}] vtr avtr[4]; // array of vectors normal to the faces and with a magnitude // equal to the area of them [f0, f1, f2, f3] vtr w1, w2; int* map = new int[TetPolyOrderDim[PolyOrderFlag]]; if (isElectricField) Local_DG_mapE(map, 0); else Local_DG_mapH(map, 0); outputMassMat->reset(); geometry(lvtr, avtr, &vol); dim = outputMassMat->getRowDim(); // Form tensor from input matrix tensor Atensor( inputTensorMat->getEntry(0, 0), inputTensorMat->getEntry(0, 1), inputTensorMat->getEntry(0, 2), inputTensorMat->getEntry(1, 0), inputTensorMat->getEntry(1, 1), inputTensorMat->getEntry(1, 2), inputTensorMat->getEntry(2, 0), inputTensorMat->getEntry(2, 1), inputTensorMat->getEntry(2, 2) ); tensor scaledTensor = materialTensor * Atensor; fp_t (*gaussQuadPoints)[5]; GetFormula3dPtr(GAUSS_POINT_NUM[PolyOrderFlag], gaussQuadPoints); vtr* gaussBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; vtr* gaussMatBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; for (i = 0; i < dim; i++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { z = &gaussQuadPoints[k][0]; TetraBasisW(z, i, &w1); gaussBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = w1; gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = scaledTensor * w1; } } for (i = 0; i < dim; i++){ for (j = 0; j < dim; j++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { wgt = gaussQuadPoints[k][4]; w1 = gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k]; w2 = gaussBasisVtrs[j * GAUSS_POINT_NUM[PolyOrderFlag] + k]; cval += wgt * dotP(w1, w2); } outputMassMat->addEntry(i, j, cval * vol); cval = 0.0; } } delete[] gaussBasisVtrs; delete[] gaussMatBasisVtrs; if (map != nullptr) delete[] map; } void tetra::getCartesianCoord(fp_t *zeta, vtr &pnt) { pnt.reset(); for(int i = 0; i < NumOfNodes; i ++) { pnt = pnt + nd[i]->getCoord() * zeta[i]; } } void tetra::set_Conductivity_smoothProfile_Planar(fp_t planewave_xmin, fp_t planewave_ymin, fp_t planewave_zmin, fp_t planewave_xmax, fp_t planewave_ymax, fp_t planewave_zmax, vtr rc, vtr gaussPointCoord, string mode) { // Polynomial order of the PML conductivity profile fp_t m = static_cast(mat->get_PML_m_ord()); // PML thickness fp_t pml_thick = mat->get_PML_thick(); if (std::abs(pml_thick) < 1e-10) { std::cerr << "Error: PML thickness is zero or too small." << std::endl; return; } fp_t x1 = gaussPointCoord.getx(); fp_t y1 = gaussPointCoord.gety(); fp_t z1 = gaussPointCoord.getz(); fp_t x2 = rc.getx(); fp_t y2 = rc.gety(); fp_t z2 = rc.getz(); // Permittivity of free space fp_t eps_o = 8.854187817e-12; fp_t sigma_base = mat->sigma.getEntry(0, 0); // Assumed max σ // Distance to PML boundaries and conductivities fp_t dx = 0.0, dy = 0.0, dz = 0.0; fp_t dx2 = 0.0, dy2 = 0.0, dz2 = 0.0; fp_t s1 = 0.0, s2 = 0.0, s3 = 0.0; if (x1 < planewave_xmin) { dx = planewave_xmin - x1; dx2 = planewave_xmin - x2; } else if (x1 > planewave_xmax) { dx = x1 - planewave_xmax; dx2 = x2 - planewave_xmax; } if (y1 < planewave_ymin) { dy = planewave_ymin - y1; dy2 = planewave_ymin - y2; } else if (y1 > planewave_ymax) { dy = y1 - planewave_ymax; dy2 = y2 - planewave_ymax; } if (z1 < planewave_zmin) { dz = planewave_zmin - z1; dz2 = planewave_zmin - z2; } else if (z1 > planewave_zmax) { dz = z1 - planewave_zmax; dz2 = z2 - planewave_zmax; } // Compute directional conductivity σi(x) if (dx > 0.0) { s1 = sigma_base * std::pow(dx / pml_thick, m); } if (dy > 0.0) { s2 = sigma_base * std::pow(dy / pml_thick, m); } if (dz > 0.0) { s3 = sigma_base * std::pow(dz / pml_thick, m); } // diagonal of a cuboid fp_t diagonal = pml_thick * std::sqrt(3.0); // Use Euclidean distance for growth profile fp_t distance = std::sqrt(dx2 * dx2 + dy2 * dy2 + dz2 * dz2); fp_t growth_factor = std::pow(distance / diagonal, m); // K scaling (Jacobians) fp_t K_max = 2.0; fp_t K1 = 1.0 + (K_max - 1.0) * growth_factor; fp_t K2 = K1; fp_t K3 = K1; // === ALLOCATE ONCE === if (!matA) matA = new denseMat(3, 3); if (!matB) matB = new denseMat(3, 3); if (!matC) matC = new denseMat(3, 3); if (!matD) matD = new denseMat(3, 3); if (!matF) matF = new denseMat(3, 3); matA->reset(); matB->reset(); matC->reset(); matD->reset(); matF->reset(); if (mode == "A" || mode == "ALL") { matA->reset(); matA->setEntry(0, 0, K2 * K3 / K1); matA->setEntry(1, 1, K1 * K3 / K2); matA->setEntry(2, 2, K1 * K2 / K3); } if (mode == "B" || mode == "ALL") { matA->reset(); matA->setEntry(0, 0, K2 * K3 / K1); matA->setEntry(1, 1, K1 * K3 / K2); matA->setEntry(2, 2, K1 * K2 / K3); matB->reset(); fp_t A11 = matA->getEntry(0, 0); fp_t A22 = matA->getEntry(1, 1); fp_t A33 = matA->getEntry(2, 2); matB->setEntry(0, 0, (s2 * K3 + s3 * K2 - A11 * s1) / eps_o); matB->setEntry(1, 1, (s1 * K3 + s3 * K1 - A22 * s2) / eps_o); matB->setEntry(2, 2, (s1 * K2 + s2 * K1 - A33 * s3) / eps_o); } if (mode == "C" || mode == "ALL") { matA->reset(); matA->setEntry(0, 0, K2 * K3 / K1); matA->setEntry(1, 1, K1 * K3 / K2); matA->setEntry(2, 2, K1 * K2 / K3); matB->reset(); fp_t A11 = matA->getEntry(0, 0); fp_t A22 = matA->getEntry(1, 1); fp_t A33 = matA->getEntry(2, 2); matB->setEntry(0, 0, (s2 * K3 + s3 * K2 - A11 * s1) / eps_o); matB->setEntry(1, 1, (s1 * K3 + s3 * K1 - A22 * s2) / eps_o); matB->setEntry(2, 2, (s1 * K2 + s2 * K1 - A33 * s3) / eps_o); matC->reset(); fp_t B11 = matB->getEntry(0, 0); fp_t B22 = matB->getEntry(1, 1); fp_t B33 = matB->getEntry(2, 2); matC->setEntry(0, 0, s2 * s3 / (eps_o * eps_o) - B11 * s1 / eps_o); matC->setEntry(1, 1, s1 * s3 / (eps_o * eps_o) - B22 * s2 / eps_o); matC->setEntry(2, 2, s1 * s2 / (eps_o * eps_o) - B33 * s3 / eps_o); } if (mode == "D" || mode == "ALL") { matD->reset(); matD->setEntry(0, 0, s1 / (K1 * eps_o)); matD->setEntry(1, 1, s2 / (K2 * eps_o)); matD->setEntry(2, 2, s3 / (K3 * eps_o)); } if (mode == "F" || mode == "ALL") { matF->reset(); matF->setEntry(0, 0, 1.0 / K1); matF->setEntry(1, 1, 1.0 / K2); matF->setEntry(2, 2, 1.0 / K3); } } void tetra::LocalRadiiCurvature(vtr& r, fp_t radius_x, fp_t radius_y, fp_t radius_z, fp_t& r01, fp_t& r02, vtr& u1, vtr& u2, vtr& u3) { fp_t a = radius_x; fp_t b = radius_y; fp_t c = radius_z; // Calculate the local radii of curvature for a tetrahedron fp_t u; if (fabs(r.gety()) < 1.e-15 && fabs(r.getx()) < 1.e-15) u = Pi / 2.; else u = atan2(r.gety(), r.getx()); if (u < 0.0) u = u + 2.0 * Pi; fp_t v = acos(r.getz() / r.magnitude()); // sphere case Test if (a == b && b == c) { // vtr uu1, uu2, uu3; u1.setvtr(cos(u) * cos(v), sin(u) * cos(v), -sin(v)); // thet u2.setvtr(-sin(u), cos(u), 0.0); // phi u3.setvtr(cos(u) * sin(v), sin(u) * sin(v), cos(v)); // r r01 = r.magnitude(); r02 = r.magnitude(); } // Ellipsoid else { if (u == 0. && v == 0.) { r01 = b * b / c; r02 = a * a / c; u1.setvtr(1., 0., 0.); u2.setvtr(0., 1., 0.); u3 = u2 * u1; } else { // v = th; u = ph; // Tangent vectors vtr Xph(-a * sin(v) * sin(u), b * sin(v) * cos(u), 0.0); vtr Xth(a * cos(v) * cos(u), b * sin(u) * cos(v), -c * sin(v)); // First Fundamental form double E = ((b * b) * cos(u) * cos(u) + (a * a) * sin(u) * sin(u)) * sin(v) * sin(v); double F = (b * b - a * a) * cos(u) * sin(u) * cos(v) * sin(v); double G = (a * a * cos(u) * cos(u) + b * b * sin(u) * sin(u)) * cos(v) * cos(v) + c * c * sin(v) * sin(v); // Second Fundamental form double L = (a * b * c * sin(v) * sin(v)) / (sqrt(a * a * b * b * cos(v) * cos(v) + c * c * (b * b * cos(u) * cos(u) + a * a * sin(u) * sin(u)) * sin(v) * sin(v))); double M = 0.0; double N = (a * b * c) / (sqrt(a * a * b * b * cos(v) * cos(v) + c * c * (b * b * cos(u) * cos(u) + a * a * sin(u) * sin(u)) * sin(v) * sin(v))); vtr e1 = Xph / sqrt(E); vtr e2 = (Xth * E - Xph * F) / sqrt(E * (E * G - F * F)); e1.unitvtr(); e2.unitvtr(); vtr np = e2 * e1; double H = (G * L - 2.0 * F * M + E * N) / (2.0 * (E * G - F * F)); double A = (L * (E * G - 2.0 * F * F) + 2.0 * E * F * M - E * E * N) / (2.0 * E * (E * G - F * F)); double B = (E * M - F * L) / (E * sqrt(E * G - F * F)); double C = sqrt(A * A + B * B); double th0 = 0.5 * acos(A / C); double kmin = H - C; double kmax = H + C; double a0 = cos(0.5 * th0); vtr aa = np * sin(0.5 * th0); denseMat R(3, 3); R.setEntry(0, 0, a0 * a0 + aa.getx() * aa.getx() - aa.gety() * aa.gety() - aa.getz() * aa.getz()); R.setEntry(0, 1, 2.0 * (aa.getx() * aa.gety() + a0 * aa.getz())); R.setEntry(0, 2, 2.0 * (aa.getx() * aa.getz() - a0 * aa.gety())); R.setEntry(1, 0, 2.0 * (aa.getx() * aa.gety() - a0 * aa.getz())); R.setEntry(1, 1, a0 * a0 - aa.getx() * aa.getx() + aa.gety() * aa.gety() - aa.getz() * aa.getz()); R.setEntry(1, 2, 2.0 * (aa.gety() * aa.getz() + a0 * aa.getx())); R.setEntry(2, 0, 2.0 * (aa.getx() * aa.getz() + a0 * aa.gety())); R.setEntry(2, 1, 2.0 * (aa.gety() * aa.getz() - a0 * aa.getx())); R.setEntry(2, 2, a0 * a0 - aa.getx() * aa.getx() - aa.gety() * aa.gety() + aa.getz() * aa.getz()); // Rotation to match the principal directions std::array t1, t2, f1, f2; t1[0] = e1.getx(); t2[0] = e2.getx(); t1[1] = e1.gety(); t2[1] = e2.gety(); t1[2] = e1.getz(); t2[2] = e2.getz(); // Matrix-vector multiplication: f1 = R * t1, f2 = R * t2 MXV(&R, t1.data(), f1.data()); MXV(&R, t2.data(), f2.data()); // Principal raddii of Curvature r01 = 1. / kmax; r02 = 1. / kmin; // Normal at P(u,v) if (a == b && b == c && a == c) { // sphere case u1.setvtr(cos(u) * cos(v), sin(u) * cos(v), -sin(v)); // thet u2.setvtr(-sin(u), cos(u), 0.0); // phi u3.setvtr(cos(u) * sin(v), sin(u) * sin(v), cos(v)); // r } else { u1.setvtr(f1[0], f1[1], f1[2]); u2.setvtr(f2[0], f2[1], f2[2]); u3 = u2 * u1; // outward normal correct } u1.unitvtr(); u2.unitvtr(); u3.unitvtr(); } } // // Rotation Matrix if (!Jrot) Jrot = new denseMat(3, 3); Jrot->setEntry(0, 0, u1.getx()); Jrot->setEntry(0, 1, u1.gety()); Jrot->setEntry(0, 2, u1.getz()); Jrot->setEntry(1, 0, u2.getx()); Jrot->setEntry(1, 1, u2.gety()); Jrot->setEntry(1, 2, u2.getz()); Jrot->setEntry(2, 0, u3.getx()); Jrot->setEntry(2, 1, u3.gety()); Jrot->setEntry(2, 2, u3.getz()); } void tetra::Et_S_E(denseMat* E, denseMat* S, denseMat* EtSE) { int i, j, k, l, dim; double sum1 = 0.0, value = 0.0; dim = S->getRowDim(); for (i = 0; i < dim; i++) { for (j = 0; j < dim; j++) { for (l = 0; l < dim; l++) { for (k = 0; k < dim; k++) { sum1 = sum1 + S->getEntry(l, k) * E->getEntry(k, j); } value = value + E->getEntry(l, i) * sum1; sum1 = 0.0; } EtSE->addEntry(i, j, value); value = 0.0; } } } void tetra::ApplyConformalPMLRotation(denseMat* J, denseMat* tensorU1U2U3) { denseMat XYZ(3, 3); denseMat U1U2U3(3, 3); XYZ.reset(); U1U2U3.reset(); // Copy tensorU1U2U3 into U1U2U3 for (int j = 0; j < 3; ++j) for (int k = 0; k < 3; ++k) U1U2U3.setEntry(j, k, tensorU1U2U3->getEntry(j, k)); // Perform similarity transform: Et * S * E Et_S_E(J, &U1U2U3, &XYZ); // Copy result back into original tensor for (int j = 0; j < 3; ++j) for (int k = 0; k < 3; ++k) tensorU1U2U3->setEntry(j, k, XYZ.getEntry(j, k)); } void tetra::set_Conductivity_smoothProfile_conformal(fp_t radius_x, fp_t radius_y, fp_t radius_z, vtr rc, vtr gaussPointCoord, string mode) { // Polynomial order of the PML conductivity profile fp_t m = static_cast(mat->get_PML_m_ord()); // PML thickness fp_t pml_thick = mat->get_PML_thick(); if (std::abs(pml_thick) < 1e-10) { std::cerr << "Error: PML thickness is zero or too small." << std::endl; return; } // Permittivity of free space fp_t eps_o = 8.854187817e-12; fp_t sigma_max = mat->sigma.getEntry(0, 0); // Assumed max σ fp_t r01, r02; fp_t s1, s2, s3; fp_t ph = atan2(rc.gety(), rc.getx()); if (ph < 0.0) ph = ph + 2.0 * Pi; fp_t th = acos(rc.getz() / rc.magnitude()); vtr ro(radius_x * sin(th) * cos(ph), radius_y * sin(th) * sin(ph), radius_z * cos(th)); vtr u1, u2, u3; LocalRadiiCurvature(rc, radius_x, radius_y, radius_z, r01, r02, u1, u2, u3); fp_t z3 = abs(dotP(rc - ro, u3)); s1 = (sigma_max / ((m + 1) * pow(pml_thick, m) * (r01 + z3))) * abs(pow(z3, m + 1)); s2 = (sigma_max / ((m + 1) * pow(pml_thick, m) * (r02 + z3))) * abs(pow(z3, m + 1)); s3 = sigma_max * abs(pow(z3 / pml_thick, m)); // K scaling (Jacobians) fp_t K_max = 2.0; fp_t growth_factor = std::pow(z3 / pml_thick, m); fp_t K1 = 1.0 + (K_max - 1.0) * growth_factor; fp_t K2 = K1; fp_t K3 = K1; // === ALLOCATE ONCE === if (!matA) matA = new denseMat(3, 3); if (!matB) matB = new denseMat(3, 3); if (!matC) matC = new denseMat(3, 3); if (!matD) matD = new denseMat(3, 3); if (!matF) matF = new denseMat(3, 3); matA->reset(); matB->reset(); matC->reset(); matD->reset(); matF->reset(); if (mode == "A" || mode == "ALL") { matA->reset(); matA->setEntry(0, 0, K2 * K3 / K1); matA->setEntry(1, 1, K1 * K3 / K2); matA->setEntry(2, 2, K1 * K2 / K3); ApplyConformalPMLRotation(Jrot, matA); } if (mode == "B" || mode == "ALL") { matA->reset(); matA->setEntry(0, 0, K2 * K3 / K1); matA->setEntry(1, 1, K1 * K3 / K2); matA->setEntry(2, 2, K1 * K2 / K3); matB->reset(); fp_t A11 = matA->getEntry(0, 0); fp_t A22 = matA->getEntry(1, 1); fp_t A33 = matA->getEntry(2, 2); matB->setEntry(0, 0, (s2 * K3 + s3 * K2 - A11 * s1) / eps_o); matB->setEntry(1, 1, (s1 * K3 + s3 * K1 - A22 * s2) / eps_o); matB->setEntry(2, 2, (s1 * K2 + s2 * K1 - A33 * s3) / eps_o); ApplyConformalPMLRotation(Jrot, matB); } if (mode == "C" || mode == "ALL") { matA->reset(); matA->setEntry(0, 0, K2 * K3 / K1); matA->setEntry(1, 1, K1 * K3 / K2); matA->setEntry(2, 2, K1 * K2 / K3); matB->reset(); fp_t A11 = matA->getEntry(0, 0); fp_t A22 = matA->getEntry(1, 1); fp_t A33 = matA->getEntry(2, 2); matB->setEntry(0, 0, (s2 * K3 + s3 * K2 - A11 * s1) / eps_o); matB->setEntry(1, 1, (s1 * K3 + s3 * K1 - A22 * s2) / eps_o); matB->setEntry(2, 2, (s1 * K2 + s2 * K1 - A33 * s3) / eps_o); matC->reset(); fp_t B11 = matB->getEntry(0, 0); fp_t B22 = matB->getEntry(1, 1); fp_t B33 = matB->getEntry(2, 2); matC->setEntry(0, 0, s2 * s3 / (eps_o * eps_o) - B11 * s1 / eps_o); matC->setEntry(1, 1, s1 * s3 / (eps_o * eps_o) - B22 * s2 / eps_o); matC->setEntry(2, 2, s1 * s2 / (eps_o * eps_o) - B33 * s3 / eps_o); ApplyConformalPMLRotation(Jrot, matC); } if (mode == "D" || mode == "ALL") { matD->reset(); matD->setEntry(0, 0, s1 / (K1 * eps_o)); matD->setEntry(1, 1, s2 / (K2 * eps_o)); matD->setEntry(2, 2, s3 / (K3 * eps_o)); ApplyConformalPMLRotation(Jrot, matD); } if (mode == "F" || mode == "ALL") { matF->reset(); matF->setEntry(0, 0, 1.0 / K1); matF->setEntry(1, 1, 1.0 / K2); matF->setEntry(2, 2, 1.0 / K3); ApplyConformalPMLRotation(Jrot, matF); } } void tetra::Calculate_Mass_Material_Matrix_Vary_Numeric( denseMat*& outputMassMat, // Output mass matrix to fill const denseMat* inputTensorMat, // Input tensor like A1, A3 const tensor& materialTensor, // Material tensor (e.g., epsr, mur) bool isElectricField, // true → use E-field space, false → H-field space string mode, fp_t planewave_xmin, fp_t planewave_ymin, fp_t planewave_zmin, fp_t planewave_xmax, fp_t planewave_ymax, fp_t planewave_zmax, fp_t radius_x, fp_t radius_y, fp_t radius_z ) { if ((isElectricField && LocalEDOF == 0) || (!isElectricField && LocalHDOF == 0)) { outputMassMat = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); outputMassMat->reset(); return; } outputMassMat = new denseMat(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]); int i, j, k, dim; fp_t cval = 0.0; fp_t vol; fp_t* z; fp_t wgt = 0.; vtr lvtr[4]; // the 3 first positions are the vectors from the node 0 to the // others [{0,1}, {0,2}, {0,3}] vtr avtr[4]; // array of vectors normal to the faces and with a magnitude // equal to the area of them [f0, f1, f2, f3] vtr w1, w2; int* map = new int[TetPolyOrderDim[PolyOrderFlag]]; if (isElectricField) Local_DG_mapE(map, 0); else Local_DG_mapH(map, 0); outputMassMat->reset(); geometry(lvtr, avtr, &vol); dim = outputMassMat->getRowDim(); fp_t (*gaussQuadPoints)[5]; GetFormula3dPtr(GAUSS_POINT_NUM[PolyOrderFlag], gaussQuadPoints); vtr* gaussBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; vtr* gaussMatBasisVtrs = new vtr[TetPolyOrderDim[PolyOrderFlag] * GAUSS_POINT_NUM[PolyOrderFlag]]; for (i = 0; i < dim; i++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { z = &gaussQuadPoints[k][0]; TetraBasisW(z, i, &w1); gaussBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = w1; // Get the Cartesian coordinate of the Gauss point vtr gaussPointCoord; getCartesianCoord(z, gaussPointCoord); vtr rc = Center(); if (radius_x > 0.0 && radius_y > 0.0 && radius_z > 0.0) { set_Conductivity_smoothProfile_conformal(radius_x, radius_y, radius_z,rc, rc, mode); } else { set_Conductivity_smoothProfile_Planar(planewave_xmin, planewave_ymin, planewave_zmin, planewave_xmax, planewave_ymax, planewave_zmax, rc, rc, mode); } // Form tensor from input matrix tensor Atensor( inputTensorMat->getEntry(0, 0), inputTensorMat->getEntry(0, 1), inputTensorMat->getEntry(0, 2), inputTensorMat->getEntry(1, 0), inputTensorMat->getEntry(1, 1), inputTensorMat->getEntry(1, 2), inputTensorMat->getEntry(2, 0), inputTensorMat->getEntry(2, 1), inputTensorMat->getEntry(2, 2) ); /* if (mode == "B" && isElectricField) { fp_t mv = mat->sigma.getEntry(0, 0) * 2.0; tensor mod (mv,0.0,0.0,0.0,mv,0.0,0.0,0.0,mv); // Modify the tensor for B-field Atensor = mod + Atensor; } */ tensor scaledTensor = materialTensor * Atensor; gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k] = scaledTensor * w1; } } for (i = 0; i < dim; i++){ for (j = 0; j < dim; j++){ for (k = 0; k < GAUSS_POINT_NUM[PolyOrderFlag]; k++) { wgt = gaussQuadPoints[k][4]; w1 = gaussMatBasisVtrs[i * GAUSS_POINT_NUM[PolyOrderFlag] + k]; w2 = gaussBasisVtrs[j * GAUSS_POINT_NUM[PolyOrderFlag] + k]; cval += wgt * dotP(w1, w2); } outputMassMat->addEntry(i, j, cval * vol); cval = 0.0; } } delete[] gaussBasisVtrs; delete[] gaussMatBasisVtrs; if (map != nullptr) delete[] map; } vtr tetra::get_centroid() { vtr center(0.0,0.0,0.0); for (int n = 0; n < 4; ++n) { center = center + nd[n]->getCoord(); } center = center / 4.0; return center; }