new extension: upml

Operator extension implementing an uniaxial perfectly matched layer (upml)

This new pml implementation is going to replace the old split-field pml
pull/1/head
Thorsten Liebig 2010-10-04 11:52:39 +02:00
parent 887e07a394
commit 06bbec106f
7 changed files with 669 additions and 23 deletions

173
FDTD/engine_ext_upml.cpp Normal file
View File

@ -0,0 +1,173 @@
/*
* Copyright (C) 2010 Thorsten Liebig (Thorsten.Liebig@gmx.de)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "engine_ext_upml.h"
#include "operator_ext_upml.h"
#include "engine.h"
#include "engine_sse.h"
#include "tools/array_ops.h"
Engine_Ext_UPML::Engine_Ext_UPML(Operator_Ext_UPML* op_ext) : Engine_Extension(op_ext)
{
m_Op_UPML = op_ext;
//this ABC extension should be executed first!
m_Priority = 1e6;
volt = Create_N_3DArray<FDTD_FLOAT>(m_Op_UPML->m_numLines);
volt_flux = Create_N_3DArray<FDTD_FLOAT>(m_Op_UPML->m_numLines);
curr = Create_N_3DArray<FDTD_FLOAT>(m_Op_UPML->m_numLines);
curr_flux = Create_N_3DArray<FDTD_FLOAT>(m_Op_UPML->m_numLines);
}
Engine_Ext_UPML::~Engine_Ext_UPML()
{
Delete_N_3DArray<FDTD_FLOAT>(volt,m_Op_UPML->m_numLines);
volt=NULL;
Delete_N_3DArray<FDTD_FLOAT>(volt_flux,m_Op_UPML->m_numLines);
volt_flux=NULL;
Delete_N_3DArray<FDTD_FLOAT>(curr,m_Op_UPML->m_numLines);
curr=NULL;
Delete_N_3DArray<FDTD_FLOAT>(curr_flux,m_Op_UPML->m_numLines);
curr_flux=NULL;
}
void Engine_Ext_UPML::DoPreVoltageUpdates()
{
if (m_Eng==NULL)
return;
unsigned int pos[3];
unsigned int loc_pos[3];
for (loc_pos[0]=0;loc_pos[0]<m_Op_UPML->m_numLines[0];++loc_pos[0])
{
pos[0] = loc_pos[0] + m_Op_UPML->m_StartPos[0];
for (loc_pos[1]=0;loc_pos[1]<m_Op_UPML->m_numLines[1];++loc_pos[1])
{
pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1];
for (loc_pos[2]=0;loc_pos[2]<m_Op_UPML->m_numLines[2];++loc_pos[2])
{
pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2];
volt[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Op_UPML->vv[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->GetVolt(0,pos)
- m_Op_UPML->vvfo[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]];
volt[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Op_UPML->vv[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->GetVolt(1,pos)
- m_Op_UPML->vvfo[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]];
volt[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Op_UPML->vv[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->GetVolt(2,pos)
- m_Op_UPML->vvfo[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]];
m_Eng->SetVolt(0,pos, volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]);
m_Eng->SetVolt(1,pos, volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]);
m_Eng->SetVolt(2,pos, volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]);
}
}
}
}
void Engine_Ext_UPML::DoPostVoltageUpdates()
{
if (m_Eng==NULL)
return;
unsigned int pos[3];
unsigned int loc_pos[3];
for (loc_pos[0]=0;loc_pos[0]<m_Op_UPML->m_numLines[0];++loc_pos[0])
{
pos[0] = loc_pos[0] + m_Op_UPML->m_StartPos[0];
for (loc_pos[1]=0;loc_pos[1]<m_Op_UPML->m_numLines[1];++loc_pos[1])
{
pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1];
for (loc_pos[2]=0;loc_pos[2]<m_Op_UPML->m_numLines[2];++loc_pos[2])
{
pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2];
volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetVolt(0,pos);
volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetVolt(1,pos);
volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetVolt(2,pos);
m_Eng->SetVolt(0,pos, volt[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] + m_Op_UPML->vvfn[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]);
m_Eng->SetVolt(1,pos, volt[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] + m_Op_UPML->vvfn[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]);
m_Eng->SetVolt(2,pos, volt[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] + m_Op_UPML->vvfn[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]);
}
}
}
}
void Engine_Ext_UPML::DoPreCurrentUpdates()
{
if (m_Eng==NULL)
return;
unsigned int pos[3];
unsigned int loc_pos[3];
for (loc_pos[0]=0;loc_pos[0]<m_Op_UPML->m_numLines[0];++loc_pos[0])
{
pos[0] = loc_pos[0] + m_Op_UPML->m_StartPos[0];
for (loc_pos[1]=0;loc_pos[1]<m_Op_UPML->m_numLines[1];++loc_pos[1])
{
pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1];
for (loc_pos[2]=0;loc_pos[2]<m_Op_UPML->m_numLines[2];++loc_pos[2])
{
pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2];
curr[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Op_UPML->ii[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->GetCurr(0,pos)
- m_Op_UPML->iifo[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]];
curr[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Op_UPML->ii[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->GetCurr(1,pos)
- m_Op_UPML->iifo[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]];
curr[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Op_UPML->ii[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->GetCurr(2,pos)
- m_Op_UPML->iifo[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]];
m_Eng->SetCurr(0,pos, curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]);
m_Eng->SetCurr(1,pos, curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]);
m_Eng->SetCurr(2,pos, curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]);
}
}
}
}
void Engine_Ext_UPML::DoPostCurrentUpdates()
{
if (m_Eng==NULL)
return;
unsigned int pos[3];
unsigned int loc_pos[3];
for (loc_pos[0]=0;loc_pos[0]<m_Op_UPML->m_numLines[0];++loc_pos[0])
{
pos[0] = loc_pos[0] + m_Op_UPML->m_StartPos[0];
for (loc_pos[1]=0;loc_pos[1]<m_Op_UPML->m_numLines[1];++loc_pos[1])
{
pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1];
for (loc_pos[2]=0;loc_pos[2]<m_Op_UPML->m_numLines[2];++loc_pos[2])
{
pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2];
curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetCurr(0,pos);
curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetCurr(1,pos);
curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetCurr(2,pos);
m_Eng->SetCurr(0,pos, curr[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] + m_Op_UPML->iifn[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]);
m_Eng->SetCurr(1,pos, curr[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] + m_Op_UPML->iifn[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]);
m_Eng->SetCurr(2,pos, curr[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] + m_Op_UPML->iifn[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]);
}
}
}
}

48
FDTD/engine_ext_upml.h Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2010 Thorsten Liebig (Thorsten.Liebig@gmx.de)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ENGINE_EXT_UPML_H
#define ENGINE_EXT_UPML_H
#include "engine_extension.h"
#include "engine.h"
#include "operator.h"
class Operator_Ext_UPML;
class Engine_Ext_UPML : public Engine_Extension
{
public:
Engine_Ext_UPML(Operator_Ext_UPML* op_ext);
virtual ~Engine_Ext_UPML();
virtual void DoPreVoltageUpdates();
virtual void DoPostVoltageUpdates();
virtual void DoPreCurrentUpdates();
virtual void DoPostCurrentUpdates();
protected:
Operator_Ext_UPML* m_Op_UPML;
FDTD_FLOAT**** volt;
FDTD_FLOAT**** curr;
FDTD_FLOAT**** volt_flux;
FDTD_FLOAT**** curr_flux;
};
#endif // ENGINE_EXT_UPML_H

View File

@ -563,6 +563,25 @@ int Operator::CalcECOperator()
}
}
//Apply PEC to all boundary's
bool PEC[6]={1,1,1,1,1,1};
//make an exception for BC == -1
for (int n=0;n<6;++n)
if ((m_BC[n]==-1))
PEC[n] = false;
ApplyElectricBC(PEC);
CalcPEC();
bool PMC[6];
for (int n=0;n<6;++n)
PMC[n] = m_BC[n]==1;
ApplyMagneticBC(PMC);
InitExcitation();
if (CalcFieldExcitation()==false) return -1;
//all information available for extension... create now...
for (size_t n=0;n<m_Op_exts.size();++n)
m_Op_exts.at(n)->BuildExtension();
@ -576,25 +595,6 @@ int Operator::CalcECOperator()
delete[] EC_R[n];EC_R[n]=NULL;
}
//Apply PEC to all boundary's
bool PEC[6]={1,1,1,1,1,1};
//exception for pml boundaries
for (int n=0;n<6;++n)
if ((m_BC[n]==3) || (m_BC[n]==-1))
PEC[n] = false;
ApplyElectricBC(PEC);
InitExcitation();
if (CalcFieldExcitation()==false) return -1;
CalcPEC();
bool PMC[6];
for (int n=0;n<6;++n)
PMC[n] = m_BC[n]==1;
ApplyMagneticBC(PMC);
return 0;
}
@ -654,6 +654,15 @@ void Operator::ApplyMagneticBC(bool* dirs)
GetIV(nP,pos[0],pos[1],pos[2]) *= (FDTD_FLOAT)!dirs[2*n+1];
GetII(nPP,pos[0],pos[1],pos[2]) *= (FDTD_FLOAT)!dirs[2*n+1];
GetIV(nPP,pos[0],pos[1],pos[2]) *= (FDTD_FLOAT)!dirs[2*n+1];
//the last current lines are outside the FDTD domain and cannot be iterated by the FDTD engine
pos[n]=numLines[n]-1;
GetII(n,pos[0],pos[1],pos[2]) = 0;
GetIV(n,pos[0],pos[1],pos[2]) = 0;
GetII(nP,pos[0],pos[1],pos[2]) = 0;
GetIV(nP,pos[0],pos[1],pos[2]) = 0;
GetII(nPP,pos[0],pos[1],pos[2]) = 0;
GetIV(nPP,pos[0],pos[1],pos[2]) = 0;
}
}
}

321
FDTD/operator_ext_upml.cpp Normal file
View File

@ -0,0 +1,321 @@
/*
* Copyright (C) 2010 Thorsten Liebig (Thorsten.Liebig@gmx.de)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "operator_ext_upml.h"
#include "operator_cylinder.h"
#include "engine_ext_upml.h"
#include "tools/array_ops.h"
#include "fparser.hh"
Operator_Ext_UPML::Operator_Ext_UPML(Operator* op) : Operator_Extension(op)
{
m_GradingFunction = new FunctionParser();
//default grading function
SetGradingFunction(" -log(1e-6)*log(2.5)/(2*dl*pow(2.5,W/dl)-1) * pow(2.5, D/dl) / Z ");
for (int n=0;n<6;++n)
{
m_BC[n]=0;
m_Size[n]=0;
}
for (int n=0;n<3;++n)
{
m_StartPos[n]=0;
m_numLines[n]=0;
}
vv = NULL;
vvfo = NULL;
vvfn = NULL;
ii = NULL;
iifo = NULL;
iifn = NULL;
}
Operator_Ext_UPML::~Operator_Ext_UPML()
{
delete m_GradingFunction;
m_GradingFunction = NULL;
DeleteOp();
}
bool Operator_Ext_UPML::Create_UPML(Operator* op, int BC[6], unsigned int size[6], string gradFunc)
{
Operator_Ext_UPML* op_ext_upml=NULL;
unsigned int start[3]={0 ,0 ,0};
unsigned int stop[3] ={op->GetNumberOfLines(0)-1,op->GetNumberOfLines(1)-1,op->GetNumberOfLines(2)-1};
//create a pml in x-direction over the full width of yz-space
if (BC[0]==3)
{
op_ext_upml = new Operator_Ext_UPML(op);
op_ext_upml->SetGradingFunction(gradFunc);
start[0]=0;
stop[0] =size[0];
op_ext_upml->SetBoundaryCondition(BC, size);
op_ext_upml->SetRange(start,stop);
op->AddExtension(op_ext_upml);
}
if (BC[1]==3)
{
op_ext_upml = new Operator_Ext_UPML(op);
op_ext_upml->SetGradingFunction(gradFunc);
start[0]=op->GetNumberOfLines(0)-1-size[1];
stop[0] =op->GetNumberOfLines(0)-1;
op_ext_upml->SetBoundaryCondition(BC, size);
op_ext_upml->SetRange(start,stop);
op->AddExtension(op_ext_upml);
}
//create a pml in y-direction over the xz-space (if a pml in x-direction already exists, skip that corner regions)
start[0]=(size[0]+1)*(BC[0]==3);
stop[0] =op->GetNumberOfLines(0)-1-(size[0]+1)*(BC[1]==3);
if (BC[2]==3)
{
op_ext_upml = new Operator_Ext_UPML(op);
op_ext_upml->SetGradingFunction(gradFunc);
start[1]=0;
stop[1] =size[2];
op_ext_upml->SetBoundaryCondition(BC, size);
op_ext_upml->SetRange(start,stop);
op->AddExtension(op_ext_upml);
}
if (BC[3]==3)
{
op_ext_upml = new Operator_Ext_UPML(op);
op_ext_upml->SetGradingFunction(gradFunc);
start[1]=op->GetNumberOfLines(1)-1-size[3];
stop[1] =op->GetNumberOfLines(1)-1;
op_ext_upml->SetBoundaryCondition(BC, size);
op_ext_upml->SetRange(start,stop);
op->AddExtension(op_ext_upml);
}
//create a pml in z-direction over the xy-space (if a pml in x- and/or y-direction already exists, skip that corner/edge regions)
start[1]=(size[2]+1)*(BC[2]==3);
stop[1] =op->GetNumberOfLines(1)-1-(size[3]+1)*(BC[3]==3);
if (BC[4]==3)
{
op_ext_upml = new Operator_Ext_UPML(op);
op_ext_upml->SetGradingFunction(gradFunc);
start[2]=0;
stop[2] =size[4];
op_ext_upml->SetBoundaryCondition(BC, size);
op_ext_upml->SetRange(start,stop);
op->AddExtension(op_ext_upml);
}
if (BC[5]==3)
{
op_ext_upml = new Operator_Ext_UPML(op);
op_ext_upml->SetGradingFunction(gradFunc);
start[2]=op->GetNumberOfLines(2)-1-size[5];
stop[2] =op->GetNumberOfLines(2)-1;
op_ext_upml->SetBoundaryCondition(BC, size);
op_ext_upml->SetRange(start,stop);
op->AddExtension(op_ext_upml);
}
return true;
}
void Operator_Ext_UPML::DeleteOp()
{
Delete_N_3DArray<FDTD_FLOAT>(vv,m_numLines);
vv = NULL;
Delete_N_3DArray<FDTD_FLOAT>(vvfo,m_numLines);
vvfo = NULL;
Delete_N_3DArray<FDTD_FLOAT>(vvfn,m_numLines);
vvfn = NULL;
Delete_N_3DArray<FDTD_FLOAT>(ii,m_numLines);
ii = NULL;
Delete_N_3DArray<FDTD_FLOAT>(iifo,m_numLines);
iifo = NULL;
Delete_N_3DArray<FDTD_FLOAT>(iifn,m_numLines);
iifn = NULL;
}
bool Operator_Ext_UPML::SetGradingFunction(string func)
{
if (func.empty())
return true;
m_GradFunc = func;
int res = m_GradingFunction->Parse(m_GradFunc.c_str(), "D,dl,W,Z,N");
if(res < 0) return true;
cerr << "Operator_Ext_UPML::SetGradingFunction: Warning, an error occured parsing the pml grading function (see below) ..." << endl;
cerr << func << "\n" << string(res, ' ') << "^\n" << m_GradingFunction->ErrorMsg() << "\n";
return false;
}
void Operator_Ext_UPML::CalcGradingKappa(int ny, unsigned int pos[3], double Zm[3], double kappa_v[3], double kappa_i[3])
{
double depth=0;
double width=0;
for (int n=0;n<3;++n)
{
if ((pos[n] <= m_Size[2*n]) && (m_BC[2*n]==3)) //lower pml in n-dir
{
width = (m_Op->GetDiscLine(n,m_Size[2*n]) - m_Op->GetDiscLine(n,0))*m_Op->GetGridDelta();
depth = width - (m_Op->GetDiscLine(n,pos[n]) - m_Op->GetDiscLine(n,0))*m_Op->GetGridDelta();
if (n==ny)
depth-=m_Op->GetMeshDelta(n,pos)/2;
double vars[5] = {depth, width/m_Size[2*n], width, Zm[n], m_Size[2*n]};
if (depth>0)
kappa_v[n] = m_GradingFunction->Eval(vars);
else
kappa_v[n]=0;
if (n==ny)
depth+=m_Op->GetMeshDelta(n,pos)/2;
if (n!=ny)
depth-=m_Op->GetMeshDelta(n,pos)/2;
if (depth<0)
depth=0;
vars[0]=depth;
if (depth>0)
kappa_i[n] = m_GradingFunction->Eval(vars);
else
kappa_i[n] = 0;
}
else if ((pos[n] >= m_Op->GetNumberOfLines(n) -1 -m_Size[2*n+1]) && (m_BC[2*n+1]==3)) //upper pml in n-dir
{
width = (m_Op->GetDiscLine(n,m_Op->GetNumberOfLines(n)-1) - m_Op->GetDiscLine(n,m_Op->GetNumberOfLines(n)-m_Size[2*n+1]-1))*m_Op->GetGridDelta();
depth = width - (m_Op->GetDiscLine(n,m_Op->GetNumberOfLines(n)-1) - m_Op->GetDiscLine(n,pos[n]))*m_Op->GetGridDelta();
if (n==ny)
depth+=m_Op->GetMeshDelta(n,pos)/2;
double vars[5] = {depth, width/(m_Size[2*n]), width, Zm[n], m_Size[2*n]};
if (depth>0)
kappa_v[n] = m_GradingFunction->Eval(vars);
else
kappa_v[n]=0;
if (n==ny)
depth-=m_Op->GetMeshDelta(n,pos)/2;
if (n!=ny)
depth+=m_Op->GetMeshDelta(n,pos)/2;
if (depth>width)
depth=0;
vars[0]=depth;
if (depth>0)
kappa_i[n] = m_GradingFunction->Eval(vars);
else
kappa_i[n]=0;
}
else
{
kappa_v[n] = 0;
kappa_i[n] = 0;
}
}
}
bool Operator_Ext_UPML::BuildExtension()
{
/*Calculate the upml coefficients as defined in:
Allen Taflove, computational electrodynamics - the FDTD method, third edition, chapter 7.8, pages 297-300
- modified by Thorsten Liebig to match the equivalent circuit (EC) FDTD method
- kappa is used for conductivities (instead of sigma)
*/
if (m_Op==NULL)
return false;
DeleteOp();
vv = Create_N_3DArray<FDTD_FLOAT>(m_numLines);
vvfo = Create_N_3DArray<FDTD_FLOAT>(m_numLines);
vvfn = Create_N_3DArray<FDTD_FLOAT>(m_numLines);
ii = Create_N_3DArray<FDTD_FLOAT>(m_numLines);
iifo = Create_N_3DArray<FDTD_FLOAT>(m_numLines);
iifn = Create_N_3DArray<FDTD_FLOAT>(m_numLines);
unsigned int pos[3];
unsigned int loc_pos[3];
int nP,nPP;
double kappa_v[3]={0,0,0};
double kappa_i[3]={0,0,0};
double eff_Mat[3][4];
double Zm[3];
double dT = m_Op->GetTimestep();
for (loc_pos[0]=0;loc_pos[0]<m_numLines[0];++loc_pos[0])
{
pos[0] = loc_pos[0] + m_StartPos[0];
for (loc_pos[1]=0;loc_pos[1]<m_numLines[1];++loc_pos[1])
{
pos[1] = loc_pos[1] + m_StartPos[1];
for (loc_pos[2]=0;loc_pos[2]<m_numLines[2];++loc_pos[2])
{
pos[2] = loc_pos[2] + m_StartPos[2];
//calc kappa here for all dir ...
m_Op->Calc_EffMatPos(0,pos,eff_Mat[0]);
m_Op->Calc_EffMatPos(1,pos,eff_Mat[1]);
m_Op->Calc_EffMatPos(2,pos,eff_Mat[2]);
Zm[0] = sqrt(eff_Mat[0][2]/eff_Mat[0][0]);
Zm[1] = sqrt(eff_Mat[1][2]/eff_Mat[1][0]);
Zm[2] = sqrt(eff_Mat[2][2]/eff_Mat[2][0]);
for (int n=0;n<3;++n)
{
CalcGradingKappa(n, pos,Zm,kappa_v,kappa_i);
nP = (n+1)%3;
nPP = (n+2)%3;
//check if pos is on PEC
if ( (m_Op->GetVV(n,pos[0],pos[1],pos[2]) + m_Op->GetVI(n,pos[0],pos[1],pos[2])) != 0 )
{
//modify the original operator to perform eq. (7.85) by the main engine (EC-FDTD: equation is multiplied by delta_n)
//the engine extension will replace the original voltages with the "voltage flux" (volt*eps0) prior to the voltage updates
//after the updates are done the extension will calculate the new voltages (see below) and place them back into the main field domain
m_Op->GetVV(n,pos[0],pos[1],pos[2]) = (2*__EPS0__ - kappa_v[nP]*dT) / (2*__EPS0__ + kappa_v[nP]*dT);
m_Op->GetVI(n,pos[0],pos[1],pos[2]) = (2*__EPS0__*dT) / (2*__EPS0__ + kappa_v[nP]*dT) * m_Op->GetEdgeLength(n,pos) / m_Op->GetEdgeArea(n,pos);
//operators needed by eq. (7.88) to calculate new voltages from old voltages and old and new "voltage fluxes"
vv [n][loc_pos[0]][loc_pos[1]][loc_pos[2]] = (2*__EPS0__ - kappa_v[nPP]*dT) / (2*__EPS0__ + kappa_v[nPP]*dT);
vvfn[n][loc_pos[0]][loc_pos[1]][loc_pos[2]] = (2*__EPS0__ + kappa_v[n]*dT) / (2*__EPS0__ + kappa_v[nPP]*dT)/eff_Mat[n][0];
vvfo[n][loc_pos[0]][loc_pos[1]][loc_pos[2]] = (2*__EPS0__ - kappa_v[n]*dT) / (2*__EPS0__ + kappa_v[nPP]*dT)/eff_Mat[n][0];
}
//check if pos is on PMC
if ( (m_Op->GetII(n,pos[0],pos[1],pos[2]) + m_Op->GetIV(n,pos[0],pos[1],pos[2])) != 0 )
{
//modify the original operator to perform eq. (7.89) by the main engine (EC-FDTD: equation is multiplied by delta_n)
//the engine extension will replace the original currents with the "current flux" (curr*mu0) prior to the current updates
//after the updates are done the extension will calculate the new currents (see below) and place them back into the main field domain
m_Op->GetII(n,pos[0],pos[1],pos[2]) = (2*__EPS0__ - kappa_i[nP]*dT) / (2*__EPS0__ + kappa_i[nP]*dT);
m_Op->GetIV(n,pos[0],pos[1],pos[2]) = (2*__EPS0__*dT) / (2*__EPS0__ + kappa_i[nP]*dT) * m_Op->GetEdgeLength(n,pos,true) / m_Op->GetEdgeArea(n,pos,true);
//operators needed by eq. (7.90) to calculate new currents from old currents and old and new "current fluxes"
ii [n][loc_pos[0]][loc_pos[1]][loc_pos[2]] = (2*__EPS0__ - kappa_i[nPP]*dT) / (2*__EPS0__ + kappa_i[nPP]*dT);
iifn[n][loc_pos[0]][loc_pos[1]][loc_pos[2]] = (2*__EPS0__ + kappa_i[n]*dT) / (2*__EPS0__ + kappa_i[nPP]*dT)/eff_Mat[n][2];
iifo[n][loc_pos[0]][loc_pos[1]][loc_pos[2]] = (2*__EPS0__ - kappa_i[n]*dT) / (2*__EPS0__ + kappa_i[nPP]*dT)/eff_Mat[n][2];
}
}
}
}
}
return true;
}
Engine_Extension* Operator_Ext_UPML::CreateEngineExtention()
{
Engine_Ext_UPML* eng_ext = new Engine_Ext_UPML(this);
return eng_ext;
}

