You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
7363 lines
222 KiB
7363 lines
222 KiB
#include <cmath>
|
|
// #include <direct.h> // 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 <fstream>
|
|
#include <iomanip>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <unistd.h> // 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<int> myNeighset; // Stores cnt() indices of neighboring tetrahedra
|
|
std::vector<int> 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<int> 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<std::array<double, 3>, 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<int> 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 <vtr> 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<fp_t>* nxh_inc, ArrayFP<fp_t>* nxnxe_inc) {
|
|
int i, j;
|
|
Coordinate coord;
|
|
int LocalFaceDim;
|
|
ArrayFP<fp_t>* nxh;
|
|
ArrayFP<fp_t>* nxnxe;
|
|
|
|
LocalFaceDim = FacePolyOrderDim[PolyOrderFlag];
|
|
|
|
nxh = new ArrayFP<fp_t>(LocalFaceDim);
|
|
nxnxe = new ArrayFP<fp_t>(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<fp_t>* nxe_inc, ArrayFP<fp_t>* nxnxh_inc) {
|
|
int i, j;
|
|
Coordinate coord;
|
|
int LocalFaceDim;
|
|
ArrayFP<fp_t>* nxe;
|
|
ArrayFP<fp_t>* nxnxh;
|
|
|
|
LocalFaceDim = FacePolyOrderDim[PolyOrderFlag];
|
|
|
|
nxe = new ArrayFP<fp_t>(LocalFaceDim);
|
|
nxnxh = new ArrayFP<fp_t>(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<fp_t>* 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<fp_t>* 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<fp_t>* 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<fp_t>* 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<fp_t>* 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<fp_t>* 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<fp_t>* 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<fp_t>* 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<fp_t>* 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<fp_t>* 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<fp_t>* 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<fp_t>* 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<fp_t>(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]);
|
|
MassE->reset();
|
|
return;
|
|
}
|
|
|
|
MassE = new denseMat<fp_t>(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<fp_t>* 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<fp_t> tetBe(LocalDim, LocalDim);
|
|
// Matrices On the Faces
|
|
denseMat<fp_t> 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<fp_t>(LocalDim, LocalDim);
|
|
|
|
denseMat<fp_t> 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<fp_t>(LocalDim, 4 * LocalFaceDim);
|
|
|
|
denseMat<fp_t> 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<fp_t>(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<fp_t>(LocalDim, LocalDim);
|
|
|
|
denseMat<fp_t> 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<fp_t>(LocalDim, 4 * LocalFaceDim);
|
|
|
|
denseMat<fp_t> 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<fp_t>(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]);
|
|
MassE->reset();
|
|
return;
|
|
}
|
|
|
|
|
|
MassE = new denseMat<fp_t>(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<fp_t>* 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<fp_t> tetBe(LocalDim, LocalDim);
|
|
// Matrices On the Faces
|
|
denseMat<fp_t> 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<fp_t>(LocalDim, LocalDim);
|
|
|
|
denseMat<fp_t> 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<fp_t>(LocalDim, 4 * LocalFaceDim);
|
|
|
|
denseMat<fp_t> 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<fp_t>(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<fp_t>(LocalDim, LocalDim);
|
|
|
|
denseMat<fp_t> 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<fp_t>(LocalDim, 4 * LocalFaceDim);
|
|
|
|
denseMat<fp_t> 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<fp_t>(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]);
|
|
MassH->reset();
|
|
return;
|
|
}
|
|
|
|
MassH = new denseMat<fp_t>(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<fp_t>* 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<fp_t> tetBh(LocalDim, LocalDim);
|
|
|
|
// Matrices On the Faces
|
|
denseMat<fp_t> 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<fp_t>(LocalDim, LocalDim);
|
|
|
|
denseMat<fp_t> 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<fp_t>(LocalDim, 4 * LocalFaceDim);
|
|
|
|
denseMat<fp_t> 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<fp_t>(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<fp_t>(LocalDim, LocalDim);
|
|
|
|
denseMat<fp_t> 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<fp_t>(LocalDim, 4 * LocalFaceDim);
|
|
|
|
denseMat<fp_t> 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<fp_t>(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]);
|
|
MassH->reset();
|
|
return;
|
|
}
|
|
MassH = new denseMat<fp_t>(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<fp_t>* 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<fp_t> tetBh(LocalDim, LocalDim);
|
|
|
|
// Matrices On the Faces
|
|
denseMat<fp_t> 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<fp_t>(LocalDim, LocalDim);
|
|
|
|
denseMat<fp_t> 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<fp_t>(LocalDim, 4 * LocalFaceDim);
|
|
|
|
denseMat<fp_t> 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<fp_t>(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<fp_t>(LocalDim, LocalDim);
|
|
|
|
denseMat<fp_t> 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<fp_t>(LocalDim, 4 * LocalFaceDim);
|
|
|
|
denseMat<fp_t> 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<fp_t> RMatrixE(LocalDim, LocalDim);
|
|
Calculate_R_Matrix_E(&RMatrixE, dt);
|
|
|
|
RHSLoc1E = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
RHSLoc2E = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
RHSCoup1E = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
RHSCoup2E = new denseMat<fp_t>(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<fp_t>(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<fp_t> RMatrixE(LocalDim, LocalDim);
|
|
Calculate_R_Matrix_E_Numeric(&RMatrixE, dt);
|
|
|
|
RHSLoc1E = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
RHSLoc2E = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
RHSCoup1E = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
RHSCoup2E = new denseMat<fp_t>(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<fp_t>(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<fp_t> RMatrixH(LocalDim, LocalDim);
|
|
Calculate_R_Matrix_H(&RMatrixH, dt);
|
|
|
|
RHSLoc1H = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
RHSLoc2H = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
RHSCoup1H = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
RHSCoup2H = new denseMat<fp_t>(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<fp_t>(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<fp_t> RMatrixH(LocalDim, LocalDim);
|
|
Calculate_R_Matrix_H_Numeric(&RMatrixH, dt);
|
|
|
|
RHSLoc1H = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
RHSLoc2H = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
RHSCoup1H = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
RHSCoup2H = new denseMat<fp_t>(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<fp_t>(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<fp_t>& En_1, ArrayFP<fp_t>& En, ArrayFP<fp_t>& 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<fp_t> 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<fp_t> nei_e(NeighFaceDim);
|
|
ArrayFP<fp_t> 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<fp_t> RHSCoup1E_aux(LocalDim, NeighFaceDim);
|
|
denseMat<fp_t> 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<fp_t> 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<fp_t> nei_e(NeighFaceDim);
|
|
ArrayFP<fp_t> 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<fp_t> RHSCoup1E_aux(LocalDim, NeighFaceDim);
|
|
denseMat<fp_t> 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<fp_t> 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<fp_t> loc_e(LocalDim);
|
|
ArrayFP<fp_t> 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<fp_t>& Hn_32, ArrayFP<fp_t>& En_1, ArrayFP<fp_t>& 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<fp_t> 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<fp_t> nei_e(NeighFaceDim);
|
|
ArrayFP<fp_t> 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<fp_t> RHSCoup1H_aux(LocalDim, NeighFaceDim);
|
|
denseMat<fp_t> 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<fp_t> 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<fp_t> nei_e(NeighFaceDim);
|
|
ArrayFP<fp_t> 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<fp_t> RHSCoup1H_aux(LocalDim, NeighFaceDim);
|
|
denseMat<fp_t> 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<fp_t> 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<fp_t> loc_e(LocalDim);
|
|
ArrayFP<fp_t> 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<fp_t>& En_1, fp_t t, fp_t dt, ArrayFP<fp_t>& work2) {
|
|
if (LocalEDOF == 0)
|
|
return;
|
|
if (t < 0.)
|
|
return;
|
|
int i;
|
|
int LocalDim;
|
|
fp_t Y;
|
|
fp_t eps_o = Eo;
|
|
ArrayFP<fp_t>* nxh;
|
|
ArrayFP<fp_t>* nxnxe;
|
|
|
|
// excitation
|
|
LocalDim = TetPolyOrderDim[PolyOrderFlag];
|
|
|
|
nxh = new ArrayFP<fp_t>(LocalDim);
|
|
nxnxe = new ArrayFP<fp_t>(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<fp_t>& Hn_32, fp_t t, fp_t dt, ArrayFP<fp_t>& work2) {
|
|
if (LocalHDOF == 0)
|
|
return;
|
|
if (t < 0.)
|
|
return;
|
|
int i;
|
|
int LocalDim;
|
|
fp_t Z;
|
|
fp_t mu_o = Uo;
|
|
ArrayFP<fp_t>* nxe;
|
|
ArrayFP<fp_t>* nxnxh;
|
|
|
|
// excitation
|
|
LocalDim = TetPolyOrderDim[PolyOrderFlag];
|
|
|
|
nxe = new ArrayFP<fp_t>(LocalDim);
|
|
nxnxh = new ArrayFP<fp_t>(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"<<endl;
|
|
if (EdofMap != 0)
|
|
delete[] EdofMap;
|
|
|
|
EdofMap = 0;
|
|
|
|
if (HdofMap != 0)
|
|
delete[] HdofMap;
|
|
|
|
HdofMap = 0;
|
|
}
|
|
|
|
int* tetra::get_NeighMapsE() {
|
|
int FaceNum = 4;
|
|
int NeighFace = 0;
|
|
int MapCol = FacePolyOrderDim[PolyOrderFlag] * 2;
|
|
int MapDim = MapCol * FaceNum;
|
|
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->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<fp_t>[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<fp_t> 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<fp_t> 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<int, bool> OverlapMap;
|
|
map<int, bool> IntersectionMap;
|
|
map<int, int> IntersectionFaceMap;
|
|
vector<map<int, bool>>::iterator it2;
|
|
vector<map<int, int>>::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<fp_t>* RHSCoup1E_aux;
|
|
denseMat<fp_t>* RHSCoup2E_aux;
|
|
denseMat<fp_t>* RHSLoc1E_aux;
|
|
denseMat<fp_t>* RHSLoc2E_aux;
|
|
|
|
if(LocalEDOF != 0){
|
|
RHSCoup1E_aux = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
AB(*LHSInvE, *RHSCoup1E, *RHSCoup1E_aux);
|
|
RHSCoup1E->Clear();
|
|
|
|
RHSCoup2E_aux = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
AB(*LHSInvE, *RHSCoup2E, *RHSCoup2E_aux);
|
|
RHSCoup2E->Clear();
|
|
|
|
RHSLoc1E_aux = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
AB(*LHSInvE, *RHSLoc1E, *RHSLoc1E_aux);
|
|
RHSLoc1E->Clear();
|
|
|
|
RHSLoc2E_aux = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
AB(*LHSInvE, *RHSLoc2E, *RHSLoc2E_aux);
|
|
RHSLoc2E->Clear();
|
|
}
|
|
|
|
denseMat<fp_t>* RHSCoup1H_aux;
|
|
denseMat<fp_t>* RHSCoup2H_aux;
|
|
denseMat<fp_t>* RHSLoc1H_aux;
|
|
denseMat<fp_t>* RHSLoc2H_aux;
|
|
if(LocalHDOF != 0){
|
|
RHSCoup1H_aux = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
AB(*LHSInvH, *RHSCoup1H, *RHSCoup1H_aux);
|
|
RHSCoup1H->Clear();
|
|
|
|
RHSCoup2H_aux = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
AB(*LHSInvH, *RHSCoup2H, *RHSCoup2H_aux);
|
|
RHSCoup2H->Clear();
|
|
|
|
RHSLoc1H_aux = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
AB(*LHSInvH, *RHSLoc1H, *RHSLoc1H_aux);
|
|
RHSLoc1H->Clear();
|
|
|
|
RHSLoc2H_aux = new denseMat<fp_t>(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<fp_t>* RHSCoup1E_NC = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
denseMat<fp_t>* RHSCoup2E_NC = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
denseMat<fp_t>* RHSCoup1H_NC = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
denseMat<fp_t>* RHSCoup2H_NC = new denseMat<fp_t>(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<fp_t>* RHSCoup1E_NC_aux = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
AB(*LHSInvE, *RHSCoup1E_NC, *RHSCoup1E_NC_aux);
|
|
RHSCoup1E_NC->Clear();
|
|
|
|
denseMat<fp_t>* RHSCoup2E_NC_aux = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
AB(*LHSInvE, *RHSCoup2E_NC, *RHSCoup2E_NC_aux);
|
|
RHSCoup2E_NC->Clear();
|
|
|
|
denseMat<fp_t>* RHSCoup1H_NC_aux = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
AB(*LHSInvH, *RHSCoup1H_NC, *RHSCoup1H_NC_aux);
|
|
RHSCoup1H_NC->Clear();
|
|
|
|
denseMat<fp_t>* RHSCoup2H_NC_aux = new denseMat<fp_t>(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<fp_t> x(TetPolyOrderDim[PolyOrderFlag]);
|
|
ArrayFP<fp_t> 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<fp_t> x(TetPolyOrderDim[PolyOrderFlag]);
|
|
ArrayFP<fp_t> 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<fp_t>* RHSCoup1E_aux;
|
|
denseMat<fp_t>* RHSCoup2E_aux;
|
|
denseMat<fp_t>* RHSLoc1E_aux;
|
|
denseMat<fp_t>* RHSLoc2E_aux;
|
|
|
|
if(LocalEDOF != 0){
|
|
RHSCoup1E_aux = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
AB(*LHSInvE, *RHSCoup1E, *RHSCoup1E_aux);
|
|
RHSCoup1E->Clear();
|
|
|
|
RHSCoup2E_aux = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
AB(*LHSInvE, *RHSCoup2E, *RHSCoup2E_aux);
|
|
RHSCoup2E->Clear();
|
|
|
|
RHSLoc1E_aux = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
AB(*LHSInvE, *RHSLoc1E, *RHSLoc1E_aux);
|
|
RHSLoc1E->Clear();
|
|
|
|
RHSLoc2E_aux = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
AB(*LHSInvE, *RHSLoc2E, *RHSLoc2E_aux);
|
|
RHSLoc2E->Clear();
|
|
}
|
|
|
|
denseMat<fp_t>* RHSCoup1H_aux;
|
|
denseMat<fp_t>* RHSCoup2H_aux;
|
|
denseMat<fp_t>* RHSLoc1H_aux;
|
|
denseMat<fp_t>* RHSLoc2H_aux;
|
|
|
|
if(LocalHDOF != 0){
|
|
RHSCoup1H_aux = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
AB(*LHSInvH, *RHSCoup1H, *RHSCoup1H_aux);
|
|
RHSCoup1H->Clear();
|
|
|
|
RHSCoup2H_aux = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
AB(*LHSInvH, *RHSCoup2H, *RHSCoup2H_aux);
|
|
RHSCoup2H->Clear();
|
|
|
|
RHSLoc1H_aux = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
AB(*LHSInvH, *RHSLoc1H, *RHSLoc1H_aux);
|
|
RHSLoc1H->Clear();
|
|
|
|
RHSLoc2H_aux = new denseMat<fp_t>(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<fp_t>* RHSCoup1E_NC = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
denseMat<fp_t>* RHSCoup2E_NC = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
denseMat<fp_t>* RHSCoup1H_NC = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
denseMat<fp_t>* RHSCoup2H_NC = new denseMat<fp_t>(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<fp_t>* RHSCoup1E_NC_aux = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
AB(*LHSInvE, *RHSCoup1E_NC, *RHSCoup1E_NC_aux);
|
|
RHSCoup1E_NC->Clear();
|
|
|
|
denseMat<fp_t>* RHSCoup2E_NC_aux = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
AB(*LHSInvE, *RHSCoup2E_NC, *RHSCoup2E_NC_aux);
|
|
RHSCoup2E_NC->Clear();
|
|
|
|
denseMat<fp_t>* RHSCoup1H_NC_aux = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
AB(*LHSInvH, *RHSCoup1H_NC, *RHSCoup1H_NC_aux);
|
|
RHSCoup1H_NC->Clear();
|
|
|
|
denseMat<fp_t>* RHSCoup2H_NC_aux = new denseMat<fp_t>(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<fp_t>* RHSCoup1E_aux;
|
|
denseMat<fp_t>* RHSCoup2E_aux;
|
|
denseMat<fp_t>* RHSLoc1E_aux;
|
|
denseMat<fp_t>* RHSLoc2E_aux;
|
|
|
|
denseMat<fp_t>* AuxE_aux;
|
|
denseMat<fp_t>* AuxJ1_aux;
|
|
denseMat<fp_t>* AuxJ2_aux;
|
|
|
|
|
|
if(LocalEDOF != 0){
|
|
RHSCoup1E_aux = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
AB(*LHSInvE, *RHSCoup1E, *RHSCoup1E_aux);
|
|
RHSCoup1E->Clear();
|
|
|
|
RHSCoup2E_aux = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
AB(*LHSInvE, *RHSCoup2E, *RHSCoup2E_aux);
|
|
RHSCoup2E->Clear();
|
|
|
|
RHSLoc1E_aux = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
AB(*LHSInvE, *RHSLoc1E, *RHSLoc1E_aux);
|
|
RHSLoc1E->Clear();
|
|
|
|
RHSLoc2E_aux = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
AB(*LHSInvE, *RHSLoc2E, *RHSLoc2E_aux);
|
|
RHSLoc2E->Clear();
|
|
|
|
AuxE_aux = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
AB(*LHSInvE, *RHSAuxE, *AuxE_aux);
|
|
RHSAuxE->Clear();
|
|
|
|
AuxJ1_aux = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
AB(*LHSInvAuxJ, *RHSLocAuxJ1, *AuxJ1_aux);
|
|
RHSLocAuxJ1->Clear();
|
|
|
|
AuxJ2_aux = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
AB(*LHSInvAuxJ, *RHSLocAuxJ2, *AuxJ2_aux);
|
|
RHSLocAuxJ2->Clear();
|
|
}
|
|
|
|
denseMat<fp_t>* RHSCoup1H_aux;
|
|
denseMat<fp_t>* RHSCoup2H_aux;
|
|
denseMat<fp_t>* RHSLoc1H_aux;
|
|
denseMat<fp_t>* RHSLoc2H_aux;
|
|
|
|
denseMat<fp_t>* AuxH_aux;
|
|
denseMat<fp_t>* AuxM1_aux;
|
|
denseMat<fp_t>* AuxM2_aux;
|
|
|
|
|
|
|
|
if(LocalHDOF != 0){
|
|
RHSCoup1H_aux = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
AB(*LHSInvH, *RHSCoup1H, *RHSCoup1H_aux);
|
|
RHSCoup1H->Clear();
|
|
|
|
RHSCoup2H_aux = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
AB(*LHSInvH, *RHSCoup2H, *RHSCoup2H_aux);
|
|
RHSCoup2H->Clear();
|
|
|
|
RHSLoc1H_aux = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
AB(*LHSInvH, *RHSLoc1H, *RHSLoc1H_aux);
|
|
RHSLoc1H->Clear();
|
|
|
|
RHSLoc2H_aux = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
AB(*LHSInvH, *RHSLoc2H, *RHSLoc2H_aux);
|
|
RHSLoc2H->Clear();
|
|
|
|
AuxH_aux = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
AB(*LHSInvH, *RHSAuxH, *AuxH_aux);
|
|
RHSAuxH->Clear();
|
|
|
|
AuxM1_aux = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
AB(*LHSInvAuxM, *RHSLocAuxM1, *AuxM1_aux);
|
|
RHSLocAuxM1->Clear();
|
|
|
|
AuxM2_aux = new denseMat<fp_t>(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<fp_t>* RHSCoup1E_NC = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
denseMat<fp_t>* RHSCoup2E_NC = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
denseMat<fp_t>* RHSCoup1H_NC = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
denseMat<fp_t>* RHSCoup2H_NC = new denseMat<fp_t>(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<fp_t>* RHSCoup1E_NC_aux = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
AB(*LHSInvE, *RHSCoup1E_NC, *RHSCoup1E_NC_aux);
|
|
RHSCoup1E_NC->Clear();
|
|
|
|
denseMat<fp_t>* RHSCoup2E_NC_aux = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
AB(*LHSInvE, *RHSCoup2E_NC, *RHSCoup2E_NC_aux);
|
|
RHSCoup2E_NC->Clear();
|
|
|
|
denseMat<fp_t>* RHSCoup1H_NC_aux = new denseMat<fp_t>(LocalDim, LocalFaceDim);
|
|
AB(*LHSInvH, *RHSCoup1H_NC, *RHSCoup1H_NC_aux);
|
|
RHSCoup1H_NC->Clear();
|
|
|
|
denseMat<fp_t>* RHSCoup2H_NC_aux = new denseMat<fp_t>(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<fp_t>(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]);
|
|
MassI_H->reset();
|
|
return;
|
|
}
|
|
MassI_H = new denseMat<fp_t>(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<fp_t> tetBh(LocalDim, LocalDim);
|
|
|
|
// Matrices On the Faces
|
|
denseMat<fp_t> 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<fp_t>(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<fp_t>(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]);
|
|
MassI_E->reset();
|
|
return;
|
|
}
|
|
|
|
|
|
MassI_E = new denseMat<fp_t>(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<fp_t> tetBe(LocalDim, LocalDim);
|
|
// Matrices On the Faces
|
|
denseMat<fp_t> 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<fp_t>(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<fp_t>(LocalDim, LocalDim);
|
|
RHSLoc2E = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
RHSCoup1E = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
RHSCoup2E = new denseMat<fp_t>(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<fp_t>(LocalDim, LocalDim);
|
|
*LHSInvE = *Mass_epA_E + (*Mass_epB_E + *ABC_tetBe);
|
|
*LHSInvE = LHSInvE->inverse();
|
|
|
|
|
|
RHSAuxE = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
*RHSAuxE = *Mass_epC_E;
|
|
RHSAuxE->scale(-1.0 * dt);
|
|
ApplyPEC(RHSAuxE, LocalDim);
|
|
|
|
// ------------------------------
|
|
// PML
|
|
|
|
LHSInvAuxJ = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
RHSLocAuxJ1 = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
RHSLocAuxJ2 = new denseMat<fp_t>(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<fp_t>(LocalDim, LocalDim);
|
|
RHSLoc2H = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
RHSCoup1H = new denseMat<fp_t>(LocalDim, NumOfFaces * LocalFaceDim);
|
|
RHSCoup2H = new denseMat<fp_t>(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<fp_t>(LocalDim, LocalDim);
|
|
*LHSInvH = *Mass_muA_H + (*Mass_muB_H + *ABC_tetBh);
|
|
*LHSInvH = LHSInvH->inverse();
|
|
|
|
|
|
RHSAuxH = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
*RHSAuxH = *Mass_muC_H;
|
|
RHSAuxH->scale(-1.0 * dt);
|
|
ApplyPMC(RHSAuxH, LocalDim);
|
|
|
|
// ------------------------------
|
|
// PML
|
|
LHSInvAuxM = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
RHSLocAuxM1 = new denseMat<fp_t>(LocalDim, LocalDim);
|
|
RHSLocAuxM2 = new denseMat<fp_t>(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<fp_t>* 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<fp_t>(3, 3);
|
|
matB = new denseMat<fp_t>(3, 3);
|
|
matC = new denseMat<fp_t>(3, 3);
|
|
matD = new denseMat<fp_t>(3, 3);
|
|
matF = new denseMat<fp_t>(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<fp_t> 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<fp_t> RT = R.transpose(); // Needed for tensor rotation
|
|
denseMat<fp_t> A_cart(3,3);
|
|
denseMat<fp_t> 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<fp_t> 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<fp_t> 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<fp_t>(3, 3);
|
|
matB = new denseMat<fp_t>(3, 3);
|
|
matC = new denseMat<fp_t>(3, 3);
|
|
matD = new denseMat<fp_t>(3, 3);
|
|
matF = new denseMat<fp_t>(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<fp_t> 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<fp_t>(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<fp_t>(3, 3);
|
|
matB = new denseMat<fp_t>(3, 3);
|
|
matC = new denseMat<fp_t>(3, 3);
|
|
matD = new denseMat<fp_t>(3, 3);
|
|
matF = new denseMat<fp_t>(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<fp_t>(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]);
|
|
MassI_H->reset();
|
|
return;
|
|
}
|
|
MassI_H = new denseMat<fp_t>(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<fp_t> tetBh(LocalDim, LocalDim);
|
|
|
|
// Matrices On the Faces
|
|
denseMat<fp_t> 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<fp_t>(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<fp_t>(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]);
|
|
MassI_E->reset();
|
|
return;
|
|
}
|
|
|
|
|
|
MassI_E = new denseMat<fp_t>(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<fp_t> tetBe(LocalDim, LocalDim);
|
|
// Matrices On the Faces
|
|
denseMat<fp_t> 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<fp_t>(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]);
|
|
*ABC_tetBe = tetBe;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void tetra::Calculate_Mass_Material_Matrix(
|
|
denseMat<fp_t>*& outputMassMat, // Output mass matrix to fill
|
|
const denseMat<fp_t>* 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<fp_t>(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]);
|
|
outputMassMat->reset();
|
|
return;
|
|
}
|
|
|
|
outputMassMat = new denseMat<fp_t>(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<fp_t>*& outputMassMat, // Output mass matrix to fill
|
|
const denseMat<fp_t>* 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<fp_t>(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]);
|
|
outputMassMat->reset();
|
|
return;
|
|
}
|
|
|
|
outputMassMat = new denseMat<fp_t>(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<fp_t>(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<fp_t>(3, 3);
|
|
if (!matB) matB = new denseMat<fp_t>(3, 3);
|
|
if (!matC) matC = new denseMat<fp_t>(3, 3);
|
|
if (!matD) matD = new denseMat<fp_t>(3, 3);
|
|
if (!matF) matF = new denseMat<fp_t>(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<fp_t> 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<fp_t, 3> 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<fp_t>(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<fp_t>* E, denseMat<fp_t>* S, denseMat<fp_t>* 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<fp_t>* J, denseMat<fp_t>* tensorU1U2U3)
|
|
{
|
|
denseMat<fp_t> XYZ(3, 3);
|
|
denseMat<fp_t> 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<fp_t>(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<fp_t>(3, 3);
|
|
if (!matB) matB = new denseMat<fp_t>(3, 3);
|
|
if (!matC) matC = new denseMat<fp_t>(3, 3);
|
|
if (!matD) matD = new denseMat<fp_t>(3, 3);
|
|
if (!matF) matF = new denseMat<fp_t>(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<fp_t>*& outputMassMat, // Output mass matrix to fill
|
|
const denseMat<fp_t>* 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<fp_t>(TetPolyOrderDim[PolyOrderFlag], TetPolyOrderDim[PolyOrderFlag]);
|
|
outputMassMat->reset();
|
|
return;
|
|
}
|
|
|
|
|
|
outputMassMat = new denseMat<fp_t>(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;
|
|
} |