88
FDTD/operator_ext_upml.h Normal file
View File

@ -0,0 +1,88 @@
/*
* Copyright (C) 2010 Thorsten Liebig (Thorsten.Liebig@gmx.de)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPERATOR_EXT_UPML_H
#define OPERATOR_EXT_UPML_H
#include "operator.h"
#include "operator_extension.h"
class FunctionParser;
//! Operator extension implemention an uniaxial perfectly matched layer (upml)
/*
The priority for this extension should be the highest of all extensions since this operator will use the main engine to perform vital parts in the upml implementation.
Therefore the voltages and currents as well as the operator are replaced during these update process.
This extension is propably incompatible with the most other extensions operating in the same regions.
*/
class Operator_Ext_UPML : public Operator_Extension
{
friend class Engine_Ext_UPML;
public:
virtual ~Operator_Ext_UPML();
void SetBoundaryCondition(int* BCs, unsigned int size[6]) {for (int n=0;n<6;++n) {m_BC[n]=BCs[n];m_Size[n]=size[n];}}
void SetRange(const unsigned int start[3], const unsigned int stop[3]) {for (int n=0;n<3;++n) {m_StartPos[n]=start[n];m_numLines[n]=stop[n]-start[n]+1;}}
//! Set the grading function for the pml
/*!
Define the pml grading grading function.
Predefined variables in this grading function are:
D = depth in the pml in meter
dl = mesh delta inside the pml in meter
W = width (length) of the pml in meter
N = number of cells for the pml
Z = wave impedance at the current depth and position
example: SetGradingFunction("-log(1e-6)*log(2.5)/(2*dl*pow(2.5,W/dl)-1) * pow(2.5, D/dl) / Z");
An empty function string will be ignored.
*/
virtual bool SetGradingFunction(string func);
virtual bool BuildExtension();
virtual Engine_Extension* CreateEngineExtention();
virtual string GetExtensionName() const {return string("Uniaxial PML Extension");}
//! Create the UPML
static bool Create_UPML(Operator* op, int BC[6], unsigned int size[6], string gradFunc);
protected:
Operator_Ext_UPML(Operator* op);
int m_BC[6];
unsigned int m_Size[6];
unsigned int m_StartPos[3];
unsigned int m_numLines[3];
string m_GradFunc;
FunctionParser* m_GradingFunction;
void CalcGradingKappa(int ny, unsigned int pos[3], double Zm[3], double kappa_v[3], double kappa_i[3]);
void DeleteOp();
FDTD_FLOAT**** vv; //calc new voltage from old voltage
FDTD_FLOAT**** vvfo; //calc new voltage from old voltage flux
FDTD_FLOAT**** vvfn; //calc new voltage from new voltage flux
FDTD_FLOAT**** ii; //calc new current from old current
FDTD_FLOAT**** iifo; //calc new current from old current flux
FDTD_FLOAT**** iifn; //calc new current from new current flux
};
#endif // OPERATOR_EXT_UPML_H

View File

@ -84,7 +84,9 @@ SOURCES += main.cpp \
FDTD/processmodematch.cpp \
FDTD/operator_cylindermultigrid.cpp \
FDTD/engine_cylindermultigrid.cpp \
FDTD/engine_ext_cylindermultigrid.cpp
FDTD/engine_ext_cylindermultigrid.cpp \
FDTD/operator_ext_upml.cpp \
FDTD/engine_ext_upml.cpp
HEADERS += tools/ErrorMsg.h \
tools/AdrOp.h \
tools/constants.h \
@ -126,7 +128,9 @@ HEADERS += tools/ErrorMsg.h \
FDTD/operator_cylindermultigrid.h \
FDTD/engine_cylindermultigrid.h \
FDTD/engine_ext_cylindermultigrid.h \
tools/aligned_allocator.h
tools/aligned_allocator.h \
FDTD/operator_ext_upml.h \
FDTD/engine_ext_upml.h
QMAKE_CXXFLAGS_RELEASE = -O3 \
-g \
-march=native

View File

@ -24,6 +24,7 @@
#include "FDTD/operator_multithread.h"
#include "FDTD/operator_ext_mur_abc.h"
#include "FDTD/operator_ext_pml_sf.h"
#include "FDTD/operator_ext_upml.h"
#include "FDTD/processvoltage.h"
#include "FDTD/processcurrent.h"
#include "FDTD/process_efield.h"
@ -191,7 +192,7 @@ bool openEMS::SetupBoundaryConditions(TiXmlElement* BC)
{
int EC; //error code of tinyxml
int bounds[6] = {0,0,0,0,0,0}; //default boundary cond. (PEC)
int pml_size[6] = {8,8,8,8,8,8}; //default pml size
unsigned int pml_size[6] = {8,8,8,8,8,8}; //default pml size
string s_bc;
const char* tmp = BC->Attribute("PML_Grading");
string pml_gradFunc;
@ -244,7 +245,9 @@ bool openEMS::SetupBoundaryConditions(TiXmlElement* BC)
FDTD_Op->AddExtension(op_ext_mur);
}
}
Build_Split_Field_PML(FDTD_Op,bounds,pml_size,pml_gradFunc);
//create the upml
Operator_Ext_UPML::Create_UPML(FDTD_Op,bounds,pml_size,pml_gradFunc);
return true;
}