diff options
author | Ruben Undheim <ruben.undheim@gmail.com> | 2016-07-05 18:02:38 +0200 |
---|---|---|
committer | Ruben Undheim <ruben.undheim@gmail.com> | 2016-07-05 18:02:38 +0200 |
commit | ef962f6008f25ab7cbd4ca21bcc72b97a1e2d76f (patch) | |
tree | 8149bee93d1a3f91d4503bfb3853adac4af0a85e /openEMS/FDTD |
Imported Upstream version 0.0.34
Diffstat (limited to 'openEMS/FDTD')
82 files changed, 14445 insertions, 0 deletions
diff --git a/openEMS/FDTD/CMakeLists.txt b/openEMS/FDTD/CMakeLists.txt new file mode 100644 index 0000000..b0358d3 --- /dev/null +++ b/openEMS/FDTD/CMakeLists.txt @@ -0,0 +1,30 @@ + +if (WITH_MPI) + set(MPI_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/openems_fdtd_mpi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_mpi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_mpi.cpp + ) +endif() + +set(SOURCES + ${SOURCES} + ${MPI_SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/engine.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_multithread.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_cylinder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_cylinder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_sse.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_sse.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_sse_compressed.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_sse_compressed.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_multithread.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/excitation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_cylindermultigrid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_cylindermultigrid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_interface_fdtd.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_interface_sse_fdtd.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_interface_cylindrical_fdtd.cpp + PARENT_SCOPE +) diff --git a/openEMS/FDTD/engine.cpp b/openEMS/FDTD/engine.cpp new file mode 100644 index 0000000..26725e6 --- /dev/null +++ b/openEMS/FDTD/engine.cpp @@ -0,0 +1,232 @@ +/* +* 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.h" +#include "extensions/engine_extension.h" +#include "extensions/operator_extension.h" +#include "tools/array_ops.h" + +//! \brief construct an Engine instance +//! it's the responsibility of the caller to free the returned pointer +Engine* Engine::New(const Operator* op) +{ + cout << "Create FDTD engine" << endl; + Engine* e = new Engine(op); + e->Init(); + return e; +} + +Engine::Engine(const Operator* op) +{ + m_type = BASIC; + numTS = 0; + Op = op; + for (int n=0; n<3; ++n) + numLines[n] = Op->GetNumberOfLines(n, true); + volt=NULL; + curr=NULL; +} + +Engine::~Engine() +{ + this->Reset(); +} + +void Engine::Init() +{ + numTS = 0; + volt = Create_N_3DArray<FDTD_FLOAT>(numLines); + curr = Create_N_3DArray<FDTD_FLOAT>(numLines); + + InitExtensions(); + SortExtensionByPriority(); +} + +void Engine::InitExtensions() +{ + for (size_t n=0; n<Op->GetNumberOfExtentions(); ++n) + { + Operator_Extension* op_ext = Op->GetExtension(n); + Engine_Extension* eng_ext = op_ext->CreateEngineExtention(); + if (eng_ext) + { + eng_ext->SetEngine(this); + m_Eng_exts.push_back(eng_ext); + } + } +} + +void Engine::ClearExtensions() +{ + for (size_t n=0; n<m_Eng_exts.size(); ++n) + delete m_Eng_exts.at(n); + m_Eng_exts.clear(); +} + +bool CompareExtensions(Engine_Extension* i, Engine_Extension* j) +{ + return (*i<*j); +} + +void Engine::SortExtensionByPriority() +{ + stable_sort(m_Eng_exts.begin(),m_Eng_exts.end(), CompareExtensions); + reverse(m_Eng_exts.begin(),m_Eng_exts.end()); + + if (g_settings.GetVerboseLevel()>1) + { + cout << "--- Engine::SortExtensionByPriority() ---" << endl; + for (size_t n=0; n<m_Eng_exts.size(); ++n) + cout << " #" << n << ": " << m_Eng_exts.at(n)->GetExtensionName() << " (" << m_Eng_exts.at(n)->GetPriority() << ")" << endl; + } +} + +void Engine::Reset() +{ + Delete_N_3DArray(volt,numLines); + volt=NULL; + Delete_N_3DArray(curr,numLines); + curr=NULL; + + ClearExtensions(); +} + +void Engine::UpdateVoltages(unsigned int startX, unsigned int numX) +{ + unsigned int pos[3]; + bool shift[3]; + + pos[0] = startX; + //voltage updates + for (unsigned int posX=0; posX<numX; ++posX) + { + shift[0]=pos[0]; + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + shift[1]=pos[1]; + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + shift[2]=pos[2]; + //do the updates here + //for x + volt[0][pos[0]][pos[1]][pos[2]] *= Op->vv[0][pos[0]][pos[1]][pos[2]]; + volt[0][pos[0]][pos[1]][pos[2]] += Op->vi[0][pos[0]][pos[1]][pos[2]] * ( curr[2][pos[0]][pos[1]][pos[2]] - curr[2][pos[0]][pos[1]-shift[1]][pos[2]] - curr[1][pos[0]][pos[1]][pos[2]] + curr[1][pos[0]][pos[1]][pos[2]-shift[2]]); + + //for y + volt[1][pos[0]][pos[1]][pos[2]] *= Op->vv[1][pos[0]][pos[1]][pos[2]]; + volt[1][pos[0]][pos[1]][pos[2]] += Op->vi[1][pos[0]][pos[1]][pos[2]] * ( curr[0][pos[0]][pos[1]][pos[2]] - curr[0][pos[0]][pos[1]][pos[2]-shift[2]] - curr[2][pos[0]][pos[1]][pos[2]] + curr[2][pos[0]-shift[0]][pos[1]][pos[2]]); + + //for z + volt[2][pos[0]][pos[1]][pos[2]] *= Op->vv[2][pos[0]][pos[1]][pos[2]]; + volt[2][pos[0]][pos[1]][pos[2]] += Op->vi[2][pos[0]][pos[1]][pos[2]] * ( curr[1][pos[0]][pos[1]][pos[2]] - curr[1][pos[0]-shift[0]][pos[1]][pos[2]] - curr[0][pos[0]][pos[1]][pos[2]] + curr[0][pos[0]][pos[1]-shift[1]][pos[2]]); + } + } + ++pos[0]; + } +} + +void Engine::UpdateCurrents(unsigned int startX, unsigned int numX) +{ + unsigned int pos[3]; + pos[0] = startX; + for (unsigned int posX=0; posX<numX; ++posX) + { + for (pos[1]=0; pos[1]<numLines[1]-1; ++pos[1]) + { + for (pos[2]=0; pos[2]<numLines[2]-1; ++pos[2]) + { + //do the updates here + //for x + curr[0][pos[0]][pos[1]][pos[2]] *= Op->ii[0][pos[0]][pos[1]][pos[2]]; + curr[0][pos[0]][pos[1]][pos[2]] += Op->iv[0][pos[0]][pos[1]][pos[2]] * ( volt[2][pos[0]][pos[1]][pos[2]] - volt[2][pos[0]][pos[1]+1][pos[2]] - volt[1][pos[0]][pos[1]][pos[2]] + volt[1][pos[0]][pos[1]][pos[2]+1]); + + //for y + curr[1][pos[0]][pos[1]][pos[2]] *= Op->ii[1][pos[0]][pos[1]][pos[2]]; + curr[1][pos[0]][pos[1]][pos[2]] += Op->iv[1][pos[0]][pos[1]][pos[2]] * ( volt[0][pos[0]][pos[1]][pos[2]] - volt[0][pos[0]][pos[1]][pos[2]+1] - volt[2][pos[0]][pos[1]][pos[2]] + volt[2][pos[0]+1][pos[1]][pos[2]]); + + //for z + curr[2][pos[0]][pos[1]][pos[2]] *= Op->ii[2][pos[0]][pos[1]][pos[2]]; + curr[2][pos[0]][pos[1]][pos[2]] += Op->iv[2][pos[0]][pos[1]][pos[2]] * ( volt[1][pos[0]][pos[1]][pos[2]] - volt[1][pos[0]+1][pos[1]][pos[2]] - volt[0][pos[0]][pos[1]][pos[2]] + volt[0][pos[0]][pos[1]+1][pos[2]]); + } + } + ++pos[0]; + } +} + +void Engine::DoPreVoltageUpdates() +{ + //execute extensions in reverse order -> highest priority gets access to the voltages last + for (int n=m_Eng_exts.size()-1; n>=0; --n) + m_Eng_exts.at(n)->DoPreVoltageUpdates(); + +} + +void Engine::DoPostVoltageUpdates() +{ + //execute extensions in normal order -> highest priority gets access to the voltages first + for (size_t n=0; n<m_Eng_exts.size(); ++n) + m_Eng_exts.at(n)->DoPostVoltageUpdates(); +} + +void Engine::Apply2Voltages() +{ + //execute extensions in normal order -> highest priority gets access to the voltages first + for (size_t n=0; n<m_Eng_exts.size(); ++n) + m_Eng_exts.at(n)->Apply2Voltages(); +} + +void Engine::DoPreCurrentUpdates() +{ + //execute extensions in reverse order -> highest priority gets access to the currents last + for (int n=m_Eng_exts.size()-1; n>=0; --n) + m_Eng_exts.at(n)->DoPreCurrentUpdates(); +} + +void Engine::DoPostCurrentUpdates() +{ + //execute extensions in normal order -> highest priority gets access to the currents first + for (size_t n=0; n<m_Eng_exts.size(); ++n) + m_Eng_exts.at(n)->DoPostCurrentUpdates(); +} + +void Engine::Apply2Current() +{ + //execute extensions in normal order -> highest priority gets access to the currents first + for (size_t n=0; n<m_Eng_exts.size(); ++n) + m_Eng_exts.at(n)->Apply2Current(); +} + +bool Engine::IterateTS(unsigned int iterTS) +{ + for (unsigned int iter=0; iter<iterTS; ++iter) + { + //voltage updates with extensions + DoPreVoltageUpdates(); + UpdateVoltages(0,numLines[0]); + DoPostVoltageUpdates(); + Apply2Voltages(); + + //current updates with extensions + DoPreCurrentUpdates(); + UpdateCurrents(0,numLines[0]-1); + DoPostCurrentUpdates(); + Apply2Current(); + + ++numTS; + } + return true; +} diff --git a/openEMS/FDTD/engine.h b/openEMS/FDTD/engine.h new file mode 100644 index 0000000..72d17e1 --- /dev/null +++ b/openEMS/FDTD/engine.h @@ -0,0 +1,104 @@ +/* +* 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_H +#define ENGINE_H + +#include <fstream> +#include "operator.h" + +namespace NS_Engine_Multithread +{ +class thread; // evil hack to access numTS from multithreading context +} + +class Engine_Extension; + +class Engine +{ +public: + enum EngineType + { + BASIC, SSE, UNKNOWN + }; + + static Engine* New(const Operator* op); + virtual ~Engine(); + + virtual void Init(); + virtual void Reset(); + + //!Iterate a number of timesteps + virtual bool IterateTS(unsigned int iterTS); + + virtual unsigned int GetNumberOfTimesteps() {return numTS;} + + //this access functions muss be overloaded by any new engine using a different storage model + inline virtual FDTD_FLOAT GetVolt( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return volt[n][x][y][z]; } + inline virtual FDTD_FLOAT GetVolt( unsigned int n, const unsigned int pos[3] ) const { return volt[n][pos[0]][pos[1]][pos[2]]; } + inline virtual FDTD_FLOAT GetCurr( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return curr[n][x][y][z]; } + inline virtual FDTD_FLOAT GetCurr( unsigned int n, const unsigned int pos[3] ) const { return curr[n][pos[0]][pos[1]][pos[2]]; } + + inline virtual void SetVolt( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value) { volt[n][x][y][z]=value; } + inline virtual void SetVolt( unsigned int n, const unsigned int pos[3], FDTD_FLOAT value ) { volt[n][pos[0]][pos[1]][pos[2]]=value; } + inline virtual void SetCurr( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value) { curr[n][x][y][z]=value; } + inline virtual void SetCurr( unsigned int n, const unsigned int pos[3], FDTD_FLOAT value ) { curr[n][pos[0]][pos[1]][pos[2]]=value; } + + //! Execute Pre-Voltage extension updates + virtual void DoPreVoltageUpdates(); + //! Main FDTD engine voltage updates + virtual void UpdateVoltages(unsigned int startX, unsigned int numX); + //! Execute Post-Voltage extension updates + virtual void DoPostVoltageUpdates(); + //! Apply extension voltage changes + virtual void Apply2Voltages(); + + //! Execute Pre-Current extension updates + virtual void DoPreCurrentUpdates(); + //! Main FDTD engine current updates + virtual void UpdateCurrents(unsigned int startX, unsigned int numX); + //! Execute Post-Current extension updates + virtual void DoPostCurrentUpdates(); + //! Apply extension current changes + virtual void Apply2Current(); + + inline size_t GetExtensionCount() {return m_Eng_exts.size();} + inline Engine_Extension* GetExtension(size_t nr) {return m_Eng_exts.at(nr);} + virtual void SortExtensionByPriority(); + + EngineType GetType() const {return m_type;} + +protected: + EngineType m_type; + + Engine(const Operator* op); + const Operator* Op; + + unsigned int numLines[3]; + + FDTD_FLOAT**** volt; + FDTD_FLOAT**** curr; + unsigned int numTS; + + virtual void InitExtensions(); + virtual void ClearExtensions(); + vector<Engine_Extension*> m_Eng_exts; + + friend class NS_Engine_Multithread::thread; // evil hack to access numTS from multithreading context +}; + +#endif // ENGINE_H diff --git a/openEMS/FDTD/engine_cylinder.cpp b/openEMS/FDTD/engine_cylinder.cpp new file mode 100644 index 0000000..8d62cb9 --- /dev/null +++ b/openEMS/FDTD/engine_cylinder.cpp @@ -0,0 +1,38 @@ +/* +* Copyright (C) 2012 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_cylinder.h" + +Engine_Cylinder::Engine_Cylinder(const Operator_Cylinder* op) : Engine_Multithread(op) +{ + m_Op_Cyl = op; +} + +Engine_Cylinder::~Engine_Cylinder() +{ + +} + +Engine_Cylinder* Engine_Cylinder::New(const Operator_Cylinder* op, unsigned int numThreads) +{ + cout << "Create FDTD engine (cylindrical mesh using sse compression + multithreading)" << endl; + Engine_Cylinder* e = new Engine_Cylinder(op); + e->setNumThreads(numThreads); + e->Init(); + return e; +} + diff --git a/openEMS/FDTD/engine_cylinder.h b/openEMS/FDTD/engine_cylinder.h new file mode 100644 index 0000000..cbf33c0 --- /dev/null +++ b/openEMS/FDTD/engine_cylinder.h @@ -0,0 +1,36 @@ +/* +* Copyright (C) 2012 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_CYLINDER_H +#define ENGINE_CYLINDER_H + +#include "operator_cylinder.h" +#include "engine_multithread.h" + +class Engine_Cylinder : public Engine_Multithread +{ +public: + static Engine_Cylinder* New(const Operator_Cylinder* op, unsigned int numThreads = 0); + virtual ~Engine_Cylinder(); + +protected: + Engine_Cylinder(const Operator_Cylinder* op); + + const Operator_Cylinder* m_Op_Cyl; +}; + +#endif // ENGINE_CYLINDER_H diff --git a/openEMS/FDTD/engine_cylindermultigrid.cpp b/openEMS/FDTD/engine_cylindermultigrid.cpp new file mode 100644 index 0000000..8e5ce85 --- /dev/null +++ b/openEMS/FDTD/engine_cylindermultigrid.cpp @@ -0,0 +1,226 @@ +/* +* 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_cylindermultigrid.h" +#include "operator_cylindermultigrid.h" +#include "extensions/engine_ext_cylindermultigrid.h" + +Engine_CylinderMultiGrid* Engine_CylinderMultiGrid::New(const Operator_CylinderMultiGrid* op, unsigned int numThreads) +{ + cout << "Create FDTD engine (cylindrical multi grid mesh using sse compression + multithreading)" << endl; + Engine_CylinderMultiGrid* e = new Engine_CylinderMultiGrid(op); + e->setNumThreads( numThreads ); + e->Init(); + return e; +} + +Engine_CylinderMultiGrid::Engine_CylinderMultiGrid(const Operator_CylinderMultiGrid* op) : Engine_Cylinder(op) +{ + Op_CMG = op; + + m_WaitOnBase = new boost::barrier(2); + m_WaitOnChild = new boost::barrier(2); + m_WaitOnSync = new boost::barrier(2); + + m_Eng_Ext_MG = new Engine_Ext_CylinderMultiGrid(NULL,true); + m_Eng_Ext_MG->SetBarrier(m_WaitOnBase, m_WaitOnChild, m_WaitOnSync); + m_Eng_Ext_MG->SetEngine(this); + + Engine* eng = op->GetInnerOperator()->CreateEngine(); + m_InnerEngine = dynamic_cast<Engine_Multithread*>(eng); + + Engine_Ext_CylinderMultiGrid* m_InnerEng_Ext_MG = new Engine_Ext_CylinderMultiGrid(NULL,false); + m_InnerEng_Ext_MG->SetBarrier(m_WaitOnBase, m_WaitOnChild, m_WaitOnSync); + + // if already has a base extension, switch places ... seems to be faster... + for (size_t n=0; n<m_InnerEngine->m_Eng_exts.size(); ++n) + { + Engine_Ext_CylinderMultiGrid* eng_mg = dynamic_cast<Engine_Ext_CylinderMultiGrid*>(m_InnerEngine->m_Eng_exts.at(n)); + if (eng_mg) + { + m_InnerEngine->m_Eng_exts.at(n) = m_InnerEng_Ext_MG; + m_InnerEng_Ext_MG = eng_mg; + break; + } + } + m_InnerEngine->m_Eng_exts.push_back(m_InnerEng_Ext_MG); +} + +Engine_CylinderMultiGrid::~Engine_CylinderMultiGrid() +{ +#ifdef MPI_SUPPORT + delete m_InnerEngine->m_MPI_Barrier; + m_InnerEngine->m_MPI_Barrier = NULL; +#endif + + m_Thread_NumTS = 0; + m_startBarrier->wait(); + + m_IteratorThread_Group.join_all(); + + delete m_InnerEngine; + m_InnerEngine = NULL; + + delete m_WaitOnBase; + m_WaitOnBase = NULL; + delete m_WaitOnChild; + m_WaitOnChild = NULL; + delete m_WaitOnSync; + m_WaitOnSync = NULL; + + delete m_startBarrier; + m_startBarrier = NULL; + delete m_stopBarrier; + m_stopBarrier = NULL; +} + +void Engine_CylinderMultiGrid::Init() +{ + Engine_Multithread::Init(); + + m_Eng_exts.push_back(m_Eng_Ext_MG); + + m_startBarrier = new boost::barrier(3); //both engines + organizer + m_stopBarrier = new boost::barrier(3); //both engines + organizer + + boost::thread *t = NULL; + + t = new boost::thread( Engine_CylinderMultiGrid_Thread(this,m_startBarrier,m_stopBarrier,&m_Thread_NumTS, true) ); + m_IteratorThread_Group.add_thread( t ); + + t = new boost::thread( Engine_CylinderMultiGrid_Thread(m_InnerEngine,m_startBarrier,m_stopBarrier,&m_Thread_NumTS, false) ); + m_IteratorThread_Group.add_thread( t ); + + m_InnerEngine->SortExtensionByPriority(); + SortExtensionByPriority(); + +#ifdef MPI_SUPPORT + //assign an MPI barrier to inner Engine + m_InnerEngine->m_MPI_Barrier = new boost::barrier(2); +#endif +} + +bool Engine_CylinderMultiGrid::IterateTS(unsigned int iterTS) +{ + m_Thread_NumTS = iterTS; + + m_startBarrier->wait(); //start base and child iterations + + m_stopBarrier->wait(); //tell base and child to wait for another start event... + + //interpolate child data to base mesh... + for (unsigned int n=0; n<Op_CMG->m_Split_Pos-1; ++n) + InterpolVoltChild2Base(n); + for (unsigned int n=0; n<Op_CMG->m_Split_Pos-2; ++n) + InterpolCurrChild2Base(n); + + return true; +} + +void Engine_CylinderMultiGrid::InterpolVoltChild2Base(unsigned int rPos) +{ + //interpolate voltages from child engine to the base engine... + unsigned int pos[3]; + pos[0] = rPos; + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + for (pos[2]=0; pos[2]<numVectors; ++pos[2]) + { + //r - direction + f4_volt[0][pos[0]][pos[1]][pos[2]].v = Op_CMG->f4_interpol_v_2p[0][pos[1]].v * m_InnerEngine->f4_volt[0][pos[0]][Op_CMG->m_interpol_pos_v_2p[0][pos[1]]][pos[2]].v + + Op_CMG->f4_interpol_v_2pp[0][pos[1]].v * m_InnerEngine->f4_volt[0][pos[0]][Op_CMG->m_interpol_pos_v_2pp[0][pos[1]]][pos[2]].v; + + //z - direction + f4_volt[2][pos[0]][pos[1]][pos[2]].v = Op_CMG->f4_interpol_v_2p[0][pos[1]].v * m_InnerEngine->f4_volt[2][pos[0]][Op_CMG->m_interpol_pos_v_2p[0][pos[1]]][pos[2]].v + + Op_CMG->f4_interpol_v_2pp[0][pos[1]].v * m_InnerEngine->f4_volt[2][pos[0]][Op_CMG->m_interpol_pos_v_2pp[0][pos[1]]][pos[2]].v; + + //alpha - direction + f4_volt[1][pos[0]][pos[1]][pos[2]].v = Op_CMG->f4_interpol_v_2p[1][pos[1]].v * m_InnerEngine->f4_volt[1][pos[0]][Op_CMG->m_interpol_pos_v_2p[1][pos[1]]][pos[2]].v + + Op_CMG->f4_interpol_v_2pp[1][pos[1]].v * m_InnerEngine->f4_volt[1][pos[0]][Op_CMG->m_interpol_pos_v_2pp[1][pos[1]]][pos[2]].v; + } + } +} + +void Engine_CylinderMultiGrid::InterpolCurrChild2Base(unsigned int rPos) +{ + //interpolate voltages from child engine to the base engine... + unsigned int pos[3]; + pos[0] = rPos; + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + for (pos[2]=0; pos[2]<numVectors; ++pos[2]) + { + //r - direction + f4_curr[0][pos[0]][pos[1]][pos[2]].v = Op_CMG->f4_interpol_i_2p[0][pos[1]].v * m_InnerEngine->f4_curr[0][pos[0]][Op_CMG->m_interpol_pos_i_2p[0][pos[1]]][pos[2]].v + + Op_CMG->f4_interpol_i_2pp[0][pos[1]].v * m_InnerEngine->f4_curr[0][pos[0]][Op_CMG->m_interpol_pos_i_2pp[0][pos[1]]][pos[2]].v; + + //z - direction + f4_curr[2][pos[0]][pos[1]][pos[2]].v = Op_CMG->f4_interpol_i_2p[0][pos[1]].v * m_InnerEngine->f4_curr[2][pos[0]][Op_CMG->m_interpol_pos_i_2p[0][pos[1]]][pos[2]].v + + Op_CMG->f4_interpol_i_2pp[0][pos[1]].v * m_InnerEngine->f4_curr[2][pos[0]][Op_CMG->m_interpol_pos_i_2pp[0][pos[1]]][pos[2]].v; + + //alpha - direction + f4_curr[1][pos[0]][pos[1]][pos[2]].v = Op_CMG->f4_interpol_i_2p[1][pos[1]].v * m_InnerEngine->f4_curr[1][pos[0]][Op_CMG->m_interpol_pos_i_2p[1][pos[1]]][pos[2]].v + + Op_CMG->f4_interpol_i_2pp[1][pos[1]].v * m_InnerEngine->f4_curr[1][pos[0]][Op_CMG->m_interpol_pos_i_2pp[1][pos[1]]][pos[2]].v; + } + } +} + +#ifdef MPI_SUPPORT + void Engine_CylinderMultiGrid::SendReceiveVoltages() + { + //do the local voltage sync, child is waiting... + Engine_Multithread::SendReceiveVoltages(); + + //run inner voltage sync + m_InnerEngine->m_MPI_Barrier->wait(); + } + + void Engine_CylinderMultiGrid::SendReceiveCurrents() + { + //do the local current sync, child is waiting... + Engine_Multithread::SendReceiveCurrents(); + + //run inner voltage sync + m_InnerEngine->m_MPI_Barrier->wait(); + } + +#endif + +/****************************************************************************************/ +Engine_CylinderMultiGrid_Thread::Engine_CylinderMultiGrid_Thread( Engine_Multithread* engine, boost::barrier *start, boost::barrier *stop, volatile unsigned int* numTS, bool isBase) +{ + m_startBarrier = start; + m_stopBarrier = stop; + m_Eng=engine; + m_isBase=isBase; + m_numTS = numTS; +} + +void Engine_CylinderMultiGrid_Thread::operator()() +{ + m_startBarrier->wait(); //wait for Base engine to start the iterations... + + while (*m_numTS>0) //m_numTS==0 request to terminate this thread... + { + if (m_isBase) + m_Eng->Engine_Multithread::IterateTS(*m_numTS); + else + m_Eng->IterateTS(*m_numTS); + m_stopBarrier->wait(); //sync all workers after iterations are performed + m_startBarrier->wait(); //wait for Base engine to start the iterations again ... + } +} diff --git a/openEMS/FDTD/engine_cylindermultigrid.h b/openEMS/FDTD/engine_cylindermultigrid.h new file mode 100644 index 0000000..66f337f --- /dev/null +++ b/openEMS/FDTD/engine_cylindermultigrid.h @@ -0,0 +1,85 @@ +/* +* 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_CYLINDERMULTIGRID_H +#define ENGINE_CYLINDERMULTIGRID_H + +#include "engine_cylinder.h" + +class Operator_CylinderMultiGrid; +class Engine_CylinderMultiGrid_Thread; +class Engine_Ext_CylinderMultiGrid; + +class Engine_CylinderMultiGrid : public Engine_Cylinder +{ + friend class Engine_Ext_CylinderMultiGrid; +public: +// Engine_CylinderMultiGrid(); + + static Engine_CylinderMultiGrid* New(const Operator_CylinderMultiGrid* op, unsigned int numThreads = 0); + virtual ~Engine_CylinderMultiGrid(); + + virtual void InterpolVoltChild2Base(unsigned int rPos); + virtual void InterpolCurrChild2Base(unsigned int rPos); + + virtual void Init(); + + //! Iterate \a iterTS number of timesteps + virtual bool IterateTS(unsigned int iterTS); + +protected: + Engine_CylinderMultiGrid(const Operator_CylinderMultiGrid* op); + const Operator_CylinderMultiGrid* Op_CMG; + + Engine_Multithread* m_InnerEngine; + + volatile unsigned int m_Thread_NumTS; + boost::thread_group m_IteratorThread_Group; + boost::barrier *m_startBarrier; + boost::barrier *m_stopBarrier; + Engine_CylinderMultiGrid_Thread* m_IteratorThread; + Engine_CylinderMultiGrid_Thread* m_InnerIteratorThread; + + //extension barrier + boost::barrier *m_WaitOnBase; + boost::barrier *m_WaitOnChild; + boost::barrier *m_WaitOnSync; + + Engine_Ext_CylinderMultiGrid* m_Eng_Ext_MG; + +#ifdef MPI_SUPPORT + virtual void SendReceiveVoltages(); + virtual void SendReceiveCurrents(); +#endif +}; + + +class Engine_CylinderMultiGrid_Thread +{ +public: + Engine_CylinderMultiGrid_Thread( Engine_Multithread* engine, boost::barrier *start, boost::barrier *stop, volatile unsigned int* numTS, bool isBase); + void operator()(); + +protected: + Engine_Multithread *m_Eng; + bool m_isBase; + boost::barrier *m_startBarrier; + boost::barrier *m_stopBarrier; + volatile unsigned int *m_numTS; +}; + +#endif // ENGINE_CYLINDERMULTIGRID_H diff --git a/openEMS/FDTD/engine_interface_cylindrical_fdtd.cpp b/openEMS/FDTD/engine_interface_cylindrical_fdtd.cpp new file mode 100644 index 0000000..065a4ef --- /dev/null +++ b/openEMS/FDTD/engine_interface_cylindrical_fdtd.cpp @@ -0,0 +1,64 @@ +/* +* Copyright (C) 2011 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_interface_cylindrical_fdtd.h" + +Engine_Interface_Cylindrical_FDTD::Engine_Interface_Cylindrical_FDTD(Operator_sse* op) : Engine_Interface_SSE_FDTD(op) +{ + m_Op_Cyl = dynamic_cast<Operator_Cylinder*>(op); + if (m_Op_Cyl==NULL) + { + cerr << "Engine_Interface_Cylindrical_FDTD::Engine_Interface_Cylindrical_FDTD: Error: Operator is not a cylindrical operator! Exit!" << endl; + exit(1); + } +} + +Engine_Interface_Cylindrical_FDTD::~Engine_Interface_Cylindrical_FDTD() +{ +} + +double* Engine_Interface_Cylindrical_FDTD::GetHField(const unsigned int* pos, double* out) const +{ + if (m_Op_Cyl->GetClosedAlpha()==false) + return Engine_Interface_FDTD::GetHField(pos, out); + + unsigned int iPos[] = {pos[0],pos[1],pos[2]}; + + if ((m_InterpolType==CELL_INTERPOLATE) && (pos[1]==m_Op->GetNumberOfLines(1))) + iPos[1]=0; + + if ((m_InterpolType==NODE_INTERPOLATE) && (iPos[1]==0)) + iPos[1]=m_Op->GetNumberOfLines(1); + + return Engine_Interface_FDTD::GetHField(iPos, out); +} + +double* Engine_Interface_Cylindrical_FDTD::GetRawInterpolatedField(const unsigned int* pos, double* out, int type) const +{ + if (m_Op_Cyl->GetClosedAlpha()==false) + return Engine_Interface_FDTD::GetRawInterpolatedField(pos,out,type); + + unsigned int iPos[] = {pos[0],pos[1],pos[2]}; + + if ((m_InterpolType==NODE_INTERPOLATE) && (pos[1]==0)) + iPos[1]=m_Op->GetNumberOfLines(1); + + if ((m_InterpolType==CELL_INTERPOLATE) && (pos[1]==m_Op->GetNumberOfLines(1))) + iPos[1]=0; + + return Engine_Interface_FDTD::GetRawInterpolatedField(iPos,out,type); +} diff --git a/openEMS/FDTD/engine_interface_cylindrical_fdtd.h b/openEMS/FDTD/engine_interface_cylindrical_fdtd.h new file mode 100644 index 0000000..adbe184 --- /dev/null +++ b/openEMS/FDTD/engine_interface_cylindrical_fdtd.h @@ -0,0 +1,39 @@ +/* +* Copyright (C) 2011 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_interface_sse_fdtd.h" +#include "operator_cylinder.h" + +#ifndef ENGINE_INTERFACE_CYLINDRICAL_FDTD_H +#define ENGINE_INTERFACE_CYLINDRICAL_FDTD_H + +class Engine_Interface_Cylindrical_FDTD : public Engine_Interface_SSE_FDTD +{ +public: + Engine_Interface_Cylindrical_FDTD(Operator_sse* op); + virtual ~Engine_Interface_Cylindrical_FDTD(); + + virtual double* GetHField(const unsigned int* pos, double* out) const; + +protected: + Operator_Cylinder* m_Op_Cyl; + + //! Internal method to get an interpolated field of a given type. (0: E, 1: J, 2: rotH) + virtual double* GetRawInterpolatedField(const unsigned int* pos, double* out, int type) const; +}; + +#endif // ENGINE_INTERFACE_CYLINDRICAL_FDTD_H diff --git a/openEMS/FDTD/engine_interface_fdtd.cpp b/openEMS/FDTD/engine_interface_fdtd.cpp new file mode 100644 index 0000000..b8fd9de --- /dev/null +++ b/openEMS/FDTD/engine_interface_fdtd.cpp @@ -0,0 +1,274 @@ +/* +* 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_interface_fdtd.h" + +Engine_Interface_FDTD::Engine_Interface_FDTD(Operator* op) : Engine_Interface_Base(op) +{ + if (op==NULL) + { + cerr << "Engine_Interface_FDTD::Engine_Interface_FDTD: Error: Operator is not set! Exit!" << endl; + exit(1); + } + m_Op = op; + m_Eng = m_Op->GetEngine(); + if (m_Eng==NULL) + { + cerr << "Engine_Interface_FDTD::Engine_Interface_FDTD: Error: Engine is not set! Exit!" << endl; + exit(1); + } +} + +Engine_Interface_FDTD::~Engine_Interface_FDTD() +{ +} + +double* Engine_Interface_FDTD::GetEField(const unsigned int* pos, double* out) const +{ + return GetRawInterpolatedField(pos, out, 0); +} + +double* Engine_Interface_FDTD::GetJField(const unsigned int* pos, double* out) const +{ + return GetRawInterpolatedField(pos, out, 1); +} + +double* Engine_Interface_FDTD::GetRotHField(const unsigned int* pos, double* out) const +{ + return GetRawInterpolatedField(pos, out, 2); +} + +double* Engine_Interface_FDTD::GetRawInterpolatedField(const unsigned int* pos, double* out, int type) const +{ + unsigned int iPos[] = {pos[0],pos[1],pos[2]}; + int nP,nPP; + double delta; + switch (m_InterpolType) + { + default: + case NO_INTERPOLATION: + for (int n=0; n<3; ++n) + out[n] = GetRawField(n,pos,type); + break; + case NODE_INTERPOLATE: + for (int n=0; n<3; ++n) + { + if (pos[n]==m_Op->GetNumberOfLines(n, true)-1) // use only the "lower value" at the upper bound + { + --iPos[n]; + out[n] = (double)GetRawField(n,iPos,type); + ++iPos[n]; + continue; + } + delta = m_Op->GetEdgeLength(n,iPos); + out[n] = GetRawField(n,iPos,type); + if (delta==0) + { + out[n]=0; + continue; + } + if (pos[n]==0) // use only the "upper value" at the lower bound + continue; + --iPos[n]; + double deltaDown = m_Op->GetEdgeLength(n,iPos); + double deltaRel = delta / (delta+deltaDown); + out[n] = out[n]*(1.0-deltaRel) + (double)GetRawField(n,iPos,type)*deltaRel; + ++iPos[n]; + } + break; + case CELL_INTERPOLATE: + for (int n=0; n<3; ++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + if ((pos[0]==m_Op->GetNumberOfLines(0,true)-1) || (pos[1]==m_Op->GetNumberOfLines(1,true)-1) || (pos[2]==m_Op->GetNumberOfLines(2,true)-1)) + { + out[n] = 0; //electric field outside the field domain is always zero + continue; + } + out[n]=GetRawField(n,iPos,type); + ++iPos[nP]; + out[n]+=GetRawField(n,iPos,type); + ++iPos[nPP]; + out[n]+=GetRawField(n,iPos,type); + --iPos[nP]; + out[n]+=GetRawField(n,iPos,type); + --iPos[nPP]; + out[n]/=4; + } + break; + } + return out; +} + +double* Engine_Interface_FDTD::GetHField(const unsigned int* pos, double* out) const +{ + unsigned int iPos[] = {pos[0],pos[1],pos[2]}; + int nP,nPP; + double delta; + switch (m_InterpolType) + { + default: + case NO_INTERPOLATION: + out[0] = m_Eng->GetCurr(0,pos) / m_Op->GetEdgeLength(0,pos,true); + out[1] = m_Eng->GetCurr(1,pos) / m_Op->GetEdgeLength(1,pos,true); + out[2] = m_Eng->GetCurr(2,pos) / m_Op->GetEdgeLength(2,pos,true); + break; + case NODE_INTERPOLATE: + for (int n=0; n<3; ++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + if ((pos[0]==m_Op->GetNumberOfLines(0,true)-1) || (pos[1]==m_Op->GetNumberOfLines(1,true)-1) || (pos[2]==m_Op->GetNumberOfLines(2,true)-1) || (pos[nP]==0) || (pos[nPP]==0)) + { + out[n] = 0; + continue; + } + out[n]=m_Eng->GetCurr(n,iPos)/m_Op->GetEdgeLength(n,iPos,true); + --iPos[nP]; + out[n]+=m_Eng->GetCurr(n,iPos)/m_Op->GetEdgeLength(n,iPos,true); + --iPos[nPP]; + out[n]+=m_Eng->GetCurr(n,iPos)/m_Op->GetEdgeLength(n,iPos,true); + ++iPos[nP]; + out[n]+=m_Eng->GetCurr(n,iPos)/m_Op->GetEdgeLength(n,iPos,true); + ++iPos[nPP]; + out[n]/=4; + } + break; + case CELL_INTERPOLATE: + for (int n=0; n<3; ++n) + { + delta = m_Op->GetEdgeLength(n,iPos,true); + out[n] = m_Eng->GetCurr(n,iPos); + if ((pos[n]>=m_Op->GetNumberOfLines(n,true)-1)) + { + out[n] = 0; //magnetic field on the outer boundaries is always zero + continue; + } + ++iPos[n]; + double deltaUp = m_Op->GetEdgeLength(n,iPos,true); + double deltaRel = delta / (delta+deltaUp); + out[n] = out[n]*(1.0-deltaRel)/delta + (double)m_Eng->GetCurr(n,iPos)/deltaUp*deltaRel; + --iPos[n]; + } + break; + } + + return out; +} + +double Engine_Interface_FDTD::CalcVoltageIntegral(const unsigned int* start, const unsigned int* stop) const +{ + double result=0; + for (int n=0; n<3; ++n) + { + if (start[n]<stop[n]) + { + unsigned int pos[3]={start[0],start[1],start[2]}; + for (; pos[n]<stop[n]; ++pos[n]) + result += m_Eng->GetVolt(n,pos[0],pos[1],pos[2]); + } + else + { + unsigned int pos[3]={stop[0],stop[1],stop[2]}; + for (; pos[n]<start[n]; ++pos[n]) + result -= m_Eng->GetVolt(n,pos[0],pos[1],pos[2]); + } + } + return result; +} + + +double Engine_Interface_FDTD::GetRawField(unsigned int n, const unsigned int* pos, int type) const +{ + double value = m_Eng->GetVolt(n,pos[0],pos[1],pos[2]); + double delta = m_Op->GetEdgeLength(n,pos); + if ((type==0) && (delta)) + return value/delta; + if ((type==1) && (m_Op->m_kappa) && (delta)) + return value*m_Op->m_kappa[n][pos[0]][pos[1]][pos[2]]/delta; + if (type==2) //calc rot(H) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + unsigned int locPos[] = {pos[0],pos[1],pos[2]}; + double area = m_Op->GetEdgeArea(n,pos); + value = m_Eng->GetCurr(nPP,pos); + value -= m_Eng->GetCurr(nP,pos); + if (pos[nPP]>0) + { + --locPos[nPP]; + value += m_Eng->GetCurr(nP,locPos); + ++locPos[nPP]; + } + if (pos[nP]>0) + { + --locPos[nP]; + value -= m_Eng->GetCurr(nPP,locPos); + } + return value/area; + } + + return 0.0; +} + +double Engine_Interface_FDTD::CalcFastEnergy() const +{ + double E_energy=0.0; + double H_energy=0.0; + + unsigned int pos[3]; + if (m_Eng->GetType()==Engine::BASIC) + { + for (pos[0]=0; pos[0]<m_Op->GetNumberOfLines(0)-1; ++pos[0]) + { + for (pos[1]=0; pos[1]<m_Op->GetNumberOfLines(1)-1; ++pos[1]) + { + for (pos[2]=0; pos[2]<m_Op->GetNumberOfLines(2)-1; ++pos[2]) + { + E_energy+=m_Eng->Engine::GetVolt(0,pos[0],pos[1],pos[2]) * m_Eng->Engine::GetVolt(0,pos[0],pos[1],pos[2]); + E_energy+=m_Eng->Engine::GetVolt(1,pos[0],pos[1],pos[2]) * m_Eng->Engine::GetVolt(1,pos[0],pos[1],pos[2]); + E_energy+=m_Eng->Engine::GetVolt(2,pos[0],pos[1],pos[2]) * m_Eng->Engine::GetVolt(2,pos[0],pos[1],pos[2]); + + H_energy+=m_Eng->Engine::GetCurr(0,pos[0],pos[1],pos[2]) * m_Eng->Engine::GetCurr(0,pos[0],pos[1],pos[2]); + H_energy+=m_Eng->Engine::GetCurr(1,pos[0],pos[1],pos[2]) * m_Eng->Engine::GetCurr(1,pos[0],pos[1],pos[2]); + H_energy+=m_Eng->Engine::GetCurr(2,pos[0],pos[1],pos[2]) * m_Eng->Engine::GetCurr(2,pos[0],pos[1],pos[2]); + } + } + } + } + else + { + for (pos[0]=0; pos[0]<m_Op->GetNumberOfLines(0)-1; ++pos[0]) + { + for (pos[1]=0; pos[1]<m_Op->GetNumberOfLines(1)-1; ++pos[1]) + { + for (pos[2]=0; pos[2]<m_Op->GetNumberOfLines(2)-1; ++pos[2]) + { + E_energy+=m_Eng->GetVolt(0,pos[0],pos[1],pos[2]) * m_Eng->GetVolt(0,pos[0],pos[1],pos[2]); + E_energy+=m_Eng->GetVolt(1,pos[0],pos[1],pos[2]) * m_Eng->GetVolt(1,pos[0],pos[1],pos[2]); + E_energy+=m_Eng->GetVolt(2,pos[0],pos[1],pos[2]) * m_Eng->GetVolt(2,pos[0],pos[1],pos[2]); + + H_energy+=m_Eng->GetCurr(0,pos[0],pos[1],pos[2]) * m_Eng->GetCurr(0,pos[0],pos[1],pos[2]); + H_energy+=m_Eng->GetCurr(1,pos[0],pos[1],pos[2]) * m_Eng->GetCurr(1,pos[0],pos[1],pos[2]); + H_energy+=m_Eng->GetCurr(2,pos[0],pos[1],pos[2]) * m_Eng->GetCurr(2,pos[0],pos[1],pos[2]); + } + } + } + } + return __EPS0__*E_energy + __MUE0__*H_energy; +} diff --git a/openEMS/FDTD/engine_interface_fdtd.h b/openEMS/FDTD/engine_interface_fdtd.h new file mode 100644 index 0000000..4e824ac --- /dev/null +++ b/openEMS/FDTD/engine_interface_fdtd.h @@ -0,0 +1,65 @@ +/* +* 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_INTERFACE_FDTD_H +#define ENGINE_INTERFACE_FDTD_H + +#include <cmath> + +#include "Common/engine_interface_base.h" +#include "operator.h" +#include "engine.h" + +class Engine_Interface_FDTD : public Engine_Interface_Base +{ +public: + Engine_Interface_FDTD(Operator* op); + virtual ~Engine_Interface_FDTD(); + + //! Set the FDTD operator + virtual void SetFDTDOperator(Operator* op) {SetOperator(op); m_Op=op;} + //! Set the FDTD engine + virtual void SetFDTDEngine(Engine* eng) {m_Eng=eng;} + + //! Get the FDTD engine in case direct access is needed. Direct access is not recommended! + const Engine* GetFDTDEngine() const {return m_Eng;} + //! Get the FDTD operator in case direct access is needed. Direct access is not recommended! + const Operator* GetFDTDOperator() const {return m_Op;} + + virtual double* GetEField(const unsigned int* pos, double* out) const; + virtual double* GetHField(const unsigned int* pos, double* out) const; + virtual double* GetJField(const unsigned int* pos, double* out) const; + virtual double* GetRotHField(const unsigned int* pos, double* out) const; + + virtual double CalcVoltageIntegral(const unsigned int* start, const unsigned int* stop) const; + + virtual double GetTime(bool dualTime=false) const {return ((double)m_Eng->GetNumberOfTimesteps() + (double)dualTime*0.5)*m_Op->GetTimestep();}; + virtual unsigned int GetNumberOfTimesteps() const {return m_Eng->GetNumberOfTimesteps();} + + virtual double CalcFastEnergy() const; + +protected: + Operator* m_Op; + Engine* m_Eng; + + //! Internal method to get an interpolated field of a given type. (0: E, 1: J, 2: rotH) + virtual double* GetRawInterpolatedField(const unsigned int* pos, double* out, int type) const; + //! Internal method to get a raw field of a given type. (0: E, 1: J, 2: rotH) + virtual double GetRawField(unsigned int n, const unsigned int* pos, int type) const; +}; + +#endif // ENGINE_INTERFACE_FDTD_H diff --git a/openEMS/FDTD/engine_interface_sse_fdtd.cpp b/openEMS/FDTD/engine_interface_sse_fdtd.cpp new file mode 100644 index 0000000..b7e9a3c --- /dev/null +++ b/openEMS/FDTD/engine_interface_sse_fdtd.cpp @@ -0,0 +1,69 @@ +/* +* Copyright (C) 2011 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_interface_sse_fdtd.h" + +Engine_Interface_SSE_FDTD::Engine_Interface_SSE_FDTD(Operator_sse* op) : Engine_Interface_FDTD(op) +{ + m_Op_SSE = op; + m_Eng_SSE = dynamic_cast<Engine_sse*>(m_Op_SSE->GetEngine()); + if (m_Eng_SSE==NULL) + { + cerr << "Engine_Interface_SSE_FDTD::Engine_Interface_SSE_FDTD: Error: SSE-Engine is not set! Exit!" << endl; + exit(1); + } +} + +Engine_Interface_SSE_FDTD::~Engine_Interface_SSE_FDTD() +{ + m_Op_SSE=NULL; + m_Eng_SSE=NULL; +} + +double Engine_Interface_SSE_FDTD::CalcFastEnergy() const +{ + f4vector E_energy; + E_energy.f[0]=0; + E_energy.f[1]=0; + E_energy.f[2]=0; + E_energy.f[3]=0; + f4vector H_energy; + H_energy = E_energy; + + if (m_Eng_SSE->GetType()!=Engine::SSE) + return Engine_Interface_FDTD::CalcFastEnergy(); + + unsigned int pos[3]; + for (pos[0]=0; pos[0]<m_Op_SSE->GetNumberOfLines(0)-1; ++pos[0]) + { + for (pos[1]=0; pos[1]<m_Op_SSE->GetNumberOfLines(1)-1; ++pos[1]) + { + for (pos[2]=0; pos[2]<m_Op_SSE->numVectors; ++pos[2]) + { + E_energy.v += m_Eng_SSE->Engine_sse::f4_volt[0][pos[0]][pos[1]][pos[2]].v * m_Eng_SSE->Engine_sse::f4_volt[0][pos[0]][pos[1]][pos[2]].v; + E_energy.v += m_Eng_SSE->Engine_sse::f4_volt[1][pos[0]][pos[1]][pos[2]].v * m_Eng_SSE->Engine_sse::f4_volt[1][pos[0]][pos[1]][pos[2]].v; + E_energy.v += m_Eng_SSE->Engine_sse::f4_volt[2][pos[0]][pos[1]][pos[2]].v * m_Eng_SSE->Engine_sse::f4_volt[2][pos[0]][pos[1]][pos[2]].v; + + H_energy.v += m_Eng_SSE->Engine_sse::f4_curr[0][pos[0]][pos[1]][pos[2]].v * m_Eng_SSE->Engine_sse::f4_curr[0][pos[0]][pos[1]][pos[2]].v; + H_energy.v += m_Eng_SSE->Engine_sse::f4_curr[1][pos[0]][pos[1]][pos[2]].v * m_Eng_SSE->Engine_sse::f4_curr[1][pos[0]][pos[1]][pos[2]].v; + H_energy.v += m_Eng_SSE->Engine_sse::f4_curr[2][pos[0]][pos[1]][pos[2]].v * m_Eng_SSE->Engine_sse::f4_curr[2][pos[0]][pos[1]][pos[2]].v; + } + } + } + + return __EPS0__*(E_energy.f[0]+E_energy.f[1]+E_energy.f[2]+E_energy.f[3]) + __MUE0__*(H_energy.f[0]+H_energy.f[1]+H_energy.f[2]+H_energy.f[3]); +} diff --git a/openEMS/FDTD/engine_interface_sse_fdtd.h b/openEMS/FDTD/engine_interface_sse_fdtd.h new file mode 100644 index 0000000..b8f837a --- /dev/null +++ b/openEMS/FDTD/engine_interface_sse_fdtd.h @@ -0,0 +1,38 @@ +/* +* Copyright (C) 2011 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_INTERFACE_SSE_FDTD_H +#define ENGINE_INTERFACE_SSE_FDTD_H + +#include "engine_interface_fdtd.h" +#include "operator_sse.h" +#include "engine_sse.h" + +class Engine_Interface_SSE_FDTD : public Engine_Interface_FDTD +{ +public: + Engine_Interface_SSE_FDTD(Operator_sse* op); + virtual ~Engine_Interface_SSE_FDTD(); + + virtual double CalcFastEnergy() const; + +protected: + Operator_sse* m_Op_SSE; + Engine_sse* m_Eng_SSE; +}; + +#endif // ENGINE_INTERFACE_SSE_FDTD_H diff --git a/openEMS/FDTD/engine_mpi.cpp b/openEMS/FDTD/engine_mpi.cpp new file mode 100644 index 0000000..c6a5b2c --- /dev/null +++ b/openEMS/FDTD/engine_mpi.cpp @@ -0,0 +1,211 @@ +/* +* Copyright (C) 2011 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_mpi.h" + +Engine_MPI* Engine_MPI::New(const Operator_MPI* op) +{ + cout << "Create FDTD engine (compressed SSE + MPI)" << endl; + Engine_MPI* e = new Engine_MPI(op); + e->Init(); + return e; +} + +Engine_MPI::Engine_MPI(const Operator_MPI* op) : Engine_SSE_Compressed(op) +{ + m_Op_MPI = op; +} + +Engine_MPI::~Engine_MPI() +{ + Reset(); +} + +void Engine_MPI::Init() +{ + Engine_SSE_Compressed::Init(); + + for (int i=0;i<3;++i) + { + m_BufferUp[i]=NULL; + m_BufferDown[i]=NULL; + m_BufferSize[i]=0; + } + + if (m_Op_MPI->GetMPIEnabled()) + { + // init buffers, nx*ny*2 for the tangential electric or magnetic fields at the interface + for (int n=0;n<3;++n) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + m_BufferSize[n] = m_Op_MPI->numLines[nP]*m_Op_MPI->numLines[nPP]; + + if (m_Op_MPI->m_NeighborDown[n]>=0) + { + m_BufferDown[n] = new float[m_BufferSize[n]*2]; + } + if (m_Op_MPI->m_NeighborUp[n]>=0) + { + m_BufferUp[n] = new float[m_BufferSize[n]*2]; + } + } + } +} + +void Engine_MPI::Reset() +{ + for (int i=0;i<3;++i) + { + delete[] m_BufferUp[i]; + delete[] m_BufferDown[i]; + m_BufferUp[i]=NULL; + m_BufferDown[i]=NULL; + m_BufferSize[i]=0; + } + + Engine_SSE_Compressed::Reset(); +} + +void Engine_MPI::SendReceiveVoltages() +{ + unsigned int pos[3]; + + //non-blocking prepare for receive... + for (int n=0;n<3;++n) + if (m_Op_MPI->m_NeighborDown[n]>=0) + MPI_Irecv( m_BufferDown[n] , m_BufferSize[n]*2, MPI_FLOAT, m_Op_MPI->m_NeighborDown[n], m_Op_MPI->m_MyTag, MPI_COMM_WORLD, &Recv_Request[n]); + + for (int n=0;n<3;++n) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + + //send voltages + unsigned int iPos=0; + pos[n]=numLines[n]-2; + if (m_Op_MPI->m_NeighborUp[n]>=0) + { + for (pos[nP]=0; pos[nP]<numLines[nP]; ++pos[nP]) + { + for (pos[nPP]=0; pos[nPP]<numLines[nPP]; ++pos[nPP]) + { + m_BufferUp[n][iPos++] = Engine_SSE_Compressed::GetVolt(nP ,pos); + m_BufferUp[n][iPos++] = Engine_SSE_Compressed::GetVolt(nPP,pos); + } + } + MPI_Isend( m_BufferUp[n] , m_BufferSize[n]*2, MPI_FLOAT, m_Op_MPI->m_NeighborUp[n], m_Op_MPI->m_MyTag, MPI_COMM_WORLD, &Send_Request[n]); + } + + //receive voltages + pos[n]=0; + iPos=0; + if (m_Op_MPI->m_NeighborDown[n]>=0) + { + //wait for receive to finish... + MPI_Wait(&Recv_Request[n],&stat); + for (pos[nP]=0; pos[nP]<numLines[nP]; ++pos[nP]) + { + for (pos[nPP]=0; pos[nPP]<numLines[nPP]; ++pos[nPP]) + { + Engine_SSE_Compressed::SetVolt(nP ,pos,m_BufferDown[n][iPos++]); + Engine_SSE_Compressed::SetVolt(nPP,pos,m_BufferDown[n][iPos++]); + } + } + } + + } +} + +void Engine_MPI::SendReceiveCurrents() +{ + unsigned int pos[3]; + + //non-blocking prepare for receive... + for (int n=0;n<3;++n) + if (m_Op_MPI->m_NeighborUp[n]>=0) + MPI_Irecv( m_BufferUp[n] , m_BufferSize[n]*2, MPI_FLOAT, m_Op_MPI->m_NeighborUp[n], m_Op_MPI->m_MyTag, MPI_COMM_WORLD, &Recv_Request[n]); + + for (int n=0;n<3;++n) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + + //send currents + unsigned int iPos=0; + pos[n]=0; + if (m_Op_MPI->m_NeighborDown[n]>=0) + { + for (pos[nP]=0; pos[nP]<numLines[nP]; ++pos[nP]) + { + for (pos[nPP]=0; pos[nPP]<numLines[nPP]; ++pos[nPP]) + { + m_BufferDown[n][iPos++] = Engine_SSE_Compressed::GetCurr(nP ,pos); + m_BufferDown[n][iPos++] = Engine_SSE_Compressed::GetCurr(nPP,pos); + } + } + MPI_Isend( m_BufferDown[n] , m_BufferSize[n]*2, MPI_FLOAT, m_Op_MPI->m_NeighborDown[n], m_Op_MPI->m_MyTag, MPI_COMM_WORLD, &Send_Request[n]); + } + + //receive currents + pos[n]=numLines[n]-2; + iPos=0; + if (m_Op_MPI->m_NeighborUp[n]>=0) + { + //wait for receive to finish... + MPI_Wait(&Recv_Request[n],&stat); + for (pos[nP]=0; pos[nP]<numLines[nP]; ++pos[nP]) + { + for (pos[nPP]=0; pos[nPP]<numLines[nPP]; ++pos[nPP]) + { + Engine_SSE_Compressed::SetCurr(nP ,pos,m_BufferUp[n][iPos++]); + Engine_SSE_Compressed::SetCurr(nPP,pos,m_BufferUp[n][iPos++]); + } + } + } + + } +} + +bool Engine_MPI::IterateTS(unsigned int iterTS) +{ + if (!m_Op_MPI->GetMPIEnabled()) + { + return Engine_SSE_Compressed::IterateTS(iterTS); + } + + for (unsigned int iter=0; iter<iterTS; ++iter) + { + //voltage updates with extensions + DoPreVoltageUpdates(); + UpdateVoltages(0,numLines[0]); + DoPostVoltageUpdates(); + Apply2Voltages(); + SendReceiveVoltages(); + + //current updates with extensions + DoPreCurrentUpdates(); + UpdateCurrents(0,numLines[0]-1); + DoPostCurrentUpdates(); + Apply2Current(); + SendReceiveCurrents(); + + ++numTS; + } + return true; +} + diff --git a/openEMS/FDTD/engine_mpi.h b/openEMS/FDTD/engine_mpi.h new file mode 100644 index 0000000..5aa1226 --- /dev/null +++ b/openEMS/FDTD/engine_mpi.h @@ -0,0 +1,57 @@ +/* +* Copyright (C) 2011 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_MPI_H +#define ENGINE_MPI_H + +#include "operator_mpi.h" +#include "engine_sse_compressed.h" +#include "mpi.h" + +class Engine_MPI : public Engine_SSE_Compressed +{ +public: + Engine_MPI(); + + static Engine_MPI* New(const Operator_MPI* op); + virtual ~Engine_MPI(); + + virtual void Init(); + virtual void Reset(); + + virtual bool IterateTS(unsigned int iterTS); + +protected: + Engine_MPI(const Operator_MPI* op); + const Operator_MPI* m_Op_MPI; + + MPI_Status stat; + MPI_Request Send_Request[3]; + MPI_Request Recv_Request[3]; + + //field buffer for MPI transfer... + unsigned int m_BufferSize[3]; + float* m_BufferUp[3]; + float* m_BufferDown[3]; + + //! Transfer all tangential voltages at the upper bounds to the lower bounds of the neighbouring MPI-processes + virtual void SendReceiveVoltages(); + //! Transfer all tangential currents at the lower bounds to the upper bounds of the neighbouring MPI-processes + virtual void SendReceiveCurrents(); +}; + +#endif // ENGINE_MPI_H diff --git a/openEMS/FDTD/engine_multithread.cpp b/openEMS/FDTD/engine_multithread.cpp new file mode 100644 index 0000000..7370198 --- /dev/null +++ b/openEMS/FDTD/engine_multithread.cpp @@ -0,0 +1,343 @@ +/* +* Copyright (C) 2010 Sebastian Held (sebastian.held@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/>. +*/ + +//#define ENABLE_DEBUG_TIME + +#ifdef ENABLE_DEBUG_TIME +#define DEBUG_TIME(x) x; +#else +#define DEBUG_TIME(x) ; +#endif + + + +#include "engine_multithread.h" +#include "extensions/engine_extension.h" +#include "tools/array_ops.h" + +#include "boost/date_time/posix_time/posix_time.hpp" +#include "boost/date_time/gregorian/gregorian.hpp" +#include <iomanip> +#include <xmmintrin.h> + +//! \brief construct an Engine_Multithread instance +//! it's the responsibility of the caller to free the returned pointer +Engine_Multithread* Engine_Multithread::New(const Operator_Multithread* op, unsigned int numThreads) +{ + cout << "Create FDTD engine (compressed SSE + multi-threading)" << endl; + Engine_Multithread* e = new Engine_Multithread(op); + e->setNumThreads( numThreads ); + e->Init(); + return e; +} + +Engine_Multithread::Engine_Multithread(const Operator_Multithread* op) : ENGINE_MULTITHREAD_BASE(op) +{ + m_Op_MT = op; + m_type = SSE; + m_IterateBarrier = 0; + m_startBarrier = 0; + m_stopBarrier = 0; + +#ifdef ENABLE_DEBUG_TIME + m_MPI_Barrier = 0; +#endif +} + +Engine_Multithread::~Engine_Multithread() +{ +#ifdef ENABLE_DEBUG_TIME + NS_Engine_Multithread::DBG().cout() << "Engine_Multithread::~Engine_Multithread()" << endl; + std::map<boost::thread::id, std::vector<double> >::iterator it; + for (it=m_timer_list.begin(); it!=m_timer_list.end(); it++) + { + NS_Engine_Multithread::DBG().cout() << "*** DEBUG Thread: " << it->first << std::endl; + std::vector<double>::iterator it2; + for (it2=it->second.begin(); it2<it->second.end();) + { + NS_Engine_Multithread::DBG().cout() << "after voltage update, before barrier1: " << fixed << setprecision(6) << *(it2++) << std::endl; + NS_Engine_Multithread::DBG().cout() << "after barrier1, before barrier2: " << fixed << setprecision(6) << *(it2++) << std::endl; + NS_Engine_Multithread::DBG().cout() << "after barrier2, before current update: " << fixed << setprecision(6) << *(it2++) << std::endl; + NS_Engine_Multithread::DBG().cout() << "after current update, before barrier3: " << fixed << setprecision(6) << *(it2++) << std::endl; + NS_Engine_Multithread::DBG().cout() << "after barrier3: " << fixed << setprecision(6) << *(it2++) << std::endl; + } + } +#endif + + Reset(); +} + +void Engine_Multithread::setNumThreads( unsigned int numThreads ) +{ + m_numThreads = numThreads; +} + +void Engine_Multithread::Init() +{ + m_stopThreads = true; + ENGINE_MULTITHREAD_BASE::Init(); + + // initialize threads + m_stopThreads = false; + if (m_numThreads == 0) + m_numThreads = boost::thread::hardware_concurrency(); + + vector<unsigned int> m_Start_Lines; + vector<unsigned int> m_Stop_Lines; + m_Op_MT->CalcStartStopLines( m_numThreads, m_Start_Lines, m_Stop_Lines ); + + if (g_settings.GetVerboseLevel()>0) + cout << "Multithreaded engine using " << m_numThreads << " threads. Utilization: ("; + m_IterateBarrier = new boost::barrier(m_numThreads); // numThread workers + + m_startBarrier = new boost::barrier(m_numThreads+1); // numThread workers + 1 controller + m_stopBarrier = new boost::barrier(m_numThreads+1); // numThread workers + 1 controller +#ifdef MPI_SUPPORT + m_MPI_Barrier = 0; +#endif + + for (unsigned int n=0; n<m_numThreads; n++) + { + unsigned int start = m_Start_Lines.at(n); + unsigned int stop = m_Stop_Lines.at(n); + unsigned int stop_h = stop; + if (n == m_numThreads-1) + { + // last thread + stop_h = stop-1; + if (g_settings.GetVerboseLevel()>0) + cout << stop-start+1 << ")" << endl; + } + else + if (g_settings.GetVerboseLevel()>0) + cout << stop-start+1 << ";"; +// NS_Engine_Multithread::DBG().cout() << "###DEBUG## Thread " << n << ": start=" << start << " stop=" << stop << " stop_h=" << stop_h << std::endl; + boost::thread *t = new boost::thread( NS_Engine_Multithread::thread(this,start,stop,stop_h,n) ); + m_thread_group.add_thread( t ); + } + + for (size_t n=0; n<m_Eng_exts.size(); ++n) + m_Eng_exts.at(n)->SetNumberOfThreads(m_numThreads); +} + +void Engine_Multithread::Reset() +{ + if (!m_stopThreads) // prevent multiple invocations + { + ClearExtensions(); //prevent extensions from interfering with thread reset... + + // stop the threads + //NS_Engine_Multithread::DBG().cout() << "stopping all threads" << endl; + m_iterTS = 1; + m_startBarrier->wait(); // start the threads + m_stopThreads = true; + m_stopBarrier->wait(); // wait for the threads to finish + m_thread_group.join_all(); // wait for termination + delete m_IterateBarrier; + m_IterateBarrier = 0; + delete m_startBarrier; + m_startBarrier = 0; + delete m_stopBarrier; + m_stopBarrier = 0; + } + + ENGINE_MULTITHREAD_BASE::Reset(); +} + +bool Engine_Multithread::IterateTS(unsigned int iterTS) +{ + m_iterTS = iterTS; + + //cout << "bool Engine_Multithread::IterateTS(): starting threads ..."; + m_startBarrier->wait(); // start the threads + + //cout << "... threads started"; + + m_stopBarrier->wait(); // wait for the threads to finish <iterTS> time steps + return true; +} + +void Engine_Multithread::DoPreVoltageUpdates(int threadID) +{ + //execute extensions in reverse order -> highest priority gets access to the voltages last + for (int n=m_Eng_exts.size()-1; n>=0; --n) + { + m_Eng_exts.at(n)->DoPreVoltageUpdates(threadID); + m_IterateBarrier->wait(); + } + +} + +void Engine_Multithread::DoPostVoltageUpdates(int threadID) +{ + //execute extensions in normal order -> highest priority gets access to the voltages first + for (size_t n=0; n<m_Eng_exts.size(); ++n) + { + m_Eng_exts.at(n)->DoPostVoltageUpdates(threadID); + m_IterateBarrier->wait(); + } +} + +void Engine_Multithread::Apply2Voltages(int threadID) +{ + //execute extensions in normal order -> highest priority gets access to the voltages first + for (size_t n=0; n<m_Eng_exts.size(); ++n) + { + m_Eng_exts.at(n)->Apply2Voltages(threadID); + m_IterateBarrier->wait(); + } +} + +void Engine_Multithread::DoPreCurrentUpdates(int threadID) +{ + //execute extensions in reverse order -> highest priority gets access to the currents last + for (int n=m_Eng_exts.size()-1; n>=0; --n) + { + m_Eng_exts.at(n)->DoPreCurrentUpdates(threadID); + m_IterateBarrier->wait(); + } +} + +void Engine_Multithread::DoPostCurrentUpdates(int threadID) +{ + //execute extensions in normal order -> highest priority gets access to the currents first + for (size_t n=0; n<m_Eng_exts.size(); ++n) + { + m_Eng_exts.at(n)->DoPostCurrentUpdates(threadID); + m_IterateBarrier->wait(); + } +} + +void Engine_Multithread::Apply2Current(int threadID) +{ + //execute extensions in normal order -> highest priority gets access to the currents first + for (size_t n=0; n<m_Eng_exts.size(); ++n) + { + m_Eng_exts.at(n)->Apply2Current(threadID); + m_IterateBarrier->wait(); + } +} + +// +// ************************************************************************************************************************* +// +namespace NS_Engine_Multithread +{ + +thread::thread( Engine_Multithread* ptr, unsigned int start, unsigned int stop, unsigned int stop_h, unsigned int threadID ) +{ + m_enginePtr = ptr; + m_start = start; + m_stop = stop; + m_stop_h = stop_h; + m_threadID = threadID; +} + +void thread::operator()() +{ + //std::cout << "thread::operator() Parameters: " << m_start << " " << m_stop << std::endl; + //DBG().cout() << "Thread " << m_threadID << " (" << boost::this_thread::get_id() << ") started." << endl; + + // speed up the calculation of denormal floating point values (flush-to-zero) +#ifndef SSE_CORRECT_DENORMALS + unsigned int oldMXCSR = _mm_getcsr(); //read the old MXCSR setting + unsigned int newMXCSR = oldMXCSR | 0x8040; // set DAZ and FZ bits + _mm_setcsr( newMXCSR ); //write the new MXCSR setting to the MXCSR +#endif + + while (!m_enginePtr->m_stopThreads) + { + // wait for start + //DBG().cout() << "Thread " << m_threadID << " (" << boost::this_thread::get_id() << ") waiting..." << endl; + m_enginePtr->m_startBarrier->wait(); + //cout << "Thread " << boost::this_thread::get_id() << " waiting... started." << endl; + + DEBUG_TIME( Timer timer1 ); + + for (unsigned int iter=0; iter<m_enginePtr->m_iterTS; ++iter) + { + // pre voltage stuff... + m_enginePtr->DoPreVoltageUpdates(m_threadID); + + //voltage updates + m_enginePtr->UpdateVoltages(m_start,m_stop-m_start+1); + + // record time + DEBUG_TIME( m_enginePtr->m_timer_list[boost::this_thread::get_id()].push_back( timer1.elapsed() ); ) + + //cout << "Thread " << boost::this_thread::get_id() << " m_barrier1 waiting..." << endl; + m_enginePtr->m_IterateBarrier->wait(); + + // record time + DEBUG_TIME( m_enginePtr->m_timer_list[boost::this_thread::get_id()].push_back( timer1.elapsed() ); ) + + //post voltage stuff... + m_enginePtr->DoPostVoltageUpdates(m_threadID); + m_enginePtr->Apply2Voltages(m_threadID); + +#ifdef MPI_SUPPORT + if (m_threadID==0) + { + if (m_enginePtr->m_MPI_Barrier) + m_enginePtr->m_MPI_Barrier->wait(); + m_enginePtr->SendReceiveVoltages(); + } + m_enginePtr->m_IterateBarrier->wait(); +#endif + + // record time + DEBUG_TIME( m_enginePtr->m_timer_list[boost::this_thread::get_id()].push_back( timer1.elapsed() ); ) + + //pre current stuff + m_enginePtr->DoPreCurrentUpdates(m_threadID); + + //current updates + m_enginePtr->UpdateCurrents(m_start,m_stop_h-m_start+1); + + // record time + DEBUG_TIME( m_enginePtr->m_timer_list[boost::this_thread::get_id()].push_back( timer1.elapsed() ); ) + m_enginePtr->m_IterateBarrier->wait(); + + // record time + DEBUG_TIME( m_enginePtr->m_timer_list[boost::this_thread::get_id()].push_back( timer1.elapsed() ); ) + + //post current stuff + m_enginePtr->DoPostCurrentUpdates(m_threadID); + m_enginePtr->Apply2Current(m_threadID); + +#ifdef MPI_SUPPORT + if (m_threadID==0) + { + if (m_enginePtr->m_MPI_Barrier) + m_enginePtr->m_MPI_Barrier->wait(); + m_enginePtr->SendReceiveCurrents(); + } + m_enginePtr->m_IterateBarrier->wait(); +#endif + + if (m_threadID == 0) + ++m_enginePtr->numTS; // only the first thread increments numTS + } + + m_enginePtr->m_stopBarrier->wait(); + } + + //DBG().cout() << "Thread " << m_threadID << " (" << boost::this_thread::get_id() << ") finished." << endl; +} + +} // namespace + diff --git a/openEMS/FDTD/engine_multithread.h b/openEMS/FDTD/engine_multithread.h new file mode 100644 index 0000000..20e7073 --- /dev/null +++ b/openEMS/FDTD/engine_multithread.h @@ -0,0 +1,127 @@ +/* +* Copyright (C) 2010 Sebastian Held (sebastian.held@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_MULTITHREAD_H +#define ENGINE_MULTITHREAD_H + +#include "operator_multithread.h" +#include "engine_sse_compressed.h" + +#include <boost/thread.hpp> +#include <boost/fusion/include/list.hpp> +#include <boost/fusion/container/list/list_fwd.hpp> +#include <boost/fusion/include/list_fwd.hpp> + +//#ifdef WIN32 +//#include <Winsock2.h> // for struct timeval +//#endif + +#include <sys/time.h> + +#ifdef MPI_SUPPORT + #define ENGINE_MULTITHREAD_BASE Engine_MPI + #include "engine_mpi.h" +#else + #define ENGINE_MULTITHREAD_BASE Engine_SSE_Compressed +#endif + + +class Engine_Multithread; + +namespace NS_Engine_Multithread +{ + +class DBG // debug +{ +public: + DBG() {} + ~DBG() { std::cout << os.str();} + std::ostringstream& cout() {return os;} +protected: + std::ostringstream os; +}; + +class Timer //debug +{ +public: + Timer() {gettimeofday(&t1,NULL);} + double elapsed() {gettimeofday(&t2,NULL); return (t2.tv_sec-t1.tv_sec) + (t2.tv_usec-t1.tv_usec)*1e-6;} +protected: + timeval t1,t2; +}; + +class thread +{ +public: + thread( Engine_Multithread* ptr, unsigned int start, unsigned int stop, unsigned int stop_h, unsigned int threadID ); + void operator()(); + +protected: + unsigned int m_start, m_stop, m_stop_h, m_threadID; + Engine_Multithread *m_enginePtr; +}; +} // namespace + + +class Engine_Multithread : public ENGINE_MULTITHREAD_BASE +{ + friend class NS_Engine_Multithread::thread; + friend class Engine_CylinderMultiGrid; +public: + static Engine_Multithread* New(const Operator_Multithread* op, unsigned int numThreads = 0); + virtual ~Engine_Multithread(); + + virtual void setNumThreads( unsigned int numThreads ); + virtual void Init(); + virtual void Reset(); + + //! Iterate \a iterTS number of timesteps + virtual bool IterateTS(unsigned int iterTS); + + virtual void DoPreVoltageUpdates(int threadID); + virtual void DoPostVoltageUpdates(int threadID); + virtual void Apply2Voltages(int threadID); + + virtual void DoPreCurrentUpdates(int threadID); + virtual void DoPostCurrentUpdates(int threadID); + virtual void Apply2Current(int threadID); + +protected: + Engine_Multithread(const Operator_Multithread* op); + const Operator_Multithread* m_Op_MT; + boost::thread_group m_thread_group; + boost::barrier *m_startBarrier, *m_stopBarrier; + boost::barrier *m_IterateBarrier; + volatile unsigned int m_iterTS; + unsigned int m_numThreads; //!< number of worker threads + volatile bool m_stopThreads; + +#ifdef MPI_SUPPORT + /*! Workaround needed for subgridding scheme... (see Engine_CylinderMultiGrid) + Some engines may need an additional barrier for synchronizing MPI communication. + This engine will not initialize or cleanup this barrier, but check for it and wait before executing any MPI sync. + Make sure to cleanup (delete) this barriere before Engine_Multithread::Reset() is called. + */ + boost::barrier *m_MPI_Barrier; +#endif + +#ifdef ENABLE_DEBUG_TIME + std::map<boost::thread::id, std::vector<double> > m_timer_list; +#endif +}; + +#endif // ENGINE_MULTITHREAD_H diff --git a/openEMS/FDTD/engine_sse.cpp b/openEMS/FDTD/engine_sse.cpp new file mode 100644 index 0000000..660e6d6 --- /dev/null +++ b/openEMS/FDTD/engine_sse.cpp @@ -0,0 +1,176 @@ +/* +* 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 <xmmintrin.h> +#include "engine_sse.h" + +//! \brief construct an Engine_sse instance +//! it's the responsibility of the caller to free the returned pointer +Engine_sse* Engine_sse::New(const Operator_sse* op) +{ + cout << "Create FDTD engine (SSE)" << endl; + Engine_sse* e = new Engine_sse(op); + e->Init(); + return e; +} + +Engine_sse::Engine_sse(const Operator_sse* op) : Engine(op) +{ + m_type = SSE; + Op = op; + f4_volt = 0; + f4_curr = 0; + numVectors = ceil((double)numLines[2]/4.0); + + // speed up the calculation of denormal floating point values (flush-to-zero) +#ifndef SSE_CORRECT_DENORMALS + unsigned int oldMXCSR = _mm_getcsr(); //read the old MXCSR setting + unsigned int newMXCSR = oldMXCSR | 0x8040; // set DAZ and FZ bits + _mm_setcsr( newMXCSR ); //write the new MXCSR setting to the MXCSR +#endif +} + +Engine_sse::~Engine_sse() +{ + //_mm_setcsr( oldMXCSR ); // restore old setting + Reset(); +} + +void Engine_sse::Init() +{ + Engine::Init(); + + Delete_N_3DArray(volt,numLines); + volt=NULL; // not used + Delete_N_3DArray(curr,numLines); + curr=NULL; // not used + + f4_volt = Create_N_3DArray_v4sf(numLines); + f4_curr = Create_N_3DArray_v4sf(numLines); +} + +void Engine_sse::Reset() +{ + Engine::Reset(); + Delete_N_3DArray_v4sf(f4_volt,numLines); + f4_volt = 0; + Delete_N_3DArray_v4sf(f4_curr,numLines); + f4_curr = 0; +} + +void Engine_sse::UpdateVoltages(unsigned int startX, unsigned int numX) +{ + unsigned int pos[3]; + bool shift[2]; + f4vector temp; + + pos[0] = startX; + for (unsigned int posX=0; posX<numX; ++posX) + { + shift[0]=pos[0]; + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + shift[1]=pos[1]; + for (pos[2]=1; pos[2]<numVectors; ++pos[2]) + { + // x-polarization + f4_volt[0][pos[0]][pos[1]][pos[2]].v *= Op->f4_vv[0][pos[0]][pos[1]][pos[2]].v; + f4_volt[0][pos[0]][pos[1]][pos[2]].v += Op->f4_vi[0][pos[0]][pos[1]][pos[2]].v * ( f4_curr[2][pos[0]][pos[1]][pos[2]].v - f4_curr[2][pos[0]][pos[1]-shift[1]][pos[2]].v - f4_curr[1][pos[0]][pos[1]][pos[2]].v + f4_curr[1][pos[0]][pos[1]][pos[2]-1].v ); + + // y-polarization + f4_volt[1][pos[0]][pos[1]][pos[2]].v *= Op->f4_vv[1][pos[0]][pos[1]][pos[2]].v; + f4_volt[1][pos[0]][pos[1]][pos[2]].v += Op->f4_vi[1][pos[0]][pos[1]][pos[2]].v * ( f4_curr[0][pos[0]][pos[1]][pos[2]].v - f4_curr[0][pos[0]][pos[1]][pos[2]-1].v - f4_curr[2][pos[0]][pos[1]][pos[2]].v + f4_curr[2][pos[0]-shift[0]][pos[1]][pos[2]].v); + + // z-polarization + f4_volt[2][pos[0]][pos[1]][pos[2]].v *= Op->f4_vv[2][pos[0]][pos[1]][pos[2]].v; + f4_volt[2][pos[0]][pos[1]][pos[2]].v += Op->f4_vi[2][pos[0]][pos[1]][pos[2]].v * ( f4_curr[1][pos[0]][pos[1]][pos[2]].v - f4_curr[1][pos[0]-shift[0]][pos[1]][pos[2]].v - f4_curr[0][pos[0]][pos[1]][pos[2]].v + f4_curr[0][pos[0]][pos[1]-shift[1]][pos[2]].v); + } + + // for pos[2] = 0 + // x-polarization + temp.f[0] = 0; + temp.f[1] = f4_curr[1][pos[0]][pos[1]][numVectors-1].f[0]; + temp.f[2] = f4_curr[1][pos[0]][pos[1]][numVectors-1].f[1]; + temp.f[3] = f4_curr[1][pos[0]][pos[1]][numVectors-1].f[2]; + f4_volt[0][pos[0]][pos[1]][0].v *= Op->f4_vv[0][pos[0]][pos[1]][0].v; + f4_volt[0][pos[0]][pos[1]][0].v += Op->f4_vi[0][pos[0]][pos[1]][0].v * ( f4_curr[2][pos[0]][pos[1]][0].v - f4_curr[2][pos[0]][pos[1]-shift[1]][0].v - f4_curr[1][pos[0]][pos[1]][0].v + temp.v ); + + // y-polarization + temp.f[0] = 0; + temp.f[1] = f4_curr[0][pos[0]][pos[1]][numVectors-1].f[0]; + temp.f[2] = f4_curr[0][pos[0]][pos[1]][numVectors-1].f[1]; + temp.f[3] = f4_curr[0][pos[0]][pos[1]][numVectors-1].f[2]; + f4_volt[1][pos[0]][pos[1]][0].v *= Op->f4_vv[1][pos[0]][pos[1]][0].v; + f4_volt[1][pos[0]][pos[1]][0].v += Op->f4_vi[1][pos[0]][pos[1]][0].v * ( f4_curr[0][pos[0]][pos[1]][0].v - temp.v - f4_curr[2][pos[0]][pos[1]][0].v + f4_curr[2][pos[0]-shift[0]][pos[1]][0].v); + + // z-polarization + f4_volt[2][pos[0]][pos[1]][0].v *= Op->f4_vv[2][pos[0]][pos[1]][0].v; + f4_volt[2][pos[0]][pos[1]][0].v += Op->f4_vi[2][pos[0]][pos[1]][0].v * ( f4_curr[1][pos[0]][pos[1]][0].v - f4_curr[1][pos[0]-shift[0]][pos[1]][0].v - f4_curr[0][pos[0]][pos[1]][0].v + f4_curr[0][pos[0]][pos[1]-shift[1]][0].v); + } + ++pos[0]; + } +} + +void Engine_sse::UpdateCurrents(unsigned int startX, unsigned int numX) +{ + unsigned int pos[5]; + f4vector temp; + + pos[0] = startX; + for (unsigned int posX=0; posX<numX; ++posX) + { + for (pos[1]=0; pos[1]<numLines[1]-1; ++pos[1]) + { + for (pos[2]=0; pos[2]<numVectors-1; ++pos[2]) + { + // x-pol + f4_curr[0][pos[0]][pos[1]][pos[2]].v *= Op->f4_ii[0][pos[0]][pos[1]][pos[2]].v; + f4_curr[0][pos[0]][pos[1]][pos[2]].v += Op->f4_iv[0][pos[0]][pos[1]][pos[2]].v * ( f4_volt[2][pos[0]][pos[1]][pos[2]].v - f4_volt[2][pos[0]][pos[1]+1][pos[2]].v - f4_volt[1][pos[0]][pos[1]][pos[2]].v + f4_volt[1][pos[0]][pos[1]][pos[2]+1].v); + + // y-pol + f4_curr[1][pos[0]][pos[1]][pos[2]].v *= Op->f4_ii[1][pos[0]][pos[1]][pos[2]].v; + f4_curr[1][pos[0]][pos[1]][pos[2]].v += Op->f4_iv[1][pos[0]][pos[1]][pos[2]].v * ( f4_volt[0][pos[0]][pos[1]][pos[2]].v - f4_volt[0][pos[0]][pos[1]][pos[2]+1].v - f4_volt[2][pos[0]][pos[1]][pos[2]].v + f4_volt[2][pos[0]+1][pos[1]][pos[2]].v); + + // z-pol + f4_curr[2][pos[0]][pos[1]][pos[2]].v *= Op->f4_ii[2][pos[0]][pos[1]][pos[2]].v; + f4_curr[2][pos[0]][pos[1]][pos[2]].v += Op->f4_iv[2][pos[0]][pos[1]][pos[2]].v * ( f4_volt[1][pos[0]][pos[1]][pos[2]].v - f4_volt[1][pos[0]+1][pos[1]][pos[2]].v - f4_volt[0][pos[0]][pos[1]][pos[2]].v + f4_volt[0][pos[0]][pos[1]+1][pos[2]].v); + } + + // for pos[2] = numVectors-1 + // x-pol + temp.f[0] = f4_volt[1][pos[0]][pos[1]][0].f[1]; + temp.f[1] = f4_volt[1][pos[0]][pos[1]][0].f[2]; + temp.f[2] = f4_volt[1][pos[0]][pos[1]][0].f[3]; + temp.f[3] = 0; + f4_curr[0][pos[0]][pos[1]][numVectors-1].v *= Op->f4_ii[0][pos[0]][pos[1]][numVectors-1].v; + f4_curr[0][pos[0]][pos[1]][numVectors-1].v += Op->f4_iv[0][pos[0]][pos[1]][numVectors-1].v * ( f4_volt[2][pos[0]][pos[1]][numVectors-1].v - f4_volt[2][pos[0]][pos[1]+1][numVectors-1].v - f4_volt[1][pos[0]][pos[1]][numVectors-1].v + temp.v); + + // y-pol + temp.f[0] = f4_volt[0][pos[0]][pos[1]][0].f[1]; + temp.f[1] = f4_volt[0][pos[0]][pos[1]][0].f[2]; + temp.f[2] = f4_volt[0][pos[0]][pos[1]][0].f[3]; + temp.f[3] = 0; + f4_curr[1][pos[0]][pos[1]][numVectors-1].v *= Op->f4_ii[1][pos[0]][pos[1]][numVectors-1].v; + f4_curr[1][pos[0]][pos[1]][numVectors-1].v += Op->f4_iv[1][pos[0]][pos[1]][numVectors-1].v * ( f4_volt[0][pos[0]][pos[1]][numVectors-1].v - temp.v - f4_volt[2][pos[0]][pos[1]][numVectors-1].v + f4_volt[2][pos[0]+1][pos[1]][numVectors-1].v); + + // z-pol + f4_curr[2][pos[0]][pos[1]][numVectors-1].v *= Op->f4_ii[2][pos[0]][pos[1]][numVectors-1].v; + f4_curr[2][pos[0]][pos[1]][numVectors-1].v += Op->f4_iv[2][pos[0]][pos[1]][numVectors-1].v * ( f4_volt[1][pos[0]][pos[1]][numVectors-1].v - f4_volt[1][pos[0]+1][pos[1]][numVectors-1].v - f4_volt[0][pos[0]][pos[1]][numVectors-1].v + f4_volt[0][pos[0]][pos[1]+1][numVectors-1].v); + } + ++pos[0]; + } +} diff --git a/openEMS/FDTD/engine_sse.h b/openEMS/FDTD/engine_sse.h new file mode 100644 index 0000000..9389f84 --- /dev/null +++ b/openEMS/FDTD/engine_sse.h @@ -0,0 +1,60 @@ +/* +* 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_SSE_H +#define ENGINE_SSE_H + +#include "engine.h" +#include "operator_sse.h" + +class Engine_sse : public Engine +{ +public: + static Engine_sse* New(const Operator_sse* op); + virtual ~Engine_sse(); + + virtual void Init(); + virtual void Reset(); + + virtual unsigned int GetNumberOfTimesteps() {return numTS;}; + + //this access functions muss be overloaded by any new engine using a different storage model + inline virtual FDTD_FLOAT GetVolt( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return f4_volt[n][x][y][z%numVectors].f[z/numVectors]; } + inline virtual FDTD_FLOAT GetVolt( unsigned int n, const unsigned int pos[3] ) const { return f4_volt[n][pos[0]][pos[1]][pos[2]%numVectors].f[pos[2]/numVectors]; } + inline virtual FDTD_FLOAT GetCurr( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return f4_curr[n][x][y][z%numVectors].f[z/numVectors]; } + inline virtual FDTD_FLOAT GetCurr( unsigned int n, const unsigned int pos[3] ) const { return f4_curr[n][pos[0]][pos[1]][pos[2]%numVectors].f[pos[2]/numVectors]; } + + inline virtual void SetVolt( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value) { f4_volt[n][x][y][z%numVectors].f[z/numVectors]=value; } + inline virtual void SetVolt( unsigned int n, const unsigned int pos[3], FDTD_FLOAT value ) { f4_volt[n][pos[0]][pos[1]][pos[2]%numVectors].f[pos[2]/numVectors]=value; } + inline virtual void SetCurr( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value) { f4_curr[n][x][y][z%numVectors].f[z/numVectors]=value; } + inline virtual void SetCurr( unsigned int n, const unsigned int pos[3], FDTD_FLOAT value ) { f4_curr[n][pos[0]][pos[1]][pos[2]%numVectors].f[pos[2]/numVectors]=value; } + +protected: + Engine_sse(const Operator_sse* op); + const Operator_sse* Op; + + virtual void UpdateVoltages(unsigned int startX, unsigned int numX); + virtual void UpdateCurrents(unsigned int startX, unsigned int numX); + + unsigned int numVectors; + +public: //public access to the sse arrays for efficient extensions access... use careful... + f4vector**** f4_volt; + f4vector**** f4_curr; +}; + +#endif // ENGINE_SSE_H diff --git a/openEMS/FDTD/engine_sse_compressed.cpp b/openEMS/FDTD/engine_sse_compressed.cpp new file mode 100644 index 0000000..8e83387 --- /dev/null +++ b/openEMS/FDTD/engine_sse_compressed.cpp @@ -0,0 +1,163 @@ +/* +* 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_sse_compressed.h" +#ifdef __SSE2__ +#include <emmintrin.h> +#endif + +Engine_SSE_Compressed* Engine_SSE_Compressed::New(const Operator_SSE_Compressed* op) +{ + cout << "Create FDTD engine (compressed SSE)" << endl; + Engine_SSE_Compressed* e = new Engine_SSE_Compressed(op); + e->Init(); + return e; +} + +Engine_SSE_Compressed::Engine_SSE_Compressed(const Operator_SSE_Compressed* op) : Engine_sse(op) +{ + Op = op; +} + +Engine_SSE_Compressed::~Engine_SSE_Compressed() +{ +} + +void Engine_SSE_Compressed::UpdateVoltages(unsigned int startX, unsigned int numX) +{ + unsigned int pos[3]; + bool shift[2]; + f4vector temp; + + pos[0] = startX; + unsigned int index=0; + for (unsigned int posX=0; posX<numX; ++posX) + { + shift[0]=pos[0]; + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + shift[1]=pos[1]; + for (pos[2]=1; pos[2]<numVectors; ++pos[2]) + { + index = Op->m_Op_index[pos[0]][pos[1]][pos[2]]; + // x-polarization + f4_volt[0][pos[0]][pos[1]][pos[2]].v *= Op->f4_vv_Compressed[0][index].v; + f4_volt[0][pos[0]][pos[1]][pos[2]].v += Op->f4_vi_Compressed[0][index].v * ( f4_curr[2][pos[0]][pos[1]][pos[2]].v - f4_curr[2][pos[0]][pos[1]-shift[1]][pos[2]].v - f4_curr[1][pos[0]][pos[1]][pos[2]].v + f4_curr[1][pos[0]][pos[1]][pos[2]-1].v ); + + // y-polarization + f4_volt[1][pos[0]][pos[1]][pos[2]].v *= Op->f4_vv_Compressed[1][index].v; + f4_volt[1][pos[0]][pos[1]][pos[2]].v += Op->f4_vi_Compressed[1][index].v * ( f4_curr[0][pos[0]][pos[1]][pos[2]].v - f4_curr[0][pos[0]][pos[1]][pos[2]-1].v - f4_curr[2][pos[0]][pos[1]][pos[2]].v + f4_curr[2][pos[0]-shift[0]][pos[1]][pos[2]].v); + + // z-polarization + f4_volt[2][pos[0]][pos[1]][pos[2]].v *= Op->f4_vv_Compressed[2][index].v; + f4_volt[2][pos[0]][pos[1]][pos[2]].v += Op->f4_vi_Compressed[2][index].v * ( f4_curr[1][pos[0]][pos[1]][pos[2]].v - f4_curr[1][pos[0]-shift[0]][pos[1]][pos[2]].v - f4_curr[0][pos[0]][pos[1]][pos[2]].v + f4_curr[0][pos[0]][pos[1]-shift[1]][pos[2]].v); + } + + // for pos[2] = 0 + // x-polarization + index = Op->m_Op_index[pos[0]][pos[1]][0]; +#ifdef __SSE2__ + temp.v = (__m128)_mm_slli_si128( (__m128i)f4_curr[1][pos[0]][pos[1]][numVectors-1].v, 4 ); +#else + temp.f[0] = 0; + temp.f[1] = f4_curr[1][pos[0]][pos[1]][numVectors-1].f[0]; + temp.f[2] = f4_curr[1][pos[0]][pos[1]][numVectors-1].f[1]; + temp.f[3] = f4_curr[1][pos[0]][pos[1]][numVectors-1].f[2]; +#endif + f4_volt[0][pos[0]][pos[1]][0].v *= Op->f4_vv_Compressed[0][index].v; + f4_volt[0][pos[0]][pos[1]][0].v += Op->f4_vi_Compressed[0][index].v * ( f4_curr[2][pos[0]][pos[1]][0].v - f4_curr[2][pos[0]][pos[1]-shift[1]][0].v - f4_curr[1][pos[0]][pos[1]][0].v + temp.v ); + + // y-polarization +#ifdef __SSE2__ + temp.v = (__m128)_mm_slli_si128( (__m128i)f4_curr[0][pos[0]][pos[1]][numVectors-1].v, 4 ); +#else + temp.f[0] = 0; + temp.f[1] = f4_curr[0][pos[0]][pos[1]][numVectors-1].f[0]; + temp.f[2] = f4_curr[0][pos[0]][pos[1]][numVectors-1].f[1]; + temp.f[3] = f4_curr[0][pos[0]][pos[1]][numVectors-1].f[2]; +#endif + f4_volt[1][pos[0]][pos[1]][0].v *= Op->f4_vv_Compressed[1][index].v; + f4_volt[1][pos[0]][pos[1]][0].v += Op->f4_vi_Compressed[1][index].v * ( f4_curr[0][pos[0]][pos[1]][0].v - temp.v - f4_curr[2][pos[0]][pos[1]][0].v + f4_curr[2][pos[0]-shift[0]][pos[1]][0].v); + + // z-polarization + f4_volt[2][pos[0]][pos[1]][0].v *= Op->f4_vv_Compressed[2][index].v; + f4_volt[2][pos[0]][pos[1]][0].v += Op->f4_vi_Compressed[2][index].v * ( f4_curr[1][pos[0]][pos[1]][0].v - f4_curr[1][pos[0]-shift[0]][pos[1]][0].v - f4_curr[0][pos[0]][pos[1]][0].v + f4_curr[0][pos[0]][pos[1]-shift[1]][0].v); + } + ++pos[0]; + } +} + +void Engine_SSE_Compressed::UpdateCurrents(unsigned int startX, unsigned int numX) +{ + unsigned int pos[3]; + f4vector temp; + + pos[0] = startX; + unsigned int index; + for (unsigned int posX=0; posX<numX; ++posX) + { + for (pos[1]=0; pos[1]<numLines[1]-1; ++pos[1]) + { + for (pos[2]=0; pos[2]<numVectors-1; ++pos[2]) + { + index = Op->m_Op_index[pos[0]][pos[1]][pos[2]]; + // x-pol + f4_curr[0][pos[0]][pos[1]][pos[2]].v *= Op->f4_ii_Compressed[0][index].v; + f4_curr[0][pos[0]][pos[1]][pos[2]].v += Op->f4_iv_Compressed[0][index].v * ( f4_volt[2][pos[0]][pos[1]][pos[2]].v - f4_volt[2][pos[0]][pos[1]+1][pos[2]].v - f4_volt[1][pos[0]][pos[1]][pos[2]].v + f4_volt[1][pos[0]][pos[1]][pos[2]+1].v); + + // y-pol + f4_curr[1][pos[0]][pos[1]][pos[2]].v *= Op->f4_ii_Compressed[1][index].v; + f4_curr[1][pos[0]][pos[1]][pos[2]].v += Op->f4_iv_Compressed[1][index].v * ( f4_volt[0][pos[0]][pos[1]][pos[2]].v - f4_volt[0][pos[0]][pos[1]][pos[2]+1].v - f4_volt[2][pos[0]][pos[1]][pos[2]].v + f4_volt[2][pos[0]+1][pos[1]][pos[2]].v); + + // z-pol + f4_curr[2][pos[0]][pos[1]][pos[2]].v *= Op->f4_ii_Compressed[2][index].v; + f4_curr[2][pos[0]][pos[1]][pos[2]].v += Op->f4_iv_Compressed[2][index].v * ( f4_volt[1][pos[0]][pos[1]][pos[2]].v - f4_volt[1][pos[0]+1][pos[1]][pos[2]].v - f4_volt[0][pos[0]][pos[1]][pos[2]].v + f4_volt[0][pos[0]][pos[1]+1][pos[2]].v); + } + + index = Op->m_Op_index[pos[0]][pos[1]][numVectors-1]; + // for pos[2] = numVectors-1 + // x-pol +#ifdef __SSE2__ + temp.v = (__m128)_mm_srli_si128( (__m128i)f4_volt[1][pos[0]][pos[1]][0].v, 4 ); +#else + temp.f[0] = f4_volt[1][pos[0]][pos[1]][0].f[1]; + temp.f[1] = f4_volt[1][pos[0]][pos[1]][0].f[2]; + temp.f[2] = f4_volt[1][pos[0]][pos[1]][0].f[3]; + temp.f[3] = 0; +#endif + f4_curr[0][pos[0]][pos[1]][numVectors-1].v *= Op->f4_ii_Compressed[0][index].v; + f4_curr[0][pos[0]][pos[1]][numVectors-1].v += Op->f4_iv_Compressed[0][index].v * ( f4_volt[2][pos[0]][pos[1]][numVectors-1].v - f4_volt[2][pos[0]][pos[1]+1][numVectors-1].v - f4_volt[1][pos[0]][pos[1]][numVectors-1].v + temp.v); + + // y-pol +#ifdef __SSE2__ + temp.v = (__m128)_mm_srli_si128( (__m128i)f4_volt[0][pos[0]][pos[1]][0].v, 4 ); +#else + temp.f[0] = f4_volt[0][pos[0]][pos[1]][0].f[1]; + temp.f[1] = f4_volt[0][pos[0]][pos[1]][0].f[2]; + temp.f[2] = f4_volt[0][pos[0]][pos[1]][0].f[3]; + temp.f[3] = 0; +#endif + f4_curr[1][pos[0]][pos[1]][numVectors-1].v *= Op->f4_ii_Compressed[1][index].v; + f4_curr[1][pos[0]][pos[1]][numVectors-1].v += Op->f4_iv_Compressed[1][index].v * ( f4_volt[0][pos[0]][pos[1]][numVectors-1].v - temp.v - f4_volt[2][pos[0]][pos[1]][numVectors-1].v + f4_volt[2][pos[0]+1][pos[1]][numVectors-1].v); + + // z-pol + f4_curr[2][pos[0]][pos[1]][numVectors-1].v *= Op->f4_ii_Compressed[2][index].v; + f4_curr[2][pos[0]][pos[1]][numVectors-1].v += Op->f4_iv_Compressed[2][index].v * ( f4_volt[1][pos[0]][pos[1]][numVectors-1].v - f4_volt[1][pos[0]+1][pos[1]][numVectors-1].v - f4_volt[0][pos[0]][pos[1]][numVectors-1].v + f4_volt[0][pos[0]][pos[1]+1][numVectors-1].v); + } + ++pos[0]; + } +} diff --git a/openEMS/FDTD/engine_sse_compressed.h b/openEMS/FDTD/engine_sse_compressed.h new file mode 100644 index 0000000..ab86cc8 --- /dev/null +++ b/openEMS/FDTD/engine_sse_compressed.h @@ -0,0 +1,38 @@ +/* +* 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_SSE_COMPRESSED_H +#define ENGINE_SSE_COMPRESSED_H + +#include "engine_sse.h" +#include "operator_sse_compressed.h" + +class Engine_SSE_Compressed : public Engine_sse +{ +public: + static Engine_SSE_Compressed* New(const Operator_SSE_Compressed* op); + virtual ~Engine_SSE_Compressed(); + +protected: + Engine_SSE_Compressed(const Operator_SSE_Compressed* op); + const Operator_SSE_Compressed* Op; + + virtual void UpdateVoltages(unsigned int startX, unsigned int numX); + virtual void UpdateCurrents(unsigned int startX, unsigned int numX); +}; + +#endif // ENGINE_SSE_COMPRESSED_H diff --git a/openEMS/FDTD/excitation.cpp b/openEMS/FDTD/excitation.cpp new file mode 100644 index 0000000..f095b53 --- /dev/null +++ b/openEMS/FDTD/excitation.cpp @@ -0,0 +1,304 @@ +/* +* 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 "tools/array_ops.h" +#include "tools/useful.h" +#include <iostream> +#include <fstream> +#include "fparser.hh" +#include "excitation.h" + +using namespace std; + +Excitation::Excitation() +{ + Signal_volt = 0; + Signal_curr = 0; + + this->Reset(0); + + m_Excit_Type = Excitation::UNDEFINED; + m_SignalPeriod = 0; +} + +Excitation::~Excitation() +{ + this->Reset(0); +} + +void Excitation::Reset( double timestep ) +{ + delete[] Signal_volt; + Signal_volt = 0; + delete[] Signal_curr; + Signal_curr = 0; + + dT = timestep; + m_nyquistTS = 0; + m_f_max = 0; + m_foi = 0; +} + +bool Excitation::SetupGaussianPulse(double f0, double fc) +{ + m_Excit_Type = Excitation::GaissianPulse; + m_f0 = f0; + m_fc = fc; + m_f_max = f0+fc; + m_SignalPeriod = 0; +} + +bool Excitation::SetupSinusoidal(double f0) +{ + m_Excit_Type = Excitation::Sinusoidal; + m_f0 = f0; + m_f_max = f0; + m_SignalPeriod = 1/f0; +} + +bool Excitation::SetupDiracPulse(double fmax) +{ + m_Excit_Type = Excitation::DiracPulse; + m_SignalPeriod = 0; + m_f_max = fmax; +} + +bool Excitation::SetupStepExcite(double fmax) +{ + m_Excit_Type = Excitation::Step; + m_SignalPeriod = 0; + m_f_max = fmax; +} + +bool Excitation::SetupCustomExcite(string str, double f0, double fmax) +{ + m_Excit_Type = Excitation::CustomExcite; + m_CustomExc_Str = str; + m_f0 = f0; + m_SignalPeriod = 0; + m_f_max = fmax; +} + +bool Excitation::buildExcitationSignal(unsigned int maxTS) +{ + if (dT<=0) + { + cerr << "Excitation::setupExcitation: Error, invalid timestep... " << endl; + return false; + } + + switch (m_Excit_Type) + { + case Excitation::GaissianPulse: + CalcGaussianPulsExcitation(m_f0,m_fc,maxTS); + break; + case Excitation::Sinusoidal: + CalcSinusExcitation(m_f0,maxTS); + break; + case Excitation::DiracPulse: + CalcDiracPulsExcitation(); + break; + case Excitation::Step: + CalcStepExcitation(); + break; + case Excitation::CustomExcite: + CalcCustomExcitation(m_f0,maxTS,m_CustomExc_Str); + break; + default: + cerr << "Excitation::buildExcitationSignal: Unknown excitation type: \"" << m_Excit_Type<< "\" !!" << endl; + m_Excit_Type = Excitation::UNDEFINED; + return false; + } + + if (GetNyquistNum() == 0) + { + cerr << "Excitation::buildExcitationSignal: Unknown error... excitation setup failed!!" << endl; + return false; + } + + return true; +} + +unsigned int Excitation::GetMaxExcitationTimestep() const +{ + FDTD_FLOAT maxAmp=0; + unsigned int maxStep=0; + for (unsigned int n=1; n<Length+1; ++n) + { + if (fabs(Signal_volt[n])>maxAmp) + { + maxAmp = fabs(Signal_volt[n]); + maxStep = n; + } + } + return maxStep; +} + +void Excitation::CalcGaussianPulsExcitation(double f0, double fc, int nTS) +{ + if (dT==0) return; + + Length = (unsigned int)(2.0 * 9.0/(2.0*PI*fc) / dT); + if (Length>(unsigned int)nTS) + { + cerr << "Operator::CalcGaussianPulsExcitation: Requested excitation pusle would be " << Length << " timesteps or " << Length * dT << " s long. Cutting to max number of timesteps!" << endl; + Length=(unsigned int)nTS; + } + delete[] Signal_volt; + delete[] Signal_curr; + Signal_volt = new FDTD_FLOAT[Length+1]; + Signal_curr = new FDTD_FLOAT[Length+1]; + Signal_volt[0]=0.0; + Signal_curr[0]=0.0; + for (unsigned int n=1; n<Length+1; ++n) + { + double t = (n-1)*dT; + Signal_volt[n] = cos(2.0*PI*f0*(t-9.0/(2.0*PI*fc)))*exp(-1*pow(2.0*PI*fc*t/3.0-3,2)); + t += 0.5*dT; + Signal_curr[n] = cos(2.0*PI*f0*(t-9.0/(2.0*PI*fc)))*exp(-1*pow(2.0*PI*fc*t/3.0-3,2)); + } + + m_foi = f0; + m_f_max = f0+fc; + + SetNyquistNum( CalcNyquistNum(f0+fc,dT) ); +} + +void Excitation::CalcDiracPulsExcitation() +{ + if (dT==0) return; + + Length = 1; +// cerr << "Operator::CalcDiracPulsExcitation: Length of the excite signal: " << ExciteLength << " timesteps" << endl; + delete[] Signal_volt; + delete[] Signal_curr; + Signal_volt = new FDTD_FLOAT[Length+1]; + Signal_curr = new FDTD_FLOAT[Length+1]; + Signal_volt[0]=0.0; + Signal_volt[1]=1.0; + Signal_curr[0]=0.0; + Signal_curr[1]=1.0; + + m_foi = 0; + m_f_max = 0; + + SetNyquistNum( 1 ); +} + +void Excitation::CalcStepExcitation() +{ + if (dT==0) return; + + Length = 1; + delete[] Signal_volt; + delete[] Signal_curr; + Signal_volt = new FDTD_FLOAT[Length+1]; + Signal_curr = new FDTD_FLOAT[Length+1]; + Signal_volt[0]=1.0; + Signal_volt[1]=1.0; + Signal_curr[0]=1.0; + Signal_curr[1]=1.0; + + m_foi = 0; + m_f_max = 0; + + SetNyquistNum( 1 ); +} + +void Excitation::CalcCustomExcitation(double f0, int nTS, string signal) +{ + if (dT==0) return; + if (nTS<=0) return; + + Length = (unsigned int)(nTS); +// cerr << "Operator::CalcSinusExcitation: Length of the excite signal: " << ExciteLength << " timesteps" << endl; + delete[] Signal_volt; + delete[] Signal_curr; + Signal_volt = new FDTD_FLOAT[Length+1]; + Signal_curr = new FDTD_FLOAT[Length+1]; + Signal_volt[0]=0.0; + Signal_curr[0]=0.0; + FunctionParser fParse; + fParse.AddConstant("pi", 3.14159265358979323846); + fParse.AddConstant("e", 2.71828182845904523536); + fParse.Parse(signal,"t"); + if (fParse.GetParseErrorType()!=FunctionParser::FP_NO_ERROR) + { + cerr << "Operator::CalcCustomExcitation: Function Parser error: " << fParse.ErrorMsg() << endl; + exit(1); + } + double vars[1]; + for (unsigned int n=1; n<Length+1; ++n) + { + vars[0] = (n-1)*dT; + Signal_volt[n] = fParse.Eval(vars); + vars[0] += 0.5*dT; + Signal_curr[n] = fParse.Eval(vars); + } + + m_f_max = f0; + m_foi = f0; + SetNyquistNum( CalcNyquistNum(f0,dT) ); +} + +void Excitation::CalcSinusExcitation(double f0, int nTS) +{ + if (dT==0) return; + if (nTS<=0) return; + + Length = (unsigned int)(2.0/f0/dT); + //cerr << "Operator::CalcSinusExcitation: Length of the excite signal: " << Length << " timesteps " << Length*dT << "s" << endl; + delete[] Signal_volt; + delete[] Signal_curr; + Signal_volt = new FDTD_FLOAT[Length+1]; + Signal_curr = new FDTD_FLOAT[Length+1]; + Signal_volt[0]=0.0; + Signal_curr[0]=0.0; + for (unsigned int n=1; n<Length+1; ++n) + { + double t = (n-1)*dT; + Signal_volt[n] = sin(2.0*PI*f0*t); + t += 0.5*dT; + Signal_curr[n] = sin(2.0*PI*f0*t); + } + m_f_max = f0; + m_foi = f0; + SetNyquistNum( CalcNyquistNum(f0,dT) ); +} + +void Excitation::DumpVoltageExcite(string filename) +{ + ofstream file; + file.open( filename.c_str() ); + if (file.fail()) + return; + for (unsigned int n=1; n<Length+1; ++n) + file << (n-1)*dT << "\t" << Signal_volt[n] << "\n"; + file.close(); +} + +void Excitation::DumpCurrentExcite(string filename) +{ + ofstream file; + file.open( filename.c_str() ); + if (file.fail()) + return; + for (unsigned int n=1; n<Length+1; ++n) + file << (n-1)*dT + 0.5*dT << "\t" << Signal_curr[n] << "\n"; + file.close(); +} + diff --git a/openEMS/FDTD/excitation.h b/openEMS/FDTD/excitation.h new file mode 100644 index 0000000..8ae3a5b --- /dev/null +++ b/openEMS/FDTD/excitation.h @@ -0,0 +1,115 @@ +/* +* 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 EXCITATION_H +#define EXCITATION_H + +#include <vector> +#include <string> +#include "tools/constants.h" + +class Excitation +{ +public: + enum ExciteTypes {UNDEFINED=-1, GaissianPulse=0, Sinusoidal=1, DiracPulse=2, Step=3, CustomExcite=10}; + Excitation(); + virtual ~Excitation(); + + virtual void Reset( double timestep ); + + bool SetupGaussianPulse(double f0, double fc); + bool SetupSinusoidal(double f0); + bool SetupDiracPulse(double fmax); + bool SetupStepExcite(double fmax); + bool SetupCustomExcite(std::string str, double f0, double fmax); + + double GetCenterFreq() {return m_f0;} + double GetCutOffFreq() {return m_fc;} + double GetMaxFreq() {return m_f_max;} + + bool buildExcitationSignal(unsigned int maxTS); + + //! Get the excitation timestep with the (first) max amplitude + virtual unsigned int GetMaxExcitationTimestep() const; + + void SetNyquistNum(unsigned int nyquist) {m_nyquistTS=nyquist;} + unsigned int GetNyquistNum() const {return m_nyquistTS;} + + //! Dump voltage excitation signal to ASCII file + void DumpVoltageExcite(std::string filename); + + //! Dump current excitation signal to ASCII file + void DumpCurrentExcite(std::string filename); + + //! Get the used timestep + double GetTimestep() const {return dT;} + + //! Get the type of excitation + int GetExciteType() const {return m_Excit_Type;} + + //! Get the length of the excitation signal + unsigned int GetLength() const {return Length;} + + //! Get the max frequeny excited by this signal + double GetMaxFrequency() const {return m_f_max;} + + //! Get the frequency of interest + double GetFrequencyOfInterest() const {return m_foi;} + + //! Get the signal period, 0 if not a periodical signal + double GetSignalPeriod() const {return m_SignalPeriod;} + + FDTD_FLOAT* GetVoltageSignal() const {return Signal_volt;} + FDTD_FLOAT* GetCurrentSignal() const {return Signal_curr;} + +protected: + double dT; + unsigned int m_nyquistTS; + double m_SignalPeriod; + ExciteTypes m_Excit_Type; + + //Excitation time-signal + unsigned int Length; + FDTD_FLOAT* Signal_volt; + FDTD_FLOAT* Signal_curr; + + // center frequency + double m_f0; + + // cutoff-frequency (Gaussian pulse only) + double m_fc; + + std::string m_CustomExc_Str; + + // max frequency + double m_f_max; + // frequency of interest + double m_foi; + + //! Calculate a custom signal + virtual void CalcCustomExcitation(double f0, int nTS, std::string signal); + //! Calculate an excitation with center of \a f0 and the half bandwidth \a fc + virtual void CalcGaussianPulsExcitation(double f0, double fc, int nTS); + //! Calculate a sinusoidal excitation with frequency \a f0 and a duration of \a nTS number of timesteps + virtual void CalcSinusExcitation(double f0, int nTS); + //! Calculate a dirac impuls excitation + virtual void CalcDiracPulsExcitation(); + //! Calculate a step excitation + virtual void CalcStepExcitation(); +}; + +#endif // EXCITATION_H diff --git a/openEMS/FDTD/extensions/CMakeLists.txt b/openEMS/FDTD/extensions/CMakeLists.txt new file mode 100644 index 0000000..3566944 --- /dev/null +++ b/openEMS/FDTD/extensions/CMakeLists.txt @@ -0,0 +1,32 @@ + +#INCLUDE_DIRECTORIES( ${openEMS_SOURCE_DIR} ) +#INCLUDE_DIRECTORIES( ${CSXCAD_SOURCE_DIR}/src ) + +set(SOURCES + ${SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/engine_extension.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_dispersive.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_lorentzmaterial.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_conductingsheet.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_dispersive.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_lorentzmaterial.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_cylindermultigrid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_upml.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_upml.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_extension.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_mur_abc.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_mur_abc.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_cylinder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_cylinder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_excitation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_excitation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_tfsf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_tfsf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_steadystate.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_steadystate.cpp + PARENT_SCOPE +) + +# FDTD/extensions lib +#add_library( extensions STATIC ${SOURCES} ) + diff --git a/openEMS/FDTD/extensions/OptimizeCondSheetParameter.m b/openEMS/FDTD/extensions/OptimizeCondSheetParameter.m new file mode 100644 index 0000000..12ac8ec --- /dev/null +++ b/openEMS/FDTD/extensions/OptimizeCondSheetParameter.m @@ -0,0 +1,107 @@ +function OptimizeCondSheetParameter +% function OptimizeCondSheetParameter +% +% internal openEMS function to create the "cond_sheet_parameter.h" header +% file containing optimized parameter values for the conducting sheet model +% +% (c) 2012: Thorsten Liebig, thorsten.liebig@gmx.de + + +close all +clear +clc + + +X = [1 1 1 1 1]; +lb = zeros(size(X)); +ub = ones(size(X))*1000; + + +Omega = linspace(0,20,51); +Omega = Omega(2:end); + +Omega_fine = linspace(0,20,15001); +Omega_fine = Omega_fine(2:end); + +options = optimset('fzero'); +% options = optimset(options,'Display','iter') +options = optimset(options,'MaxFunEvals',5000); +options = optimset(options,'MaxIter',5000); + +omg_stop_str = []; +omg_critical_20 = []; +omg_critical_5 = []; +g_str = []; +r1_str= []; +r2_str= []; +l1_str= []; +l2_str= []; + +numPara = 30; +factor = 1.5; + +for p = 1:numPara + + X = lsqnonlin(@(X)CalcYDiff(Omega,X),X,lb,ub,options); + + omg_stop_str = [omg_stop_str num2str(Omega(end),10) ',']; + g_str = [g_str num2str(X(1),10) ',']; + r1_str = [r1_str num2str(X(2),10) ',']; + l1_str = [l1_str num2str(X(3),10) ',']; + r2_str = [r2_str num2str(X(4),10) ',']; + l2_str = [l2_str num2str(X(5),10) ',']; + + Ys = tanh((1+1j)*sqrt(Omega_fine))/(1+1j)./sqrt(Omega_fine); + + err = (CalcYDiff(Omega_fine,X))./real(1./Ys); + + fc = Omega_fine(find(abs(err)>0.2,1,'last')); + if (isempty(fc)) + fc = 0; + end + omg_critical_20 = [omg_critical_20 num2str(fc,10) ',']; + + fc = Omega_fine(find(abs(err)>0.05,1,'last')); + if (isempty(fc)) + fc = 0; + end + omg_critical_5 = [omg_critical_5 num2str(fc,10) ',']; + +% disp(['max error: ' num2str(max(abs(err)*100)) ]) +% figure +% plot(Omega_fine,err*100,'g--'); + + Omega_fine = Omega_fine*factor; + Omega = Omega*factor; +end + +%% write to file +fid = fopen('cond_sheet_parameter.h','w'); + +fprintf(fid,'// This is a list of conducting sheet model parameter for different ranges of omega = w/w0\n'); +fprintf(fid,'// This file was created automatically using Matlab: OptimizeCondSheetParameter.m \n'); +fprintf(fid,'// Do not change this file! \n'); +fprintf(fid,'// Creation: %s \n\n',datestr(now)); + + + +fprintf(fid,'unsigned int numOptPara=%d;\n',numPara); + +fprintf(fid,'double omega_stop[%d]={%s};\n',numPara,omg_stop_str(1:end-1)); +fprintf(fid,'double omega_critical_5[%d]={%s};\n',numPara,omg_critical_5(1:end-1)); +fprintf(fid,'double omega_critical_20[%d]={%s};\n',numPara,omg_critical_20(1:end-1)); +fprintf(fid,'double g[%d]={%s};\n',numPara,g_str(1:end-1)); +fprintf(fid,'double r1[%d]={%s};\n',numPara,r1_str(1:end-1)); +fprintf(fid,'double l1[%d]={%s};\n',numPara,l1_str(1:end-1)); +fprintf(fid,'double r2[%d]={%s};\n',numPara,r2_str(1:end-1)); +fprintf(fid,'double l2[%d]={%s};\n',numPara,l2_str(1:end-1)); + +fclose(fid); + +function Ydiff = CalcYDiff(omega, X) + +Ys = tanh((1+1j)*sqrt(omega))/(1+1j)./sqrt(omega); + +Y = X(1) + 1./(X(2)+1j*omega*X(3)) + 1./(X(4)+1j*omega*X(5)); + +Ydiff = real(1./Ys)-real(1./Y);
\ No newline at end of file diff --git a/openEMS/FDTD/extensions/cond_sheet_parameter.h b/openEMS/FDTD/extensions/cond_sheet_parameter.h new file mode 100644 index 0000000..b3fc77b --- /dev/null +++ b/openEMS/FDTD/extensions/cond_sheet_parameter.h @@ -0,0 +1,14 @@ +// This is a list of conducting sheet model parameter for different ranges of omega = w/w0 +// This file was created automatically using Matlab: OptimizeCondSheetParameter.m +// Do not change this file! +// Creation: 08-May-2012 09:49:53 + +unsigned int numOptPara=30; +double omega_stop[30]={20,30,45,67.5,101.25,151.875,227.8125,341.71875,512.578125,768.8671875,1153.300781,1729.951172,2594.926758,3892.390137,5838.585205,8757.877808,13136.81671,19705.22507,29557.8376,44336.7564,66505.1346,99757.7019,149636.5529,224454.8293,336682.2439,505023.3659,757535.0488,1136302.573,1704453.86,2556680.79}; +double omega_critical_5[30]={0,0,0,1.566,6.8445,10.4085,15.1419375,22.30284375,33.45426562,50.28391406,75.42587109,113.1388066,169.70821,254.5623149,381.8434724,572.7652086,859.1478129,1288.721719,1933.082579,2899.623869,4349.435803,6524.153704,9786.230557,14679.34583,22019.01875,33028.52813,35503.14262,119084.5097,180444.8486,704280.3349}; +double omega_critical_20[30]={0,0,0,0,1.41075,2.7135,4.100625,5.90034375,8.6113125,12.86571094,19.37545312,29.06317969,43.59476953,65.3921543,98.08823145,147.1323472,220.6985208,331.0477811,496.5716717,744.8575075,1117.286261,1675.929392,2513.894088,3770.841132,5656.261698,8484.392547,10504.48601,11363.02573,11135.76522,7499.596983}; +double g[30]={0.1370843401,0.1244327709,0.1087425925,0.09215450299,0.07639249525,0.06239206861,0.05068701937,0.04124161681,0.03364925947,0.0274825647,0.02244156564,0.01832317373,0.01496080786,0.01221545053,0.009973874666,0.008143635713,0.006649251918,0.005429092739,0.00443283702,0.003619397792,0.002955227653,0.002412935361,0.001970156167,0.001608629812,0.001313423397,0.001072422468,0.0009031383439,0.0007674973627,0.0006482579571,0.0005450699565}; +double r1[30]={1.302754546,1.2992612,1.320033314,1.41829213,1.674326257,2.138770494,2.769126112,3.498802047,4.311446869,5.266204065,6.443980095,7.893402541,9.667414736,11.84010502,14.50110421,17.76014698,21.75163911,26.64019322,32.6274156,39.96021835,48.94100192,59.94011376,73.41109983,89.90930992,110.1195785,134.8631576,149.2770459,153.5258961,148.9373215,119.3522908}; +double l1[30]={0.9542567116,0.9412051444,0.8999655165,0.8189903271,0.702028543,0.5718817624,0.4577262324,0.3689027719,0.3004106661,0.2455514861,0.2005633225,0.1637496639,0.1337010005,0.1091664663,0.0891340699,0.07277768839,0.05942276018,0.04851850861,0.03961522618,0.03234573021,0.02641021614,0.02156389712,0.0176069076,0.01437606898,0.0117376269,0.009584103516,0.008750848841,0.008547706786,0.00854127488,0.008801399365}; +double r2[30]={10.62245057,10.21952962,10.24755832,10.99147713,12.70450822,15.59830718,19.55714986,24.32580904,29.88733852,36.55680626,44.75374078,54.81575133,67.13533424,82.22360504,100.7029064,123.3353165,151.0542147,185.0027444,226.5809553,277.5035137,339.8704104,416.2534638,509.8022059,624.3729288,764.7279941,936.5525496,1000,999.9999981,999.999984,999.9999985}; +double l2[30]={0.7925524826,0.6926195458,0.5814718257,0.4784644339,0.3916667501,0.3204661897,0.2620413998,0.2140939121,0.1748272154,0.1427375388,0.1165424396,0.09515681664,0.07769522035,0.06343788358,0.05179681795,0.04229192785,0.03453121766,0.02819462457,0.0230208182,0.01879642336,0.01534721999,0.01253095815,0.01023149158,0.008353988465,0.006820957973,0.005569332359,0.004553963932,0.003696380632,0.002978504727,0.002391295771}; diff --git a/openEMS/FDTD/extensions/engine_ext_cylinder.cpp b/openEMS/FDTD/extensions/engine_ext_cylinder.cpp new file mode 100644 index 0000000..e240f1b --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_cylinder.cpp @@ -0,0 +1,101 @@ +/* +* 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 "FDTD/engine.h" +#include "engine_ext_cylinder.h" +#include "operator_ext_cylinder.h" +#include "FDTD/engine_sse.h" + +Engine_Ext_Cylinder::Engine_Ext_Cylinder(Operator_Ext_Cylinder* op_ext) : Engine_Extension(op_ext) +{ + cyl_Op = op_ext; + m_Eng_SSE = NULL; + + CC_closedAlpha = op_ext->CC_closedAlpha; + CC_R0_included = op_ext->CC_R0_included; + + for (int n=0; n<3; ++n) + numLines[n] = op_ext->m_Op->GetNumberOfLines(n,true); + + //this cylindrical extension should be executed first? + m_Priority = ENG_EXT_PRIO_CYLINDER; +} + +void Engine_Ext_Cylinder::SetEngine(Engine* eng) +{ + Engine_Extension::SetEngine(eng); + m_Eng_SSE = dynamic_cast<Engine_sse*>(m_Eng); +} + +void Engine_Ext_Cylinder::DoPostVoltageUpdates() +{ + if (CC_closedAlpha==false) return; + + if (CC_R0_included) + { + unsigned int pos[3]; + pos[0] = 0; + FDTD_FLOAT volt=0; + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + volt =m_Eng_SSE->Engine_sse::GetVolt(2,0,0,pos[2])*cyl_Op->vv_R0[pos[2]]; + for (pos[1]=0; pos[1]<numLines[1]-1; ++pos[1]) + volt +=cyl_Op->vi_R0[pos[2]] * m_Eng_SSE->Engine_sse::GetCurr(1,0,pos[1],pos[2]); + m_Eng_SSE->Engine_sse::SetVolt(2,0,0,pos[2], volt); + } + + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + m_Eng_SSE->Engine_sse::SetVolt(1,0,pos[1],pos[2], 0); //no voltage in alpha-direction at r=0 + m_Eng_SSE->Engine_sse::SetVolt(2,0,pos[1],pos[2], m_Eng_SSE->Engine_sse::GetVolt(2,0,0,pos[2]) ); + } + } + } + + //close alpha + unsigned int pos[3]; + // copy tangential voltages from last alpha-plane to first + unsigned int last_A_Line = numLines[1]-2; + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + m_Eng_SSE->Engine_sse::SetVolt(0,pos[0],0,pos[2], m_Eng_SSE->Engine_sse::GetVolt(0,pos[0],last_A_Line,pos[2]) ); + m_Eng_SSE->Engine_sse::SetVolt(2,pos[0],0,pos[2], m_Eng_SSE->Engine_sse::GetVolt(2,pos[0],last_A_Line,pos[2]) ); + } + } +} + +void Engine_Ext_Cylinder::DoPostCurrentUpdates() +{ + if (CC_closedAlpha==false) return; + + //close alpha + unsigned int pos[3]; + // copy tangential currents from first alpha-plane to last + for (pos[0]=0; pos[0]<numLines[0]-1; ++pos[0]) + { + unsigned int last_A_Line = numLines[1]-2; + for (pos[2]=0; pos[2]<numLines[2]-1; ++pos[2]) + { + m_Eng_SSE->Engine_sse::SetCurr(0,pos[0],last_A_Line,pos[2], m_Eng_SSE->Engine_sse::GetCurr(0,pos[0],0,pos[2]) ); + m_Eng_SSE->Engine_sse::SetCurr(2,pos[0],last_A_Line,pos[2], m_Eng_SSE->Engine_sse::GetCurr(2,pos[0],0,pos[2]) ); + } + } +} diff --git a/openEMS/FDTD/extensions/engine_ext_cylinder.h b/openEMS/FDTD/extensions/engine_ext_cylinder.h new file mode 100644 index 0000000..c996a9d --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_cylinder.h @@ -0,0 +1,49 @@ +/* +* 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_CYLINDER_H +#define ENGINE_CYLINDER_H + +#include "FDTD/engine.h" +#include "engine_extension.h" +#include "FDTD/operator_cylinder.h" + +class Operator_Ext_Cylinder; +class Engine_sse; + +class Engine_Ext_Cylinder : public Engine_Extension +{ +public: + Engine_Ext_Cylinder(Operator_Ext_Cylinder* op_ext); + + virtual void DoPostVoltageUpdates(); + + virtual void DoPostCurrentUpdates(); + + virtual void SetEngine(Engine* eng); + +protected: + Operator_Ext_Cylinder* cyl_Op; + Engine_sse* m_Eng_SSE; + + unsigned int numLines[3]; + + bool CC_closedAlpha; + bool CC_R0_included; +}; + +#endif // ENGINE_CYLINDER_H diff --git a/openEMS/FDTD/extensions/engine_ext_cylindermultigrid.cpp b/openEMS/FDTD/extensions/engine_ext_cylindermultigrid.cpp new file mode 100644 index 0000000..eca2c9e --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_cylindermultigrid.cpp @@ -0,0 +1,165 @@ +/* +* 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 "FDTD/engine.h" +#include "engine_ext_cylindermultigrid.h" +#include "FDTD/engine_cylindermultigrid.h" + +Engine_Ext_CylinderMultiGrid::Engine_Ext_CylinderMultiGrid(Operator_Extension* op_ext, bool isBase) : Engine_Extension(op_ext) +{ + m_IsBase = isBase; + m_Eng_MG = NULL; + + // the multi-grid should be applies last? + m_Priority = ENG_EXT_PRIO_CYLINDERMULTIGRID; +} + +Engine_Ext_CylinderMultiGrid::~Engine_Ext_CylinderMultiGrid() +{ +} + +void Engine_Ext_CylinderMultiGrid::SetBarrier(boost::barrier* waitBase, boost::barrier* waitChild, boost::barrier* waitSync) +{ + m_WaitOnBase = waitBase; + m_WaitOnChild = waitChild; + m_WaitOnSync = waitSync; +} + +void Engine_Ext_CylinderMultiGrid::SetEngine(Engine* eng) +{ + m_Eng_MG = dynamic_cast<Engine_CylinderMultiGrid*>(eng); + if (m_Eng_MG==NULL) + { + cerr << "Engine_Ext_CylinderMultiGrid::SetEngine(): Error" << endl; + exit(0); + } +} + +void Engine_Ext_CylinderMultiGrid::DoPreVoltageUpdates() +{ + //cerr << "Engine_Ext_CylinderMultiGrid::DoPreVoltageUpdates() for " << m_IsBase << endl; + if (!m_IsBase) + { + //cerr << "child: volt wait on base " << endl; + m_WaitOnBase->wait(); //wait on base to finisch current sync and/or to finisch voltage updates, than start child voltage updates + } +} + +void Engine_Ext_CylinderMultiGrid::DoPostVoltageUpdates() +{ + +} + +void Engine_Ext_CylinderMultiGrid::Apply2Voltages() +{ + if (m_IsBase) + { + m_WaitOnBase->wait(); //base voltage updates are done, tell child to start its voltage updates + m_WaitOnChild->wait(); //wait for child to finisch its updates + SyncVoltages(); //child is finisch, run sync and go to current updates next + m_WaitOnSync->wait(); //sync is done... move on and tell child to move on... + } + else + { + m_WaitOnChild->wait(); //child is finished voltage updates, will tell base to run sync + m_WaitOnSync->wait(); //wait for base to finisch sync before going to wait for current updates + } +} + +void Engine_Ext_CylinderMultiGrid::SyncVoltages() +{ + if (m_Eng_MG==NULL) + { + cerr << "Engine_Ext_CylinderMultiGrid::SyncVoltages: Error engine is NULL" << endl; + return; + } + + unsigned int* numLines = m_Eng_MG->numLines; + + Engine_Multithread* m_InnerEng = m_Eng_MG->m_InnerEngine; + + //interpolate voltages from base engine to child engine... + unsigned int pos[3]; + pos[0] = m_Eng_MG->Op_CMG->GetSplitPos()-1; + unsigned int pos1_half = 0; + f4vector v_null; + v_null.f[0] = 0; + v_null.f[1] = 0; + v_null.f[2] = 0; + v_null.f[3] = 0; + for (pos[1]=0; pos[1]<numLines[1]-1; pos[1]+=2) + { + pos1_half = pos[1]/2; + for (pos[2]=0; pos[2]<m_Eng_MG->numVectors; ++pos[2]) + { + //r - direczion + m_InnerEng->f4_volt[0][pos[0]][pos1_half][pos[2]].v = v_null.v; + + //z - direction + m_InnerEng->f4_volt[2][pos[0]][pos1_half][pos[2]].v = m_Eng_MG->f4_volt[2][pos[0]][pos[1]][pos[2]].v; + + //alpha - direction + m_InnerEng->f4_volt[1][pos[0]][pos1_half][pos[2]].v = m_Eng_MG->f4_volt[1][pos[0]][pos[1]][pos[2]].v; + m_InnerEng->f4_volt[1][pos[0]][pos1_half][pos[2]].v += m_Eng_MG->f4_volt[1][pos[0]][pos[1]+1][pos[2]].v; + } + } +} + +void Engine_Ext_CylinderMultiGrid::DoPreCurrentUpdates() +{ + //cerr << "Engine_Ext_CylinderMultiGrid::DoPreCurrentUpdates() for " << m_IsBase << endl; + if (!m_IsBase) + { + //cerr << "child: curr wait on base " << endl; + m_WaitOnBase->wait(); //wait on base to finisch voltage sync and current updates, than start child current updates + } +} + +void Engine_Ext_CylinderMultiGrid::DoPostCurrentUpdates() +{ + +} + +void Engine_Ext_CylinderMultiGrid::Apply2Current() +{ + if (m_IsBase) + { + //cerr << "Base: curr wait on base done, wait on sync" << endl; + m_WaitOnBase->wait(); //base current updates are done, tell child to start its current updates + m_WaitOnChild->wait(); //wait for child to finisch its updates + SyncCurrents(); //child is finisch, run sync and go to voltage updates next + m_WaitOnSync->wait(); //sync is done... move on and tell child to move on... + } + else + { + m_WaitOnChild->wait(); //child is finished current updates, will tell base to run sync... + m_WaitOnSync->wait(); //wait for base to finisch sync before going to wait for next voltage updates + //cerr << "Child: curr done, wait on sync" << endl; + } +} + +void Engine_Ext_CylinderMultiGrid::SyncCurrents() +{ + if (m_Eng_MG==NULL) + { + cerr << "Engine_Ext_CylinderMultiGrid::SyncCurrents: Error engine is NULL" << endl; + return; + } + + m_Eng_MG->InterpolCurrChild2Base(m_Eng_MG->Op_CMG->GetSplitPos()-2); + return; +} diff --git a/openEMS/FDTD/extensions/engine_ext_cylindermultigrid.h b/openEMS/FDTD/extensions/engine_ext_cylindermultigrid.h new file mode 100644 index 0000000..e9226f5 --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_cylindermultigrid.h @@ -0,0 +1,58 @@ +/* +* 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_CYLINDERMULTIGRID_H +#define ENGINE_EXT_CYLINDERMULTIGRID_H + +#include "FDTD/engine_cylindermultigrid.h" +#include "engine_extension.h" +#include "FDTD/operator_cylindermultigrid.h" + +class Operator_Ext_CylinderMultiGrid; + +class Engine_Ext_CylinderMultiGrid : public Engine_Extension +{ +public: + Engine_Ext_CylinderMultiGrid(Operator_Extension* op_ext, bool isBase); + virtual ~Engine_Ext_CylinderMultiGrid(); + + void SetBarrier(boost::barrier* waitBase, boost::barrier* waitChild, boost::barrier* waitSync); + + virtual void DoPreVoltageUpdates(); + virtual void DoPostVoltageUpdates(); + virtual void Apply2Voltages(); + + virtual void DoPreCurrentUpdates(); + virtual void DoPostCurrentUpdates(); + virtual void Apply2Current(); + + virtual void SetEngine(Engine* eng); + +protected: + void SyncVoltages(); + void SyncCurrents(); + + Engine_CylinderMultiGrid* m_Eng_MG; + + boost::barrier *m_WaitOnBase; + boost::barrier *m_WaitOnChild; + boost::barrier *m_WaitOnSync; + + bool m_IsBase; +}; + +#endif // ENGINE_EXT_CYLINDERMULTIGRID_H diff --git a/openEMS/FDTD/extensions/engine_ext_dispersive.cpp b/openEMS/FDTD/extensions/engine_ext_dispersive.cpp new file mode 100644 index 0000000..d9c431b --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_dispersive.cpp @@ -0,0 +1,162 @@ +/* +* 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_dispersive.h" +#include "operator_ext_dispersive.h" +#include "FDTD/engine_sse.h" + +Engine_Ext_Dispersive::Engine_Ext_Dispersive(Operator_Ext_Dispersive* op_ext_disp) : Engine_Extension(op_ext_disp) +{ + m_Op_Ext_Disp = op_ext_disp; + int order = m_Op_Ext_Disp->m_Order; + curr_ADE = new FDTD_FLOAT**[order]; + volt_ADE = new FDTD_FLOAT**[order]; + for (int o=0;o<order;++o) + { + curr_ADE[o] = new FDTD_FLOAT*[3]; + volt_ADE[o] = new FDTD_FLOAT*[3]; + for (int n=0; n<3; ++n) + { + if (m_Op_Ext_Disp->m_curr_ADE_On[o]==true) + { + curr_ADE[o][n] = new FDTD_FLOAT[m_Op_Ext_Disp->m_LM_Count[o]]; + for (unsigned int i=0; i<m_Op_Ext_Disp->m_LM_Count[o]; ++i) + curr_ADE[o][n][i]=0.0; + } + else + curr_ADE[o][n] = NULL; + if (m_Op_Ext_Disp->m_volt_ADE_On[o]==true) + { + volt_ADE[o][n] = new FDTD_FLOAT[m_Op_Ext_Disp->m_LM_Count[o]]; + for (unsigned int i=0; i<m_Op_Ext_Disp->m_LM_Count[o]; ++i) + volt_ADE[o][n][i]=0.0; + } + else + volt_ADE[o][n] = NULL; + } + } +} + +Engine_Ext_Dispersive::~Engine_Ext_Dispersive() +{ + if (curr_ADE==NULL && volt_ADE==NULL) + return; + + for (int o=0;o<m_Op_Ext_Disp->m_Order;++o) + { + for (int n=0; n<3; ++n) + { + delete[] curr_ADE[o][n]; + delete[] volt_ADE[o][n]; + } + delete[] curr_ADE[o]; + delete[] volt_ADE[o]; + } + delete[] curr_ADE; + curr_ADE=NULL; + + delete[] volt_ADE; + volt_ADE=NULL; +} + +void Engine_Ext_Dispersive::Apply2Voltages() +{ + for (int o=0;o<m_Op_Ext_Disp->m_Order;++o) + { + if (m_Op_Ext_Disp->m_volt_ADE_On[o]==false) continue; + + unsigned int **pos = m_Op_Ext_Disp->m_LM_pos[o]; + + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int i=0; i<m_Op_Ext_Disp->m_LM_Count.at(o); ++i) + { + m_Eng->Engine::SetVolt(0,pos[0][i],pos[1][i],pos[2][i], m_Eng->Engine::GetVolt(0,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][0][i]); + m_Eng->Engine::SetVolt(1,pos[0][i],pos[1][i],pos[2][i], m_Eng->Engine::GetVolt(1,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][1][i]); + m_Eng->Engine::SetVolt(2,pos[0][i],pos[1][i],pos[2][i], m_Eng->Engine::GetVolt(2,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][2][i]); + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*)m_Eng; + for (unsigned int i=0; i<m_Op_Ext_Disp->m_LM_Count.at(o); ++i) + { + eng_sse->Engine_sse::SetVolt(0,pos[0][i],pos[1][i],pos[2][i], eng_sse->Engine_sse::GetVolt(0,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][0][i]); + eng_sse->Engine_sse::SetVolt(1,pos[0][i],pos[1][i],pos[2][i], eng_sse->Engine_sse::GetVolt(1,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][1][i]); + eng_sse->Engine_sse::SetVolt(2,pos[0][i],pos[1][i],pos[2][i], eng_sse->Engine_sse::GetVolt(2,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][2][i]); + } + break; + } + default: + for (unsigned int i=0; i<m_Op_Ext_Disp->m_LM_Count.at(o); ++i) + { + m_Eng->SetVolt(0,pos[0][i],pos[1][i],pos[2][i], m_Eng->GetVolt(0,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][0][i]); + m_Eng->SetVolt(1,pos[0][i],pos[1][i],pos[2][i], m_Eng->GetVolt(1,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][1][i]); + m_Eng->SetVolt(2,pos[0][i],pos[1][i],pos[2][i], m_Eng->GetVolt(2,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][2][i]); + } + break; + } + } +} + +void Engine_Ext_Dispersive::Apply2Current() +{ + for (int o=0;o<m_Op_Ext_Disp->m_Order;++o) + { + if (m_Op_Ext_Disp->m_curr_ADE_On[o]==false) continue; + + unsigned int **pos = m_Op_Ext_Disp->m_LM_pos[o]; + + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int i=0; i<m_Op_Ext_Disp->m_LM_Count.at(o); ++i) + { + m_Eng->Engine::SetCurr(0,pos[0][i],pos[1][i],pos[2][i], m_Eng->Engine::GetCurr(0,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][0][i]); + m_Eng->Engine::SetCurr(1,pos[0][i],pos[1][i],pos[2][i], m_Eng->Engine::GetCurr(1,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][1][i]); + m_Eng->Engine::SetCurr(2,pos[0][i],pos[1][i],pos[2][i], m_Eng->Engine::GetCurr(2,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][2][i]); + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*)m_Eng; + for (unsigned int i=0; i<m_Op_Ext_Disp->m_LM_Count.at(o); ++i) + { + eng_sse->Engine_sse::SetCurr(0,pos[0][i],pos[1][i],pos[2][i], eng_sse->Engine_sse::GetCurr(0,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][0][i]); + eng_sse->Engine_sse::SetCurr(1,pos[0][i],pos[1][i],pos[2][i], eng_sse->Engine_sse::GetCurr(1,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][1][i]); + eng_sse->Engine_sse::SetCurr(2,pos[0][i],pos[1][i],pos[2][i], eng_sse->Engine_sse::GetCurr(2,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][2][i]); + } + break; + } + default: + for (unsigned int i=0; i<m_Op_Ext_Disp->m_LM_Count.at(o); ++i) + { + m_Eng->SetCurr(0,pos[0][i],pos[1][i],pos[2][i], m_Eng->GetCurr(0,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][0][i]); + m_Eng->SetCurr(1,pos[0][i],pos[1][i],pos[2][i], m_Eng->GetCurr(1,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][1][i]); + m_Eng->SetCurr(2,pos[0][i],pos[1][i],pos[2][i], m_Eng->GetCurr(2,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][2][i]); + } + break; + } + } +} diff --git a/openEMS/FDTD/extensions/engine_ext_dispersive.h b/openEMS/FDTD/extensions/engine_ext_dispersive.h new file mode 100644 index 0000000..c1b84ea --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_dispersive.h @@ -0,0 +1,51 @@ +/* +* 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_DISPERSIVE_H +#define ENGINE_EXT_DISPERSIVE_H + +#include "engine_extension.h" +#include "FDTD/engine.h" +#include "FDTD/operator.h" + +class Operator_Ext_Dispersive; + +class Engine_Ext_Dispersive : public Engine_Extension +{ +public: + Engine_Ext_Dispersive(Operator_Ext_Dispersive* op_ext_disp); + virtual ~Engine_Ext_Dispersive(); + + virtual void Apply2Voltages(); + virtual void Apply2Current(); + +protected: + Operator_Ext_Dispersive* m_Op_Ext_Disp; + + //! Dispersive order + int m_Order; + + //! ADE currents + // Array setup: curr_ADE[N_order][direction][mesh_pos] + FDTD_FLOAT ***curr_ADE; + + //! ADE voltages + // Array setup: volt_ADE[N_order][direction][mesh_pos] + FDTD_FLOAT ***volt_ADE; +}; + +#endif // ENGINE_EXT_DISPERSIVE_H diff --git a/openEMS/FDTD/extensions/engine_ext_excitation.cpp b/openEMS/FDTD/extensions/engine_ext_excitation.cpp new file mode 100644 index 0000000..b5bd8bd --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_excitation.cpp @@ -0,0 +1,170 @@ +/* +* Copyright (C) 2011 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_excitation.h" +#include "operator_ext_excitation.h" +#include "FDTD/engine_sse.h" + +Engine_Ext_Excitation::Engine_Ext_Excitation(Operator_Ext_Excitation* op_ext) : Engine_Extension(op_ext) +{ + m_Op_Exc = op_ext; + m_Priority = ENG_EXT_PRIO_EXCITATION; +} + +Engine_Ext_Excitation::~Engine_Ext_Excitation() +{ + +} + +void Engine_Ext_Excitation::Apply2Voltages() +{ + //soft voltage excitation here (E-field excite) + int exc_pos; + unsigned int ny; + unsigned int pos[3]; + int numTS = m_Eng->GetNumberOfTimesteps(); + unsigned int length = m_Op_Exc->m_Exc->GetLength(); + FDTD_FLOAT* exc_volt = m_Op_Exc->m_Exc->GetVoltageSignal(); + + int p = numTS+1; + if (m_Op_Exc->m_Exc->GetSignalPeriod()>0) + p = int(m_Op_Exc->m_Exc->GetSignalPeriod()/m_Op_Exc->m_Exc->GetTimestep()); + + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int n=0; n<m_Op_Exc->Volt_Count; ++n) + { + exc_pos = numTS - (int)m_Op_Exc->Volt_delay[n]; + exc_pos *= (exc_pos>0); + exc_pos %= p; + exc_pos *= (exc_pos<=(int)length); + ny = m_Op_Exc->Volt_dir[n]; + pos[0]=m_Op_Exc->Volt_index[0][n]; + pos[1]=m_Op_Exc->Volt_index[1][n]; + pos[2]=m_Op_Exc->Volt_index[2][n]; + m_Eng->Engine::SetVolt(ny,pos, m_Eng->Engine::GetVolt(ny,pos) + m_Op_Exc->Volt_amp[n]*exc_volt[exc_pos]); + } + break; + } + case Engine::SSE: + { + for (unsigned int n=0; n<m_Op_Exc->Volt_Count; ++n) + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + exc_pos = numTS - (int)m_Op_Exc->Volt_delay[n]; + exc_pos *= (exc_pos>0); + exc_pos %= p; + exc_pos *= (exc_pos<=(int)length); + ny = m_Op_Exc->Volt_dir[n]; + pos[0]=m_Op_Exc->Volt_index[0][n]; + pos[1]=m_Op_Exc->Volt_index[1][n]; + pos[2]=m_Op_Exc->Volt_index[2][n]; + eng_sse->Engine_sse::SetVolt(ny,pos, eng_sse->Engine_sse::GetVolt(ny,pos) + m_Op_Exc->Volt_amp[n]*exc_volt[exc_pos]); + } + break; + } + default: + { + for (unsigned int n=0; n<m_Op_Exc->Volt_Count; ++n) + { + exc_pos = numTS - (int)m_Op_Exc->Volt_delay[n]; + exc_pos *= (exc_pos>0); + exc_pos %= p; + exc_pos *= (exc_pos<=(int)length); + ny = m_Op_Exc->Volt_dir[n]; + pos[0]=m_Op_Exc->Volt_index[0][n]; + pos[1]=m_Op_Exc->Volt_index[1][n]; + pos[2]=m_Op_Exc->Volt_index[2][n]; + m_Eng->SetVolt(ny,pos, m_Eng->GetVolt(ny,pos) + m_Op_Exc->Volt_amp[n]*exc_volt[exc_pos]); + } + break; + } + } +} + +void Engine_Ext_Excitation::Apply2Current() +{ + //soft current excitation here (H-field excite) + + int exc_pos; + unsigned int ny; + unsigned int pos[3]; + int numTS = m_Eng->GetNumberOfTimesteps(); + unsigned int length = m_Op_Exc->m_Exc->GetLength(); + FDTD_FLOAT* exc_curr = m_Op_Exc->m_Exc->GetCurrentSignal(); + + int p = numTS+1; + if (m_Op_Exc->m_Exc->GetSignalPeriod()>0) + p = int(m_Op_Exc->m_Exc->GetSignalPeriod()/m_Op_Exc->m_Exc->GetTimestep()); + + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int n=0; n<m_Op_Exc->Curr_Count; ++n) + { + exc_pos = numTS - (int)m_Op_Exc->Curr_delay[n]; + exc_pos *= (exc_pos>0); + exc_pos %= p; + exc_pos *= (exc_pos<=(int)length); + ny = m_Op_Exc->Curr_dir[n]; + pos[0]=m_Op_Exc->Curr_index[0][n]; + pos[1]=m_Op_Exc->Curr_index[1][n]; + pos[2]=m_Op_Exc->Curr_index[2][n]; + m_Eng->Engine::SetCurr(ny,pos, m_Eng->Engine::GetCurr(ny,pos) + m_Op_Exc->Curr_amp[n]*exc_curr[exc_pos]); + } + break; + } + case Engine::SSE: + { + for (unsigned int n=0; n<m_Op_Exc->Curr_Count; ++n) + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + exc_pos = numTS - (int)m_Op_Exc->Curr_delay[n]; + exc_pos *= (exc_pos>0); + exc_pos %= p; + exc_pos *= (exc_pos<=(int)length); + ny = m_Op_Exc->Curr_dir[n]; + pos[0]=m_Op_Exc->Curr_index[0][n]; + pos[1]=m_Op_Exc->Curr_index[1][n]; + pos[2]=m_Op_Exc->Curr_index[2][n]; + eng_sse->Engine_sse::SetCurr(ny,pos, eng_sse->Engine_sse::GetCurr(ny,pos) + m_Op_Exc->Curr_amp[n]*exc_curr[exc_pos]); + } + break; + } + default: + { + for (unsigned int n=0; n<m_Op_Exc->Curr_Count; ++n) + { + exc_pos = numTS - (int)m_Op_Exc->Curr_delay[n]; + exc_pos *= (exc_pos>0); + exc_pos %= p; + exc_pos *= (exc_pos<=(int)length); + ny = m_Op_Exc->Curr_dir[n]; + pos[0]=m_Op_Exc->Curr_index[0][n]; + pos[1]=m_Op_Exc->Curr_index[1][n]; + pos[2]=m_Op_Exc->Curr_index[2][n]; + m_Eng->SetCurr(ny,pos, m_Eng->GetCurr(ny,pos) + m_Op_Exc->Curr_amp[n]*exc_curr[exc_pos]); + } + break; + } + } +} diff --git a/openEMS/FDTD/extensions/engine_ext_excitation.h b/openEMS/FDTD/extensions/engine_ext_excitation.h new file mode 100644 index 0000000..aae58a0 --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_excitation.h @@ -0,0 +1,40 @@ +/* +* Copyright (C) 2011 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_EXCITATION_H +#define ENGINE_EXT_EXCITATION_H + +#include "engine_extension.h" +#include "FDTD/engine.h" +#include "FDTD/operator.h" + +class Operator_Ext_Excitation; + +class Engine_Ext_Excitation : public Engine_Extension +{ +public: + Engine_Ext_Excitation(Operator_Ext_Excitation* op_ext); + virtual ~Engine_Ext_Excitation(); + + virtual void Apply2Voltages(); + virtual void Apply2Current(); + +protected: + Operator_Ext_Excitation* m_Op_Exc; +}; + +#endif // ENGINE_EXT_EXCITATION_H diff --git a/openEMS/FDTD/extensions/engine_ext_lorentzmaterial.cpp b/openEMS/FDTD/extensions/engine_ext_lorentzmaterial.cpp new file mode 100644 index 0000000..9aaa1ff --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_lorentzmaterial.cpp @@ -0,0 +1,322 @@ +/* +* 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_lorentzmaterial.h" +#include "operator_ext_lorentzmaterial.h" +#include "FDTD/engine_sse.h" + +Engine_Ext_LorentzMaterial::Engine_Ext_LorentzMaterial(Operator_Ext_LorentzMaterial* op_ext_lorentz) : Engine_Ext_Dispersive(op_ext_lorentz) +{ + m_Op_Ext_Lor = op_ext_lorentz; + m_Order = m_Op_Ext_Lor->GetDispersionOrder(); + int order = m_Op_Ext_Lor->m_Order; + + curr_Lor_ADE = new FDTD_FLOAT**[order]; + volt_Lor_ADE = new FDTD_FLOAT**[order]; + for (int o=0;o<order;++o) + { + curr_Lor_ADE[o] = new FDTD_FLOAT*[3]; + volt_Lor_ADE[o] = new FDTD_FLOAT*[3]; + for (int n=0; n<3; ++n) + { + if (m_Op_Ext_Lor->m_curr_Lor_ADE_On[o]==true) + { + curr_Lor_ADE[o][n] = new FDTD_FLOAT[m_Op_Ext_Lor->m_LM_Count[o]]; + for (unsigned int i=0; i<m_Op_Ext_Lor->m_LM_Count[o]; ++i) + curr_Lor_ADE[o][n][i]=0.0; + } + else + curr_Lor_ADE[o][n] = NULL; + + if (m_Op_Ext_Lor->m_volt_Lor_ADE_On[o]==true) + { + volt_Lor_ADE[o][n] = new FDTD_FLOAT[m_Op_Ext_Lor->m_LM_Count[o]]; + for (unsigned int i=0; i<m_Op_Ext_Lor->m_LM_Count[o]; ++i) + volt_Lor_ADE[o][n][i]=0.0; + } + else + volt_Lor_ADE[o][n] = NULL; + } + } +} + +Engine_Ext_LorentzMaterial::~Engine_Ext_LorentzMaterial() +{ + if (curr_Lor_ADE==NULL && volt_Lor_ADE==NULL) + return; + + for (int o=0;o<m_Op_Ext_Lor->m_Order;++o) + { + for (int n=0; n<3; ++n) + { + delete[] curr_Lor_ADE[o][n]; + delete[] volt_Lor_ADE[o][n]; + } + delete[] curr_Lor_ADE[o]; + delete[] volt_Lor_ADE[o]; + } + delete[] curr_Lor_ADE; + curr_Lor_ADE=NULL; + + delete[] volt_Lor_ADE; + volt_Lor_ADE=NULL; +} + +void Engine_Ext_LorentzMaterial::DoPreVoltageUpdates() +{ + for (int o=0;o<m_Order;++o) + { + if (m_Op_Ext_Lor->m_volt_ADE_On[o]==false) continue; + + unsigned int **pos = m_Op_Ext_Lor->m_LM_pos[o]; + + if (m_Op_Ext_Lor->m_volt_Lor_ADE_On[o]) + { + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int i=0; i<m_Op_Ext_Lor->m_LM_Count.at(o); ++i) + { + volt_Lor_ADE[o][0][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][0][i]*volt_ADE[o][0][i]; + volt_ADE[o][0][i] *= m_Op_Ext_Lor->v_int_ADE[o][0][i]; + volt_ADE[o][0][i] += m_Op_Ext_Lor->v_ext_ADE[o][0][i] * (m_Eng->Engine::GetVolt(0,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][0][i]); + + volt_Lor_ADE[o][1][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][1][i]*volt_ADE[o][1][i]; + volt_ADE[o][1][i] *= m_Op_Ext_Lor->v_int_ADE[o][1][i]; + volt_ADE[o][1][i] += m_Op_Ext_Lor->v_ext_ADE[o][1][i] * (m_Eng->Engine::GetVolt(1,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][2][i]); + + volt_Lor_ADE[o][2][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][2][i]*volt_ADE[o][2][i]; + volt_ADE[o][2][i] *= m_Op_Ext_Lor->v_int_ADE[o][2][i]; + volt_ADE[o][2][i] += m_Op_Ext_Lor->v_ext_ADE[o][2][i] * (m_Eng->Engine::GetVolt(2,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][2][i]); + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*)m_Eng; + for (unsigned int i=0; i<m_Op_Ext_Lor->m_LM_Count.at(o); ++i) + { + volt_Lor_ADE[o][0][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][0][i]*volt_ADE[o][0][i]; + volt_ADE[o][0][i] *= m_Op_Ext_Lor->v_int_ADE[o][0][i]; + volt_ADE[o][0][i] += m_Op_Ext_Lor->v_ext_ADE[o][0][i] * (eng_sse->Engine_sse::GetVolt(0,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][0][i]); + + volt_Lor_ADE[o][1][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][1][i]*volt_ADE[o][1][i]; + volt_ADE[o][1][i] *= m_Op_Ext_Lor->v_int_ADE[o][1][i]; + volt_ADE[o][1][i] += m_Op_Ext_Lor->v_ext_ADE[o][1][i] * (eng_sse->Engine_sse::GetVolt(1,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][1][i]); + + volt_Lor_ADE[o][2][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][2][i]*volt_ADE[o][2][i]; + volt_ADE[o][2][i] *= m_Op_Ext_Lor->v_int_ADE[o][2][i]; + volt_ADE[o][2][i] += m_Op_Ext_Lor->v_ext_ADE[o][2][i] * (eng_sse->Engine_sse::GetVolt(2,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][2][i]); + } + break; + } + default: + for (unsigned int i=0; i<m_Op_Ext_Lor->m_LM_Count.at(o); ++i) + { + volt_Lor_ADE[o][0][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][0][i]*volt_ADE[o][0][i]; + volt_ADE[o][0][i] *= m_Op_Ext_Lor->v_int_ADE[o][0][i]; + volt_ADE[o][0][i] += m_Op_Ext_Lor->v_ext_ADE[o][0][i] * (m_Eng->GetVolt(0,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][0][i]); + + volt_Lor_ADE[o][1][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][1][i]*volt_ADE[o][1][i]; + volt_ADE[o][1][i] *= m_Op_Ext_Lor->v_int_ADE[o][1][i]; + volt_ADE[o][1][i] += m_Op_Ext_Lor->v_ext_ADE[o][1][i] * (m_Eng->GetVolt(1,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][1][i]); + + volt_Lor_ADE[o][2][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][2][i]*volt_ADE[o][2][i]; + volt_ADE[o][2][i] *= m_Op_Ext_Lor->v_int_ADE[o][2][i]; + volt_ADE[o][2][i] += m_Op_Ext_Lor->v_ext_ADE[o][2][i] * (m_Eng->GetVolt(2,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][2][i]); + } + break; + } + } + else + { + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int i=0; i<m_Op_Ext_Lor->m_LM_Count.at(o); ++i) + { + volt_ADE[o][0][i] *= m_Op_Ext_Lor->v_int_ADE[o][0][i]; + volt_ADE[o][0][i] += m_Op_Ext_Lor->v_ext_ADE[o][0][i] * m_Eng->Engine::GetVolt(0,pos[0][i],pos[1][i],pos[2][i]); + + volt_ADE[o][1][i] *= m_Op_Ext_Lor->v_int_ADE[o][1][i]; + volt_ADE[o][1][i] += m_Op_Ext_Lor->v_ext_ADE[o][1][i] * m_Eng->Engine::GetVolt(1,pos[0][i],pos[1][i],pos[2][i]); + + volt_ADE[o][2][i] *= m_Op_Ext_Lor->v_int_ADE[o][2][i]; + volt_ADE[o][2][i] += m_Op_Ext_Lor->v_ext_ADE[o][2][i] * m_Eng->Engine::GetVolt(2,pos[0][i],pos[1][i],pos[2][i]); + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*)m_Eng; + for (unsigned int i=0; i<m_Op_Ext_Lor->m_LM_Count.at(o); ++i) + { + volt_ADE[o][0][i] *= m_Op_Ext_Lor->v_int_ADE[o][0][i]; + volt_ADE[o][0][i] += m_Op_Ext_Lor->v_ext_ADE[o][0][i] * eng_sse->Engine_sse::GetVolt(0,pos[0][i],pos[1][i],pos[2][i]); + + volt_ADE[o][1][i] *= m_Op_Ext_Lor->v_int_ADE[o][1][i]; + volt_ADE[o][1][i] += m_Op_Ext_Lor->v_ext_ADE[o][1][i] * eng_sse->Engine_sse::GetVolt(1,pos[0][i],pos[1][i],pos[2][i]); + + volt_ADE[o][2][i] *= m_Op_Ext_Lor->v_int_ADE[o][2][i]; + volt_ADE[o][2][i] += m_Op_Ext_Lor->v_ext_ADE[o][2][i] * eng_sse->Engine_sse::GetVolt(2,pos[0][i],pos[1][i],pos[2][i]); + } + break; + } + default: + for (unsigned int i=0; i<m_Op_Ext_Lor->m_LM_Count.at(o); ++i) + { + volt_ADE[o][0][i] *= m_Op_Ext_Lor->v_int_ADE[o][0][i]; + volt_ADE[o][0][i] += m_Op_Ext_Lor->v_ext_ADE[o][0][i] * m_Eng->GetVolt(0,pos[0][i],pos[1][i],pos[2][i]); + + volt_ADE[o][1][i] *= m_Op_Ext_Lor->v_int_ADE[o][1][i]; + volt_ADE[o][1][i] += m_Op_Ext_Lor->v_ext_ADE[o][1][i] * m_Eng->GetVolt(1,pos[0][i],pos[1][i],pos[2][i]); + + volt_ADE[o][2][i] *= m_Op_Ext_Lor->v_int_ADE[o][2][i]; + volt_ADE[o][2][i] += m_Op_Ext_Lor->v_ext_ADE[o][2][i] * m_Eng->GetVolt(2,pos[0][i],pos[1][i],pos[2][i]); + } + break; + } + } + } +} + +void Engine_Ext_LorentzMaterial::DoPreCurrentUpdates() +{ + for (int o=0;o<m_Order;++o) + { + if (m_Op_Ext_Lor->m_curr_ADE_On[o]==false) continue; + + unsigned int **pos = m_Op_Ext_Lor->m_LM_pos[o]; + + if (m_Op_Ext_Lor->m_curr_Lor_ADE_On[o]) + { + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int i=0; i<m_Op_Ext_Lor->m_LM_Count.at(o); ++i) + { + curr_Lor_ADE[o][0][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][0][i]*curr_ADE[o][0][i]; + curr_ADE[o][0][i] *= m_Op_Ext_Lor->i_int_ADE[o][0][i]; + curr_ADE[o][0][i] += m_Op_Ext_Lor->i_ext_ADE[o][0][i] * (m_Eng->Engine::GetCurr(0,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][0][i]); + + curr_Lor_ADE[o][1][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][1][i]*curr_ADE[o][1][i]; + curr_ADE[o][1][i] *= m_Op_Ext_Lor->i_int_ADE[o][1][i]; + curr_ADE[o][1][i] += m_Op_Ext_Lor->i_ext_ADE[o][1][i] * (m_Eng->Engine::GetCurr(1,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][1][i]); + + curr_Lor_ADE[o][2][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][2][i]*curr_ADE[o][2][i]; + curr_ADE[o][2][i] *= m_Op_Ext_Lor->i_int_ADE[o][2][i]; + curr_ADE[o][2][i] += m_Op_Ext_Lor->i_ext_ADE[o][2][i] * (m_Eng->Engine::GetCurr(2,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][2][i]); + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*)m_Eng; + for (unsigned int i=0; i<m_Op_Ext_Lor->m_LM_Count.at(o); ++i) + { + curr_Lor_ADE[o][0][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][0][i]*curr_ADE[o][0][i]; + curr_ADE[o][0][i] *= m_Op_Ext_Lor->i_int_ADE[o][0][i]; + curr_ADE[o][0][i] += m_Op_Ext_Lor->i_ext_ADE[o][0][i] * (eng_sse->Engine_sse::GetCurr(0,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][0][i]); + + curr_Lor_ADE[o][1][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][1][i]*curr_ADE[o][1][i]; + curr_ADE[o][1][i] *= m_Op_Ext_Lor->i_int_ADE[o][1][i]; + curr_ADE[o][1][i] += m_Op_Ext_Lor->i_ext_ADE[o][1][i] * (eng_sse->Engine_sse::GetCurr(1,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][1][i]); + + curr_Lor_ADE[o][2][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][2][i]*curr_ADE[o][2][i]; + curr_ADE[o][2][i] *= m_Op_Ext_Lor->i_int_ADE[o][2][i]; + curr_ADE[o][2][i] += m_Op_Ext_Lor->i_ext_ADE[o][2][i] * (eng_sse->Engine_sse::GetCurr(2,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][2][i]); + } + break; + } + default: + for (unsigned int i=0; i<m_Op_Ext_Lor->m_LM_Count.at(o); ++i) + { + curr_Lor_ADE[o][0][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][0][i]*curr_ADE[o][0][i]; + curr_ADE[o][0][i] *= m_Op_Ext_Lor->i_int_ADE[o][0][i]; + curr_ADE[o][0][i] += m_Op_Ext_Lor->i_ext_ADE[o][0][i] * (m_Eng->GetCurr(0,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][0][i]); + + curr_Lor_ADE[o][1][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][1][i]*curr_ADE[o][1][i]; + curr_ADE[o][1][i] *= m_Op_Ext_Lor->i_int_ADE[o][1][i]; + curr_ADE[o][1][i] += m_Op_Ext_Lor->i_ext_ADE[o][1][i] * (m_Eng->GetCurr(1,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][1][i]); + + curr_Lor_ADE[o][2][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][2][i]*curr_ADE[o][2][i]; + curr_ADE[o][2][i] *= m_Op_Ext_Lor->i_int_ADE[o][2][i]; + curr_ADE[o][2][i] += m_Op_Ext_Lor->i_ext_ADE[o][2][i] * (m_Eng->GetCurr(2,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][2][i]); + } + break; + } + } + else + { + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int i=0; i<m_Op_Ext_Lor->m_LM_Count.at(o); ++i) + { + curr_ADE[o][0][i] *= m_Op_Ext_Lor->i_int_ADE[o][0][i]; + curr_ADE[o][0][i] += m_Op_Ext_Lor->i_ext_ADE[o][0][i] * m_Eng->Engine::GetCurr(0,pos[0][i],pos[1][i],pos[2][i]); + + curr_ADE[o][1][i] *= m_Op_Ext_Lor->i_int_ADE[o][1][i]; + curr_ADE[o][1][i] += m_Op_Ext_Lor->i_ext_ADE[o][1][i] * m_Eng->Engine::GetCurr(1,pos[0][i],pos[1][i],pos[2][i]); + + curr_ADE[o][2][i] *= m_Op_Ext_Lor->i_int_ADE[o][2][i]; + curr_ADE[o][2][i] += m_Op_Ext_Lor->i_ext_ADE[o][2][i] * m_Eng->Engine::GetCurr(2,pos[0][i],pos[1][i],pos[2][i]); + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*)m_Eng; + for (unsigned int i=0; i<m_Op_Ext_Lor->m_LM_Count.at(o); ++i) + { + curr_ADE[o][0][i] *= m_Op_Ext_Lor->i_int_ADE[o][0][i]; + curr_ADE[o][0][i] += m_Op_Ext_Lor->i_ext_ADE[o][0][i] * eng_sse->Engine_sse::GetCurr(0,pos[0][i],pos[1][i],pos[2][i]); + + curr_ADE[o][1][i] *= m_Op_Ext_Lor->i_int_ADE[o][1][i]; + curr_ADE[o][1][i] += m_Op_Ext_Lor->i_ext_ADE[o][1][i] * eng_sse->Engine_sse::GetCurr(1,pos[0][i],pos[1][i],pos[2][i]); + + curr_ADE[o][2][i] *= m_Op_Ext_Lor->i_int_ADE[o][2][i]; + curr_ADE[o][2][i] += m_Op_Ext_Lor->i_ext_ADE[o][2][i] * eng_sse->Engine_sse::GetCurr(2,pos[0][i],pos[1][i],pos[2][i]); + } + break; + } + default: + for (unsigned int i=0; i<m_Op_Ext_Lor->m_LM_Count.at(o); ++i) + { + curr_ADE[o][0][i] *= m_Op_Ext_Lor->i_int_ADE[o][0][i]; + curr_ADE[o][0][i] += m_Op_Ext_Lor->i_ext_ADE[o][0][i] * m_Eng->GetCurr(0,pos[0][i],pos[1][i],pos[2][i]); + + curr_ADE[o][1][i] *= m_Op_Ext_Lor->i_int_ADE[o][1][i]; + curr_ADE[o][1][i] += m_Op_Ext_Lor->i_ext_ADE[o][1][i] * m_Eng->GetCurr(1,pos[0][i],pos[1][i],pos[2][i]); + + curr_ADE[o][2][i] *= m_Op_Ext_Lor->i_int_ADE[o][2][i]; + curr_ADE[o][2][i] += m_Op_Ext_Lor->i_ext_ADE[o][2][i] * m_Eng->GetCurr(2,pos[0][i],pos[1][i],pos[2][i]); + } + break; + } + } + } +} + diff --git a/openEMS/FDTD/extensions/engine_ext_lorentzmaterial.h b/openEMS/FDTD/extensions/engine_ext_lorentzmaterial.h new file mode 100644 index 0000000..804f49a --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_lorentzmaterial.h @@ -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_LORENTZMATERIAL_H +#define ENGINE_EXT_LORENTZMATERIAL_H + +#include "engine_ext_dispersive.h" + +class Operator_Ext_LorentzMaterial; + +class Engine_Ext_LorentzMaterial : public Engine_Ext_Dispersive +{ +public: + Engine_Ext_LorentzMaterial(Operator_Ext_LorentzMaterial* op_ext_lorentz); + virtual ~Engine_Ext_LorentzMaterial(); + + virtual void DoPreVoltageUpdates(); + + virtual void DoPreCurrentUpdates(); + +protected: + Operator_Ext_LorentzMaterial* m_Op_Ext_Lor; + + //! ADE Lorentz voltages + // Array setup: volt_Lor_ADE[N_order][direction][mesh_pos] + FDTD_FLOAT ***volt_Lor_ADE; + + //! ADE Lorentz currents + // Array setup: curr_Lor_ADE[N_order][direction][mesh_pos] + FDTD_FLOAT ***curr_Lor_ADE; + +}; + +#endif // ENGINE_EXT_LORENTZMATERIAL_H diff --git a/openEMS/FDTD/extensions/engine_ext_mur_abc.cpp b/openEMS/FDTD/extensions/engine_ext_mur_abc.cpp new file mode 100644 index 0000000..d9f1b17 --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_mur_abc.cpp @@ -0,0 +1,263 @@ +/* +* 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_mur_abc.h" +#include "operator_ext_mur_abc.h" +#include "FDTD/engine.h" +#include "FDTD/engine_sse.h" +#include "tools/array_ops.h" +#include "tools/useful.h" +#include "operator_ext_excitation.h" + +Engine_Ext_Mur_ABC::Engine_Ext_Mur_ABC(Operator_Ext_Mur_ABC* op_ext) : Engine_Extension(op_ext) +{ + m_Op_mur = op_ext; + m_numLines[0] = m_Op_mur->m_numLines[0]; + m_numLines[1] = m_Op_mur->m_numLines[1]; + m_ny = m_Op_mur->m_ny; + m_nyP = m_Op_mur->m_nyP; + m_nyPP = m_Op_mur->m_nyPP; + m_LineNr = m_Op_mur->m_LineNr; + m_LineNr_Shift = m_Op_mur->m_LineNr_Shift; + + m_Mur_Coeff_nyP = m_Op_mur->m_Mur_Coeff_nyP; + m_Mur_Coeff_nyPP = m_Op_mur->m_Mur_Coeff_nyPP; + + m_volt_nyP = Create2DArray<FDTD_FLOAT>(m_numLines); + m_volt_nyPP = Create2DArray<FDTD_FLOAT>(m_numLines); + + //find if some excitation is on this mur-abc and find the max length of this excite, so that the abc can start after the excitation is done... + int maxDelay=-1; + Operator_Ext_Excitation* Exc_ext = m_Op_mur->m_Op->GetExcitationExtension(); + for (unsigned int n=0; n<Exc_ext->GetVoltCount(); ++n) + { + if ( ((Exc_ext->Volt_dir[n]==m_nyP) || (Exc_ext->Volt_dir[n]==m_nyPP)) && (Exc_ext->Volt_index[m_ny][n]==m_LineNr) ) + { + if ((int)Exc_ext->Volt_delay[n]>maxDelay) + maxDelay = (int)Exc_ext->Volt_delay[n]; + } + } + m_start_TS = 0; + if (maxDelay>=0) + { + m_start_TS = maxDelay + m_Op_mur->m_Op->GetExcitationSignal()->GetLength() + 10; //give it some extra timesteps, for the excitation to travel at least one cell away + cerr << "Engine_Ext_Mur_ABC::Engine_Ext_Mur_ABC: Warning: Excitation inside the Mur-ABC #" << m_ny << "-" << (int)(m_LineNr>0) << " found!!!! Mur-ABC will be switched on after excitation is done at " << m_start_TS << " timesteps!!! " << endl; + } + + SetNumberOfThreads(1); +} + +Engine_Ext_Mur_ABC::~Engine_Ext_Mur_ABC() +{ + Delete2DArray(m_volt_nyP,m_numLines); + m_volt_nyP = NULL; + Delete2DArray(m_volt_nyPP,m_numLines); + m_volt_nyPP = NULL; +} + + +void Engine_Ext_Mur_ABC::SetNumberOfThreads(int nrThread) +{ + Engine_Extension::SetNumberOfThreads(nrThread); + + m_numX = AssignJobs2Threads(m_numLines[0],m_NrThreads,false); + m_start.resize(m_NrThreads,0); + m_start.at(0)=0; + for (size_t n=1; n<m_numX.size(); ++n) + m_start.at(n) = m_start.at(n-1) + m_numX.at(n-1); +} + + +void Engine_Ext_Mur_ABC::DoPreVoltageUpdates(int threadID) +{ + if (IsActive()==false) return; + if (m_Eng==NULL) return; + if (threadID>=m_NrThreads) + return; + unsigned int pos[] = {0,0,0}; + unsigned int pos_shift[] = {0,0,0}; + pos[m_ny] = m_LineNr; + pos_shift[m_ny] = m_LineNr_Shift; + + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + pos[m_nyP]=lineX+m_start.at(threadID); + pos_shift[m_nyP] = pos[m_nyP]; + for (pos[m_nyPP]=0; pos[m_nyPP]<m_numLines[1]; ++pos[m_nyPP]) + { + pos_shift[m_nyPP] = pos[m_nyPP]; + m_volt_nyP[pos[m_nyP]][pos[m_nyPP]] = m_Eng->Engine::GetVolt(m_nyP,pos_shift) - m_Op_mur->m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->Engine::GetVolt(m_nyP,pos); + m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]] = m_Eng->Engine::GetVolt(m_nyPP,pos_shift) - m_Op_mur->m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->Engine::GetVolt(m_nyPP,pos); + } + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + pos[m_nyP]=lineX+m_start.at(threadID); + pos_shift[m_nyP] = pos[m_nyP]; + for (pos[m_nyPP]=0; pos[m_nyPP]<m_numLines[1]; ++pos[m_nyPP]) + { + pos_shift[m_nyPP] = pos[m_nyPP]; + m_volt_nyP[pos[m_nyP]][pos[m_nyPP]] = eng_sse->Engine_sse::GetVolt(m_nyP,pos_shift) - m_Op_mur->m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] * eng_sse->Engine_sse::GetVolt(m_nyP,pos); + m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]] = eng_sse->Engine_sse::GetVolt(m_nyPP,pos_shift) - m_Op_mur->m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] * eng_sse->Engine_sse::GetVolt(m_nyPP,pos); + } + } + break; + } + default: + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + pos[m_nyP]=lineX+m_start.at(threadID); + pos_shift[m_nyP] = pos[m_nyP]; + for (pos[m_nyPP]=0; pos[m_nyPP]<m_numLines[1]; ++pos[m_nyPP]) + { + pos_shift[m_nyPP] = pos[m_nyPP]; + m_volt_nyP[pos[m_nyP]][pos[m_nyPP]] = m_Eng->GetVolt(m_nyP,pos_shift) - m_Op_mur->m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->GetVolt(m_nyP,pos); + m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]] = m_Eng->GetVolt(m_nyPP,pos_shift) - m_Op_mur->m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->GetVolt(m_nyPP,pos); + } + } + break; + } +} + +void Engine_Ext_Mur_ABC::DoPostVoltageUpdates(int threadID) +{ + if (IsActive()==false) return; + if (m_Eng==NULL) return; + if (threadID>=m_NrThreads) + return; + unsigned int pos[] = {0,0,0}; + unsigned int pos_shift[] = {0,0,0}; + pos[m_ny] = m_LineNr; + pos_shift[m_ny] = m_LineNr_Shift; + + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + pos[m_nyP]=lineX+m_start.at(threadID); + pos_shift[m_nyP] = pos[m_nyP]; + for (pos[m_nyPP]=0; pos[m_nyPP]<m_numLines[1]; ++pos[m_nyPP]) + { + pos_shift[m_nyPP] = pos[m_nyPP]; + m_volt_nyP[pos[m_nyP]][pos[m_nyPP]] += m_Op_mur->m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->Engine::GetVolt(m_nyP,pos_shift); + m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]] += m_Op_mur->m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->Engine::GetVolt(m_nyPP,pos_shift); + } + } + break; + } + + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + pos[m_nyP]=lineX+m_start.at(threadID); + pos_shift[m_nyP] = pos[m_nyP]; + for (pos[m_nyPP]=0; pos[m_nyPP]<m_numLines[1]; ++pos[m_nyPP]) + { + pos_shift[m_nyPP] = pos[m_nyPP]; + m_volt_nyP[pos[m_nyP]][pos[m_nyPP]] += m_Op_mur->m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] * eng_sse->Engine_sse::GetVolt(m_nyP,pos_shift); + m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]] += m_Op_mur->m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] * eng_sse->Engine_sse::GetVolt(m_nyPP,pos_shift); + } + } + break; + } + + default: + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + pos[m_nyP]=lineX+m_start.at(threadID); + pos_shift[m_nyP] = pos[m_nyP]; + for (pos[m_nyPP]=0; pos[m_nyPP]<m_numLines[1]; ++pos[m_nyPP]) + { + pos_shift[m_nyPP] = pos[m_nyPP]; + m_volt_nyP[pos[m_nyP]][pos[m_nyPP]] += m_Op_mur->m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->GetVolt(m_nyP,pos_shift); + m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]] += m_Op_mur->m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->GetVolt(m_nyPP,pos_shift); + } + } + break; + } +} + +void Engine_Ext_Mur_ABC::Apply2Voltages(int threadID) +{ + if (IsActive()==false) return; + if (threadID>=m_NrThreads) + return; + if (m_Eng==NULL) return; + unsigned int pos[] = {0,0,0}; + pos[m_ny] = m_LineNr; + + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + pos[m_nyP]=lineX+m_start.at(threadID); + for (pos[m_nyPP]=0; pos[m_nyPP]<m_numLines[1]; ++pos[m_nyPP]) + { + m_Eng->Engine::SetVolt(m_nyP,pos, m_volt_nyP[pos[m_nyP]][pos[m_nyPP]]); + m_Eng->Engine::SetVolt(m_nyPP,pos, m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]]); + } + } + break; + } + + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + pos[m_nyP]=lineX+m_start.at(threadID); + for (pos[m_nyPP]=0; pos[m_nyPP]<m_numLines[1]; ++pos[m_nyPP]) + { + eng_sse->Engine_sse::SetVolt(m_nyP,pos, m_volt_nyP[pos[m_nyP]][pos[m_nyPP]]); + eng_sse->Engine_sse::SetVolt(m_nyPP,pos, m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]]); + } + } + break; + } + + default: + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + pos[m_nyP]=lineX+m_start.at(threadID); + for (pos[m_nyPP]=0; pos[m_nyPP]<m_numLines[1]; ++pos[m_nyPP]) + { + m_Eng->SetVolt(m_nyP,pos, m_volt_nyP[pos[m_nyP]][pos[m_nyPP]]); + m_Eng->SetVolt(m_nyPP,pos, m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]]); + } + } + break; + } + +} diff --git a/openEMS/FDTD/extensions/engine_ext_mur_abc.h b/openEMS/FDTD/extensions/engine_ext_mur_abc.h new file mode 100644 index 0000000..aadb2fd --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_mur_abc.h @@ -0,0 +1,63 @@ +/* +* 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_MUR_ABC_H +#define ENGINE_EXT_MUR_ABC_H + +#include "engine_extension.h" +#include "FDTD/engine.h" +#include "FDTD/operator.h" + +class Operator_Ext_Mur_ABC; + +class Engine_Ext_Mur_ABC : public Engine_Extension +{ +public: + Engine_Ext_Mur_ABC(Operator_Ext_Mur_ABC* op_ext); + virtual ~Engine_Ext_Mur_ABC(); + + virtual void SetNumberOfThreads(int nrThread); + + virtual void DoPreVoltageUpdates() {Engine_Ext_Mur_ABC::DoPreVoltageUpdates(0);} + virtual void DoPreVoltageUpdates(int threadID); + virtual void DoPostVoltageUpdates() {Engine_Ext_Mur_ABC::DoPostVoltageUpdates(0);} + virtual void DoPostVoltageUpdates(int threadID); + virtual void Apply2Voltages() {Engine_Ext_Mur_ABC::Apply2Voltages(0);} + virtual void Apply2Voltages(int threadID); + +protected: + Operator_Ext_Mur_ABC* m_Op_mur; + + inline bool IsActive() {if (m_Eng->GetNumberOfTimesteps()<m_start_TS) return false; return true;} + unsigned int m_start_TS; + + int m_ny; + int m_nyP,m_nyPP; + unsigned int m_LineNr; + int m_LineNr_Shift; + unsigned int m_numLines[2]; + + vector<unsigned int> m_start; + vector<unsigned int> m_numX; + + FDTD_FLOAT** m_Mur_Coeff_nyP; + FDTD_FLOAT** m_Mur_Coeff_nyPP; + FDTD_FLOAT** m_volt_nyP; //n+1 direction + FDTD_FLOAT** m_volt_nyPP; //n+2 direction +}; + +#endif // ENGINE_EXT_MUR_ABC_H diff --git a/openEMS/FDTD/extensions/engine_ext_steadystate.cpp b/openEMS/FDTD/extensions/engine_ext_steadystate.cpp new file mode 100644 index 0000000..9e5d0ce --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_steadystate.cpp @@ -0,0 +1,112 @@ +/* +* Copyright (C) 2015 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_steadystate.h" +#include "operator_ext_steadystate.h" +#include "FDTD/engine_sse.h" +#include "FDTD/engine_interface_fdtd.h" + +Engine_Ext_SteadyState::Engine_Ext_SteadyState(Operator_Ext_SteadyState* op_ext): Engine_Extension(op_ext) +{ + m_Op_SS = op_ext; + m_Priority = ENG_EXT_PRIO_STEADYSTATE; + + for (size_t n=0;n<m_Op_SS->m_E_probe_dir.size();++n) + { + double* rec = new double[m_Op_SS->m_TS_period*2]; + m_E_records.push_back(rec); + } + m_last_max_diff = 1; + last_total_energy = 0; + m_Eng_Interface = NULL; +} + +Engine_Ext_SteadyState::~Engine_Ext_SteadyState() +{ + for (size_t n=0;n<m_E_records.size();++n) + { + delete[] m_E_records.at(n); + m_E_records.at(n) = NULL; + } + m_E_records.clear(); + delete m_Eng_Interface; + m_Eng_Interface = NULL; +} + +void Engine_Ext_SteadyState::Apply2Voltages() +{ + unsigned int p = m_Op_SS->m_TS_period; + unsigned int TS = m_Eng->GetNumberOfTimesteps(); + unsigned int rel_pos = m_Eng->GetNumberOfTimesteps()%(2*p); + for (size_t n=0;n<m_E_records.size();++n) + m_E_records.at(n)[rel_pos] = m_Eng->GetVolt(m_Op_SS->m_E_probe_dir.at(n), m_Op_SS->m_E_probe_pos[0].at(n), m_Op_SS->m_E_probe_pos[1].at(n), m_Op_SS->m_E_probe_pos[2].at(n)); + if ((TS%(m_Op_SS->m_TS_period)==0) && (TS>=2*p)) + { + bool no_valid = true; + m_last_max_diff = 0; + double curr_total_energy = m_Eng_Interface->CalcFastEnergy(); + if (last_total_energy>0) + { + m_last_max_diff = abs(curr_total_energy-last_total_energy)/last_total_energy; + no_valid = false; + } + //cerr << curr_total_energy << "/" << last_total_energy << "=" << abs(curr_total_energy-last_total_energy)/last_total_energy << endl; + last_total_energy = curr_total_energy; + unsigned int old_pos = 0; + unsigned int new_pos = p; + if (rel_pos<=p) + { + new_pos = 0; + old_pos = p; + } + //cerr << TS << "/" << rel_pos << ": one period complete, new_pos" << new_pos << " old pos: " << old_pos << endl; + double *curr_pow = new double[m_E_records.size()]; + double *diff_pow = new double[m_E_records.size()]; + double max_pow = 0; + for (size_t n=0;n<m_E_records.size();++n) + { + double *buf = m_E_records.at(n); + curr_pow[n] = 0; + diff_pow[n] = 0; + for (unsigned int nt=0;nt<p;++nt) + { + curr_pow[n] += buf[nt+new_pos]*buf[nt+new_pos]; + diff_pow[n] += (buf[nt+old_pos]-buf[nt+new_pos])*(buf[nt+old_pos]-buf[nt+new_pos]); + } + max_pow = max(max_pow, curr_pow[n]); + } + for (size_t n=0;n<m_E_records.size();++n) + { + //cerr << "curr_pow: " << curr_pow[n] << " diff_pow: " << diff_pow[n] << " diff: " << diff_pow[n]/curr_pow[n] << endl; + if (curr_pow[n]>max_pow*1e-2) + { + m_last_max_diff = max(m_last_max_diff, diff_pow[n]/curr_pow[n]); + //cerr << m_last_max_diff << endl; + no_valid = false; + } + } + if ((no_valid) || (m_last_max_diff>1)) + m_last_max_diff = 1; + delete[] curr_pow; curr_pow = NULL; + //cerr << m_last_max_diff << endl; + } +} + +void Engine_Ext_SteadyState::Apply2Current() +{ + +} diff --git a/openEMS/FDTD/extensions/engine_ext_steadystate.h b/openEMS/FDTD/extensions/engine_ext_steadystate.h new file mode 100644 index 0000000..b66596e --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_steadystate.h @@ -0,0 +1,51 @@ +/* +* Copyright (C) 2015 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_STEADYSTATE_H +#define ENGINE_EXT_STEADYSTATE_H + +#include "engine_extension.h" +#include "FDTD/engine.h" +#include "FDTD/operator.h" + +class Operator_Ext_SteadyState; +class Engine_Interface_FDTD; + +class Engine_Ext_SteadyState : public Engine_Extension +{ +public: + Engine_Ext_SteadyState(Operator_Ext_SteadyState* op_ext); + virtual ~Engine_Ext_SteadyState(); + + virtual void Apply2Voltages(); + virtual void Apply2Current(); + + void SetEngineInterface(Engine_Interface_FDTD* eng_if) {m_Eng_Interface=eng_if;} + double GetLastDiff() {return m_last_max_diff;} + +protected: + Operator_Ext_SteadyState* m_Op_SS; + double m_last_max_diff; + vector<double*> m_E_records; + vector<double*> m_H_records; + + double last_total_energy; + Engine_Interface_FDTD* m_Eng_Interface; +}; + + +#endif // ENGINE_EXT_STEADYSTATE_H diff --git a/openEMS/FDTD/extensions/engine_ext_tfsf.cpp b/openEMS/FDTD/extensions/engine_ext_tfsf.cpp new file mode 100644 index 0000000..cd3b107 --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_tfsf.cpp @@ -0,0 +1,215 @@ +/* +* Copyright (C) 2012 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_tfsf.h" +#include "operator_ext_tfsf.h" +#include "FDTD/engine_sse.h" + +Engine_Ext_TFSF::Engine_Ext_TFSF(Operator_Ext_TFSF* op_ext) : Engine_Extension(op_ext) +{ + m_Op_TFSF = op_ext; + m_Priority = ENG_EXT_PRIO_TFSF; + + m_DelayLookup = new unsigned int[m_Op_TFSF->m_maxDelay+1]; +} + +Engine_Ext_TFSF::~Engine_Ext_TFSF() +{ + delete[] m_DelayLookup; + m_DelayLookup = NULL; +} + +void Engine_Ext_TFSF::DoPostVoltageUpdates() +{ + unsigned int numTS = m_Eng->GetNumberOfTimesteps(); + unsigned int length = m_Op_TFSF->m_Exc->GetLength(); + + int p = int(m_Op_TFSF->m_Exc->GetSignalPeriod()/m_Op_TFSF->m_Exc->GetTimestep()); + + for (unsigned int n=0;n<=m_Op_TFSF->m_maxDelay;++n) + { + if ( numTS < n ) + m_DelayLookup[n]=0; + else if ((numTS-n > length) && (p==0)) + m_DelayLookup[n]=0; + else + m_DelayLookup[n] = numTS - n; + if (p>0) + m_DelayLookup[n] = (m_DelayLookup[n] % p); + } + + //get the current signal since an H-field is added ... + FDTD_FLOAT* signal = m_Op_TFSF->m_Exc->GetCurrentSignal(); + + int nP,nPP; + unsigned int ui_pos; + unsigned int pos[3]; + for (int n=0;n<3;++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + + // lower plane + pos[nP] = m_Op_TFSF->m_Start[nP]; + ui_pos = 0; + if (m_Op_TFSF->m_ActiveDir[n][0]) + { + + for (unsigned int i=0;i<m_Op_TFSF->m_numLines[nP];++i) + { + pos[nPP] = m_Op_TFSF->m_Start[nPP]; + for (unsigned int j=0;j<m_Op_TFSF->m_numLines[nPP];++j) + { + // current updates + pos[n] = m_Op_TFSF->m_Start[n]; + + m_Eng->SetVolt(nP,pos, m_Eng->GetVolt(nP,pos) + + (1.0-m_Op_TFSF->m_VoltDelayDelta[n][0][0][ui_pos])*m_Op_TFSF->m_VoltAmp[n][0][0][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_VoltDelay[n][0][0][ui_pos]]] + + m_Op_TFSF->m_VoltDelayDelta[n][0][0][ui_pos] *m_Op_TFSF->m_VoltAmp[n][0][0][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_VoltDelay[n][0][0][ui_pos]]] ); + + m_Eng->SetVolt(nPP,pos, m_Eng->GetVolt(nPP,pos) + + (1.0-m_Op_TFSF->m_VoltDelayDelta[n][0][1][ui_pos])*m_Op_TFSF->m_VoltAmp[n][0][1][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_VoltDelay[n][0][1][ui_pos]]] + + m_Op_TFSF->m_VoltDelayDelta[n][0][1][ui_pos] *m_Op_TFSF->m_VoltAmp[n][0][1][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_VoltDelay[n][0][1][ui_pos]]] ); + + ++pos[nPP]; + ++ui_pos; + } + ++pos[nP]; + } + } + + // upper plane + pos[nP] = m_Op_TFSF->m_Start[nP]; + ui_pos = 0; + if (m_Op_TFSF->m_ActiveDir[n][1]) + { + + for (unsigned int i=0;i<m_Op_TFSF->m_numLines[nP];++i) + { + pos[nPP] = m_Op_TFSF->m_Start[nPP]; + for (unsigned int j=0;j<m_Op_TFSF->m_numLines[nPP];++j) + { + // current updates + pos[n] = m_Op_TFSF->m_Stop[n]; + + m_Eng->SetVolt(nP,pos, m_Eng->GetVolt(nP,pos) + + (1.0-m_Op_TFSF->m_VoltDelayDelta[n][1][0][ui_pos])*m_Op_TFSF->m_VoltAmp[n][1][0][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_VoltDelay[n][1][0][ui_pos]]] + + m_Op_TFSF->m_VoltDelayDelta[n][1][0][ui_pos] *m_Op_TFSF->m_VoltAmp[n][1][0][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_VoltDelay[n][1][0][ui_pos]]] ); + + m_Eng->SetVolt(nPP,pos, m_Eng->GetVolt(nPP,pos) + + (1.0-m_Op_TFSF->m_VoltDelayDelta[n][1][1][ui_pos])*m_Op_TFSF->m_VoltAmp[n][1][1][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_VoltDelay[n][1][1][ui_pos]]] + + m_Op_TFSF->m_VoltDelayDelta[n][1][1][ui_pos] *m_Op_TFSF->m_VoltAmp[n][1][1][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_VoltDelay[n][1][1][ui_pos]]] ); + + ++pos[nPP]; + ++ui_pos; + } + ++pos[nP]; + } + } + } +} + +void Engine_Ext_TFSF::DoPostCurrentUpdates() +{ + unsigned int numTS = m_Eng->GetNumberOfTimesteps(); + unsigned int length = m_Op_TFSF->m_Exc->GetLength(); + + int p = int(m_Op_TFSF->m_Exc->GetSignalPeriod()/m_Op_TFSF->m_Exc->GetTimestep()); + + for (unsigned int n=0;n<m_Op_TFSF->m_maxDelay;++n) + { + if ( numTS < n ) + m_DelayLookup[n]=0; + else if ((numTS-n > length) && (p==0)) + m_DelayLookup[n]=0; + else + m_DelayLookup[n] = numTS - n; + if (p>0) + m_DelayLookup[n] = (m_DelayLookup[n] % p); + } + + //get the current signal since an E-field is added ... + FDTD_FLOAT* signal = m_Op_TFSF->m_Exc->GetVoltageSignal(); + + int nP,nPP; + unsigned int ui_pos; + unsigned int pos[3]; + for (int n=0;n<3;++n) + { + if (!m_Op_TFSF->m_ActiveDir[n][0] && !m_Op_TFSF->m_ActiveDir[n][1]) + continue; + + nP = (n+1)%3; + nPP = (n+2)%3; + + // lower plane + pos[nP] = m_Op_TFSF->m_Start[nP]; + ui_pos = 0; + if (m_Op_TFSF->m_ActiveDir[n][0]) + { + for (unsigned int i=0;i<m_Op_TFSF->m_numLines[nP];++i) + { + pos[nPP] = m_Op_TFSF->m_Start[nPP]; + for (unsigned int j=0;j<m_Op_TFSF->m_numLines[nPP];++j) + { + // current updates + pos[n] = m_Op_TFSF->m_Start[n]-1; + + m_Eng->SetCurr(nP,pos, m_Eng->GetCurr(nP,pos) + + (1.0-m_Op_TFSF->m_CurrDelayDelta[n][0][0][ui_pos])*m_Op_TFSF->m_CurrAmp[n][0][0][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_CurrDelay[n][0][0][ui_pos]]] + + m_Op_TFSF->m_CurrDelayDelta[n][0][0][ui_pos] *m_Op_TFSF->m_CurrAmp[n][0][0][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_CurrDelay[n][0][0][ui_pos]]] ); + + m_Eng->SetCurr(nPP,pos, m_Eng->GetCurr(nPP,pos) + + (1.0-m_Op_TFSF->m_CurrDelayDelta[n][0][1][ui_pos])*m_Op_TFSF->m_CurrAmp[n][0][1][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_CurrDelay[n][0][1][ui_pos]]] + + m_Op_TFSF->m_CurrDelayDelta[n][0][1][ui_pos] *m_Op_TFSF->m_CurrAmp[n][0][1][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_CurrDelay[n][0][1][ui_pos]]] ); + + ++pos[nPP]; + ++ui_pos; + } + ++pos[nP]; + } + } + + // upper plane + pos[nP] = m_Op_TFSF->m_Start[nP]; + ui_pos = 0; + if (m_Op_TFSF->m_ActiveDir[n][1]) + { + for (unsigned int i=0;i<m_Op_TFSF->m_numLines[nP];++i) + { + pos[nPP] = m_Op_TFSF->m_Start[nPP]; + for (unsigned int j=0;j<m_Op_TFSF->m_numLines[nPP];++j) + { + // current updates + pos[n] = m_Op_TFSF->m_Stop[n]; + + m_Eng->SetCurr(nP,pos, m_Eng->GetCurr(nP,pos) + + (1.0-m_Op_TFSF->m_CurrDelayDelta[n][1][0][ui_pos])*m_Op_TFSF->m_CurrAmp[n][1][0][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_CurrDelay[n][1][0][ui_pos]]] + + m_Op_TFSF->m_CurrDelayDelta[n][1][0][ui_pos] *m_Op_TFSF->m_CurrAmp[n][1][0][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_CurrDelay[n][1][0][ui_pos]]] ); + + m_Eng->SetCurr(nPP,pos, m_Eng->GetCurr(nPP,pos) + + (1.0-m_Op_TFSF->m_CurrDelayDelta[n][1][1][ui_pos])*m_Op_TFSF->m_CurrAmp[n][1][1][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_CurrDelay[n][1][1][ui_pos]]] + + m_Op_TFSF->m_CurrDelayDelta[n][1][1][ui_pos] *m_Op_TFSF->m_CurrAmp[n][1][1][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_CurrDelay[n][1][1][ui_pos]]] ); + + ++pos[nPP]; + ++ui_pos; + } + ++pos[nP]; + } + } + } +} diff --git a/openEMS/FDTD/extensions/engine_ext_tfsf.h b/openEMS/FDTD/extensions/engine_ext_tfsf.h new file mode 100644 index 0000000..d4e662a --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_tfsf.h @@ -0,0 +1,40 @@ +/* +* Copyright (C) 2012 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_TFSF_H +#define ENGINE_EXT_TFSF_H + +#include "engine_extension.h" + +class Operator_Ext_TFSF; + +class Engine_Ext_TFSF : public Engine_Extension +{ +public: + Engine_Ext_TFSF(Operator_Ext_TFSF* op_ext); + virtual ~Engine_Ext_TFSF(); + + virtual void DoPostVoltageUpdates(); + virtual void DoPostCurrentUpdates(); + +protected: + Operator_Ext_TFSF* m_Op_TFSF; + + unsigned int* m_DelayLookup; +}; + +#endif // ENGINE_EXT_TFSF_H diff --git a/openEMS/FDTD/extensions/engine_ext_upml.cpp b/openEMS/FDTD/extensions/engine_ext_upml.cpp new file mode 100644 index 0000000..8cb365f --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_upml.cpp @@ -0,0 +1,493 @@ +/* +* 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 "FDTD/engine.h" +#include "FDTD/engine_sse.h" +#include "tools/array_ops.h" +#include "tools/useful.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 = ENG_EXT_PRIO_UPML; + + volt_flux = Create_N_3DArray<FDTD_FLOAT>(m_Op_UPML->m_numLines); + curr_flux = Create_N_3DArray<FDTD_FLOAT>(m_Op_UPML->m_numLines); + + SetNumberOfThreads(1); +} + +Engine_Ext_UPML::~Engine_Ext_UPML() +{ + Delete_N_3DArray<FDTD_FLOAT>(volt_flux,m_Op_UPML->m_numLines); + volt_flux=NULL; + Delete_N_3DArray<FDTD_FLOAT>(curr_flux,m_Op_UPML->m_numLines); + curr_flux=NULL; +} + +void Engine_Ext_UPML::SetNumberOfThreads(int nrThread) +{ + Engine_Extension::SetNumberOfThreads(nrThread); + + m_numX = AssignJobs2Threads(m_Op_UPML->m_numLines[0],m_NrThreads,false); + m_start.resize(m_NrThreads,0); + m_start.at(0)=0; + for (size_t n=1; n<m_numX.size(); ++n) + m_start.at(n) = m_start.at(n-1) + m_numX.at(n-1); +} + + +void Engine_Ext_UPML::DoPreVoltageUpdates(int threadID) +{ + if (m_Eng==NULL) + return; + + if (threadID>=m_NrThreads) + return; + + unsigned int pos[3]; + unsigned int loc_pos[3]; + FDTD_FLOAT f_help; + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + loc_pos[0]=lineX+m_start.at(threadID); + 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]; + + f_help = m_Op_UPML->vv[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->Engine::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]]; + m_Eng->Engine::SetVolt(0,pos, volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->vv[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->Engine::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]]; + m_Eng->Engine::SetVolt(1,pos, volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->vv[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->Engine::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->Engine::SetVolt(2,pos, volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + } + } + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + loc_pos[0]=lineX+m_start.at(threadID); + 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]; + + f_help = m_Op_UPML->vv[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * eng_sse->Engine_sse::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]]; + eng_sse->Engine_sse::SetVolt(0,pos, volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->vv[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * eng_sse->Engine_sse::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]]; + eng_sse->Engine_sse::SetVolt(1,pos, volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->vv[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * eng_sse->Engine_sse::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]]; + eng_sse->Engine_sse::SetVolt(2,pos, volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + } + } + } + break; + } + default: + { + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + loc_pos[0]=lineX+m_start.at(threadID); + 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]; + + f_help = 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]]; + m_Eng->SetVolt(0,pos, volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = 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]]; + m_Eng->SetVolt(1,pos, volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = 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(2,pos, volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + } + } + } + break; + } + } + +} + +void Engine_Ext_UPML::DoPostVoltageUpdates(int threadID) +{ + if (m_Eng==NULL) + return; + if (threadID>=m_NrThreads) + return; + + unsigned int pos[3]; + unsigned int loc_pos[3]; + FDTD_FLOAT f_help; + + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + loc_pos[0]=lineX+m_start.at(threadID); + 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]; + + f_help = volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->Engine::GetVolt(0,pos); + m_Eng->Engine::SetVolt(0,pos, f_help + 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]]); + + f_help = volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->Engine::GetVolt(1,pos); + m_Eng->Engine::SetVolt(1,pos, f_help + 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]]); + + f_help = volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->Engine::GetVolt(2,pos); + m_Eng->Engine::SetVolt(2,pos, f_help + 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]]); + } + } + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + loc_pos[0]=lineX+m_start.at(threadID); + 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]; + + f_help = volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = eng_sse->Engine_sse::GetVolt(0,pos); + eng_sse->Engine_sse::SetVolt(0,pos, f_help + 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]]); + + f_help = volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = eng_sse->Engine_sse::GetVolt(1,pos); + eng_sse->Engine_sse::SetVolt(1,pos, f_help + 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]]); + + f_help = volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = eng_sse->Engine_sse::GetVolt(2,pos); + eng_sse->Engine_sse::SetVolt(2,pos, f_help + 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]]); + } + } + } + break; + } + default: + { + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + loc_pos[0]=lineX+m_start.at(threadID); + 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]; + + f_help = volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetVolt(0,pos); + m_Eng->SetVolt(0,pos, f_help + 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]]); + + f_help = volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetVolt(1,pos); + m_Eng->SetVolt(1,pos, f_help + 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]]); + + f_help = volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetVolt(2,pos); + m_Eng->SetVolt(2,pos, f_help + 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]]); + } + } + } + break; + } + } + +} + +void Engine_Ext_UPML::DoPreCurrentUpdates(int threadID) +{ + if (m_Eng==NULL) + return; + if (threadID>=m_NrThreads) + return; + + unsigned int pos[3]; + unsigned int loc_pos[3]; + FDTD_FLOAT f_help; + + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + loc_pos[0]=lineX+m_start.at(threadID); + 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]; + + f_help = m_Op_UPML->ii[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->Engine::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]]; + m_Eng->Engine::SetCurr(0,pos, curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->ii[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->Engine::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]]; + m_Eng->Engine::SetCurr(1,pos, curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->ii[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->Engine::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->Engine::SetCurr(2,pos, curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + } + } + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + loc_pos[0]=lineX+m_start.at(threadID); + 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]; + + f_help = m_Op_UPML->ii[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * eng_sse->Engine_sse::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]]; + eng_sse->Engine_sse::SetCurr(0,pos, curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->ii[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * eng_sse->Engine_sse::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]]; + eng_sse->Engine_sse::SetCurr(1,pos, curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->ii[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * eng_sse->Engine_sse::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]]; + eng_sse->Engine_sse::SetCurr(2,pos, curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + } + } + } + break; + } + default: + { + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + loc_pos[0]=lineX+m_start.at(threadID); + 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]; + + f_help = 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]]; + m_Eng->SetCurr(0,pos, curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = 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]]; + m_Eng->SetCurr(1,pos, curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = 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(2,pos, curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + } + } + } + break; + } + } +} + +void Engine_Ext_UPML::DoPostCurrentUpdates(int threadID) +{ + if (m_Eng==NULL) + return; + if (threadID>=m_NrThreads) + return; + + unsigned int pos[3]; + unsigned int loc_pos[3]; + FDTD_FLOAT f_help; + + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + loc_pos[0]=lineX+m_start.at(threadID); + 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]; + + f_help = curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->Engine::GetCurr(0,pos); + m_Eng->Engine::SetCurr(0,pos, f_help + 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]]); + + f_help = curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->Engine::GetCurr(1,pos); + m_Eng->Engine::SetCurr(1,pos, f_help + 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]]); + + f_help = curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->Engine::GetCurr(2,pos); + m_Eng->Engine::SetCurr(2,pos, f_help + 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]]); + } + } + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + loc_pos[0]=lineX+m_start.at(threadID); + 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]; + + f_help = curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = eng_sse->Engine_sse::GetCurr(0,pos); + eng_sse->Engine_sse::SetCurr(0,pos, f_help + 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]]); + + f_help = curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = eng_sse->Engine_sse::GetCurr(1,pos); + eng_sse->Engine_sse::SetCurr(1,pos, f_help + 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]]); + + f_help = curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = eng_sse->Engine_sse::GetCurr(2,pos); + eng_sse->Engine_sse::SetCurr(2,pos, f_help + 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]]); + } + } + } + break; + } + default: + { + for (unsigned int lineX=0; lineX<m_numX.at(threadID); ++lineX) + { + loc_pos[0]=lineX+m_start.at(threadID); + 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]; + + f_help = curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetCurr(0,pos); + m_Eng->SetCurr(0,pos, f_help + 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]]); + + f_help = curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetCurr(1,pos); + m_Eng->SetCurr(1,pos, f_help + 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]]); + + f_help = curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetCurr(2,pos); + m_Eng->SetCurr(2,pos, f_help + 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]]); + } + } + } + break; + } + } +} diff --git a/openEMS/FDTD/extensions/engine_ext_upml.h b/openEMS/FDTD/extensions/engine_ext_upml.h new file mode 100644 index 0000000..283c886 --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_upml.h @@ -0,0 +1,55 @@ +/* +* 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 "FDTD/engine.h" +#include "FDTD/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 SetNumberOfThreads(int nrThread); + + virtual void DoPreVoltageUpdates() {Engine_Ext_UPML::DoPreVoltageUpdates(0);}; + virtual void DoPreVoltageUpdates(int threadID); + virtual void DoPostVoltageUpdates() {Engine_Ext_UPML::DoPostVoltageUpdates(0);}; + virtual void DoPostVoltageUpdates(int threadID); + + virtual void DoPreCurrentUpdates() {Engine_Ext_UPML::DoPreCurrentUpdates(0);}; + virtual void DoPreCurrentUpdates(int threadID); + virtual void DoPostCurrentUpdates() {Engine_Ext_UPML::DoPostCurrentUpdates(0);}; + virtual void DoPostCurrentUpdates(int threadID); + +protected: + Operator_Ext_UPML* m_Op_UPML; + + vector<unsigned int> m_start; + vector<unsigned int> m_numX; + + FDTD_FLOAT**** volt_flux; + FDTD_FLOAT**** curr_flux; +}; + +#endif // ENGINE_EXT_UPML_H diff --git a/openEMS/FDTD/extensions/engine_extension.cpp b/openEMS/FDTD/extensions/engine_extension.cpp new file mode 100644 index 0000000..6f688a3 --- /dev/null +++ b/openEMS/FDTD/extensions/engine_extension.cpp @@ -0,0 +1,95 @@ +/* +* 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_extension.h" +#include "operator_extension.h" + +#include "FDTD/engine.h" + +Engine_Extension::Engine_Extension(Operator_Extension* op_ext) +{ + m_Op_ext = op_ext; + m_Eng = NULL; + m_Priority = ENG_EXT_PRIO_DEFAULT; + m_NrThreads = 1; +} + +Engine_Extension::~Engine_Extension() +{ +} + +void Engine_Extension::SetNumberOfThreads(int nrThread) +{ + if (nrThread<1) + return; + m_NrThreads=nrThread; +} + +string Engine_Extension::GetExtensionName() const +{ + if (m_Op_ext) + return m_Op_ext->GetExtensionName(); + else + return "Unknown Extension"; +} + +void Engine_Extension::DoPreVoltageUpdates(int threadID) +{ + //if this method gets called the derived extension obviously doesn't support multithrading, calling non-MT method... + if (threadID==0) + DoPreVoltageUpdates(); +} + +void Engine_Extension::DoPostVoltageUpdates(int threadID) +{ + //if this method gets called the derived extension obviously doesn't support multithrading, calling non-MT method... + if (threadID==0) + DoPostVoltageUpdates(); +} + +void Engine_Extension::Apply2Voltages(int threadID) +{ + //if this method gets called the derived extension obviously doesn't support multithrading, calling non-MT method... + if (threadID==0) + Apply2Voltages(); +} + +void Engine_Extension::DoPreCurrentUpdates(int threadID) +{ + //if this method gets called the derived extension obviously doesn't support multithrading, calling non-MT method... + if (threadID==0) + DoPreCurrentUpdates(); +} + +void Engine_Extension::DoPostCurrentUpdates(int threadID) +{ + //if this method gets called the derived extension obviously doesn't support multithrading, calling non-MT method... + if (threadID==0) + DoPostCurrentUpdates(); +} + +void Engine_Extension::Apply2Current(int threadID) +{ + //if this method gets called the derived extension obviously doesn't support multithrading, calling non-MT method... + if (threadID==0) + Apply2Current(); +} + +bool Engine_Extension::operator< (const Engine_Extension& other) +{ + return (GetPriority()<other.GetPriority()); +} diff --git a/openEMS/FDTD/extensions/engine_extension.h b/openEMS/FDTD/extensions/engine_extension.h new file mode 100644 index 0000000..12ef712 --- /dev/null +++ b/openEMS/FDTD/extensions/engine_extension.h @@ -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 ENGINE_EXTENSION_H +#define ENGINE_EXTENSION_H + +#define ENG_EXT_PRIO_DEFAULT 0 //default engine extension priority + +// priority definitions for some important extensions +#define ENG_EXT_PRIO_STEADYSTATE +2e6 //steady state extension priority +#define ENG_EXT_PRIO_UPML +1e6 //unaxial pml extension priority +#define ENG_EXT_PRIO_CYLINDER +1e5 //cylindrial extension priority +#define ENG_EXT_PRIO_TFSF +5e4 //total-field/scattered-field extension priority +#define ENG_EXT_PRIO_EXCITATION -1000 //excitation priority +#define ENG_EXT_PRIO_CYLINDERMULTIGRID -3000 //cylindrial multi-grid extension priority + +#include <string> + +class Operator_Extension; +class Engine; + +//! Abstract base-class for all engine extensions +class Engine_Extension +{ +public: + virtual ~Engine_Extension(); + + virtual void SetNumberOfThreads(int nrThread); + + //! This methode will be called __before__ the main engine does the usual voltage updates. This methode may __not__ change the engine voltages!!! + virtual void DoPreVoltageUpdates() {} + virtual void DoPreVoltageUpdates(int threadID); + //! This methode will be called __after__ the main engine does the usual voltage updates. This methode may __not__ change the engine voltages!!! + virtual void DoPostVoltageUpdates() {} + virtual void DoPostVoltageUpdates(int threadID); + //! This methode will be called __after__ all updates to the voltages and extensions and may add/set its results to the engine voltages, but may __not__ rely on the current value of the engine voltages!!! + virtual void Apply2Voltages() {} + virtual void Apply2Voltages(int threadID); + + //! This methode will be called __before__ the main engine does the usual current updates. This methode may __not__ change the engine current!!! + virtual void DoPreCurrentUpdates() {} + virtual void DoPreCurrentUpdates(int threadID); + //! This methode will be called __after__ the main engine does the usual current updates. This methode may __not__ change the engine current!!! + virtual void DoPostCurrentUpdates() {} + virtual void DoPostCurrentUpdates(int threadID); + //! This methode will be called __after__ all updates to the current and extensions and may add/set its results to the engine current, but may __not__ rely on the current value of the engine current!!! + virtual void Apply2Current() {} + virtual void Apply2Current(int threadID); + + //! Set the Engine to this extention. This will usually done automatically by Engine::AddExtension + virtual void SetEngine(Engine* eng) {m_Eng=eng;} + + //! Get the priority for this extension + virtual int GetPriority() const {return m_Priority;} + + //! Set the priority for this extension + virtual void SetPriority(int val) {m_Priority=val;} + + virtual bool operator< (const Engine_Extension& other); + + virtual std::string GetExtensionName() const; + +protected: + Engine_Extension(Operator_Extension* op_ext); + + Operator_Extension* m_Op_ext; + Engine* m_Eng; + + int m_Priority; + + int m_NrThreads; +}; + +#endif // ENGINE_EXTENSION_H diff --git a/openEMS/FDTD/extensions/operator_ext_conductingsheet.cpp b/openEMS/FDTD/extensions/operator_ext_conductingsheet.cpp new file mode 100644 index 0000000..28c51bb --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_conductingsheet.cpp @@ -0,0 +1,261 @@ +/* +* Copyright (C) 2012 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_conductingsheet.h" +#include "tools/array_ops.h" +#include "tools/constants.h" +#include "cond_sheet_parameter.h" + +#include "CSPropConductingSheet.h" + +Operator_Ext_ConductingSheet::Operator_Ext_ConductingSheet(Operator* op, double f_max) : Operator_Ext_LorentzMaterial(op) +{ + m_f_max = f_max; +} + +Operator_Ext_ConductingSheet::Operator_Ext_ConductingSheet(Operator* op, Operator_Ext_ConductingSheet* op_ext) : Operator_Ext_LorentzMaterial(op, op_ext) +{ + m_f_max = op_ext->m_f_max; +} + +Operator_Extension* Operator_Ext_ConductingSheet::Clone(Operator* op) +{ + if (dynamic_cast<Operator_Ext_ConductingSheet*>(this)==NULL) + return NULL; + return new Operator_Ext_ConductingSheet(op, this); +} + +bool Operator_Ext_ConductingSheet::BuildExtension() +{ + double dT = m_Op->GetTimestep(); + unsigned int pos[] = {0,0,0}; + double coord[3]; + unsigned int numLines[3] = {m_Op->GetNumberOfLines(0,true),m_Op->GetNumberOfLines(1,true),m_Op->GetNumberOfLines(2,true)}; + + m_Order = 0; + vector<unsigned int> v_pos[3]; + int ****tanDir = Create_N_3DArray<int>(numLines); + float ****Conductivity = Create_N_3DArray<float>(numLines); + float ****Thickness = Create_N_3DArray<float>(numLines); + + CSPrimitives* cs_sheet = NULL; + double box[6]; + int nP, nPP; + bool b_pos_on; + bool disable_pos; + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + vector<CSPrimitives*> vPrims = m_Op->GetPrimitivesBoundBox(pos[0], pos[1], -1, (CSProperties::PropertyType)(CSProperties::MATERIAL | CSProperties::METAL)); + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + b_pos_on = false; + disable_pos = false; + // disable conducting sheet model inside the boundary conditions, especially inside a pml + for (int m=0;m<3;++m) + if ((pos[m]<=(unsigned int)m_Op->GetBCSize(2*m)) || (pos[m]>=(numLines[m]-m_Op->GetBCSize(2*m+1)-1))) + disable_pos = true; + + for (int n=0; n<3; ++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + + tanDir[n][pos[0]][pos[1]][pos[2]] = -1; //deactivate by default + Conductivity[n][pos[0]][pos[1]][pos[2]] = 0; //deactivate by default + Thickness[n][pos[0]][pos[1]][pos[2]] = 0; //deactivate by default + + if (m_Op->GetYeeCoords(n,pos,coord,false)==false) + continue; + + // Ez at r==0 not supported --> set to PEC + if (m_CC_R0_included && (n==2) && (pos[0]==0)) + disable_pos = true; + +// CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord,(CSProperties::PropertyType)(CSProperties::METAL | CSProperties::MATERIAL), false, &cs_sheet); + CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord, vPrims, false, &cs_sheet); + CSPropConductingSheet* cs_prop = dynamic_cast<CSPropConductingSheet*>(prop); + if (cs_prop) + { + if (cs_sheet==NULL) + return false; //sanity check, this should never happen + if (cs_sheet->GetDimension()!=2) + { + cerr << "Operator_Ext_ConductingSheet::BuildExtension: A conducting sheet primitive (ID: " << cs_sheet->GetID() << ") with dimension: " << cs_sheet->GetDimension() << " found, fallback to PEC!" << endl; + m_Op->SetVV(n,pos[0],pos[1],pos[2], 0 ); + m_Op->SetVI(n,pos[0],pos[1],pos[2], 0 ); + ++m_Op->m_Nr_PEC[n]; + continue; + } + cs_sheet->SetPrimitiveUsed(true); + + if (disable_pos) + { + m_Op->SetVV(n,pos[0],pos[1],pos[2], 0 ); + m_Op->SetVI(n,pos[0],pos[1],pos[2], 0 ); + ++m_Op->m_Nr_PEC[n]; + continue; + } + + Conductivity[n][pos[0]][pos[1]][pos[2]] = cs_prop->GetConductivity(); + Thickness[n][pos[0]][pos[1]][pos[2]] = cs_prop->GetThickness(); + + if ((Conductivity[n][pos[0]][pos[1]][pos[2]]<=0) || (Thickness[n][pos[0]][pos[1]][pos[2]]<=0)) + { + cerr << "Operator_Ext_ConductingSheet::BuildExtension: Warning: Zero conductivity or thickness detected... fallback to PEC!" << endl; + m_Op->SetVV(n,pos[0],pos[1],pos[2], 0 ); + m_Op->SetVI(n,pos[0],pos[1],pos[2], 0 ); + ++m_Op->m_Nr_PEC[n]; + continue; + } + + cs_sheet->GetBoundBox(box); + if (box[2*nP]!=box[2*nP+1]) + tanDir[n][pos[0]][pos[1]][pos[2]] = nP; + if (box[2*nPP]!=box[2*nPP+1]) + tanDir[n][pos[0]][pos[1]][pos[2]] = nPP; + b_pos_on = true; + } + } + if (b_pos_on) + { + for (int n=0; n<3; ++n) + v_pos[n].push_back(pos[n]); + } + } + } + } + + size_t numCS = v_pos[0].size(); + if (numCS==0) + return false; + + m_LM_Count.push_back(numCS); + m_LM_Count.push_back(numCS); + + m_Order = 2; + m_volt_ADE_On = new bool[m_Order]; + m_volt_ADE_On[0] = m_volt_ADE_On[1]=true; + m_curr_ADE_On = new bool[m_Order]; + m_curr_ADE_On[0] = m_curr_ADE_On[1]=false; + + m_volt_Lor_ADE_On = new bool[m_Order]; + m_volt_Lor_ADE_On[0] = m_volt_Lor_ADE_On[1]=false; + m_curr_Lor_ADE_On = new bool[m_Order]; + m_curr_Lor_ADE_On[0] = m_curr_Lor_ADE_On[1]=false; + + m_LM_pos = new unsigned int**[m_Order]; + m_LM_pos[0] = new unsigned int*[3]; + m_LM_pos[1] = new unsigned int*[3]; + + v_int_ADE = new FDTD_FLOAT**[m_Order]; + v_ext_ADE = new FDTD_FLOAT**[m_Order]; + + v_int_ADE[0] = new FDTD_FLOAT*[3]; + v_ext_ADE[0] = new FDTD_FLOAT*[3]; + v_int_ADE[1] = new FDTD_FLOAT*[3]; + v_ext_ADE[1] = new FDTD_FLOAT*[3]; + + for (int n=0; n<3; ++n) + { + m_LM_pos[0][n] = new unsigned int[numCS]; + m_LM_pos[1][n] = new unsigned int[numCS]; + for (unsigned int i=0; i<numCS; ++i) + { + m_LM_pos[0][n][i] = v_pos[n].at(i); + m_LM_pos[1][n][i] = v_pos[n].at(i); + } + v_int_ADE[0][n] = new FDTD_FLOAT[numCS]; + v_int_ADE[1][n] = new FDTD_FLOAT[numCS]; + v_ext_ADE[0][n] = new FDTD_FLOAT[numCS]; + v_ext_ADE[1][n] = new FDTD_FLOAT[numCS]; + } + + unsigned int index; + float w_stop = m_f_max*2*PI; + float Omega_max=0; + float G,L1,L2,R1,R2,Lmin; + float G0, w0; + float wtl; //width to length factor + float factor=1; + int t_dir=0; //tangential sheet direction + unsigned int tpos[] = {0,0,0}; + unsigned int optParaPos; + for (unsigned int i=0;i<numCS;++i) + { + pos[0]=m_LM_pos[0][0][i];pos[1]=m_LM_pos[0][1][i];pos[2]=m_LM_pos[0][2][i]; + tpos[0]=pos[0];tpos[1]=pos[1];tpos[2]=pos[2]; + index = m_Op->MainOp->SetPos(pos[0],pos[1],pos[2]); + for (int n=0;n<3;++n) + { + tpos[0]=pos[0];tpos[1]=pos[1];tpos[2]=pos[2]; + t_dir = tanDir[n][pos[0]][pos[1]][pos[2]]; + G0 = Conductivity[n][pos[0]][pos[1]][pos[2]]*Thickness[n][pos[0]][pos[1]][pos[2]]; + w0 = 8.0/ G0 / Thickness[n][pos[0]][pos[1]][pos[2]]/__MUE0__; + Omega_max = w_stop/w0; + for (optParaPos=0;optParaPos<numOptPara;++optParaPos) + if (omega_stop[optParaPos]>Omega_max) + break; + if (optParaPos>=numOptPara) + { + cerr << "Operator_Ext_ConductingSheet::BuildExtension(): Error, conductor thickness, conductivity or max. simulation frequency of interest is too high! Check parameter!" << endl; + cerr << " --> max f: " << m_f_max << "Hz, Conductivity: " << Conductivity[n][pos[0]][pos[1]][pos[2]] << "S/m, Thickness " << Thickness[n][pos[0]][pos[1]][pos[2]]*1e6 << "um" << endl; + optParaPos = numOptPara-1; + } + v_int_ADE[0][n][i]=0; + v_ext_ADE[0][n][i]=0; + v_int_ADE[1][n][i]=0; + v_ext_ADE[1][n][i]=0; + if (t_dir>=0) + { + wtl = m_Op->GetEdgeLength(n,pos)/m_Op->GetNodeWidth(t_dir,pos); + factor = 1; + if (tanDir[t_dir][tpos[0]][tpos[1]][tpos[2]]<0) + factor = 2; + --tpos[t_dir]; + if (tanDir[t_dir][tpos[0]][tpos[1]][tpos[2]]<0) + factor = 2; + + L1 = l1[optParaPos]/G0/w0*factor; + L2 = l2[optParaPos]/G0/w0*factor; + R1 = r1[optParaPos]/G0*factor; + R2 = r2[optParaPos]/G0*factor; + G = G0*g[optParaPos]/factor; + + L1*=wtl; + L2*=wtl; + R1*=wtl; + R2*=wtl; + G/=wtl; + + Lmin = L1; + if (L2<L1) + Lmin = L2; + m_Op->EC_G[n][index]= G; + m_Op->EC_C[n][index]= dT*dT/4.0*(16.0/Lmin + 1/L1 + 1/L2); + m_Op->Calc_ECOperatorPos(n,pos); + + v_int_ADE[0][n][i]=(2.0*L1-dT*R1)/(2.0*L1+dT*R1); + v_ext_ADE[0][n][i]=dT/(L1+dT*R1/2.0)*m_Op->GetVI(n,pos[0],pos[1],pos[2]); + v_int_ADE[1][n][i]=(2.0*L2-dT*R2)/(2.0*L2+dT*R2); + v_ext_ADE[1][n][i]=dT/(L2+dT*R2/2.0)*m_Op->GetVI(n,pos[0],pos[1],pos[2]); + } + } + } + return true; +} diff --git a/openEMS/FDTD/extensions/operator_ext_conductingsheet.h b/openEMS/FDTD/extensions/operator_ext_conductingsheet.h new file mode 100644 index 0000000..f84dc4b --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_conductingsheet.h @@ -0,0 +1,51 @@ +/* +* Copyright (C) 2012 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_CONDUCTINGSHEET_H +#define OPERATOR_EXT_CONDUCTINGSHEET_H + +#include "FDTD/operator.h" +#include "operator_ext_lorentzmaterial.h" + +/*! + FDTD extension for a conducting sheet model as described in: + Lauer, A.; Wolff, I.; , "A conducting sheet model for efficient wide band FDTD analysis of planar waveguides and circuits," Microwave Symposium Digest, 1999 IEEE MTT-S International , vol.4, no., pp.1589-1592 vol.4, 1999 + doi: 10.1109/MWSYM.1999.780262 + URL: http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=780262&isnumber=16934 + */ +class Operator_Ext_ConductingSheet : public Operator_Ext_LorentzMaterial +{ +public: + Operator_Ext_ConductingSheet(Operator* op, double f_max); + + virtual Operator_Extension* Clone(Operator* op); + + virtual bool BuildExtension(); + + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const {UNUSED(closedAlpha); UNUSED(R0_included); return true;} + virtual bool IsCylindricalMultiGridSave(bool child) const {UNUSED(child); return true;} + virtual bool IsMPISave() const {return true;} + + virtual string GetExtensionName() const {return string("Conducting Sheet Extension");} + +protected: + //! Copy constructor + Operator_Ext_ConductingSheet(Operator* op, Operator_Ext_ConductingSheet* op_ext); + double m_f_max; +}; + +#endif // OPERATOR_EXT_CONDUCTINGSHEET_H diff --git a/openEMS/FDTD/extensions/operator_ext_cylinder.cpp b/openEMS/FDTD/extensions/operator_ext_cylinder.cpp new file mode 100644 index 0000000..d400bf8 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_cylinder.cpp @@ -0,0 +1,114 @@ +/* +* 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_cylinder.h" +#include "FDTD/operator_cylinder.h" +#include "engine_ext_cylinder.h" + +Operator_Ext_Cylinder::Operator_Ext_Cylinder(Operator_Cylinder* op) : Operator_Extension(op) +{ + m_Op_Cyl = op; + + CC_R0_included=m_Op_Cyl->GetR0Included(); + CC_closedAlpha=m_Op_Cyl->GetClosedAlpha(); + + vv_R0 = NULL; + vi_R0 = NULL; +} + +Operator_Ext_Cylinder::~Operator_Ext_Cylinder() +{ + delete[] vv_R0; + vv_R0=NULL; + delete[] vi_R0; + vi_R0=NULL; +} + +bool Operator_Ext_Cylinder::BuildExtension() +{ + delete[] vv_R0; + vv_R0=NULL; + delete[] vi_R0; + vi_R0=NULL; + + //if r=0 is not included -> obviously no special treatment for r=0 + //if alpha direction is not closed, PEC-BC at r=0 necessary and already set... + if (CC_R0_included==false) + return true; + + vv_R0 = new FDTD_FLOAT[m_Op->GetNumberOfLines(2,true)]; + vi_R0 = new FDTD_FLOAT[m_Op->GetNumberOfLines(2,true)]; + + unsigned int pos[3]; + double coord[3]; + double inEC[4]; + double dT = m_Op->GetTimestep(); + pos[0]=0; + vector<CSPrimitives*> vPrims_metal = m_Op->GetPrimitivesBoundBox(pos[0], -1, -1, (CSProperties::PropertyType)(CSProperties::MATERIAL | CSProperties::METAL)); + for (pos[2]=0; pos[2]<m_Op->GetNumberOfLines(2,true); ++pos[2]) + { + double C=0; + double G=0; + vector<CSPrimitives*> vPrims_mat = m_Op->GetPrimitivesBoundBox(pos[0], -1, pos[2], CSProperties::MATERIAL); + for (pos[1]=0; pos[1]<m_Op->GetNumberOfLines(1,true)-2; ++pos[1]) + { + m_Op_Cyl->Calc_ECPos(2,pos,inEC,vPrims_mat); + C+=inEC[0]; + G+=inEC[1]; + } + m_Op->SetVV(2,0,0,pos[2], 1); + vv_R0[pos[2]] = (1-dT*G/2/C)/(1+dT*G/2/C); + vi_R0[pos[2]] = (dT/C)/(1+dT*G/2/C); + + for (unsigned int i=0; i<m_Op->GetNumberOfLines(1,true); ++i) + { + m_Op->EC_C[2][m_Op->MainOp->SetPos(0,i,pos[2])] = C; + m_Op->EC_G[2][m_Op->MainOp->SetPos(0,i,pos[2])] = G; + } + + //search for metal on z-axis + m_Op_Cyl->GetYeeCoords(2,pos,coord,false); + CSProperties* prop = m_Op->CSX->GetPropertyByCoordPriority(coord, vPrims_metal, true); + if (prop) + { + if (prop->GetType()==CSProperties::METAL) //set to PEC + { + m_Op->SetVV(2,0,0,pos[2], 0); + vv_R0[pos[2]] = 0; + vi_R0[pos[2]] = 0; + m_Op->EC_C[2][m_Op->MainOp->SetPos(0,0,pos[2])] = 0; + m_Op->EC_G[2][m_Op->MainOp->SetPos(0,0,pos[2])] = 0; + } + } + } + return true; +} + +Engine_Extension* Operator_Ext_Cylinder::CreateEngineExtention() +{ + Engine_Ext_Cylinder* eng_ext = new Engine_Ext_Cylinder(this); + return eng_ext; +} + + +void Operator_Ext_Cylinder::ShowStat(ostream &ostr) const +{ + Operator_Extension::ShowStat(ostr); + string On_Off[2] = {"Off", "On"}; + ostr << " Zeroth Radius\t\t: " << On_Off[CC_R0_included] << endl; + ostr << " Closed Rotation\t: " << On_Off[CC_closedAlpha] << endl; +} diff --git a/openEMS/FDTD/extensions/operator_ext_cylinder.h b/openEMS/FDTD/extensions/operator_ext_cylinder.h new file mode 100644 index 0000000..c8dff2d --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_cylinder.h @@ -0,0 +1,60 @@ +/* +* 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_CYLINDER_H +#define OPERATOR_EXT_CYLINDER_H + +#include "operator_extension.h" +#include "FDTD/operator.h" + +class Operator_Cylinder; + +class Operator_Ext_Cylinder : public Operator_Extension +{ + friend class Engine_Ext_Cylinder; + friend class Operator_Ext_LorentzMaterial; +public: + Operator_Ext_Cylinder(Operator_Cylinder* op); + ~Operator_Ext_Cylinder(); + + virtual bool BuildExtension(); + + virtual Engine_Extension* CreateEngineExtention(); + + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const {UNUSED(closedAlpha); UNUSED(R0_included); return true;} + virtual bool IsCylindricalMultiGridSave(bool child) const {UNUSED(child); return true;} + + // FIXME, this extension is not save or unknown to be save to use with MPI + virtual bool IsMPISave() const {return false;} + + virtual std::string GetExtensionName() const {return std::string("Extension for the Cylinder-Coords Operator");} + + virtual void ShowStat(ostream &ostr) const; + +protected: + Operator_Cylinder* m_Op_Cyl; + + bool CC_closedAlpha; + bool CC_R0_included; + + //special EC operator for R0 + FDTD_FLOAT* vv_R0; //calc new voltage from old voltage + FDTD_FLOAT* vi_R0; //calc new voltage from old current + +}; + +#endif // OPERATOR_EXT_CYLINDER_H diff --git a/openEMS/FDTD/extensions/operator_ext_dispersive.cpp b/openEMS/FDTD/extensions/operator_ext_dispersive.cpp new file mode 100644 index 0000000..ed01f1d --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_dispersive.cpp @@ -0,0 +1,78 @@ +/* +* 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_dispersive.h" + +#include "tools/array_ops.h" + +using namespace std; + +Operator_Ext_Dispersive::Operator_Ext_Dispersive(Operator* op) : Operator_Extension(op) +{ + m_curr_ADE_On = NULL; + m_volt_ADE_On = NULL; + + m_LM_pos=NULL; + m_curr_ADE_On=NULL; + m_volt_ADE_On=NULL; + + m_Order = 0; +} + +Operator_Ext_Dispersive::Operator_Ext_Dispersive(Operator* op, Operator_Ext_Dispersive* op_ext) : Operator_Extension(op,op_ext) +{ + m_curr_ADE_On = NULL; + m_volt_ADE_On = NULL; + + m_LM_pos=NULL; + m_curr_ADE_On=NULL; + m_volt_ADE_On=NULL; + + m_Order = 0; +} + +Operator_Ext_Dispersive::~Operator_Ext_Dispersive() +{ + delete[] m_curr_ADE_On; + delete[] m_volt_ADE_On; + m_curr_ADE_On=NULL; + m_volt_ADE_On=NULL; + + for (int n=0;n<m_Order;++n) + { + delete[] m_LM_pos[n][0]; + delete[] m_LM_pos[n][1]; + delete[] m_LM_pos[n][2]; + } + delete[] m_LM_pos; + m_LM_pos=NULL; + m_Order=0; + m_LM_Count.clear(); +} + +void Operator_Ext_Dispersive::ShowStat(ostream &ostr) const +{ + Operator_Extension::ShowStat(ostr); + string On_Off[2] = {"Off", "On"}; + ostr << " Max. Dispersion Order N = " << m_Order << endl; + for (int i=0;i<m_Order;++i) + { + ostr << " N=" << i << ":\t Active cells\t\t: " << m_LM_Count.at(i) << endl; + ostr << " N=" << i << ":\t Voltage ADE is \t: " << On_Off[m_volt_ADE_On[i]] << endl; + ostr << " N=" << i << ":\t Current ADE is \t: " << On_Off[m_curr_ADE_On[i]] << endl; + } +} diff --git a/openEMS/FDTD/extensions/operator_ext_dispersive.h b/openEMS/FDTD/extensions/operator_ext_dispersive.h new file mode 100644 index 0000000..fab354c --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_dispersive.h @@ -0,0 +1,56 @@ +/* +* 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_DISPERSIVE_H +#define OPERATOR_EXT_DISPERSIVE_H + +//#include "operator.h" +#include "operator_extension.h" +#include "vector" + +//! Abstract base class for all dispersive material models, based on an ADE (additional differential equation) +class Operator_Ext_Dispersive : public Operator_Extension +{ + friend class Engine_Ext_Dispersive; +public: + virtual ~Operator_Ext_Dispersive(); + + virtual int GetDispersionOrder() {return m_Order;} + + virtual std::string GetExtensionName() const {return std::string("Dispersive Material Abstract Base class");} + + virtual void ShowStat(std::ostream &ostr) const; + +protected: + Operator_Ext_Dispersive(Operator* op); + //! Copy constructor + Operator_Ext_Dispersive(Operator* op, Operator_Ext_Dispersive* op_ext); + + //! Dispersive order + int m_Order; + + //! Dispersive material count + std::vector<unsigned int> m_LM_Count; + //! Index with dispersive material + // Array setup: m_LM_pos[N_order][direction][mesh_pos] + unsigned int ***m_LM_pos; + + bool *m_curr_ADE_On; + bool *m_volt_ADE_On; +}; + +#endif // OPERATOR_EXT_DISPERSIVE_H diff --git a/openEMS/FDTD/extensions/operator_ext_excitation.cpp b/openEMS/FDTD/extensions/operator_ext_excitation.cpp new file mode 100644 index 0000000..d2085ff --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_excitation.cpp @@ -0,0 +1,372 @@ +/* +* Copyright (C) 2011 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_excitation.h" +#include "engine_ext_excitation.h" +#include "FDTD/excitation.h" +#include "ContinuousStructure.h" + +#include "CSPrimCurve.h" +#include "CSPropExcitation.h" + +Operator_Ext_Excitation::Operator_Ext_Excitation(Operator* op) : Operator_Extension(op) +{ + Init(); +} + +Operator_Ext_Excitation::~Operator_Ext_Excitation() +{ + Reset(); +} + +Operator_Extension* Operator_Ext_Excitation::Clone(Operator* op) +{ + Operator_Ext_Excitation* clone = new Operator_Ext_Excitation(op, this); + return clone; +} + +void Operator_Ext_Excitation::Init() +{ + Operator_Extension::Init(); + Volt_delay = 0; + Volt_amp = 0; + Volt_dir = 0; + Volt_Count = 0; + Curr_delay = 0; + Curr_amp = 0; + Curr_dir = 0; + Curr_Count = 0; + + for (int n=0; n<3; ++n) + { + Volt_index[n] = 0; + Curr_index[n] = 0; + Volt_Count_Dir[n] = 0; + Curr_Count_Dir[n] = 0; + } + m_Exc = 0; +} + +void Operator_Ext_Excitation::Reset() +{ + Operator_Extension::Reset(); + delete[] Volt_delay; + Volt_delay = 0; + delete[] Volt_dir; + Volt_dir = 0; + delete[] Volt_amp; + Volt_amp = 0; + delete[] Curr_delay; + Curr_delay = 0; + delete[] Curr_dir; + Curr_dir = 0; + delete[] Curr_amp; + Curr_amp = 0; + + Volt_Count = 0; + Curr_Count = 0; + + for (int n=0; n<3; ++n) + { + delete[] Volt_index[n]; + Volt_index[n] = 0; + delete[] Curr_index[n]; + Curr_index[n] = 0; + + Volt_Count_Dir[n] = 0; + Curr_Count_Dir[n] = 0; + } +} + + +Operator_Ext_Excitation::Operator_Ext_Excitation(Operator* op, Operator_Ext_Excitation* op_ext) : Operator_Extension(op, op_ext) +{ + Init(); +} + +bool Operator_Ext_Excitation::BuildExtension() +{ + m_Exc = m_Op->GetExcitationSignal(); + double dT = m_Op->GetTimestep(); + if (dT==0) + return false; + if (m_Exc==0) + return false; + + Reset(); + ContinuousStructure* CSX = m_Op->GetGeometryCSX(); + + unsigned int pos[3]; + double amp=0; + + vector<unsigned int> volt_vIndex[3]; + vector<FDTD_FLOAT> volt_vExcit; + vector<unsigned int> volt_vDelay; + vector<unsigned int> volt_vDir; + double volt_coord[3]; + + vector<unsigned int> curr_vIndex[3]; + vector<FDTD_FLOAT> curr_vExcit; + vector<unsigned int> curr_vDelay; + vector<unsigned int> curr_vDir; + double curr_coord[3]; + + vector<CSProperties*> vec_prop = CSX->GetPropertyByType(CSProperties::EXCITATION); + + if (vec_prop.size()==0) + { + cerr << "Operator::CalcFieldExcitation: Warning, no excitation properties found" << endl; + return false; + } + + CSPropExcitation* elec=NULL; + CSProperties* prop=NULL; + int priority=0; + + unsigned int numLines[] = {m_Op->GetNumberOfLines(0,true),m_Op->GetNumberOfLines(1,true),m_Op->GetNumberOfLines(2,true)}; + + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + //electric field excite + for (int n=0; n<3; ++n) + { + if (m_Op->GetYeeCoords(n,pos,volt_coord,false)==false) + continue; + if (m_CC_R0_included && (n==2) && (pos[0]==0)) + volt_coord[1] = m_Op->GetDiscLine(1,0); + + if (m_CC_R0_included && (n==1) && (pos[0]==0)) + continue; + + for (size_t p=0; p<vec_prop.size(); ++p) + { + prop = vec_prop.at(p); + elec = prop->ToExcitation(); + if (elec==NULL) + continue; + if (prop->CheckCoordInPrimitive(volt_coord,priority,true)) + { + if ((elec->GetActiveDir(n)) && ( (elec->GetExcitType()==0) || (elec->GetExcitType()==1) ))//&& (pos[n]<numLines[n]-1)) + { + amp = elec->GetWeightedExcitation(n,volt_coord)*m_Op->GetEdgeLength(n,pos);// delta[n]*gridDelta; + if (amp!=0) + { + volt_vExcit.push_back(amp); + volt_vDelay.push_back((unsigned int)(elec->GetDelay()/dT)); + volt_vDir.push_back(n); + volt_vIndex[0].push_back(pos[0]); + volt_vIndex[1].push_back(pos[1]); + volt_vIndex[2].push_back(pos[2]); + } + if (elec->GetExcitType()==1) //hard excite + { + m_Op->SetVV(n,pos[0],pos[1],pos[2], 0 ); + m_Op->SetVI(n,pos[0],pos[1],pos[2], 0 ); + } + } + } + } + } + + //magnetic field excite + for (int n=0; n<3; ++n) + { + if ((pos[0]>=numLines[0]-1) || (pos[1]>=numLines[1]-1) || (pos[2]>=numLines[2]-1)) + continue; //skip the last H-Line which is outside the FDTD-domain + if (m_Op->GetYeeCoords(n,pos,curr_coord,true)==false) + continue; + for (size_t p=0; p<vec_prop.size(); ++p) + { + prop = vec_prop.at(p); + elec = prop->ToExcitation(); + if (elec==NULL) + continue; + if (prop->CheckCoordInPrimitive(curr_coord,priority,true)) + { + if ((elec->GetActiveDir(n)) && ( (elec->GetExcitType()==2) || (elec->GetExcitType()==3) )) + { + amp = elec->GetWeightedExcitation(n,curr_coord)*m_Op->GetEdgeLength(n,pos,true);// delta[n]*gridDelta; + if (amp!=0) + { + curr_vExcit.push_back(amp); + curr_vDelay.push_back((unsigned int)(elec->GetDelay()/dT)); + curr_vDir.push_back(n); + curr_vIndex[0].push_back(pos[0]); + curr_vIndex[1].push_back(pos[1]); + curr_vIndex[2].push_back(pos[2]); + } + if (elec->GetExcitType()==3) //hard excite + { + m_Op->SetII(n,pos[0],pos[1],pos[2], 0 ); + m_Op->SetIV(n,pos[0],pos[1],pos[2], 0 ); + } + } + } + } + } + + } + } + } + + //special treatment for primitives of type curve (treated as wires) see also Calc_PEC + double p1[3]; + double p2[3]; + Grid_Path path; + for (size_t p=0; p<vec_prop.size(); ++p) + { + prop = vec_prop.at(p); + elec = prop->ToExcitation(); + for (size_t n=0; n<prop->GetQtyPrimitives(); ++n) + { + CSPrimitives* prim = prop->GetPrimitive(n); + CSPrimCurve* curv = prim->ToCurve(); + if (curv) + { + for (size_t i=1; i<curv->GetNumberOfPoints(); ++i) + { + curv->GetPoint(i-1,p1,m_Op->m_MeshType); + curv->GetPoint(i,p2,m_Op->m_MeshType); + path = m_Op->FindPath(p1,p2); + if (path.dir.size()>0) + prim->SetPrimitiveUsed(true); + for (size_t t=0; t<path.dir.size(); ++t) + { + n = path.dir.at(t); + pos[0] = path.posPath[0].at(t); + pos[1] = path.posPath[1].at(t); + pos[2] = path.posPath[2].at(t); + m_Op->GetYeeCoords(n,pos,volt_coord,false); + if (elec!=NULL) + { + if ((elec->GetActiveDir(n)) && (pos[n]<numLines[n]-1) && ( (elec->GetExcitType()==0) || (elec->GetExcitType()==1) )) + { + amp = elec->GetWeightedExcitation(n,volt_coord)*m_Op->GetEdgeLength(n,pos); + if (amp!=0) + { + volt_vExcit.push_back(amp); + volt_vDelay.push_back((unsigned int)(elec->GetDelay()/dT)); + volt_vDir.push_back(n); + volt_vIndex[0].push_back(pos[0]); + volt_vIndex[1].push_back(pos[1]); + volt_vIndex[2].push_back(pos[2]); + } + if (elec->GetExcitType()==1) //hard excite + { + m_Op->SetVV(n,pos[0],pos[1],pos[2], 0 ); + m_Op->SetVI(n,pos[0],pos[1],pos[2], 0 ); + } + } + } + } + } + } + } + } + + // set voltage excitations + setupVoltageExcitation( volt_vIndex, volt_vExcit, volt_vDelay, volt_vDir ); + + // set current excitations + setupCurrentExcitation( curr_vIndex, curr_vExcit, curr_vDelay, curr_vDir ); + + return true; +} + +void Operator_Ext_Excitation::setupVoltageExcitation( vector<unsigned int> const volt_vIndex[3], vector<FDTD_FLOAT> const& volt_vExcit, + vector<unsigned int> const& volt_vDelay, vector<unsigned int> const& volt_vDir ) +{ + Volt_Count = volt_vIndex[0].size(); + for (int n=0; n<3; n++) + { + Volt_Count_Dir[n]=0; + delete[] Volt_index[n]; + Volt_index[n] = new unsigned int[Volt_Count]; + } + delete[] Volt_delay; + delete[] Volt_amp; + delete[] Volt_dir; + Volt_delay = new unsigned int[Volt_Count]; + Volt_amp = new FDTD_FLOAT[Volt_Count]; + Volt_dir = new unsigned short[Volt_Count]; + +// cerr << "Excitation::setupVoltageExcitation(): Number of voltage excitation points: " << Volt_Count << endl; +// if (Volt_Count==0) +// cerr << "No E-Field/voltage excitation found!" << endl; + for (int n=0; n<3; n++) + for (unsigned int i=0; i<Volt_Count; i++) + Volt_index[n][i] = volt_vIndex[n].at(i); + for (unsigned int i=0; i<Volt_Count; i++) + { + Volt_delay[i] = volt_vDelay.at(i); + Volt_amp[i] = volt_vExcit.at(i); + Volt_dir[i] = volt_vDir.at(i); + ++Volt_Count_Dir[Volt_dir[i]]; + } +} + +void Operator_Ext_Excitation::setupCurrentExcitation( vector<unsigned int> const curr_vIndex[3], vector<FDTD_FLOAT> const& curr_vExcit, + vector<unsigned int> const& curr_vDelay, vector<unsigned int> const& curr_vDir ) +{ + Curr_Count = curr_vIndex[0].size(); + for (int n=0; n<3; n++) + { + Curr_Count_Dir[n]=0; + delete[] Curr_index[n]; + Curr_index[n] = new unsigned int[Curr_Count]; + } + delete[] Curr_delay; + delete[] Curr_amp; + delete[] Curr_dir; + Curr_delay = new unsigned int[Curr_Count]; + Curr_amp = new FDTD_FLOAT[Curr_Count]; + Curr_dir = new unsigned short[Curr_Count]; + +// cerr << "Excitation::setupCurrentExcitation(): Number of current excitation points: " << Curr_Count << endl; +// if (Curr_Count==0) +// cerr << "No H-Field/current excitation found!" << endl; + for (int n=0; n<3; ++n) + for (unsigned int i=0; i<Curr_Count; i++) + Curr_index[n][i] = curr_vIndex[n].at(i); + for (unsigned int i=0; i<Curr_Count; i++) + { + Curr_delay[i] = curr_vDelay.at(i); + Curr_amp[i] = curr_vExcit.at(i); + Curr_dir[i] = curr_vDir.at(i); + ++Curr_Count_Dir[Curr_dir[i]]; + } + +} + +Engine_Extension* Operator_Ext_Excitation::CreateEngineExtention() +{ + return new Engine_Ext_Excitation(this); +} + +void Operator_Ext_Excitation::ShowStat(ostream &ostr) const +{ + Operator_Extension::ShowStat(ostr); + cout << "Voltage excitations\t: " << Volt_Count << "\t (" << Volt_Count_Dir[0] << ", " << Volt_Count_Dir[1] << ", " << Volt_Count_Dir[2] << ")" << endl; + cout << "Current excitations\t: " << Curr_Count << "\t (" << Curr_Count_Dir[0] << ", " << Curr_Count_Dir[1] << ", " << Curr_Count_Dir[2] << ")" << endl; + cout << "Excitation Length (TS)\t: " << m_Exc->GetLength() << endl; + cout << "Excitation Length (s)\t: " << m_Exc->GetLength()*m_Op->GetTimestep() << endl; +} + diff --git a/openEMS/FDTD/extensions/operator_ext_excitation.h b/openEMS/FDTD/extensions/operator_ext_excitation.h new file mode 100644 index 0000000..2abcef0 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_excitation.h @@ -0,0 +1,84 @@ +/* +* Copyright (C) 2011 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_EXCITATION_H +#define OPERATOR_EXT_EXCITATION_H + +#include "operator_extension.h" +#include "FDTD/operator.h" + +class Excitation; + +class Operator_Ext_Excitation : public Operator_Extension +{ + friend class Engine_Ext_Excitation; + friend class Engine_Ext_Mur_ABC; + friend class Operator; +public: + Operator_Ext_Excitation(Operator* op); + ~Operator_Ext_Excitation(); + + virtual Operator_Extension* Clone(Operator* op); + + virtual bool BuildExtension(); + + virtual Engine_Extension* CreateEngineExtention(); + + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const {UNUSED(closedAlpha); UNUSED(R0_included); return true;} + virtual bool IsCylindricalMultiGridSave(bool child) const {UNUSED(child); return true;} + virtual bool IsMPISave() const {return true;} + + virtual string GetExtensionName() const {return string("Excitation Extension");} + + virtual void ShowStat(ostream &ostr) const; + + virtual void Init(); + virtual void Reset(); + + unsigned int GetVoltCount() const {return Volt_Count;} + unsigned int GetVoltCount(int ny) const {return Volt_Count_Dir[ny];} + + unsigned int GetCurrCount() const {return Curr_Count;} + unsigned int GetCurrCount(int ny) const {return Curr_Count_Dir[ny];} + +protected: + Operator_Ext_Excitation(Operator* op, Operator_Ext_Excitation* op_ext); + + Excitation* m_Exc; + + void setupVoltageExcitation( vector<unsigned int> const volt_vIndex[3], vector<FDTD_FLOAT> const& volt_vExcit, + vector<unsigned int> const& volt_vDelay, vector<unsigned int> const& volt_vDir ); + void setupCurrentExcitation( vector<unsigned int> const curr_vIndex[3], vector<FDTD_FLOAT> const& curr_vExcit, + vector<unsigned int> const& curr_vDelay, vector<unsigned int> const& curr_vDir ); + //E-Field/voltage Excitation + unsigned int Volt_Count; + unsigned int Volt_Count_Dir[3]; + unsigned int* Volt_index[3]; + unsigned short* Volt_dir; + FDTD_FLOAT* Volt_amp; //represented as edge-voltages!! + unsigned int* Volt_delay; + + //H-Field/current Excitation + unsigned int Curr_Count; + unsigned int Curr_Count_Dir[3]; + unsigned int* Curr_index[3]; + unsigned short* Curr_dir; + FDTD_FLOAT* Curr_amp; //represented as edge-currents!! + unsigned int* Curr_delay; +}; + +#endif // OPERATOR_EXT_EXCITATION_H diff --git a/openEMS/FDTD/extensions/operator_ext_lorentzmaterial.cpp b/openEMS/FDTD/extensions/operator_ext_lorentzmaterial.cpp new file mode 100644 index 0000000..9f386fc --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_lorentzmaterial.cpp @@ -0,0 +1,453 @@ +/* +* 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_lorentzmaterial.h" +#include "engine_ext_lorentzmaterial.h" +#include "operator_ext_cylinder.h" +#include "../operator_cylinder.h" + +#include "CSPropLorentzMaterial.h" +#include "CSPropDebyeMaterial.h" + +Operator_Ext_LorentzMaterial::Operator_Ext_LorentzMaterial(Operator* op) : Operator_Ext_Dispersive(op) +{ + v_int_ADE = NULL; + v_ext_ADE = NULL; + i_int_ADE = NULL; + i_ext_ADE = NULL; + + v_Lor_ADE = NULL; + i_Lor_ADE = NULL; + + m_curr_Lor_ADE_On = NULL; + m_curr_Lor_ADE_On = NULL; +} + +Operator_Ext_LorentzMaterial::Operator_Ext_LorentzMaterial(Operator* op, Operator_Ext_LorentzMaterial* op_ext) : Operator_Ext_Dispersive(op,op_ext) +{ + v_int_ADE = NULL; + v_ext_ADE = NULL; + i_int_ADE = NULL; + i_ext_ADE = NULL; + + v_Lor_ADE = NULL; + i_Lor_ADE = NULL; + + m_curr_Lor_ADE_On = NULL; + m_curr_Lor_ADE_On = NULL; +} + +Operator_Ext_LorentzMaterial::~Operator_Ext_LorentzMaterial() +{ + for (int i=0;i<m_Order;++i) + { + for (int n=0; n<3; ++n) + { + if (m_volt_ADE_On[i]) + { + delete[] v_int_ADE[i][n]; + delete[] v_ext_ADE[i][n]; + } + if (m_curr_ADE_On[i]) + { + delete[] i_int_ADE[i][n]; + delete[] i_ext_ADE[i][n]; + } + if (m_volt_Lor_ADE_On[i]) + delete[] v_Lor_ADE[i][n]; + if (m_curr_Lor_ADE_On[i]) + delete[] i_Lor_ADE[i][n]; + } + if (m_volt_ADE_On[i]) + { + delete[] v_int_ADE[i]; + delete[] v_ext_ADE[i]; + } + if (m_curr_ADE_On[i]) + { + delete[] i_int_ADE[i]; + delete[] i_ext_ADE[i]; + } + if (m_volt_Lor_ADE_On[i]) + delete[] v_Lor_ADE[i]; + if (m_curr_Lor_ADE_On[i]) + delete[] i_Lor_ADE[i]; + } + delete[] v_int_ADE; + delete[] v_ext_ADE; + delete[] i_int_ADE; + delete[] i_ext_ADE; + v_int_ADE = NULL; + v_ext_ADE = NULL; + i_int_ADE = NULL; + i_ext_ADE = NULL; + + delete[] v_Lor_ADE; + delete[] i_Lor_ADE; + v_Lor_ADE = NULL; + i_Lor_ADE = NULL; + + delete[] m_curr_Lor_ADE_On; + delete[] m_volt_Lor_ADE_On; + m_curr_Lor_ADE_On = NULL; + m_curr_Lor_ADE_On = NULL; +} + +Operator_Extension* Operator_Ext_LorentzMaterial::Clone(Operator* op) +{ + if (dynamic_cast<Operator_Ext_LorentzMaterial*>(this)==NULL) + return NULL; + return new Operator_Ext_LorentzMaterial(op, this); +} + +bool Operator_Ext_LorentzMaterial::BuildExtension() +{ + double dT = m_Op->GetTimestep(); + unsigned int pos[] = {0,0,0}; + double coord[3]; + unsigned int numLines[3] = {m_Op->GetNumberOfLines(0,true),m_Op->GetNumberOfLines(1,true),m_Op->GetNumberOfLines(2,true)}; + CSPropLorentzMaterial* mat = NULL; + CSPropDebyeMaterial* debye_mat = NULL; + + bool warn_once = true; + + bool b_pos_on; + vector<unsigned int> v_pos[3]; + + // drude material parameter + double w_plasma,t_relax; + double L_D[3], C_D[3]; + double R_D[3], G_D[3]; + vector<double> v_int[3]; + vector<double> v_ext[3]; + vector<double> i_int[3]; + vector<double> i_ext[3]; + + //additional Dorentz material parameter + double w_Lor_Pol; + double C_L[3]; + double L_L[3]; + vector<double> v_Lor[3]; + vector<double> i_Lor[3]; + + m_Order = 0; + vector<CSProperties*> LD_props = m_Op->CSX->GetPropertyByType(CSProperties::LORENTZMATERIAL); + for (size_t n=0;n<LD_props.size();++n) + { + CSPropLorentzMaterial* LorMat = dynamic_cast<CSPropLorentzMaterial*>(LD_props.at(n)); + if (LorMat==NULL) + return false; //sanity check, this should not happen + if (LorMat->GetDispersionOrder()>m_Order) + m_Order=LorMat->GetDispersionOrder(); + } + LD_props = m_Op->CSX->GetPropertyByType(CSProperties::DEBYEMATERIAL); + for (size_t n=0;n<LD_props.size();++n) + { + CSPropDebyeMaterial* DebyeMat = dynamic_cast<CSPropDebyeMaterial*>(LD_props.at(n)); + if (DebyeMat==NULL) + return false; //sanity check, this should not happen + if (DebyeMat->GetDispersionOrder()>m_Order) + m_Order=DebyeMat->GetDispersionOrder(); + } + + m_LM_pos = new unsigned int**[m_Order]; + + m_volt_ADE_On = new bool[m_Order]; + m_curr_ADE_On = new bool[m_Order]; + m_volt_Lor_ADE_On = new bool[m_Order]; + m_curr_Lor_ADE_On = new bool[m_Order]; + + v_int_ADE = new FDTD_FLOAT**[m_Order]; + v_ext_ADE = new FDTD_FLOAT**[m_Order]; + i_int_ADE = new FDTD_FLOAT**[m_Order]; + i_ext_ADE = new FDTD_FLOAT**[m_Order]; + + v_Lor_ADE = new FDTD_FLOAT**[m_Order]; + i_Lor_ADE = new FDTD_FLOAT**[m_Order]; + + for (int order=0;order<m_Order;++order) + { + m_volt_ADE_On[order]=false; + m_curr_ADE_On[order]=false; + + m_volt_Lor_ADE_On[order]=false; + m_curr_Lor_ADE_On[order]=false; + + for (int n=0;n<3;++n) + { + v_pos[n].clear(); + + v_int[n].clear(); + v_ext[n].clear(); + i_int[n].clear(); + i_ext[n].clear(); + + v_Lor[n].clear(); + i_Lor[n].clear(); + } + + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + vector<CSPrimitives*> vPrims = m_Op->GetPrimitivesBoundBox(pos[0], pos[1], -1, (CSProperties::PropertyType)(CSProperties::MATERIAL | CSProperties::METAL)); + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + unsigned int index = m_Op->MainOp->SetPos(pos[0],pos[1],pos[2]); + //calc epsilon lorentz material + b_pos_on = false; + for (int n=0; n<3; ++n) + { + L_D[n]=0; + R_D[n]=0; + C_L[n]=0; + if (m_Op->GetYeeCoords(n,pos,coord,false)==false) + continue; + if (m_CC_R0_included && (n==2) && (pos[0]==0)) + coord[1] = m_Op->GetDiscLine(1,0); + + if (m_Op->GetVI(n,pos[0],pos[1],pos[2])==0) + continue; + +// CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord,(CSProperties::PropertyType)(CSProperties::METAL | CSProperties::MATERIAL), true); + CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord, vPrims, true); + if ((mat = prop->ToLorentzMaterial())) + { + w_plasma = mat->GetEpsPlasmaFreqWeighted(order,n,coord) * 2 * PI; + if ((w_plasma>0) && (m_Op->EC_C[n][index]>0)) + { + b_pos_on = true; + m_volt_ADE_On[order] = true; + L_D[n] = 1/(w_plasma*w_plasma*m_Op->EC_C[n][index]); + } + t_relax = mat->GetEpsRelaxTimeWeighted(order,n,coord); + if ((t_relax>0) && m_volt_ADE_On[order]) + { + R_D[n] = L_D[n]/t_relax; + } + w_Lor_Pol = mat->GetEpsLorPoleFreqWeighted(order,n,coord) * 2 * PI; + if ((w_Lor_Pol>0) && (L_D[n]>0)) + { + m_volt_Lor_ADE_On[order] = true; + C_L[n] = 1/(w_Lor_Pol*w_Lor_Pol*L_D[n]); + } + } + if ((debye_mat = prop->ToDebyeMaterial())) + { + C_L[n] = 8.85418781762e-12*debye_mat->GetEpsDeltaWeighted(order,n,coord) * m_Op->GetEdgeArea(n, pos) / m_Op->GetEdgeLength(n,pos); + t_relax = debye_mat->GetEpsRelaxTimeWeighted(order,n,coord); + if ((t_relax<2.0*dT) && warn_once) + { + warn_once = false; + cerr << "Operator_Ext_LorentzMaterial::BuildExtension(): Warning, debye relaxation time is to small, skipping..." << endl; + } + if ((C_L[n]>0) && (t_relax>0) && (t_relax>2.0*dT)) + { + R_D[n] = t_relax/C_L[n]; + b_pos_on = true; + m_volt_ADE_On[order] = true; + m_volt_Lor_ADE_On[order] = true; + } + } + } + + for (int n=0; n<3; ++n) + { + C_D[n]=0; + G_D[n]=0; + L_L[n]=0; + if (m_Op->GetYeeCoords(n,pos,coord,true)==false) + continue; + if (m_Op->GetIV(n,pos[0],pos[1],pos[2])==0) + continue; + +// CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord,(CSProperties::PropertyType)(CSProperties::METAL | CSProperties::MATERIAL), true); + CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord, vPrims, true); + if ((mat = prop->ToLorentzMaterial())) + { + w_plasma = mat->GetMuePlasmaFreqWeighted(order,n,coord) * 2 * PI; + if ((w_plasma>0) && (m_Op->EC_L[n][index]>0)) + { + b_pos_on = true; + m_curr_ADE_On[order] = true; + C_D[n] = 1/(w_plasma*w_plasma*m_Op->EC_L[n][index]); + } + t_relax = mat->GetMueRelaxTimeWeighted(order,n,coord); + if ((t_relax>0) && m_curr_ADE_On[order]) + { + G_D[n] = C_D[n]/t_relax; + } + w_Lor_Pol = mat->GetMueLorPoleFreqWeighted(order,n,coord) * 2 * PI; + if ((w_Lor_Pol>0) && (C_D[n]>0)) + { + m_curr_Lor_ADE_On[order] = true; + L_L[n] = 1/(w_Lor_Pol*w_Lor_Pol*C_D[n]); + } + } + } + + if (b_pos_on) //this position has active drude material + { + for (unsigned int n=0; n<3; ++n) + { + v_pos[n].push_back(pos[n]); + if (L_D[n]>0) + { + v_int[n].push_back((2.0*L_D[n]-dT*R_D[n])/(2.0*L_D[n]+dT*R_D[n])); + // check for r==0 in clyindrical coords and get special VI cooefficient + if (m_CC_R0_included && n==2 && pos[0]==0) + v_ext[n].push_back(dT/(L_D[n]+dT*R_D[n]/2.0)*m_Op_Cyl->m_Cyl_Ext->vi_R0[pos[2]]); + else + v_ext[n].push_back(dT/(L_D[n]+dT*R_D[n]/2.0)*m_Op->GetVI(n,pos[0],pos[1],pos[2])); + } + else if ((R_D[n]>0) && (C_L[n]>0)) + { + v_int[n].push_back((2.0*dT-R_D[n]*C_L[n])/(C_L[n]*R_D[n])); + v_ext[n].push_back(2.0/R_D[n]*m_Op->GetVI(n,pos[0],pos[1],pos[2])); + } + else + { + v_int[n].push_back(1); + v_ext[n].push_back(0); + } + if (C_D[n]>0) + { + i_int[n].push_back((2.0*C_D[n]-dT*G_D[n])/(2.0*C_D[n]+dT*G_D[n])); + i_ext[n].push_back(dT/(C_D[n]+dT*G_D[n]/2.0)*m_Op->GetIV(n,pos[0],pos[1],pos[2])); + } + else + { + i_int[n].push_back(1); + i_ext[n].push_back(0); + } + if (C_L[n]>0) + v_Lor[n].push_back(dT/C_L[n]/m_Op->GetVI(n,pos[0],pos[1],pos[2])); + else + v_Lor[n].push_back(0); + if (L_L[n]>0) + i_Lor[n].push_back(dT/L_L[n]/m_Op->GetIV(n,pos[0],pos[1],pos[2])); + else + i_Lor[n].push_back(0); + } + } + } + } + } + + //copy all vectors into the array's + m_LM_Count.push_back(v_pos[0].size()); + + m_LM_pos[order] = new unsigned int*[3]; + + if (m_volt_ADE_On[order]) + { + v_int_ADE[order] = new FDTD_FLOAT*[3]; + v_ext_ADE[order] = new FDTD_FLOAT*[3]; + } + else + { + v_int_ADE[order] = NULL; + v_ext_ADE[order] = NULL; + } + + if (m_curr_ADE_On[order]) + { + i_int_ADE[order] = new FDTD_FLOAT*[3]; + i_ext_ADE[order] = new FDTD_FLOAT*[3]; + } + else + { + i_int_ADE[order] = NULL; + i_ext_ADE[order] = NULL; + } + + if (m_volt_Lor_ADE_On[order]) + v_Lor_ADE[order] = new FDTD_FLOAT*[3]; + else + v_Lor_ADE[order] = NULL; + + if (m_curr_Lor_ADE_On[order]) + i_Lor_ADE[order] = new FDTD_FLOAT*[3]; + else + i_Lor_ADE[order] = NULL; + + for (int n=0; n<3; ++n) + { + m_LM_pos[order][n] = new unsigned int[m_LM_Count.at(order)]; + for (unsigned int i=0; i<m_LM_Count.at(order); ++i) + m_LM_pos[order][n][i] = v_pos[n].at(i); + if (m_volt_ADE_On[order]) + { + v_int_ADE[order][n] = new FDTD_FLOAT[m_LM_Count.at(order)]; + v_ext_ADE[order][n] = new FDTD_FLOAT[m_LM_Count.at(order)]; + + for (unsigned int i=0; i<m_LM_Count.at(order); ++i) + { + v_int_ADE[order][n][i] = v_int[n].at(i); + v_ext_ADE[order][n][i] = v_ext[n].at(i); + } + } + if (m_curr_ADE_On[order]) + { + i_int_ADE[order][n] = new FDTD_FLOAT[m_LM_Count.at(order)]; + i_ext_ADE[order][n] = new FDTD_FLOAT[m_LM_Count.at(order)]; + + for (unsigned int i=0; i<m_LM_Count.at(order); ++i) + { + i_int_ADE[order][n][i] = i_int[n].at(i); + i_ext_ADE[order][n][i] = i_ext[n].at(i); + } + } + + if (m_volt_Lor_ADE_On[order]) + { + v_Lor_ADE[order][n] = new FDTD_FLOAT[m_LM_Count.at(order)]; + for (unsigned int i=0; i<m_LM_Count.at(order); ++i) + v_Lor_ADE[order][n][i] = v_Lor[n].at(i); + } + if (m_curr_Lor_ADE_On[order]) + { + i_Lor_ADE[order][n] = new FDTD_FLOAT[m_LM_Count.at(order)]; + for (unsigned int i=0; i<m_LM_Count.at(order); ++i) + i_Lor_ADE[order][n][i] = i_Lor[n].at(i); + } + } + } + + return true; +} + +Engine_Extension* Operator_Ext_LorentzMaterial::CreateEngineExtention() +{ + Engine_Ext_LorentzMaterial* eng_ext_lor = new Engine_Ext_LorentzMaterial(this); + return eng_ext_lor; +} + +void Operator_Ext_LorentzMaterial::ShowStat(ostream &ostr) const +{ + Operator_Extension::ShowStat(ostr); + string On_Off[2] = {"Off", "On"}; + ostr << " Max. Dispersion Order N = " << m_Order << endl; + for (int i=0;i<m_Order;++i) + { + ostr << " N=" << i << ":\t Active cells\t\t: " << m_LM_Count.at(i) << endl; + ostr << " N=" << i << ":\t Voltage ADE is \t: " << On_Off[m_volt_ADE_On[i]] << endl; + ostr << " N=" << i << ":\t Voltage Lor-ADE is \t: " << On_Off[m_volt_Lor_ADE_On[i]] << endl; + ostr << " N=" << i << ":\t Current ADE is \t: " << On_Off[m_curr_ADE_On[i]] << endl; + ostr << " N=" << i << ":\t Current Lor-ADE is \t: " << On_Off[m_curr_Lor_ADE_On[i]] << endl; + } +} diff --git a/openEMS/FDTD/extensions/operator_ext_lorentzmaterial.h b/openEMS/FDTD/extensions/operator_ext_lorentzmaterial.h new file mode 100644 index 0000000..d9e600b --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_lorentzmaterial.h @@ -0,0 +1,62 @@ +/* +* 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_LORENTZMATERIAL_H +#define OPERATOR_EXT_LORENTZMATERIAL_H + +#include "FDTD/operator.h" +#include "operator_ext_dispersive.h" + +class Operator_Ext_LorentzMaterial : public Operator_Ext_Dispersive +{ + friend class Engine_Ext_LorentzMaterial; +public: + Operator_Ext_LorentzMaterial(Operator* op); + virtual ~Operator_Ext_LorentzMaterial(); + + virtual Operator_Extension* Clone(Operator* op); + + virtual bool BuildExtension(); + + virtual Engine_Extension* CreateEngineExtention(); + + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const {UNUSED(closedAlpha); UNUSED(R0_included); return true;} + virtual bool IsCylindricalMultiGridSave(bool child) const {UNUSED(child); return true;} + virtual bool IsMPISave() const {return true;} + + virtual string GetExtensionName() const {return string("Drude/Lorentz Dispersive Material Extension");} + + virtual void ShowStat(ostream &ostr) const; + +protected: + //! Copy constructor + Operator_Ext_LorentzMaterial(Operator* op, Operator_Ext_LorentzMaterial* op_ext); + + //ADE update coefficients, array setup: coeff[N_order][direction][mesh_pos_index] + FDTD_FLOAT ***v_int_ADE; + FDTD_FLOAT ***v_ext_ADE; + FDTD_FLOAT ***i_int_ADE; + FDTD_FLOAT ***i_ext_ADE; + + bool *m_curr_Lor_ADE_On; + bool *m_volt_Lor_ADE_On; + + FDTD_FLOAT ***v_Lor_ADE; + FDTD_FLOAT ***i_Lor_ADE; +}; + +#endif // OPERATOR_EXT_LORENTZMATERIAL_H diff --git a/openEMS/FDTD/extensions/operator_ext_mur_abc.cpp b/openEMS/FDTD/extensions/operator_ext_mur_abc.cpp new file mode 100644 index 0000000..1df8583 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_mur_abc.cpp @@ -0,0 +1,210 @@ +/* +* 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_mur_abc.h" +#include "engine_ext_mur_abc.h" + +#include "tools/array_ops.h" + +#include "CSPropMaterial.h" + +Operator_Ext_Mur_ABC::Operator_Ext_Mur_ABC(Operator* op) : Operator_Extension(op) +{ + Initialize(); +} + +Operator_Ext_Mur_ABC::~Operator_Ext_Mur_ABC() +{ + Delete2DArray(m_Mur_Coeff_nyP,m_numLines); + m_Mur_Coeff_nyP = NULL; + Delete2DArray(m_Mur_Coeff_nyPP,m_numLines); + m_Mur_Coeff_nyPP = NULL; +} + +Operator_Ext_Mur_ABC::Operator_Ext_Mur_ABC(Operator* op, Operator_Ext_Mur_ABC* op_ext) : Operator_Extension(op, op_ext) +{ + Initialize(); + m_v_phase = op_ext->m_v_phase; + SetDirection(op_ext->m_ny,op_ext->m_top); +} + +Operator_Extension* Operator_Ext_Mur_ABC::Clone(Operator* op) +{ + if (dynamic_cast<Operator_Ext_Mur_ABC*>(this)==NULL) + return NULL; + return new Operator_Ext_Mur_ABC(op, this); +} + +bool Operator_Ext_Mur_ABC::IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const +{ + if ((m_ny==0) && (!m_top) && (R0_included || closedAlpha)) + return false; + if ((m_ny==1) && (closedAlpha)) + return false; + return true; +} + +bool Operator_Ext_Mur_ABC::IsCylindricalMultiGridSave(bool child) const +{ + if (m_ny==2) //always allow in z-direction + return true; + if ((m_ny==0) && (m_top) && (!child)) //if top r-direction and is not a child grid allow Mur... + return true; + //in all other cases this ABC is not save to use in CylindricalMultiGrid + return false; +} + +void Operator_Ext_Mur_ABC::Initialize() +{ + m_ny = -1; + m_nyP = -1; + m_nyPP = -1; + m_LineNr = 0; + m_LineNr_Shift = 0; + + m_v_phase = 0.0; + + m_Mur_Coeff_nyP = NULL; + m_Mur_Coeff_nyPP = NULL; + + m_numLines[0]=0; + m_numLines[1]=0; +} + +void Operator_Ext_Mur_ABC::SetDirection(int ny, bool top_ny) +{ + if ((ny<0) || (ny>2)) + return; + + Delete2DArray(m_Mur_Coeff_nyP,m_numLines); + Delete2DArray(m_Mur_Coeff_nyPP,m_numLines); + + m_ny = ny; + m_top = top_ny; + m_nyP = (ny+1)%3; + m_nyPP = (ny+2)%3; + if (!top_ny) + { + m_LineNr = 0; + m_LineNr_Shift = 1; + } + else + { + m_LineNr = m_Op->GetNumberOfLines(m_ny,true)-1; + m_LineNr_Shift = m_Op->GetNumberOfLines(m_ny,true) - 2; + } + + m_numLines[0] = m_Op->GetNumberOfLines(m_nyP,true); + m_numLines[1] = m_Op->GetNumberOfLines(m_nyPP,true); + + m_Mur_Coeff_nyP = Create2DArray<FDTD_FLOAT>(m_numLines); + m_Mur_Coeff_nyPP = Create2DArray<FDTD_FLOAT>(m_numLines); + +} + +bool Operator_Ext_Mur_ABC::BuildExtension() +{ + if (m_ny<0) + { + cerr << "Operator_Ext_Mur_ABC::BuildExtension: Warning, Extension not initialized! Use SetDirection!! Abort build!!" << endl; + return false; + } + double dT = m_Op->GetTimestep(); + unsigned int pos[] = {0,0,0}; + pos[m_ny] = m_LineNr; + double delta = fabs(m_Op->GetEdgeLength(m_ny,pos)); + double coord[] = {0,0,0}; + coord[0] = m_Op->GetDiscLine(0,pos[0]); + coord[1] = m_Op->GetDiscLine(1,pos[1]); + coord[2] = m_Op->GetDiscLine(2,pos[2]); + + double eps,mue; + double c0t; + + if (m_LineNr==0) + coord[m_ny] = m_Op->GetDiscLine(m_ny,pos[m_ny]) + delta/2 / m_Op->GetGridDelta(); + else + coord[m_ny] = m_Op->GetDiscLine(m_ny,pos[m_ny]) - delta/2 / m_Op->GetGridDelta(); + + int posBB[3]; + posBB[m_ny] =pos[m_ny]; + posBB[m_nyPP]=-1; + + for (pos[m_nyP]=0; pos[m_nyP]<m_numLines[0]; ++pos[m_nyP]) + { + posBB[m_nyP]=pos[m_nyP]; + vector<CSPrimitives*> vPrims = m_Op->GetPrimitivesBoundBox(posBB[0], posBB[1], posBB[2], CSProperties::MATERIAL); + coord[m_nyP] = m_Op->GetDiscLine(m_nyP,pos[m_nyP]); + for (pos[m_nyPP]=0; pos[m_nyPP]<m_numLines[1]; ++pos[m_nyPP]) + { + coord[m_nyPP] = m_Op->GetDiscLine(m_nyPP,pos[m_nyPP]); +// CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord, CSProperties::MATERIAL, false); + CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord, vPrims, false); + if (prop) + { + CSPropMaterial* mat = prop->ToMaterial(); + + //nP + eps = mat->GetEpsilonWeighted(m_nyP,coord); + mue = mat->GetMueWeighted(m_nyP,coord); + if (m_v_phase>0.0) + c0t = m_v_phase * dT; + else + c0t = __C0__ * dT / sqrt(eps*mue); + m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] = (c0t - delta) / (c0t + delta); + + //nPP + eps = mat->GetEpsilonWeighted(m_nyPP,coord); + mue = mat->GetMueWeighted(m_nyPP,coord); + if (m_v_phase>0.0) + c0t = m_v_phase * dT; + else + c0t = __C0__ * dT / sqrt(eps*mue); + m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] = (c0t - delta) / (c0t + delta); + + } + else + { + if (m_v_phase>0.0) + c0t = m_v_phase * dT; + else + c0t = __C0__ / sqrt(m_Op->GetBackgroundEpsR()*m_Op->GetBackgroundMueR()) * dT; + m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] = (c0t - delta) / (c0t + delta); + m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] = m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]]; + } +// cerr << m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] << " : " << m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] << endl; + } + } +// cerr << "Operator_Ext_Mur_ABC::BuildExtension(): " << m_ny << " @ " << m_LineNr << endl; + return true; +} + +Engine_Extension* Operator_Ext_Mur_ABC::CreateEngineExtention() +{ + Engine_Ext_Mur_ABC* eng_ext = new Engine_Ext_Mur_ABC(this); + return eng_ext; +} + + +void Operator_Ext_Mur_ABC::ShowStat(ostream &ostr) const +{ + Operator_Extension::ShowStat(ostr); + string XYZ[3] = {"x","y","z"}; + ostr << " Active direction\t: " << XYZ[m_ny] << " at line: " << m_LineNr << endl; + if (m_v_phase>0.0) + ostr << " Used phase velocity\t: " << m_v_phase << " (" << m_v_phase/__C0__ << " * c_0)" <<endl; +} diff --git a/openEMS/FDTD/extensions/operator_ext_mur_abc.h b/openEMS/FDTD/extensions/operator_ext_mur_abc.h new file mode 100644 index 0000000..ddc43c1 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_mur_abc.h @@ -0,0 +1,68 @@ +/* +* 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_MUR_ABC_H +#define OPERATOR_EXT_MUR_ABC_H + +#include "FDTD/operator.h" +#include "operator_extension.h" + +class Operator_Ext_Mur_ABC : public Operator_Extension +{ + friend class Engine_Ext_Mur_ABC; +public: + Operator_Ext_Mur_ABC(Operator* op); + ~Operator_Ext_Mur_ABC(); + + virtual Operator_Extension* Clone(Operator* op); + + //! Define the direction of this ABC: \a ny=0,1,2 -> x,y,z and if at bottom_ny -> e.g. x=0 or x=end + void SetDirection(int ny, bool top_ny); + + //! Set (override) the expected phase velocity of the incoming wave + void SetPhaseVelocity(double c_phase) {m_v_phase=c_phase;}; + + virtual bool BuildExtension(); + + virtual Engine_Extension* CreateEngineExtention(); + + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const; + virtual bool IsCylindricalMultiGridSave(bool child) const; + virtual bool IsMPISave() const {return true;} + + virtual string GetExtensionName() const {return string("Mur ABC Extension");} + + virtual void ShowStat(ostream &ostr) const; + +protected: + Operator_Ext_Mur_ABC(Operator* op, Operator_Ext_Mur_ABC* op_ext); + void Initialize(); + int m_ny; + int m_nyP,m_nyPP; + bool m_top; + unsigned int m_LineNr; + int m_LineNr_Shift; + + double m_v_phase; + + unsigned int m_numLines[2]; + + FDTD_FLOAT** m_Mur_Coeff_nyP; + FDTD_FLOAT** m_Mur_Coeff_nyPP; +}; + +#endif // OPERATOR_EXT_MUR_ABC_H diff --git a/openEMS/FDTD/extensions/operator_ext_steadystate.cpp b/openEMS/FDTD/extensions/operator_ext_steadystate.cpp new file mode 100644 index 0000000..b8395a8 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_steadystate.cpp @@ -0,0 +1,104 @@ +/* +* Copyright (C) 2015 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_steadystate.h" +#include "engine_ext_steadystate.h" + +Operator_Ext_SteadyState::Operator_Ext_SteadyState(Operator* op, double period): Operator_Extension(op) +{ + this->Reset(); + m_T_period = period; +} + +Operator_Ext_SteadyState::Operator_Ext_SteadyState(Operator* op, Operator_Ext_SteadyState* op_ext): Operator_Extension(op, op_ext) +{ + this->Reset(); + m_T_period = op_ext->m_T_period; +} + +Operator_Ext_SteadyState::~Operator_Ext_SteadyState() +{ +} + +Operator_Extension* Operator_Ext_SteadyState::Clone(Operator* op) +{ + //disable cloning, only the main operator needs to have a steady state detection + UNUSED(op); + return NULL; +} + +bool Operator_Ext_SteadyState::BuildExtension() +{ + double dT = m_Op->GetTimestep(); + m_TS_period = round(m_T_period/dT); + m_T_period = m_TS_period*dT; + return true; +} + +void Operator_Ext_SteadyState::Reset() +{ + for (int n=0;n<3;++n) + { + m_E_probe_pos[n].clear(); + m_H_probe_pos[n].clear(); + } + m_E_probe_dir.clear(); + m_H_probe_dir.clear(); + m_T_period = 0; + m_TS_period = 0; +} + +bool Operator_Ext_SteadyState::Add_E_Probe(unsigned int pos[3], int dir) +{ + if ((dir<0) || (dir>2)) + return false; + for (int n=0;n<3;++n) + if (pos[n]>=m_Op->GetNumberOfLines(n)) + return false; + for (int n=0;n<3;++n) + m_E_probe_pos[n].push_back(pos[n]); + m_E_probe_dir.push_back(dir); + return true; +} + +bool Operator_Ext_SteadyState::Add_H_Probe(unsigned int pos[3], int dir) +{ + if ((dir<0) || (dir>2)) + return false; + for (int n=0;n<3;++n) + if (pos[n]>=m_Op->GetNumberOfLines(n)) + return false; + for (int n=0;n<3;++n) + m_H_probe_pos[n].push_back(pos[n]); + m_H_probe_dir.push_back(dir); + return true; +} + +Engine_Extension* Operator_Ext_SteadyState::CreateEngineExtention() +{ + m_Eng_Ext = new Engine_Ext_SteadyState(this); + return m_Eng_Ext; +} + +void Operator_Ext_SteadyState::ShowStat(ostream &ostr) const +{ + Operator_Extension::ShowStat(ostr); + cout << "Period time (s): " << m_T_period << "\t Period TS: " << m_TS_period << endl; + cout << "Number of E probes\t: " << m_E_probe_dir.size() << endl; + cout << "Number of H probes\t: " << m_H_probe_dir.size() << endl; +} + diff --git a/openEMS/FDTD/extensions/operator_ext_steadystate.h b/openEMS/FDTD/extensions/operator_ext_steadystate.h new file mode 100644 index 0000000..b735ca3 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_steadystate.h @@ -0,0 +1,61 @@ +/* +* Copyright (C) 2015 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_STEADYSTATE_H +#define OPERATOR_EXT_STEADYSTATE_H + +#include "operator_extension.h" +#include "FDTD/operator.h" + +class Engine_Ext_SteadyState; + +class Operator_Ext_SteadyState : public Operator_Extension +{ + friend class Engine_Ext_SteadyState; +public: + Operator_Ext_SteadyState(Operator* op, double period); + virtual ~Operator_Ext_SteadyState(); + + virtual Operator_Extension* Clone(Operator* op); + + virtual bool BuildExtension(); + virtual Engine_Extension* CreateEngineExtention(); + + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const {UNUSED(closedAlpha); UNUSED(R0_included); return true;} + virtual bool IsCylindricalMultiGridSave(bool child) const {UNUSED(child); return true;} + virtual bool IsMPISave() const {return true;} + + virtual string GetExtensionName() const {return string("Steady-State Detection Extension");} + + virtual void ShowStat(ostream &ostr) const; + + virtual void Reset(); + + bool Add_E_Probe(unsigned int pos[3], int dir); + bool Add_H_Probe(unsigned int pos[3], int dir); + +protected: + Operator_Ext_SteadyState(Operator* op, Operator_Ext_SteadyState* op_ext); + double m_T_period; + unsigned int m_TS_period; + vector<unsigned int> m_E_probe_pos[3]; + vector<unsigned int> m_E_probe_dir; + vector<unsigned int> m_H_probe_pos[3]; + vector<unsigned int> m_H_probe_dir; +}; + +#endif // OPERATOR_EXT_STEADYSTATE_H diff --git a/openEMS/FDTD/extensions/operator_ext_tfsf.cpp b/openEMS/FDTD/extensions/operator_ext_tfsf.cpp new file mode 100644 index 0000000..663dc1f --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_tfsf.cpp @@ -0,0 +1,429 @@ +/* +* Copyright (C) 2012 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_tfsf.h" +#include "engine_ext_tfsf.h" +#include <cmath> + +#include "CSPrimBox.h" +#include "CSPropExcitation.h" + +Operator_Ext_TFSF::Operator_Ext_TFSF(Operator* op) : Operator_Extension(op) +{ + Init(); +} + +Operator_Ext_TFSF::~Operator_Ext_TFSF() +{ + Reset(); +} + +void Operator_Ext_TFSF::Init() +{ + for (int n=0;n<3;++n) + for (int l=0;l<2;++l) + for (int c=0;c<2;++c) + { + m_VoltDelay[n][l][c]=NULL; + m_VoltDelayDelta[n][l][c]=NULL; + m_VoltAmp[n][l][c]=NULL; + m_CurrDelay[n][l][c]=NULL; + m_CurrDelayDelta[n][l][c]=NULL; + m_CurrAmp[n][l][c]=NULL; + } + + m_Frequency = 0.0; + m_PhVel = __C0__; + Operator_Extension::Init(); +} + +void Operator_Ext_TFSF::Reset() +{ + for (int n=0;n<3;++n) + for (int l=0;l<2;++l) + for (int c=0;c<2;++c) + { + delete[] m_VoltDelay[n][l][c]; + m_VoltDelay[n][l][c]=NULL; + delete[] m_VoltDelayDelta[n][l][c]; + m_VoltDelayDelta[n][l][c]=NULL; + delete[] m_VoltAmp[n][l][c]; + m_VoltAmp[n][l][c]=NULL; + delete[] m_CurrDelay[n][l][c]; + m_CurrDelay[n][l][c]=NULL; + delete[] m_CurrDelayDelta[n][l][c]; + m_CurrDelayDelta[n][l][c]=NULL; + delete[] m_CurrAmp[n][l][c]; + m_CurrAmp[n][l][c]=NULL; + } + Operator_Extension::Reset(); +} + +Operator_Extension* Operator_Ext_TFSF::Clone(Operator* op) +{ + UNUSED(op); + return NULL; +} + +bool Operator_Ext_TFSF::BuildExtension() +{ + m_Exc = m_Op->GetExcitationSignal(); + double dT = m_Op->GetTimestep(); + if (dT==0) + return false; + if (m_Exc==0) + return false; + + Reset(); + ContinuousStructure* CSX = m_Op->GetGeometryCSX(); + + vector<CSProperties*> vec_prop = CSX->GetPropertyByType(CSProperties::EXCITATION); + + if (vec_prop.size()==0) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, no excitation properties found" << endl; + SetActive(false); + return false; + } + + double ref_index = sqrt(m_Op->GetBackgroundEpsR()*m_Op->GetBackgroundMueR()); + m_PhVel = __C0__/ref_index; + CSPropExcitation* elec=NULL; + CSProperties* prop=NULL; + CSPrimitives* prim=NULL; + CSPrimBox* box=NULL; + for (size_t p=0; p<vec_prop.size(); ++p) + { + prop = vec_prop.at(p); + elec = prop->ToExcitation(); + if (elec->GetExcitType()!=10) + continue; + if (prop->GetQtyPrimitives()!=1) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, plane wave excitation found with more (or less) than one primitive, skipping..." << endl; + continue; + } + prim = prop->GetPrimitive(0); + if (prim->GetType()!=CSPrimitives::BOX) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, plane wave excitation found with false non-Box primitive, skipping..." << endl; + continue; + } + box = prim->ToBox(); + if (box==NULL) //sanity check, should not happen! + { + SetActive(false); + return false; + } + + // found a plane-wave excite with exactly one box + for (int n=0;n<3;++n) + m_PropDir[n] = elec->GetPropagationDir(n); + double dir_norm = sqrt(m_PropDir[0]*m_PropDir[0]+m_PropDir[1]*m_PropDir[1]+m_PropDir[2]*m_PropDir[2]); + if (dir_norm==0) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, plane wave direction is zero, skipping..." << endl; + SetActive(false); + return false; + } + + //make it a unit vector + m_PropDir[0]/=dir_norm;m_PropDir[1]/=dir_norm;m_PropDir[2]/=dir_norm; + + if (m_Op->SnapBox2Mesh(box->GetStartCoord()->GetNativeCoords(), box->GetStopCoord()->GetNativeCoords(), m_Start, m_Stop)!=3) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, plane wave box dimension is invalid, skipping..." << endl; + SetActive(false); + return false; + } + + m_Frequency = elec->GetFrequency(); +// if (m_Frequency<=0) +// m_Frequency = m_Op->GetExcitationSignal()->GetFrequencyOfInterest(); + if (m_Frequency<=0) + m_PhVel=__C0__/ref_index; + else + m_PhVel=m_Op->CalcNumericPhaseVelocity(m_Start,m_Stop,m_PropDir,m_Frequency); + + if ((m_PhVel<0) || (m_PhVel>__C0__/ref_index) || isnan(m_PhVel)) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, invalid phase velocity found, resetting to c0! " << endl; + m_PhVel = __C0__/ref_index; + } + + double origin[3]; + unsigned int ui_origin[3]; + for (int n=0;n<3;++n) + { + m_E_Amp[n] = elec->GetExcitation(n); + m_numLines[n] = m_Stop[n]-m_Start[n]+1; + m_IncLow[n] = m_PropDir[n]>=0; + + if (m_Start[n]==0) + m_ActiveDir[n][0]=false; + else + m_ActiveDir[n][0]=true; + if (m_Stop[n]==m_Op->GetNumberOfLines(n,true)-1) + m_ActiveDir[n][1]=false; + else + m_ActiveDir[n][1]=true; + + if (m_IncLow[n]) + { + ui_origin[n] = m_Start[n]-1; + } + else + { + ui_origin[n] = m_Stop[n]+1; + } + origin[n] = m_Op->GetDiscLine(n,ui_origin[n]); + } + + double dotEk = (m_E_Amp[0]*m_PropDir[0] + m_E_Amp[1]*m_PropDir[1] + m_E_Amp[2]*m_PropDir[2]); + double angle = acos( dotEk / (m_E_Amp[0]*m_E_Amp[0] + m_E_Amp[1]*m_E_Amp[1] + m_E_Amp[2]*m_E_Amp[2]) ) / PI * 180; + + if (angle==0) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, plane wave direction and polarization is identical, skipping..." << endl; + SetActive(false); + return false; + } + if (angle!=90) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, angle between propagation direction and polarization is not 90deg, resetting E-polarization to : ("; + for (int n=0;n<3;++n) + m_E_Amp[n]-=m_PropDir[n]*dotEk; + cerr << m_E_Amp[0] << "," << m_E_Amp[1] << "," << m_E_Amp[2] << ")" << endl; + } + + int nP,nPP; + for (int n=0;n<3;++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + m_H_Amp[n] = m_PropDir[nP]*m_E_Amp[nPP] - m_PropDir[nPP]*m_E_Amp[nP]; + m_H_Amp[n] /= __Z0__*sqrt(m_Op->GetBackgroundMueR()/m_Op->GetBackgroundEpsR()); + } + + double coord[3]; + double unit = m_Op->GetGridDelta(); + double delay; + double dist; + unsigned int pos[3]; + unsigned int numP, ui_pos; + m_maxDelay = 0; + for (int n=0;n<3;++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + pos[n] = 0; //unused + pos[nP] = m_Start[nP]; + + numP = m_numLines[nP]*m_numLines[nPP]; + + if (!m_ActiveDir[n][0] && !m_ActiveDir[n][1]) + continue; + + for (int l=0;l<2;++l) + for (int c=0;c<2;++c) + { + if (m_ActiveDir[n][l]) + { + m_VoltDelay[n][l][c]=new unsigned int[numP]; + m_VoltDelayDelta[n][l][c]=new FDTD_FLOAT[numP]; + m_VoltAmp[n][l][c]=new FDTD_FLOAT[numP]; + + m_CurrDelay[n][l][c]=new unsigned int[numP]; + m_CurrDelayDelta[n][l][c]=new FDTD_FLOAT[numP]; + m_CurrAmp[n][l][c]=new FDTD_FLOAT[numP]; + } + } + + ui_pos = 0; + for (unsigned int i=0;i<m_numLines[nP];++i) + { + pos[nPP] = m_Start[nPP]; + for (unsigned int j=0;j<m_numLines[nPP];++j) + { + // current updates + pos[n] = m_Start[n]; + + if (m_ActiveDir[n][0]) + { + m_Op->GetYeeCoords(nP,pos,coord,false); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_CurrDelay[n][0][1][ui_pos] = floor(delay); + m_CurrDelayDelta[n][0][1][ui_pos] = delay - floor(delay); + m_CurrAmp[n][0][1][ui_pos] = m_E_Amp[nP]*m_Op->GetEdgeLength(nP,pos); + + m_Op->GetYeeCoords(nPP,pos,coord,false); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_CurrDelay[n][0][0][ui_pos] = floor(delay); + m_CurrDelayDelta[n][0][0][ui_pos] = delay - floor(delay); + m_CurrAmp[n][0][0][ui_pos] = m_E_Amp[nPP]*m_Op->GetEdgeLength(nPP,pos); + + --pos[n]; + m_CurrAmp[n][0][0][ui_pos]*=m_Op->GetIV(nP,pos); + m_CurrAmp[n][0][1][ui_pos]*=m_Op->GetIV(nPP,pos); + } + + if (m_ActiveDir[n][1]) + { + pos[n] = m_Stop[n]; + m_Op->GetYeeCoords(nP,pos,coord,false); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_CurrDelay[n][1][1][ui_pos] = floor(delay); + m_CurrDelayDelta[n][1][1][ui_pos] = delay - floor(delay); + m_CurrAmp[n][1][1][ui_pos] = m_E_Amp[nP]*m_Op->GetEdgeLength(nP,pos); + + m_Op->GetYeeCoords(nPP,pos,coord,false); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_CurrDelay[n][1][0][ui_pos] = floor(delay); + m_CurrDelayDelta[n][1][0][ui_pos] = delay - floor(delay); + m_CurrAmp[n][1][0][ui_pos] = m_E_Amp[nPP]*m_Op->GetEdgeLength(nPP,pos); + + m_CurrAmp[n][1][0][ui_pos]*=m_Op->GetIV(nP,pos); + m_CurrAmp[n][1][1][ui_pos]*=m_Op->GetIV(nPP,pos); + } + + if (m_ActiveDir[n][0]) + m_CurrAmp[n][0][0][ui_pos]*=-1; + if (m_ActiveDir[n][1]) + m_CurrAmp[n][1][1][ui_pos]*=-1; + + if (pos[nP]==m_Stop[nP]) + { + if (m_ActiveDir[n][0]) + m_CurrAmp[n][0][1][ui_pos]=0; + if (m_ActiveDir[n][1]) + m_CurrAmp[n][1][1][ui_pos]=0; + } + if (pos[nPP]==m_Stop[nPP]) + { + if (m_ActiveDir[n][0]) + m_CurrAmp[n][0][0][ui_pos]=0; + if (m_ActiveDir[n][1]) + m_CurrAmp[n][1][0][ui_pos]=0; + } + + // voltage updates + pos[n] = m_Start[n]-1; + if (m_ActiveDir[n][0]) + { + m_Op->GetYeeCoords(nP,pos,coord,true); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT + 1.0; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_VoltDelay[n][0][1][ui_pos] = floor(delay); + m_VoltDelayDelta[n][0][1][ui_pos] = delay - floor(delay); + m_VoltAmp[n][0][1][ui_pos] = m_H_Amp[nP]*m_Op->GetEdgeLength(nP,pos,true); + + m_Op->GetYeeCoords(nPP,pos,coord,true); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT + 1.0; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_VoltDelay[n][0][0][ui_pos] = floor(delay); + m_VoltDelayDelta[n][0][0][ui_pos] = delay - floor(delay); + m_VoltAmp[n][0][0][ui_pos] = m_H_Amp[nPP]*m_Op->GetEdgeLength(nPP,pos,true); + + ++pos[n]; + m_VoltAmp[n][0][0][ui_pos]*=m_Op->GetVI(nP,pos); + m_VoltAmp[n][0][1][ui_pos]*=m_Op->GetVI(nPP,pos); + } + + pos[n] = m_Stop[n]; + if (m_ActiveDir[n][1]) + { + m_Op->GetYeeCoords(nP,pos,coord,true); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT + 1.0; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_VoltDelay[n][1][1][ui_pos] = floor(delay); + m_VoltDelayDelta[n][1][1][ui_pos] = delay - floor(delay); + m_VoltAmp[n][1][1][ui_pos] = m_H_Amp[nP]*m_Op->GetEdgeLength(nP,pos,true); + + m_Op->GetYeeCoords(nPP,pos,coord,true); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT + 1.0; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_VoltDelay[n][1][0][ui_pos] = floor(delay); + m_VoltDelayDelta[n][1][0][ui_pos] = delay - floor(delay); + m_VoltAmp[n][1][0][ui_pos] = m_H_Amp[nPP]*m_Op->GetEdgeLength(nPP,pos,true); + + m_VoltAmp[n][1][0][ui_pos]*=m_Op->GetVI(nP,pos); + m_VoltAmp[n][1][1][ui_pos]*=m_Op->GetVI(nPP,pos); + } + + if (m_ActiveDir[n][1]) + m_VoltAmp[n][1][0][ui_pos]*=-1; + if (m_ActiveDir[n][0]) + m_VoltAmp[n][0][1][ui_pos]*=-1; + + if (pos[nP]==m_Stop[nP]) + { + if (m_ActiveDir[n][0]) + m_VoltAmp[n][0][0][ui_pos]=0; + if (m_ActiveDir[n][1]) + m_VoltAmp[n][1][0][ui_pos]=0; + } + if (pos[nPP]==m_Stop[nPP]) + { + if (m_ActiveDir[n][0]) + m_VoltAmp[n][0][1][ui_pos]=0; + if (m_ActiveDir[n][1]) + m_VoltAmp[n][1][1][ui_pos]=0; + } + + ++pos[nPP]; + ++ui_pos; + } + ++pos[nP]; + } + } + ++m_maxDelay; + return true; + } + SetActive(false); + return false; +} + +Engine_Extension* Operator_Ext_TFSF::CreateEngineExtention() +{ + return new Engine_Ext_TFSF(this); +} + +void Operator_Ext_TFSF::ShowStat(ostream &ostr) const +{ + Operator_Extension::ShowStat(ostr); + cout << "Active directions\t: " << "(" << m_ActiveDir[0][0] << "/" << m_ActiveDir[0][1] << ", " << m_ActiveDir[1][0] << "/" << m_ActiveDir[1][1] << ", " << m_ActiveDir[2][0] << "/" << m_ActiveDir[2][1] << ")" << endl; + cout << "Propagation direction\t: " << "(" << m_PropDir[0] << ", " << m_PropDir[1] << ", " << m_PropDir[2] << ")" << endl; + cout << "Rel. propagation speed\t: " << m_PhVel/__C0__ << "*c0 @ " << m_Frequency << " Hz" << endl; + cout << "E-field amplitude (V/m)\t: " << "(" << m_E_Amp[0] << ", " << m_E_Amp[1] << ", " << m_E_Amp[2] << ")" << endl; + cout << "H-field amplitude (A/m)\t: " << "(" << m_H_Amp[0] << ", " << m_H_Amp[1] << ", " << m_H_Amp[2] << ")" << endl; + cout << "Box Dimensions\t\t: " << m_numLines[0] << " x " << m_numLines[1] << " x " << m_numLines[2] << endl; + cout << "Max. Delay (TS)\t\t: " << m_maxDelay << endl; + int dirs = m_ActiveDir[0][0] + m_ActiveDir[0][1] + m_ActiveDir[1][0] + m_ActiveDir[1][1] + m_ActiveDir[2][0] + m_ActiveDir[2][1] ; + cout << "Memory usage (est.)\t: ~" << m_numLines[0] * m_numLines[1] * m_numLines[2] * dirs * 4 * 4 / 1024 << " kiB" << endl; +} diff --git a/openEMS/FDTD/extensions/operator_ext_tfsf.h b/openEMS/FDTD/extensions/operator_ext_tfsf.h new file mode 100644 index 0000000..e1e714e --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_tfsf.h @@ -0,0 +1,82 @@ +/* +* Copyright (C) 2012 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_TFSF_H +#define OPERATOR_EXT_TFSF_H + +#include "operator_extension.h" +#include "FDTD/operator.h" +#include "tools/constants.h" + +class Excitation; + +class Operator_Ext_TFSF : public Operator_Extension +{ + friend class Engine_Ext_TFSF; +public: + Operator_Ext_TFSF(Operator* op); + ~Operator_Ext_TFSF(); + + virtual Operator_Extension* Clone(Operator* op); + + virtual bool BuildExtension(); + + virtual Engine_Extension* CreateEngineExtention(); + + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const {UNUSED(closedAlpha); UNUSED(R0_included); return false;} + virtual bool IsCylindricalMultiGridSave(bool child) const {UNUSED(child); return false;} + + // FIXME, this extension is not save to use with MPI + virtual bool IsMPISave() const {return false;} + + virtual string GetExtensionName() const {return string("Total-Field/Scattered-Field Extension");} + + virtual void ShowStat(ostream &ostr) const; + + virtual void Init(); + virtual void Reset(); + +protected: + Excitation* m_Exc; + + bool m_IncLow[3]; + bool m_ActiveDir[3][2]; // m_ActiveDir[direction][low/high] + unsigned int m_Start[3]; + unsigned int m_Stop[3]; + unsigned int m_numLines[3]; + + double m_PropDir[3]; + double m_E_Amp[3]; + double m_H_Amp[3]; + + double m_Frequency; + double m_PhVel; + + unsigned int m_maxDelay; + + // array setup [direction][low/high][component][ <mesh_position> ] + unsigned int* m_VoltDelay[3][2][2]; + FDTD_FLOAT* m_VoltDelayDelta[3][2][2]; + FDTD_FLOAT* m_VoltAmp[3][2][2]; + + unsigned int* m_CurrDelay[3][2][2]; + FDTD_FLOAT* m_CurrDelayDelta[3][2][2]; + FDTD_FLOAT* m_CurrAmp[3][2][2]; + +}; + +#endif // OPERATOR_EXT_TFSF_H diff --git a/openEMS/FDTD/extensions/operator_ext_upml.cpp b/openEMS/FDTD/extensions/operator_ext_upml.cpp new file mode 100644 index 0000000..fc46d85 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_upml.cpp @@ -0,0 +1,478 @@ +/* +* 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 "FDTD/operator_cylindermultigrid.h" +#include "engine_ext_upml.h" +#include "tools/array_ops.h" +#include "fparser.hh" + +using namespace std; + +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*Z*(pow(2.5,W/dl)-1)) * pow(2.5, D/dl) "); + + 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(); +} + +void Operator_Ext_UPML::SetBoundaryCondition(const int* BCs, const unsigned int size[6]) +{ + for (int n=0; n<6; ++n) + { + m_BC[n]=BCs[n]; + m_Size[n]=size[n]; + } +} + +void Operator_Ext_UPML::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; + } +} + +bool Operator_Ext_UPML::Create_UPML(Operator* op, const int ui_BC[6], const unsigned int ui_size[6], string gradFunc) +{ + int BC[6]={ui_BC[0],ui_BC[1],ui_BC[2],ui_BC[3],ui_BC[4],ui_BC[5]}; + unsigned int size[6]={ui_size[0],ui_size[1],ui_size[2],ui_size[3],ui_size[4],ui_size[5]}; + + //check if mesh is large enough to support the pml + for (int n=0; n<3; ++n) + if ( (size[2*n]*(BC[2*n]==3)+size[2*n+1]*(BC[2*n+1]==3)) >= op->GetNumberOfLines(n,true) ) + { + cerr << "Operator_Ext_UPML::Create_UPML: Warning: Not enough lines in direction: " << n << ", resetting to PEC" << endl; + BC[2*n]=0; + size[2*n]=0; + BC[2*n+1]=0; + size[2*n+1]=0; + } + + //check cylindrical coord compatiblility + Operator_Cylinder* op_cyl = dynamic_cast<Operator_Cylinder*>(op); + if (op_cyl) + { + if ((BC[0]==3) && (op_cyl->GetClosedAlpha() || op_cyl->GetR0Included())) + { + BC[0]=0; + size[0]=0; + cerr << "Operator_Ext_UPML::Create_UPML: Warning: An upml in r-min direction is not possible, resetting to PEC..." << endl; + } + if ( (BC[2]==3) && (op_cyl->GetClosedAlpha()) ) + { + BC[2]=0; + size[2]=0; + cerr << "Operator_Ext_UPML::Create_UPML: Warning: An upml in alpha-min direction is not possible, resetting to PEC..." << endl; + } + if ( (BC[3]==3) && (op_cyl->GetClosedAlpha()) ) + { + BC[3]=0; + size[3]=0; + cerr << "Operator_Ext_UPML::Create_UPML: Warning: An upml in alpha-max direction is not possible, resetting to PEC..." << endl; + } + } + + //check cylindrical coord compatiblility + if (dynamic_cast<Operator_CylinderMultiGrid*>(op)) + { + if (BC[2]==3) + { + BC[2]=0; + size[2]=0; + cerr << "Operator_Ext_UPML::Create_UPML: Warning: An upml in alpha direction is not possible for a cylindrical multi-grid, resetting to PEC..." << endl; + } + if (BC[3]==3) + { + BC[3]=0; + size[3]=0; + cerr << "Operator_Ext_UPML::Create_UPML: Warning: An upml in alpha direction is not possible for a cylindrical multi-grid, resetting to PEC..." << endl; + } + } + + + Operator_Ext_UPML* op_ext_upml=NULL; + unsigned int start[3]={0 ,0 ,0}; + unsigned int stop[3] ={op->GetNumberOfLines(0,true)-1,op->GetNumberOfLines(1,true)-1,op->GetNumberOfLines(2,true)-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,true)-1-size[1]; + stop[0] =op->GetNumberOfLines(0,true)-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,true)-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,true)-1-size[3]; + stop[1] =op->GetNumberOfLines(1,true)-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,true)-1-(size[3]+1)*(BC[3]==3); + + //exclude x-lines that does not belong to the base multi-grid operator; + Operator_CylinderMultiGrid* op_cyl_MG = dynamic_cast<Operator_CylinderMultiGrid*>(op); + if (op_cyl_MG) + start[0] = op_cyl_MG->GetSplitPos()-1; + + 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,true)-1-size[5]; + stop[2] =op->GetNumberOfLines(2,true)-1; + op_ext_upml->SetBoundaryCondition(BC, size); + op_ext_upml->SetRange(start,stop); + op->AddExtension(op_ext_upml); + } + + BC[1]=0; + size[1]=0; + //create pml extensions (in z-direction only) for child operators in cylindrical multigrid operators + while (op_cyl_MG) + { + Operator_Cylinder* op_child = op_cyl_MG->GetInnerOperator(); + op_cyl_MG = dynamic_cast<Operator_CylinderMultiGrid*>(op_child); + for (int n=0; n<2; ++n) + { + start[n]=0; + stop[n]=op_child->GetNumberOfLines(n,true)-1; + } + + if (op_cyl_MG) + start[0] = op_cyl_MG->GetSplitPos()-1; + + if (BC[4]==3) + { + op_ext_upml = new Operator_Ext_UPML(op_child); + 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_child->AddExtension(op_ext_upml); + } + if (BC[5]==3) + { + op_ext_upml = new Operator_Ext_UPML(op_child); + op_ext_upml->SetGradingFunction(gradFunc); + start[2]=op->GetNumberOfLines(2,true)-1-size[5]; + stop[2] =op->GetNumberOfLines(2,true)-1; + op_ext_upml->SetBoundaryCondition(BC, size); + op_ext_upml->SetRange(start,stop); + op_child->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, 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 ((m_Op_Cyl) && (n==1)) + { + width *= m_Op_Cyl->GetDiscLine(0,pos[0]); + depth *= m_Op_Cyl->GetDiscLine(0,pos[0]); + } + + if (n==ny) + depth-=m_Op->GetEdgeLength(n,pos)/2; + double vars[5] = {depth, width/m_Size[2*n], width, Zm, (double)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->GetEdgeLength(n,pos)/2; + + if (n!=ny) + depth-=m_Op->GetEdgeLength(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,true) -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,true)-1) - m_Op->GetDiscLine(n,m_Op->GetNumberOfLines(n,true)-m_Size[2*n+1]-1))*m_Op->GetGridDelta(); + depth = width - (m_Op->GetDiscLine(n,m_Op->GetNumberOfLines(n,true)-1) - m_Op->GetDiscLine(n,pos[n]))*m_Op->GetGridDelta(); + + if ((m_Op_Cyl) && (n==1)) + { + width *= m_Op_Cyl->GetDiscLine(0,pos[0]); + depth *= m_Op_Cyl->GetDiscLine(0,pos[0]); + } + + if (n==ny) + depth+=m_Op->GetEdgeLength(n,pos)/2; + double vars[5] = {depth, width/(m_Size[2*n]), width, Zm, (double)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->GetEdgeLength(n,pos)/2; + + if (n!=ny) + depth+=m_Op->GetEdgeLength(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[4]; + 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]; + vector<CSPrimitives*> vPrims = m_Op->GetPrimitivesBoundBox(pos[0], pos[1], -1, CSProperties::MATERIAL); + for (loc_pos[2]=0; loc_pos[2]<m_numLines[2]; ++loc_pos[2]) + { + pos[2] = loc_pos[2] + m_StartPos[2]; + for (int n=0; n<3; ++n) + { + m_Op->Calc_EffMatPos(n,pos,eff_Mat,vPrims); + CalcGradingKappa(n, pos,__Z0__ ,kappa_v ,kappa_i); + nP = (n+1)%3; + nPP = (n+2)%3; + if ((kappa_v[0]+kappa_v[1]+kappa_v[2])!=0) + { + //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->SetVV(n,pos[0],pos[1],pos[2], (2*__EPS0__ - kappa_v[nP]*dT) / (2*__EPS0__ + kappa_v[nP]*dT) ); + m_Op->SetVI(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" + GetVV(n,loc_pos) = (2*__EPS0__ - kappa_v[nPP]*dT) / (2*__EPS0__ + kappa_v[nPP]*dT); + GetVVFN(n,loc_pos) = (2*__EPS0__ + kappa_v[n]*dT) / (2*__EPS0__ + kappa_v[nPP]*dT)/eff_Mat[0]; + GetVVFO(n,loc_pos) = (2*__EPS0__ - kappa_v[n]*dT) / (2*__EPS0__ + kappa_v[nPP]*dT)/eff_Mat[0]; + } + } + else + { + //disable upml + GetVV(n,loc_pos) = m_Op->GetVV(n,pos[0],pos[1],pos[2]); + m_Op->SetVV(n,pos[0],pos[1],pos[2], 0 ); + GetVVFO(n,loc_pos) = 0; + GetVVFN(n,loc_pos) = 1; + } + + if ((kappa_i[0]+kappa_i[1]+kappa_i[2])!=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->SetII(n,pos[0],pos[1],pos[2], (2*__EPS0__ - kappa_i[nP]*dT) / (2*__EPS0__ + kappa_i[nP]*dT) ); + m_Op->SetIV(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" + GetII(n,loc_pos) = (2*__EPS0__ - kappa_i[nPP]*dT) / (2*__EPS0__ + kappa_i[nPP]*dT); + GetIIFN(n,loc_pos) = (2*__EPS0__ + kappa_i[n]*dT) / (2*__EPS0__ + kappa_i[nPP]*dT)/eff_Mat[2]; + GetIIFO(n,loc_pos) = (2*__EPS0__ - kappa_i[n]*dT) / (2*__EPS0__ + kappa_i[nPP]*dT)/eff_Mat[2]; + } + } + else + { + //disable upml + GetII(n,loc_pos) = m_Op->GetII(n,pos[0],pos[1],pos[2]); + m_Op->SetII(n,pos[0],pos[1],pos[2], 0 ); + GetIIFO(n,loc_pos) = 0; + GetIIFN(n,loc_pos) = 1; + } + } + } + } + } + return true; +} + +Engine_Extension* Operator_Ext_UPML::CreateEngineExtention() +{ + Engine_Ext_UPML* eng_ext = new Engine_Ext_UPML(this); + return eng_ext; +} + +void Operator_Ext_UPML::ShowStat(ostream &ostr) const +{ + Operator_Extension::ShowStat(ostr); + + ostr << " PML range\t\t: " << "[" << m_StartPos[0]<< "," << m_StartPos[1]<< "," << m_StartPos[2]<< "] to [" + << m_StartPos[0]+m_numLines[0]-1 << "," << m_StartPos[1]+m_numLines[1]-1 << "," << m_StartPos[2]+m_numLines[2]-1 << "]" << endl; + ostr << " Grading function\t: \"" << m_GradFunc << "\"" << endl; +} diff --git a/openEMS/FDTD/extensions/operator_ext_upml.h b/openEMS/FDTD/extensions/operator_ext_upml.h new file mode 100644 index 0000000..5256655 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_upml.h @@ -0,0 +1,106 @@ +/* +* 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 "FDTD/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(); + + //! Returns always true, Create_UPML method will take care of creating a valid pml for the cylindrical fdtd + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const { UNUSED(closedAlpha); UNUSED(R0_included); return true;} + + //! Returns always true if base grid, Create_UPML will create proper child pml extensions. + virtual bool IsCylindricalMultiGridSave(bool child) const {if (child) return false; return true;} + + virtual bool IsMPISave() const {return true;} + + void SetBoundaryCondition(const int* BCs, const unsigned int size[6]); + + void SetRange(const unsigned int start[3], const unsigned int stop[3]); + + //! 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*Z*(pow(2.5,W/dl)-1)) * pow(2.5, D/dl) "); + + 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");} + + virtual void ShowStat(ostream &ostr) const; + + //! Create the UPML + static bool Create_UPML(Operator* op, const int ui_BC[6], const unsigned int ui_size[6], const 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, double kappa_v[3], double kappa_i[3]); + + void DeleteOp(); + + virtual FDTD_FLOAT& GetVV(int ny, unsigned int pos[3]) {return vv[ny][pos[0]][pos[1]][pos[2]];} + virtual FDTD_FLOAT& GetVVFO(int ny, unsigned int pos[3]) {return vvfo[ny][pos[0]][pos[1]][pos[2]];} + virtual FDTD_FLOAT& GetVVFN(int ny, unsigned int pos[3]) {return vvfn[ny][pos[0]][pos[1]][pos[2]];} + virtual FDTD_FLOAT& GetII(int ny, unsigned int pos[3]) {return ii[ny][pos[0]][pos[1]][pos[2]];} + virtual FDTD_FLOAT& GetIIFO(int ny, unsigned int pos[3]) {return iifo[ny][pos[0]][pos[1]][pos[2]];} + virtual FDTD_FLOAT& GetIIFN(int ny, unsigned int pos[3]) {return iifn[ny][pos[0]][pos[1]][pos[2]];} + + 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 diff --git a/openEMS/FDTD/extensions/operator_extension.cpp b/openEMS/FDTD/extensions/operator_extension.cpp new file mode 100644 index 0000000..50e7068 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_extension.cpp @@ -0,0 +1,54 @@ +/* +* 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_extension.h" +#include "FDTD/operator.h" +#include "FDTD/operator_cylinder.h" + +using namespace std; + +Operator_Extension::Operator_Extension(Operator* op) +{ + m_Op = op; + m_Active = true; + + m_CC_R0_included = false; + m_Op_Cyl = dynamic_cast<Operator_Cylinder*>(op); + if (m_Op_Cyl) + m_CC_R0_included=m_Op_Cyl->GetR0Included(); + m_Eng_Ext = NULL; +} + +Operator_Extension::~Operator_Extension() +{ +} + +Operator_Extension::Operator_Extension(Operator* op, Operator_Extension* op_ext) +{ + UNUSED(op_ext); + m_Op = op; + m_Op_Cyl = dynamic_cast<Operator_Cylinder*>(op); + m_Active = op_ext->m_Active; + if (m_Op_Cyl) + m_CC_R0_included=m_Op_Cyl->GetR0Included(); + m_Eng_Ext = NULL; +} + +void Operator_Extension::ShowStat(ostream &ostr) const +{ + ostr << "--- " << GetExtensionName() << " ---" << endl; +} diff --git a/openEMS/FDTD/extensions/operator_extension.h b/openEMS/FDTD/extensions/operator_extension.h new file mode 100644 index 0000000..21e42af --- /dev/null +++ b/openEMS/FDTD/extensions/operator_extension.h @@ -0,0 +1,87 @@ +/* +* 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_EXTENSION_H +#define OPERATOR_EXTENSION_H + +#include <string> + +#include <iostream> +#include <stdio.h> +#include <stdlib.h> + +#include "tools/global.h" + +class Operator; +class Operator_Cylinder; +class Engine_Extension; + +//! Abstract base-class for all operator extensions +class Operator_Extension +{ + friend class Engine_Extension; +public: + virtual ~Operator_Extension(); + + //! Create a clone of this extension, will return NULL if this is impossible + /*! + Create a clone of this extension, will return NULL if this is impossible (e.g. derived extension has no clone method and copy-constructor)... + BuildExtension has to be called separatly! + */ + virtual Operator_Extension* Clone(Operator* op) {UNUSED(op); return NULL;} + + virtual bool BuildExtension() {return true;} + + virtual Engine_Extension* CreateEngineExtention() {return 0;} + virtual Engine_Extension* GetEngineExtention() {return m_Eng_Ext;} + + //! The cylindrical operator will check whether the extension is save to use. Default is false. Derive this method to override. + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const {UNUSED(closedAlpha); UNUSED(R0_included); return false;} + + //! The cylindrical multi grid operator will check whether the extension is save to use. Default is false. Derive this method to override. + virtual bool IsCylindricalMultiGridSave(bool child) const {UNUSED(child); return false;} + + //! The MPI operator (if enabled) will check whether the extension is compatible with MPI. Default is false. Derive this method to override. + virtual bool IsMPISave() const {return false;} + + virtual std::string GetExtensionName() const {return std::string("Abstract Operator Extension Base Class");} + + virtual void ShowStat(std::ostream &ostr) const; + + virtual bool IsActive() const {return m_Active;} + virtual void SetActive(bool active=true) {m_Active=active;} + + virtual void Init() {} + virtual void Reset() {} + +protected: + Operator_Extension(Operator* op); + //! Copy constructor + Operator_Extension(Operator* op, Operator_Extension* op_ext); + + bool m_Active; + + //FDTD Operator + Operator* m_Op; + Engine_Extension* m_Eng_Ext; + + //Cylindrical FDTD Operator (not NULL if a cylindrical FDTD is used) + Operator_Cylinder* m_Op_Cyl; + bool m_CC_R0_included; +}; + +#endif // OPERATOR_EXTENSION_H diff --git a/openEMS/FDTD/openems_fdtd_mpi.cpp b/openEMS/FDTD/openems_fdtd_mpi.cpp new file mode 100644 index 0000000..eaab59a --- /dev/null +++ b/openEMS/FDTD/openems_fdtd_mpi.cpp @@ -0,0 +1,545 @@ +/* +* Copyright (C) 2011 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 "openems_fdtd_mpi.h" +#include "FDTD/engine_interface_fdtd.h" +#include "FDTD/operator_mpi.h" +#include "FDTD/operator_cylinder.h" +#include "FDTD/engine_mpi.h" +#include "Common/processfields.h" +#include "Common/processintegral.h" +#include <stdio.h> +#include <stdlib.h> +#include <iostream> +#include <sstream> +#include <vector> +#include <iomanip> +#include <string.h> +#include <sys/time.h> +#include <time.h> +#include "mpi.h" +#include "tools/useful.h" +#include "tinyxml.h" + +openEMS_FDTD_MPI::openEMS_FDTD_MPI(bool m_MPI_Debug) : openEMS() +{ + m_MyID = MPI::COMM_WORLD.Get_rank(); + m_NumProc = MPI::COMM_WORLD.Get_size(); + + m_MaxEnergy = 0; + m_EnergyDecrement = 1; + m_MPI_Op = NULL; + + if (m_NumProc>1) + m_MPI_Enabled=true; + else + m_MPI_Enabled=false; + + if (m_MyID==0) + { + m_Gather_Buffer = new int[m_NumProc]; + m_Energy_Buffer = new double[m_NumProc]; + } + else + { + m_Gather_Buffer = NULL; + m_Energy_Buffer = NULL; + } + + m_MPI_Elem = NULL; + m_Original_Grid = NULL; + + //redirect output to file for all ranks > 0 + if ((m_MyID>0) && (m_MPI_Debug==false)) + { + stringstream out_name; + out_name << "ID" << m_MyID << "_" << "output.txt"; + m_Output = new ofstream(); + m_Output->open(out_name.str().c_str()); + cout.rdbuf(m_Output->rdbuf()); + cerr.rdbuf(m_Output->rdbuf()); + } + else + m_Output = NULL; +} + +openEMS_FDTD_MPI::~openEMS_FDTD_MPI() +{ + delete[] m_Gather_Buffer; + m_Gather_Buffer = NULL; + delete[] m_Energy_Buffer; + m_Energy_Buffer = NULL; + delete m_Original_Grid; + m_Original_Grid = NULL; + delete m_Output; + m_Output=NULL; +} + +string openEMS_FDTD_MPI::GetExtLibsInfo() +{ + stringstream str; + + str << openEMS::GetExtLibsInfo(); + + // MPI + str << "\t\t" << "MPI -- Version: " << MPI_VERSION << "." << MPI_SUBVERSION << endl; + str << "\t\t" << " compiled against: "; +#ifdef MPICH2_VERSION + str << "MPICH2 " << MPICH2_VERSION << endl; +#endif + +#ifdef OMPI_MAJOR_VERSION + str << "openMPI" << OMPI_MAJOR_VERSION << "." << OMPI_MINOR_VERSION << "." << OMPI_RELEASE_VERSION << endl; +#endif + + return str.str(); +} + + +bool openEMS_FDTD_MPI::parseCommandLineArgument( const char *argv ) +{ + if (!argv) + return false; + + bool ret = openEMS::parseCommandLineArgument( argv ); + + if (ret) + return ret; + + if (strcmp(argv,"--engine=MPI")==0) + { + cout << "openEMS_FDTD_MPI - enabled MPI parallel processing" << endl; + m_engine = EngineType_MPI; + return true; + } + + return false; +} + +bool openEMS_FDTD_MPI::Parse_XML_FDTDSetup(TiXmlElement* FDTD_Opts) +{ + m_MPI_Elem = FDTD_Opts->FirstChildElement("MPI"); + if (!m_MPI_Enabled) + { + if ((m_MPI_Elem!=NULL)) + cerr << "openEMS_FDTD_MPI::SetupMPI: Warning: Number of MPI processes is 1, skipping MPI engine... " << endl; + return openEMS::Parse_XML_FDTDSetup(FDTD_Opts); + } + + if (m_MPI_Elem==NULL) + { + MPI_Barrier(MPI_COMM_WORLD); + if (m_MyID==0) + cerr << "openEMS_FDTD_MPI::SetupMPI: Error: no MPI settings found, exiting MPI engine... " << endl; + exit(-1); + } + + CSRectGrid* grid = m_CSX->GetGrid(); + delete m_Original_Grid; + m_Original_Grid = CSRectGrid::Clone(grid); + + string arg_Pos_Names[] = {"SplitPos_X", "SplitPos_Y", "SplitPos_Z"}; + string arg_N_Names[] = {"SplitN_X", "SplitN_Y", "SplitN_Z"}; + const char* tmp = NULL; + for (int n=0;n<3;++n) + { + m_SplitNumber[n].clear(); + m_SplitNumber[n].push_back(0); + tmp = m_MPI_Elem->Attribute(arg_Pos_Names[n].c_str()); + if (tmp) //check if a split position is requested + { + vector<double> SplitLines = SplitString2Double(tmp, ','); + bool inside; + unsigned int line; + for (size_t lineN = 0; lineN<SplitLines.size();++lineN) + { + line = m_Original_Grid->Snap2LineNumber(n, SplitLines.at(lineN), inside); + if (inside) + m_SplitNumber[n].push_back(line); + } + } + else //check if a number of splits is requested + { + int SplitN=0; + if (m_MPI_Elem->QueryIntAttribute( arg_N_Names[n].c_str(), &SplitN) == TIXML_SUCCESS) + { + if (SplitN>1) + { + + vector<unsigned int> jobs = AssignJobs2Threads(m_Original_Grid->GetQtyLines(n)-1, SplitN, true); + unsigned int line=0; + for (size_t i = 0; i<jobs.size()-1;++i) + { + line += jobs.at(i); + m_SplitNumber[n].push_back(line); + } + } + } + } + + m_SplitNumber[n].push_back(m_Original_Grid->GetQtyLines(n)-1); + unique(m_SplitNumber[n].begin(), m_SplitNumber[n].end()); + } + + return openEMS::Parse_XML_FDTDSetup(FDTD_Opts); +} + +bool openEMS_FDTD_MPI::SetupMPI() +{ + if (!m_MPI_Enabled) + return true; + + MPI_Barrier(MPI_COMM_WORLD); + + //validate number of processes + unsigned int numProcs = (m_SplitNumber[0].size()-1)*(m_SplitNumber[1].size()-1)*(m_SplitNumber[2].size()-1); + if (numProcs!=m_NumProc) + { + if (m_MyID==0) + cerr << "openEMS_FDTD_MPI::SetupMPI: Error: Requested splits require " << numProcs << " processes, but only " << m_NumProc << " were found! Exit! " << endl; + exit(10); + } + + //create process table + unsigned int procN = 0; + unsigned int splits[] = {(unsigned int)m_SplitNumber[0].size()-1, (unsigned int)m_SplitNumber[1].size()-1, (unsigned int)m_SplitNumber[2].size()-1}; + m_MPI_Op->SetSplitNumbers(0,splits[0]); + m_MPI_Op->SetSplitNumbers(1,splits[1]); + m_MPI_Op->SetSplitNumbers(2,splits[2]); + unsigned int*** procTable=Create3DArray<unsigned int>(splits); + for (size_t i=0;i<m_SplitNumber[0].size()-1;++i) + for (size_t j=0;j<m_SplitNumber[1].size()-1;++j) + for (size_t k=0;k<m_SplitNumber[2].size()-1;++k) + { + procTable[i][j][k] = procN; + ++procN; + } + m_MPI_Op->SetProcessTable(procTable); + + CSRectGrid* grid = m_CSX->GetGrid(); + //assign mesh and neighbors to this process + for (size_t i=0;i<m_SplitNumber[0].size()-1;++i) + { + for (size_t j=0;j<m_SplitNumber[1].size()-1;++j) + { + for (size_t k=0;k<m_SplitNumber[2].size()-1;++k) + { + if (procTable[i][j][k] == m_MyID) + { + m_MPI_Op->SetProcessTablePosition(0,i); + m_MPI_Op->SetProcessTablePosition(1,j); + m_MPI_Op->SetProcessTablePosition(2,k); + + grid->ClearLines(0); + grid->ClearLines(1); + grid->ClearLines(2); + + for (unsigned int n=m_SplitNumber[0].at(i);n<=m_SplitNumber[0].at(i+1);++n) + grid->AddDiscLine(0, m_Original_Grid->GetLine(0,n) ); + for (unsigned int n=m_SplitNumber[1].at(j);n<=m_SplitNumber[1].at(j+1);++n) + grid->AddDiscLine(1, m_Original_Grid->GetLine(1,n) ); + for (unsigned int n=m_SplitNumber[2].at(k);n<=m_SplitNumber[2].at(k+1);++n) + grid->AddDiscLine(2, m_Original_Grid->GetLine(2,n) ); + + m_MPI_Op->SetSplitPos(0,m_SplitNumber[0].at(i)); + m_MPI_Op->SetSplitPos(1,m_SplitNumber[1].at(i)); + m_MPI_Op->SetSplitPos(2,m_SplitNumber[2].at(i)); + + if (i>0) + m_MPI_Op->SetNeighborDown(0,procTable[i-1][j][k]); + if (i<m_SplitNumber[0].size()-2) + { + //add one additional line + grid->AddDiscLine(0, m_Original_Grid->GetLine(0,m_SplitNumber[0].at(i+1)+1 )); + m_MPI_Op->SetNeighborUp(0,procTable[i+1][j][k]); + } + + if (j>0) + m_MPI_Op->SetNeighborDown(1,procTable[i][j-1][k]); + if (j<m_SplitNumber[1].size()-2) + { + //add one additional line + grid->AddDiscLine(1, m_Original_Grid->GetLine(1,m_SplitNumber[1].at(j+1)+1 )); + m_MPI_Op->SetNeighborUp(1,procTable[i][j+1][k]); + } + + if (k>0) + m_MPI_Op->SetNeighborDown(2,procTable[i][j][k-1]); + if (k<m_SplitNumber[2].size()-2) + { + //add one additional line + grid->AddDiscLine(2, m_Original_Grid->GetLine(2,m_SplitNumber[2].at(k+1)+1 )); + m_MPI_Op->SetNeighborUp(2,procTable[i][j][k+1]); + } + + } + } + } + } + + m_MPI_Op->SetOriginalMesh(m_Original_Grid); + + m_MPI_Op->SetTag(0); + + return true; +} + + +bool openEMS_FDTD_MPI::SetupOperator() +{ + bool ret = true; + if (m_engine == EngineType_MPI) + { + FDTD_Op = Operator_MPI::New(); + } + else + { + ret = openEMS::SetupOperator(); + } + + m_MPI_Op = dynamic_cast<Operator_MPI*>(FDTD_Op); + + if ((m_MPI_Enabled) && (m_MPI_Op==NULL)) + { + cerr << "openEMS_FDTD_MPI::SetupOperator: Error: MPI is enabled but requested engine does not support MPI... EXIT!!!" << endl; + MPI_Barrier(MPI_COMM_WORLD); + exit(0); + } + + ret &= SetupMPI(); + + return ret; +} + +unsigned int openEMS_FDTD_MPI::GetNextStep() +{ + //start processing and get local next step + int step=PA->Process(); + double currTS = FDTD_Eng->GetNumberOfTimesteps(); + if ((step<0) || (step>(int)(NrTS - currTS))) step=NrTS - currTS; + + int local_step=step; + + //find the smallest next step requestes by all processings + MPI_Reduce(&local_step, &step, 1, MPI_INT, MPI_MIN, 0, MPI_COMM_WORLD); + //send the smallest next step to all + MPI_Bcast(&step, 1, MPI_INT, 0, MPI_COMM_WORLD); + + return step; +} + +bool openEMS_FDTD_MPI::CheckEnergyCalc() +{ + int local_Check = (int)m_ProcField->CheckTimestep(); + int result; + + //check if some process request an energy calculation --> the sum is larger than 0 + MPI_Reduce(&local_Check, &result, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); + //send result to all + MPI_Bcast(&result, 1, MPI_INT, 0, MPI_COMM_WORLD); + + //calc energy if result is non-zero + return result>0; +} + +double openEMS_FDTD_MPI::CalcEnergy() +{ + double energy = 0; + double loc_energy= m_ProcField->CalcTotalEnergyEstimate(); + + //calc the sum of all local energies + MPI_Reduce(&loc_energy, &energy, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); + //send sum-energy to all processes + MPI_Bcast(&energy, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if (energy>m_MaxEnergy) + m_MaxEnergy = energy; + if (m_MaxEnergy) + m_EnergyDecrement = energy/m_MaxEnergy; + + return energy; +} + +bool openEMS_FDTD_MPI::SetupProcessing() +{ + bool ret = openEMS::SetupProcessing(); + + //search for active processings in different processes + size_t numProc = PA->GetNumberOfProcessings(); + int active=0; + bool deactivate = false; + bool rename = false; + for (size_t n=0;n<numProc;++n) + { + Processing* proc = PA->GetProcessing(n); + int isActive = (int)proc->GetEnable(); + //sum of all active processings + MPI_Reduce(&isActive, &active, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); + deactivate = false; + rename = false; + if ((m_MyID==0) && (active>1)) //more than one active processing... + { + deactivate = true; //default + if (dynamic_cast<ProcessIntegral*>(proc)!=NULL) + { + //type is integral processing --> disable! Needs to be fixed! + cerr << "openEMS_FDTD_MPI::SetupProcessing(): Warning: Processing: " << proc->GetName() << " occures multiple times and is being deactivated..." << endl; + deactivate = true; + rename = false; + } + if (dynamic_cast<ProcessFields*>(proc)!=NULL) + { + //type is field processing --> renameing! Needs to be fixed! + cerr << "openEMS_FDTD_MPI::SetupProcessing(): Warning: Processing: " << proc->GetName() << " occures multiple times and is being renamed..." << endl; + deactivate = false; + rename = true; + } + } + //broadcast informations to all + MPI_Bcast(&deactivate, 1, MPI::BOOL, 0, MPI_COMM_WORLD); + MPI_Bcast(&rename, 1, MPI::BOOL, 0, MPI_COMM_WORLD); + if (deactivate) + proc->SetEnable(false); + if (rename) + { + ProcessFields* ProcField = dynamic_cast<ProcessFields*>(proc); + if (ProcField) + { + stringstream name_ss; + name_ss << "ID" << m_MyID << "_" << ProcField->GetName(); + ProcField->SetName(name_ss.str()); + ProcField->SetFileName(name_ss.str()); + } + } + } + return ret; +} + +int openEMS_FDTD_MPI::SetupFDTD() +{ + return openEMS::SetupFDTD(); +} + +void openEMS_FDTD_MPI::RunFDTD() +{ + if (!m_MPI_Enabled) + return openEMS::RunFDTD(); + + cout << "Running MPI-FDTD engine... this may take a while... grab a cup of coffee?!?" << endl; + + //get the sum of all cells + unsigned int local_NrCells=FDTD_Op->GetNumberCells(); + MPI_Reduce(&local_NrCells, &m_NumberCells, 1, MPI_UNSIGNED, MPI_SUM, 0, MPI_COMM_WORLD); + MPI_Bcast(&m_NumberCells, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD); + + //special handling of a field processing, needed to realize the end criteria... + m_ProcField = new ProcessFields(NewEngineInterface()); + PA->AddProcessing(m_ProcField); + + //init processings + PA->InitAll(); + + double currE=0; + + //add all timesteps to end-crit field processing with max excite amplitude + unsigned int maxExcite = FDTD_Op->GetExcitationSignal()->GetMaxExcitationTimestep(); +// for (unsigned int n=0; n<FDTD_Op->Exc->Volt_Count; ++n) +// m_ProcField->AddStep(FDTD_Op->Exc->Volt_delay[n]+maxExcite); + m_ProcField->AddStep(maxExcite); + + int prevTS=0,currTS=0; + double numCells = FDTD_Op->GetNumberCells(); + double speed = 0; + double t_diff; + double t_run; + + timeval currTime; + gettimeofday(&currTime,NULL); + timeval startTime = currTime; + timeval prevTime= currTime; + + if (m_DumpStats) + InitRunStatistics(__OPENEMS_RUN_STAT_FILE__); + //*************** simulate ************// + PA->PreProcess(); + int step = GetNextStep(); + + while ((step>0) && !CheckAbortCond()) + { + FDTD_Eng->IterateTS(step); + step = GetNextStep(); + + currTS = FDTD_Eng->GetNumberOfTimesteps(); + + currE = 0; + gettimeofday(&currTime,NULL); + t_diff = CalcDiffTime(currTime,prevTime); + + if (CheckEnergyCalc()) + currE = CalcEnergy(); + + //make sure all processes are at the same simulation time + MPI_Bcast(&t_diff, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if (t_diff>4) + { + if (currE==0) + currE = CalcEnergy(); + if (m_MyID==0) + { + t_run = CalcDiffTime(currTime,startTime); + speed = numCells*(currTS-prevTS)/t_diff; + cout << "[@" << FormatTime(t_run) << "] Timestep: " << setw(12) << currTS ; + cout << " || Speed: " << setw(6) << setprecision(1) << std::fixed << speed*1e-6 << " MC/s (" << setw(4) << setprecision(3) << std::scientific << t_diff/(currTS-prevTS) << " s/TS)" ; + cout << " || Energy: ~" << setw(6) << setprecision(2) << std::scientific << currE << " (-" << setw(5) << setprecision(2) << std::fixed << fabs(10.0*log10(m_EnergyDecrement)) << "dB)" << endl; + + //set step to zero to abort simulation and send to all + if (m_EnergyDecrement<endCrit) + step=0; + + if (m_DumpStats) + DumpRunStatistics(__OPENEMS_RUN_STAT_FILE__, t_run, currTS, speed, currE); + } + + MPI_Bcast(&step, 1, MPI_INT, 0, MPI_COMM_WORLD); + + prevTime=currTime; + prevTS=currTS; + + PA->FlushNext(); + } + } + if ((m_MyID==0) && (m_EnergyDecrement>endCrit) && (FDTD_Op->GetExcitationSignal()->GetExciteType()==0)) + cerr << "RunFDTD: max. number of timesteps was reached before the end-criteria of -" << fabs(10.0*log10(endCrit)) << "dB was reached... " << endl << \ + "\tYou may want to choose a higher number of max. timesteps... " << endl; + + gettimeofday(&currTime,NULL); + + t_diff = CalcDiffTime(currTime,startTime); + + if (m_MyID==0) + { + cout << "Time for " << FDTD_Eng->GetNumberOfTimesteps() << " iterations with " << FDTD_Op->GetNumberCells() << " cells : " << t_diff << " sec" << endl; + cout << "Speed: " << numCells*(double)FDTD_Eng->GetNumberOfTimesteps()/t_diff*1e-6 << " MCells/s " << endl; + + if (m_DumpStats) + DumpStatistics(__OPENEMS_STAT_FILE__, t_diff); + } + + //*************** postproc ************// + PA->PostProcess(); +} diff --git a/openEMS/FDTD/openems_fdtd_mpi.h b/openEMS/FDTD/openems_fdtd_mpi.h new file mode 100644 index 0000000..efb1f00 --- /dev/null +++ b/openEMS/FDTD/openems_fdtd_mpi.h @@ -0,0 +1,72 @@ +/* +* Copyright (C) 2011 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 OPENEMS_FDTD_MPI_H +#define OPENEMS_FDTD_MPI_H + +#include "openems.h" + +class ProcessFields; +class Operator_MPI; +class CSRectGrid; + +class openEMS_FDTD_MPI : public openEMS +{ +public: + openEMS_FDTD_MPI(bool m_MPI_Debug=false); + virtual ~openEMS_FDTD_MPI(); + + virtual bool Parse_XML_FDTDSetup(TiXmlElement* FDTD_Opts); + virtual int SetupFDTD(); + virtual void RunFDTD(); + + virtual bool parseCommandLineArgument( const char *argv ); + + static std::string GetExtLibsInfo(); + +protected: + Operator_MPI* m_MPI_Op; + CSRectGrid* m_Original_Grid; + unsigned int m_MyID; + unsigned int m_NumProc; + bool m_MPI_Enabled; + unsigned int m_NumberCells; + + std::vector<unsigned int> m_SplitNumber[3]; + TiXmlElement* m_MPI_Elem; + virtual bool SetupMPI(); + virtual bool SetupOperator(); + + int* m_Gather_Buffer; + unsigned int GetNextStep(); + + ProcessFields* m_ProcField; + double m_MaxEnergy; + double m_EnergyDecrement; + double* m_Energy_Buffer; + //! Check if energy calc is requested... + bool CheckEnergyCalc(); + //! Calc energy in all processes and add up + double CalcEnergy(); + + virtual bool SetupProcessing(); + + //output redirection to file for ranks > 0 + std::ofstream* m_Output; +}; + +#endif // OPENEMS_FDTD_MPI_H diff --git a/openEMS/FDTD/operator.cpp b/openEMS/FDTD/operator.cpp new file mode 100644 index 0000000..a7582aa --- /dev/null +++ b/openEMS/FDTD/operator.cpp @@ -0,0 +1,2131 @@ +/* +* 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 <fstream> +#include <algorithm> +#include "operator.h" +#include "engine.h" +#include "extensions/operator_extension.h" +#include "extensions/operator_ext_excitation.h" +#include "Common/processfields.h" +#include "tools/array_ops.h" +#include "tools/vtk_file_writer.h" +#include "fparser.hh" +#include "extensions/operator_ext_excitation.h" + +#include "vtkPolyData.h" +#include "vtkCellArray.h" +#include "vtkPoints.h" +#include "vtkXMLPolyDataWriter.h" +#include "CSPrimBox.h" +#include "CSPrimCurve.h" + +#include "CSPropMaterial.h" +#include "CSPropLumpedElement.h" + +Operator* Operator::New() +{ + cout << "Create FDTD operator" << endl; + Operator* op = new Operator(); + op->Init(); + return op; +} + +Operator::Operator() : Operator_Base() +{ + m_Exc = 0; + m_InvaildTimestep = false; + m_TimeStepVar = 3; +} + +Operator::~Operator() +{ + for (size_t n=0; n<m_Op_exts.size(); ++n) + delete m_Op_exts.at(n); + m_Op_exts.clear(); + + Delete(); +} + +Engine* Operator::CreateEngine() +{ + m_Engine = Engine::New(this); + return m_Engine; +} + +void Operator::Init() +{ + CSX = NULL; + m_Engine = NULL; + + Operator_Base::Init(); + + vv=NULL; + vi=NULL; + iv=NULL; + ii=NULL; + + m_epsR=NULL; + m_kappa=NULL; + m_mueR=NULL; + m_sigma=NULL; + + MainOp=NULL; + + for (int n=0; n<3; ++n) + { + EC_C[n]=NULL; + EC_G[n]=NULL; + EC_L[n]=NULL; + EC_R[n]=NULL; + } + + m_Exc = 0; + m_TimeStepFactor = 1; + SetMaterialAvgMethod(QuarterCell); +} + +void Operator::Delete() +{ + CSX = NULL; + + Delete_N_3DArray(vv,numLines); + Delete_N_3DArray(vi,numLines); + Delete_N_3DArray(iv,numLines); + Delete_N_3DArray(ii,numLines); + vv=vi=iv=ii=0; + delete MainOp; MainOp=0; + for (int n=0; n<3; ++n) + { + delete[] EC_C[n];EC_C[n]=0; + delete[] EC_G[n];EC_G[n]=0; + delete[] EC_L[n];EC_L[n]=0; + delete[] EC_R[n];EC_R[n]=0; + } + + Delete_N_3DArray(m_epsR,numLines); + m_epsR=0; + Delete_N_3DArray(m_kappa,numLines); + m_kappa=0; + Delete_N_3DArray(m_mueR,numLines); + m_mueR=0; + Delete_N_3DArray(m_sigma,numLines); + m_sigma=0; +} + +void Operator::Reset() +{ + Delete(); + Operator_Base::Reset(); +} + +double Operator::GetDiscLine(int n, unsigned int pos, bool dualMesh) const +{ + if ((n<0) || (n>2)) return 0.0; + if (pos>=numLines[n]) return 0.0; + if (dualMesh==false) + return discLines[n][pos]; + + // return dual mesh node + if (pos<numLines[n]-1) + return 0.5*(discLines[n][pos] + discLines[n][pos+1]); + + // dual node for the last line (outside the field domain) + return discLines[n][pos] + 0.5*(discLines[n][pos] - discLines[n][pos-1]); +} + +double Operator::GetDiscDelta(int n, unsigned int pos, bool dualMesh) const +{ + if ((n<0) || (n>2)) return 0.0; + if (pos>=numLines[n]) return 0.0; + double delta=0; + if (dualMesh==false) + { + if (pos<numLines[n]-1) + delta = GetDiscLine(n,pos+1,false) - GetDiscLine(n,pos,false); + else + delta = GetDiscLine(n,pos,false) - GetDiscLine(n,pos-1,false); + return delta; + } + else + { + if (pos>0) + delta = GetDiscLine(n,pos,true) - GetDiscLine(n,pos-1,true); + else + delta = GetDiscLine(n,1,false) - GetDiscLine(n,0,false); + return delta; + } +} + +bool Operator::GetYeeCoords(int ny, unsigned int pos[3], double* coords, bool dualMesh) const +{ + for (int n=0;n<3;++n) + coords[n]=GetDiscLine(n,pos[n],dualMesh); + coords[ny]=GetDiscLine(ny,pos[ny],!dualMesh); + + //check if position is inside the FDTD domain + if (dualMesh==false) //main grid + { + if (pos[ny]>=numLines[ny]-1) + return false; + } + else //dual grid + { + int nP = (ny+1)%3; + int nPP = (ny+2)%3; + if ((pos[nP]>=numLines[nP]-1) || (pos[nPP]>=numLines[nPP]-1)) + return false; + } + return true; +} + +bool Operator::GetNodeCoords(const unsigned int pos[3], double* coords, bool dualMesh, CoordinateSystem c_system) const +{ + for (int n=0;n<3;++n) + coords[n]=GetDiscLine(n,pos[n],dualMesh); + TransformCoordSystem(coords,coords,m_MeshType,c_system); + return true; +} + +double Operator::GetEdgeLength(int n, const unsigned int* pos, bool dualMesh) const +{ + return GetDiscDelta(n,pos[n],dualMesh)*gridDelta; +} + +double Operator::GetCellVolume(const unsigned int pos[3], bool dualMesh) const +{ + double vol=1; + for (int n=0;n<3;++n) + vol*=GetEdgeLength(n,pos,dualMesh); + return vol; +} + +double Operator::GetNodeWidth(int ny, const int pos[3], bool dualMesh) const +{ + if ( (pos[0]<0) || (pos[1]<0) || (pos[2]<0) ) + return 0.0; + + //call the unsigned int version of GetNodeWidth + unsigned int uiPos[]={(unsigned int)pos[0],(unsigned int)pos[1],(unsigned int)pos[2]}; + return GetNodeWidth(ny, uiPos, dualMesh); +} + +double Operator::GetNodeArea(int ny, const unsigned int pos[3], bool dualMesh) const +{ + int nyP = (ny+1)%3; + int nyPP = (ny+2)%3; + return GetNodeWidth(nyP,pos,dualMesh) * GetNodeWidth(nyPP,pos,dualMesh); +} + +double Operator::GetNodeArea(int ny, const int pos[3], bool dualMesh) const +{ + if ( (pos[0]<0) || (pos[1]<0) || (pos[2]<0) ) + return 0.0; + + //call the unsigned int version of GetNodeArea + unsigned int uiPos[]={(unsigned int)pos[0],(unsigned int)pos[1],(unsigned int)pos[2]}; + return GetNodeArea(ny, uiPos, dualMesh); +} + +unsigned int Operator::SnapToMeshLine(int ny, double coord, bool &inside, bool dualMesh, bool fullMesh) const +{ + inside = false; + if ((ny<0) || (ny>2)) + return 0; + if (coord<GetDiscLine(ny,0)) + return 0; + unsigned int numLines = GetNumberOfLines(ny, fullMesh); + if (coord>GetDiscLine(ny,numLines-1)) + return numLines-1; + inside=true; + if (dualMesh==false) + { + for (unsigned int n=0;n<numLines;++n) + { + if (coord<=GetDiscLine(ny,n,true)) + return n; + } + } + else + { + for (unsigned int n=1;n<numLines;++n) + { + if (coord<=GetDiscLine(ny,n,false)) + return n-1; + } + } + //should not happen + return 0; +} + +bool Operator::SnapToMesh(const double* dcoord, unsigned int* uicoord, bool dualMesh, bool fullMesh, bool* inside) const +{ + bool meshInside=false; + bool ok=true; + for (int n=0; n<3; ++n) + { + uicoord[n] = SnapToMeshLine(n,dcoord[n],meshInside,dualMesh,fullMesh); + ok &= meshInside; + if (inside) + inside[n]=meshInside; + } + return ok; +} + +int Operator::SnapBox2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh, bool fullMesh, int SnapMethod, bool* bStartIn, bool* bStopIn) const +{ + double l_start[3], l_stop[3]; + for (int n=0;n<3;++n) + { + l_start[n] = fmin(start[n],stop[n]); + l_stop[n] = fmax(start[n], stop[n]); + double min = GetDiscLine(n,0); + double max = GetDiscLine(n,GetNumberOfLines(n, fullMesh)-1); + if ( ((l_start[n]<min) && (l_stop[n]<min)) || ((l_start[n]>max) && (l_stop[n]>max)) ) + { + return -2; + } + } + + SnapToMesh(l_start, uiStart, dualMesh, fullMesh, bStartIn); + SnapToMesh(l_stop, uiStop, dualMesh, fullMesh, bStopIn); + int iDim = 0; + + if (SnapMethod==0) + { + for (int n=0;n<3;++n) + if (uiStop[n]>uiStart[n]) + ++iDim; + return iDim; + } + else if (SnapMethod==1) + { + for (int n=0;n<3;++n) + { + if (uiStop[n]>uiStart[n]) + { + if ((GetDiscLine( n, uiStart[n], dualMesh ) > l_start[n]) && (uiStart[n]>0)) + --uiStart[n]; + if ((GetDiscLine( n, uiStop[n], dualMesh ) < l_stop[n]) && (uiStop[n]<GetNumberOfLines(n, fullMesh)-1)) + ++uiStop[n]; + } + if (uiStop[n]>uiStart[n]) + ++iDim; + } + return iDim; + } + else if (SnapMethod==2) + { + for (int n=0;n<3;++n) + { + if (uiStop[n]>uiStart[n]) + { + if ((GetDiscLine( n, uiStart[n], dualMesh ) < l_start[n]) && (uiStart[n]<GetNumberOfLines(n, fullMesh)-1)) + ++uiStart[n]; + if ((GetDiscLine( n, uiStop[n], dualMesh ) > l_stop[n]) && (uiStop[n]>0)) + --uiStop[n]; + } + if (uiStop[n]>uiStart[n]) + ++iDim; + } + return iDim; + } + else + cerr << "Operator::SnapBox2Mesh: Unknown snapping method!" << endl; + return -1; +} + +int Operator::SnapLine2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh, bool fullMesh) const +{ + bool bStartIn[3]; + bool bStopIn[3]; + SnapToMesh(start, uiStart, dualMesh, fullMesh, bStartIn); + SnapToMesh(stop, uiStop, dualMesh, fullMesh, bStopIn); + + for (int n=0;n<3;++n) + { + if ((start[n]<GetDiscLine(n,0)) && (stop[n]<GetDiscLine(n,0))) + return -1; //lower bound violation + if ((start[n]>GetDiscLine(n,GetNumberOfLines(n,true)-1)) && (stop[n]>GetDiscLine(n,GetNumberOfLines(n,true)-1))) + return -1; //upper bound violation + } + + int ret = 0; + if (!(bStartIn[0] && bStartIn[1] && bStartIn[2])) + ret = ret + 1; + if (!(bStopIn[0] && bStopIn[1] && bStopIn[2])) + ret = ret + 2; + if (ret==0) + return ret; + + //fixme, do we need to do something about start or stop being outside the field domain? + //maybe caclulate the intersection point and snap to that? + //it seems to work like this as well... + + return ret; +} + + +Grid_Path Operator::FindPath(double start[], double stop[]) +{ + Grid_Path path; + unsigned int uiStart[3],uiStop[3],currPos[3]; + + int ret = SnapLine2Mesh(start, stop, uiStart, uiStop, false, true); + if (ret<0) + return path; + + currPos[0]=uiStart[0]; + currPos[1]=uiStart[1]; + currPos[2]=uiStart[2]; + double meshStart[3] = {discLines[0][uiStart[0]], discLines[1][uiStart[1]], discLines[2][uiStart[2]]}; + double meshStop[3] = {discLines[0][uiStop[0]], discLines[1][uiStop[1]], discLines[2][uiStop[2]]}; + bool UpDir = false; + double foot=0,dist=0,minFoot=0,minDist=0; + int minDir=0; + unsigned int minPos[3]; + double startFoot,stopFoot,currFoot; + Point_Line_Distance(meshStart,start,stop,startFoot,dist, m_MeshType); + Point_Line_Distance(meshStop,start,stop,stopFoot,dist, m_MeshType); + currFoot=startFoot; + minFoot=startFoot; + double P[3]; + + while (minFoot<stopFoot) + { + minDist=1e300; + for (int n=0; n<3; ++n) //check all 6 surrounding points + { + P[0] = discLines[0][currPos[0]]; + P[1] = discLines[1][currPos[1]]; + P[2] = discLines[2][currPos[2]]; + if (((int)currPos[n]-1)>=0) + { + P[n] = discLines[n][currPos[n]-1]; + Point_Line_Distance(P,start,stop,foot,dist, m_MeshType); + if ((foot>currFoot) && (dist<minDist)) + { + minFoot=foot; + minDist=dist; + minDir = n; + UpDir = false; + } + } + if ((currPos[n]+1)<numLines[n]) + { + P[n] = discLines[n][currPos[n]+1]; + Point_Line_Distance(P,start,stop,foot,dist, m_MeshType); + if ((foot>currFoot) && (dist<minDist)) + { + minFoot=foot; + minDist=dist; + minDir = n; + UpDir = true; + } + } + } + minPos[0]=currPos[0]; + minPos[1]=currPos[1]; + minPos[2]=currPos[2]; + if (UpDir) + { + currPos[minDir]+=1; + } + else + { + currPos[minDir]+=-1; + minPos[minDir]-=1; + } + //check validity of current postion + for (int n=0;n<3;++n) + if (currPos[n]>=numLines[n]) + { + cerr << __func__ << ": Error, path went out of simulation domain, skipping path!" << endl; + Grid_Path empty; + return empty; + } + path.posPath[0].push_back(minPos[0]); + path.posPath[1].push_back(minPos[1]); + path.posPath[2].push_back(minPos[2]); + currFoot=minFoot; + path.dir.push_back(minDir); + } + + //close missing edges, if currPos is not equal to uiStopPos + for (int n=0; n<3; ++n) + { + if (currPos[n]>uiStop[n]) + { + --currPos[n]; + path.posPath[0].push_back(currPos[0]); + path.posPath[1].push_back(currPos[1]); + path.posPath[2].push_back(currPos[2]); + path.dir.push_back(n); + } + else if (currPos[n]<uiStop[n]) + { + path.posPath[0].push_back(currPos[0]); + path.posPath[1].push_back(currPos[1]); + path.posPath[2].push_back(currPos[2]); + path.dir.push_back(n); + } + } + + return path; +} + +void Operator::SetMaterialAvgMethod(MatAverageMethods method) +{ + switch (method) + { + default: + case QuarterCell: + return SetQuarterCellMaterialAvg(); + case CentralCell: + return SetCellConstantMaterial(); + } +} + +double Operator::GetNumberCells() const +{ + if (numLines) + return (numLines[0])*(numLines[1])*(numLines[2]); //it's more like number of nodes??? + return 0; +} + +void Operator::ShowStat() const +{ + unsigned int OpSize = 12*numLines[0]*numLines[1]*numLines[2]*sizeof(FDTD_FLOAT); + unsigned int FieldSize = 6*numLines[0]*numLines[1]*numLines[2]*sizeof(FDTD_FLOAT); + double MBdiff = 1024*1024; + + cout << "------- Stat: FDTD Operator -------" << endl; + cout << "Dimensions\t\t: " << numLines[0] << "x" << numLines[1] << "x" << numLines[2] << " = " << numLines[0]*numLines[1]*numLines[2] << " Cells (" << numLines[0]*numLines[1]*numLines[2]/1e6 << " MCells)" << endl; + cout << "Size of Operator\t: " << OpSize << " Byte (" << (double)OpSize/MBdiff << " MiB) " << endl; + cout << "Size of Field-Data\t: " << FieldSize << " Byte (" << (double)FieldSize/MBdiff << " MiB) " << endl; + cout << "-----------------------------------" << endl; + cout << "Background materials (epsR/mueR/kappa/sigma): " << GetBackgroundEpsR() << "/" << GetBackgroundMueR() << "/" << GetBackgroundKappa() << "/" << GetBackgroundSigma() << endl; + cout << "-----------------------------------" << endl; + cout << "Number of PEC edges\t: " << m_Nr_PEC[0]+m_Nr_PEC[1]+m_Nr_PEC[2] << endl; + cout << "in " << GetDirName(0) << " direction\t\t: " << m_Nr_PEC[0] << endl; + cout << "in " << GetDirName(1) << " direction\t\t: " << m_Nr_PEC[1] << endl; + cout << "in " << GetDirName(2) << " direction\t\t: " << m_Nr_PEC[2] << endl; + cout << "-----------------------------------" << endl; + cout << "Timestep (s)\t\t: " << dT ; + if (opt_dT) + cout <<"\t(" << opt_dT << ")"; + cout << endl; + cout << "Timestep method name\t: " << m_Used_TS_Name << endl; + cout << "Nyquist criteria (TS)\t: " << m_Exc->GetNyquistNum() << endl; + cout << "Nyquist criteria (s)\t: " << m_Exc->GetNyquistNum()*dT << endl; + cout << "-----------------------------------" << endl; +} + +void Operator::ShowExtStat() const +{ + if (m_Op_exts.size()==0) return; + cout << "-----------------------------------" << endl; + for (size_t n=0; n<m_Op_exts.size(); ++n) + m_Op_exts.at(n)->ShowStat(cout); + cout << "-----------------------------------" << endl; +} + +void Operator::DumpOperator2File(string filename) +{ +#ifdef OUTPUT_IN_DRAWINGUNITS + double discLines_scaling = 1; +#else + double discLines_scaling = GetGridDelta(); +#endif + + cout << "Operator: Dumping FDTD operator information to vtk file: " << filename << " ..." << flush; + + VTK_File_Writer* vtk_Writer = new VTK_File_Writer(filename.c_str(), m_MeshType); + vtk_Writer->SetMeshLines(discLines,numLines,discLines_scaling); + vtk_Writer->SetHeader("openEMS - Operator dump"); + + vtk_Writer->SetNativeDump(true); + + //find excitation extension + Operator_Ext_Excitation* Op_Ext_Exc=GetExcitationExtension(); + + if (Op_Ext_Exc) + { + FDTD_FLOAT**** exc = NULL; + if (Op_Ext_Exc->Volt_Count>0) + { + exc = Create_N_3DArray<FDTD_FLOAT>(numLines); + for (unsigned int n=0; n< Op_Ext_Exc->Volt_Count; ++n) + exc[ Op_Ext_Exc->Volt_dir[n]][ Op_Ext_Exc->Volt_index[0][n]][ Op_Ext_Exc->Volt_index[1][n]][ Op_Ext_Exc->Volt_index[2][n]] = Op_Ext_Exc->Volt_amp[n]; + vtk_Writer->AddVectorField("exc_volt",exc); + Delete_N_3DArray(exc,numLines); + } + + if ( Op_Ext_Exc->Curr_Count>0) + { + exc = Create_N_3DArray<FDTD_FLOAT>(numLines); + for (unsigned int n=0; n< Op_Ext_Exc->Curr_Count; ++n) + exc[ Op_Ext_Exc->Curr_dir[n]][ Op_Ext_Exc->Curr_index[0][n]][ Op_Ext_Exc->Curr_index[1][n]][ Op_Ext_Exc->Curr_index[2][n]] = Op_Ext_Exc->Curr_amp[n]; + vtk_Writer->AddVectorField("exc_curr",exc); + Delete_N_3DArray(exc,numLines); + } + } + + FDTD_FLOAT**** vv_temp = Create_N_3DArray<FDTD_FLOAT>(numLines); + FDTD_FLOAT**** vi_temp = Create_N_3DArray<FDTD_FLOAT>(numLines); + FDTD_FLOAT**** iv_temp = Create_N_3DArray<FDTD_FLOAT>(numLines); + FDTD_FLOAT**** ii_temp = Create_N_3DArray<FDTD_FLOAT>(numLines); + + unsigned int pos[3], n; + for (n=0; n<3; n++) + for (pos[0]=0; pos[0]<numLines[0]; pos[0]++) + for (pos[1]=0; pos[1]<numLines[1]; pos[1]++) + for (pos[2]=0; pos[2]<numLines[2]; pos[2]++) + { + vv_temp[n][pos[0]][pos[1]][pos[2]] = GetVV(n,pos); + vi_temp[n][pos[0]][pos[1]][pos[2]] = GetVI(n,pos); + iv_temp[n][pos[0]][pos[1]][pos[2]] = GetIV(n,pos); + ii_temp[n][pos[0]][pos[1]][pos[2]] = GetII(n,pos); + } + + + vtk_Writer->AddVectorField("vv",vv_temp); + Delete_N_3DArray(vv_temp,numLines); + vtk_Writer->AddVectorField("vi",vi_temp); + Delete_N_3DArray(vi_temp,numLines); + vtk_Writer->AddVectorField("iv",iv_temp); + Delete_N_3DArray(iv_temp,numLines); + vtk_Writer->AddVectorField("ii",ii_temp); + Delete_N_3DArray(ii_temp,numLines); + + if (vtk_Writer->Write()==false) + cerr << "Operator::DumpOperator2File: Error: Can't write file... skipping!" << endl; + + delete vtk_Writer; +} + +//! \brief dump PEC (perfect electric conductor) information (into VTK-file) +//! visualization via paraview +//! visualize only one component (x, y or z) +void Operator::DumpPEC2File(string filename , unsigned int *range) +{ + cout << "Operator: Dumping PEC information to vtk file: " << filename << " ..." << flush; + +#ifdef OUTPUT_IN_DRAWINGUNITS + double scaling = 1.0; +#else + double scaling = GetGridDelta();; +#endif + + unsigned int start[3] = {0, 0, 0}; + unsigned int stop[3] = {numLines[0]-1,numLines[1]-1,numLines[2]-1}; + + if (range!=NULL) + for (int n=0;n<3;++n) + { + start[n] = range[2*n]; + stop[n] = range[2*n+1]; + } + + vtkPolyData* polydata = vtkPolyData::New(); + vtkCellArray *poly = vtkCellArray::New(); + vtkPoints *points = vtkPoints::New(); + + int* pointIdx[2]; + pointIdx[0] = new int[numLines[0]*numLines[1]]; + pointIdx[1] = new int[numLines[0]*numLines[1]]; + // init point idx + for (unsigned int n=0;n<numLines[0]*numLines[1];++n) + { + pointIdx[0][n]=-1; + pointIdx[1][n]=-1; + } + + int nP,nPP; + double coord[3]; + unsigned int pos[3],rpos[3]; + unsigned int mesh_idx=0; + for (pos[2]=start[2];pos[2]<stop[2];++pos[2]) + { // each xy-plane + for (unsigned int n=0;n<numLines[0]*numLines[1];++n) + { + pointIdx[0][n]=pointIdx[1][n]; + pointIdx[1][n]=-1; + } + for (pos[0]=start[0];pos[0]<stop[0];++pos[0]) + for (pos[1]=start[1];pos[1]<stop[1];++pos[1]) + { + for (int n=0;n<3;++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + if ((GetVV(n,pos) == 0) && (GetVI(n,pos) == 0) && (pos[nP]>0) && (pos[nPP]>0)) + { + rpos[0]=pos[0]; + rpos[1]=pos[1]; + rpos[2]=pos[2]; + + poly->InsertNextCell(2); + + mesh_idx = rpos[0] + rpos[1]*numLines[0]; + if (pointIdx[0][mesh_idx]<0) + { + for (int m=0;m<3;++m) + coord[m] = discLines[m][rpos[m]]; + TransformCoordSystem(coord, coord, m_MeshType, CARTESIAN); + for (int m=0;m<3;++m) + coord[m] *= scaling; + pointIdx[0][mesh_idx] = (int)points->InsertNextPoint(coord); + } + poly->InsertCellPoint(pointIdx[0][mesh_idx]); + + ++rpos[n]; + mesh_idx = rpos[0] + rpos[1]*numLines[0]; + if (pointIdx[n==2][mesh_idx]<0) + { + for (int m=0;m<3;++m) + coord[m] = discLines[m][rpos[m]]; + TransformCoordSystem(coord, coord, m_MeshType, CARTESIAN); + for (int m=0;m<3;++m) + coord[m] *= scaling; + pointIdx[n==2][mesh_idx] = (int)points->InsertNextPoint(coord); + } + poly->InsertCellPoint(pointIdx[n==2][mesh_idx]); + } + } + } + } + delete[] pointIdx[0]; + delete[] pointIdx[1]; + + polydata->SetPoints(points); + points->Delete(); + polydata->SetLines(poly); + poly->Delete(); + + vtkXMLPolyDataWriter* writer = vtkXMLPolyDataWriter::New(); + filename += ".vtp"; + writer->SetFileName(filename.c_str()); + +#if VTK_MAJOR_VERSION>=6 + writer->SetInputData(polydata); +#else + writer->SetInput(polydata); +#endif + writer->Write(); + + writer->Delete(); + polydata->Delete(); + cout << " done." << endl; +} + +void Operator::DumpMaterial2File(string filename) +{ +#ifdef OUTPUT_IN_DRAWINGUNITS + double discLines_scaling = 1; +#else + double discLines_scaling = GetGridDelta(); +#endif + + cout << "Operator: Dumping material information to vtk file: " << filename << " ..." << flush; + + FDTD_FLOAT**** epsilon = Create_N_3DArray<FDTD_FLOAT>(numLines); + FDTD_FLOAT**** mue = Create_N_3DArray<FDTD_FLOAT>(numLines); + FDTD_FLOAT**** kappa = Create_N_3DArray<FDTD_FLOAT>(numLines); + FDTD_FLOAT**** sigma = Create_N_3DArray<FDTD_FLOAT>(numLines); + + unsigned int pos[3]; + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + vector<CSPrimitives*> vPrims = this->GetPrimitivesBoundBox(pos[0], pos[1], -1, CSProperties::MATERIAL); + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + for (int n=0; n<3; ++n) + { + double inMat[4]; + Calc_EffMatPos(n, pos, inMat, vPrims); + epsilon[n][pos[0]][pos[1]][pos[2]] = inMat[0]/__EPS0__; + mue[n][pos[0]][pos[1]][pos[2]] = inMat[2]/__MUE0__; + kappa[n][pos[0]][pos[1]][pos[2]] = inMat[1]; + sigma[n][pos[0]][pos[1]][pos[2]] = inMat[3]; + } + } + } + } + + VTK_File_Writer* vtk_Writer = new VTK_File_Writer(filename.c_str(), m_MeshType); + vtk_Writer->SetMeshLines(discLines,numLines,discLines_scaling); + vtk_Writer->SetHeader("openEMS - material dump"); + + vtk_Writer->SetNativeDump(true); + + vtk_Writer->AddVectorField("epsilon",epsilon); + Delete_N_3DArray(epsilon,numLines); + vtk_Writer->AddVectorField("mue",mue); + Delete_N_3DArray(mue,numLines); + vtk_Writer->AddVectorField("kappa",kappa); + Delete_N_3DArray(kappa,numLines); + vtk_Writer->AddVectorField("sigma",sigma); + Delete_N_3DArray(sigma,numLines); + + if (vtk_Writer->Write()==false) + cerr << "Operator::DumpMaterial2File: Error: Can't write file... skipping!" << endl; + + delete vtk_Writer; +} + + bool Operator::SetupCSXGrid(CSRectGrid* grid) + { + for (int n=0; n<3; ++n) + { + discLines[n] = grid->GetLines(n,discLines[n],numLines[n],true); + if (numLines[n]<3) + { + cerr << "CartOperator::SetupCSXGrid: you need at least 3 disc-lines in every direction (3D!)!!!" << endl; + Reset(); + return false; + } + } + MainOp = new AdrOp(numLines[0],numLines[1],numLines[2]); + MainOp->SetGrid(discLines[0],discLines[1],discLines[2]); + if (grid->GetDeltaUnit()<=0) + { + cerr << "CartOperator::SetupCSXGrid: grid delta unit must not be <=0 !!!" << endl; + Reset(); + return false; + } + else gridDelta=grid->GetDeltaUnit(); + MainOp->SetGridDelta(1); + MainOp->AddCellAdrOp(); + + //delete the grid clone... + delete grid; + return true; + } + +bool Operator::SetGeometryCSX(ContinuousStructure* geo) +{ + if (geo==NULL) return false; + + CSX = geo; + + CSBackgroundMaterial* bg_mat=CSX->GetBackgroundMaterial(); + SetBackgroundEpsR(bg_mat->GetEpsilon()); + SetBackgroundMueR(bg_mat->GetMue()); + SetBackgroundKappa(bg_mat->GetKappa()); + SetBackgroundSigma(bg_mat->GetSigma()); + SetBackgroundDensity(0); + + CSRectGrid* grid=CSX->GetGrid(); + return SetupCSXGrid(CSRectGrid::Clone(grid)); +} + +void Operator::InitOperator() +{ + Delete_N_3DArray(vv,numLines); + Delete_N_3DArray(vi,numLines); + Delete_N_3DArray(iv,numLines); + Delete_N_3DArray(ii,numLines); + vv = Create_N_3DArray<FDTD_FLOAT>(numLines); + vi = Create_N_3DArray<FDTD_FLOAT>(numLines); + iv = Create_N_3DArray<FDTD_FLOAT>(numLines); + ii = Create_N_3DArray<FDTD_FLOAT>(numLines); +} + +void Operator::InitDataStorage() +{ + if (m_StoreMaterial[0]) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::InitDataStorage(): Storing epsR material data..." << endl; + Delete_N_3DArray(m_epsR,numLines); + m_epsR = Create_N_3DArray<float>(numLines); + } + if (m_StoreMaterial[1]) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::InitDataStorage(): Storing kappa material data..." << endl; + Delete_N_3DArray(m_kappa,numLines); + m_kappa = Create_N_3DArray<float>(numLines); + } + if (m_StoreMaterial[2]) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::InitDataStorage(): Storing muR material data..." << endl; + Delete_N_3DArray(m_mueR,numLines); + m_mueR = Create_N_3DArray<float>(numLines); + } + if (m_StoreMaterial[3]) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::InitDataStorage(): Storing sigma material data..." << endl; + Delete_N_3DArray(m_sigma,numLines); + m_sigma = Create_N_3DArray<float>(numLines); + } +} + +void Operator::CleanupMaterialStorage() +{ + if (!m_StoreMaterial[0] && m_epsR) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::CleanupMaterialStorage(): Delete epsR material data..." << endl; + Delete_N_3DArray(m_epsR,numLines); + m_epsR = NULL; + } + if (!m_StoreMaterial[1] && m_kappa) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::CleanupMaterialStorage(): Delete kappa material data..." << endl; + Delete_N_3DArray(m_kappa,numLines); + m_kappa = NULL; + } + if (!m_StoreMaterial[2] && m_mueR) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::CleanupMaterialStorage(): Delete mueR material data..." << endl; + Delete_N_3DArray(m_mueR,numLines); + m_mueR = NULL; + } + if (!m_StoreMaterial[3] && m_sigma) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::CleanupMaterialStorage(): Delete sigma material data..." << endl; + Delete_N_3DArray(m_sigma,numLines); + m_sigma = NULL; + } +} + +double Operator::GetDiscMaterial(int type, int n, const unsigned int pos[3]) const +{ + switch (type) + { + case 0: + if (m_epsR==0) + return 0; + return m_epsR[n][pos[0]][pos[1]][pos[2]]; + case 1: + if (m_kappa==0) + return 0; + return m_kappa[n][pos[0]][pos[1]][pos[2]]; + case 2: + if (m_mueR==0) + return 0; + return m_mueR[n][pos[0]][pos[1]][pos[2]]; + case 3: + if (m_sigma==0) + return 0; + return m_sigma[n][pos[0]][pos[1]][pos[2]]; + } + return 0; +} + +void Operator::SetExcitationSignal(Excitation* exc) +{ + m_Exc=exc; +} + +void Operator::Calc_ECOperatorPos(int n, unsigned int* pos) +{ + unsigned int i = MainOp->SetPos(pos[0],pos[1],pos[2]); + double C = EC_C[n][i]; + double G = EC_G[n][i]; + if (C>0) + { + SetVV(n,pos[0],pos[1],pos[2], (1.0-dT*G/2.0/C)/(1.0+dT*G/2.0/C) ); + SetVI(n,pos[0],pos[1],pos[2], (dT/C)/(1.0+dT*G/2.0/C) ); + } + else + { + SetVV(n,pos[0],pos[1],pos[2], 0 ); + SetVI(n,pos[0],pos[1],pos[2], 0 ); + } + + double L = EC_L[n][i]; + double R = EC_R[n][i]; + if (L>0) + { + SetII(n,pos[0],pos[1],pos[2], (1.0-dT*R/2.0/L)/(1.0+dT*R/2.0/L) ); + SetIV(n,pos[0],pos[1],pos[2], (dT/L)/(1.0+dT*R/2.0/L) ); + } + else + { + SetII(n,pos[0],pos[1],pos[2], 0 ); + SetIV(n,pos[0],pos[1],pos[2], 0 ); + } +} + +int Operator::CalcECOperator( DebugFlags debugFlags ) +{ + Init_EC(); + InitDataStorage(); + + if (Calc_EC()==0) + return -1; + + m_InvaildTimestep = false; + opt_dT = 0; + if (dT>0) + { + double save_dT = dT; + CalcTimestep(); + opt_dT = dT; + if (dT<save_dT) + { + cerr << "Operator::CalcECOperator: Warning, forced timestep: " << save_dT << "s is larger than calculated timestep: " << dT << "s! It is not recommended using this timestep!! " << endl; + m_InvaildTimestep = true; + } + + dT = save_dT; + } + else + CalcTimestep(); + + dT*=m_TimeStepFactor; + + if (m_Exc->GetSignalPeriod()>0) + { + unsigned int TS = ceil(m_Exc->GetSignalPeriod()/dT); + double new_dT = m_Exc->GetSignalPeriod()/TS; + cout << "Operartor::CalcECOperator: Decreasing timestep by " << round((dT-new_dT)/dT*1000)/10.0 << "% to " << new_dT << " (" << dT << ") to match periodic signal" << endl; + dT = new_dT; + } + + m_Exc->Reset(dT); + + InitOperator(); + + unsigned int pos[3]; + + for (int n=0; n<3; ++n) + { + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + Calc_ECOperatorPos(n,pos); + } + } + } + } + + //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(); + + Calc_LumpedElements(); + + bool PMC[6]; + for (int n=0; n<6; ++n) + PMC[n] = m_BC[n]==1; + ApplyMagneticBC(PMC); + + //all information available for extension... create now... + for (size_t n=0; n<m_Op_exts.size(); ++n) + m_Op_exts.at(n)->BuildExtension(); + + //remove inactive extensions + vector<Operator_Extension*>::iterator it = m_Op_exts.begin(); + while (it!=m_Op_exts.end()) + { + if ( (*it)->IsActive() == false) + { + DeleteExtension((*it)); + it = m_Op_exts.begin(); //restart search for inactive extension + } + else + ++it; + } + + if (debugFlags & debugMaterial) + DumpMaterial2File( "material_dump" ); + if (debugFlags & debugOperator) + DumpOperator2File( "operator_dump" ); + if (debugFlags & debugPEC) + DumpPEC2File( "PEC_dump" ); + + //cleanup + for (int n=0; n<3; ++n) + { + delete[] EC_C[n]; + EC_C[n]=NULL; + delete[] EC_G[n]; + EC_G[n]=NULL; + delete[] EC_L[n]; + EC_L[n]=NULL; + delete[] EC_R[n]; + EC_R[n]=NULL; + } + + return 0; +} + +void Operator::ApplyElectricBC(bool* dirs) +{ + if (!dirs) + return; + + unsigned int pos[3]; + for (int n=0; n<3; ++n) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + for (pos[nP]=0; pos[nP]<numLines[nP]; ++pos[nP]) + { + for (pos[nPP]=0; pos[nPP]<numLines[nPP]; ++pos[nPP]) + { + if (dirs[2*n]) + { + // set to PEC + pos[n] = 0; + SetVV(nP, pos[0],pos[1],pos[2], 0 ); + SetVI(nP, pos[0],pos[1],pos[2], 0 ); + SetVV(nPP,pos[0],pos[1],pos[2], 0 ); + SetVI(nPP,pos[0],pos[1],pos[2], 0 ); + } + + if (dirs[2*n+1]) + { + // set to PEC + pos[n] = numLines[n]-1; + SetVV(n, pos[0],pos[1],pos[2], 0 ); // these are outside the FDTD-domain as defined by the main disc + SetVI(n, pos[0],pos[1],pos[2], 0 ); // these are outside the FDTD-domain as defined by the main disc + + SetVV(nP, pos[0],pos[1],pos[2], 0 ); + SetVI(nP, pos[0],pos[1],pos[2], 0 ); + SetVV(nPP,pos[0],pos[1],pos[2], 0 ); + SetVI(nPP,pos[0],pos[1],pos[2], 0 ); + } + } + } + } +} + +void Operator::ApplyMagneticBC(bool* dirs) +{ + if (!dirs) + return; + + unsigned int pos[3]; + for (int n=0; n<3; ++n) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + for (pos[nP]=0; pos[nP]<numLines[nP]; ++pos[nP]) + { + for (pos[nPP]=0; pos[nPP]<numLines[nPP]; ++pos[nPP]) + { + if (dirs[2*n]) + { + // set to PMC + pos[n] = 0; + SetII(n, pos[0],pos[1],pos[2], 0 ); + SetIV(n, pos[0],pos[1],pos[2], 0 ); + SetII(nP, pos[0],pos[1],pos[2], 0 ); + SetIV(nP, pos[0],pos[1],pos[2], 0 ); + SetII(nPP,pos[0],pos[1],pos[2], 0 ); + SetIV(nPP,pos[0],pos[1],pos[2], 0 ); + } + + if (dirs[2*n+1]) + { + // set to PMC + pos[n] = numLines[n]-2; + SetII(nP, pos[0],pos[1],pos[2], 0 ); + SetIV(nP, pos[0],pos[1],pos[2], 0 ); + SetII(nPP,pos[0],pos[1],pos[2], 0 ); + SetIV(nPP,pos[0],pos[1],pos[2], 0 ); + } + + // the last current lines are outside the FDTD domain and cannot be iterated by the FDTD engine + pos[n] = numLines[n]-1; + SetII(n, pos[0],pos[1],pos[2], 0 ); + SetIV(n, pos[0],pos[1],pos[2], 0 ); + SetII(nP, pos[0],pos[1],pos[2], 0 ); + SetIV(nP, pos[0],pos[1],pos[2], 0 ); + SetII(nPP,pos[0],pos[1],pos[2], 0 ); + SetIV(nPP,pos[0],pos[1],pos[2], 0 ); + } + } + } +} + +bool Operator::Calc_ECPos(int ny, const unsigned int* pos, double* EC, vector<CSPrimitives*> vPrims) const +{ + double EffMat[4]; + Calc_EffMatPos(ny,pos,EffMat, vPrims); + + if (m_epsR) + m_epsR[ny][pos[0]][pos[1]][pos[2]] = EffMat[0]; + if (m_kappa) + m_kappa[ny][pos[0]][pos[1]][pos[2]] = EffMat[1]; + if (m_mueR) + m_mueR[ny][pos[0]][pos[1]][pos[2]] = EffMat[2]; + if (m_sigma) + m_sigma[ny][pos[0]][pos[1]][pos[2]] = EffMat[3]; + + double delta = GetEdgeLength(ny,pos); + double area = GetEdgeArea(ny,pos); + +// if (isnan(EffMat[0])) +// { +// cerr << ny << " " << pos[0] << " " << pos[1] << " " << pos[2] << " : " << EffMat[0] << endl; +// } + + if (delta) + { + EC[0] = EffMat[0] * area/delta; + EC[1] = EffMat[1] * area/delta; + } + else + { + EC[0] = 0; + EC[1] = 0; + } + + delta = GetEdgeLength(ny,pos,true); + area = GetEdgeArea(ny,pos,true); + + if (delta) + { + EC[2] = EffMat[2] * area/delta; + EC[3] = EffMat[3] * area/delta; + } + else + { + EC[2] = 0; + EC[3] = 0; + } + + return true; +} + +double Operator::GetRawDiscDelta(int ny, const int pos) const +{ + //numLines[ny] is expected to be larger then 1 ! + + if (pos<0) + return (discLines[ny][0] - discLines[ny][1]); + if (pos>=(int)numLines[ny]-1) + return (discLines[ny][numLines[ny]-2] - discLines[ny][numLines[ny]-1]); + + return (discLines[ny][pos+1] - discLines[ny][pos]); +} + +bool Operator::GetCellCenterMaterialAvgCoord(const int pos[], double coord[3]) const +{ + unsigned int ui_pos[3]; + for (int n=0;n<3;++n) + { + if ((pos[n]<0) || (pos[n]>=(int)numLines[n])) + return false; + ui_pos[n] = pos[n]; + } + GetNodeCoords(ui_pos, coord, true); + return true; +} + +double Operator::GetMaterial(int ny, const double* coords, int MatType, vector<CSPrimitives*> vPrims, bool markAsUsed) const +{ + CSProperties* prop = CSX->GetPropertyByCoordPriority(coords,vPrims,markAsUsed); +// CSProperties* old_prop = CSX->GetPropertyByCoordPriority(coords,CSProperties::MATERIAL,markAsUsed); +// if (old_prop!=prop) +// { +// cerr << "ERROR: Unequal properties!" << endl; +// exit(-1); +// } + + CSPropMaterial* mat = dynamic_cast<CSPropMaterial*>(prop); + if (mat) + { + switch (MatType) + { + case 0: + return mat->GetEpsilonWeighted(ny,coords); + case 1: + return mat->GetKappaWeighted(ny,coords); + case 2: + return mat->GetMueWeighted(ny,coords); + case 3: + return mat->GetSigmaWeighted(ny,coords); + case 4: + return mat->GetDensityWeighted(coords); + default: + cerr << "Operator::GetMaterial: Error: unknown material type" << endl; + return 0; + } + } + + switch (MatType) + { + case 0: + return GetBackgroundEpsR(); + case 1: + return GetBackgroundKappa(); + case 2: + return GetBackgroundMueR(); + case 3: + return GetBackgroundSigma(); + case 4: + return GetBackgroundDensity(); + default: + cerr << "Operator::GetMaterial: Error: unknown material type" << endl; + return 0; + } +} + +bool Operator::AverageMatCellCenter(int ny, const unsigned int* pos, double* EffMat, vector<CSPrimitives *> vPrims) const +{ + int n=ny; + double coord[3]; + int nP = (n+1)%3; + int nPP = (n+2)%3; + + int loc_pos[3] = {(int)pos[0],(int)pos[1],(int)pos[2]}; + double A_n; + double area = 0; + EffMat[0] = 0; + EffMat[1] = 0; + EffMat[2] = 0; + EffMat[3] = 0; + + //******************************* epsilon,kappa averaging *****************************// + //shift up-right + if (GetCellCenterMaterialAvgCoord(loc_pos,coord)) + { + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] += GetMaterial(n, coord, 0, vPrims)*A_n; + EffMat[1] += GetMaterial(n, coord, 1, vPrims)*A_n; + area+=A_n; + } + + //shift up-left + --loc_pos[nP]; + if (GetCellCenterMaterialAvgCoord(loc_pos,coord)) + { + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] += GetMaterial(n, coord, 0, vPrims)*A_n; + EffMat[1] += GetMaterial(n, coord, 1, vPrims)*A_n; + area+=A_n; + } + + //shift down-right + ++loc_pos[nP]; + --loc_pos[nPP]; + if (GetCellCenterMaterialAvgCoord(loc_pos,coord)) + { + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] += GetMaterial(n, coord, 0, vPrims)*A_n; + EffMat[1] += GetMaterial(n, coord, 1, vPrims)*A_n; + area+=A_n; + } + + //shift down-left + --loc_pos[nP]; + if (GetCellCenterMaterialAvgCoord(loc_pos,coord)) + { + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] += GetMaterial(n, coord, 0, vPrims)*A_n; + EffMat[1] += GetMaterial(n, coord, 1, vPrims)*A_n; + area+=A_n; + } + + EffMat[0]*=__EPS0__/area; + EffMat[1]/=area; + + //******************************* mu,sigma averaging *****************************// + loc_pos[0]=pos[0]; + loc_pos[1]=pos[1]; + loc_pos[2]=pos[2]; + double length=0; + double delta_ny,sigma; + //shift down + --loc_pos[n]; + if (GetCellCenterMaterialAvgCoord(loc_pos,coord)) + { + delta_ny = GetNodeWidth(n,loc_pos,true); + EffMat[2] += delta_ny / GetMaterial(n, coord, 2, vPrims); + sigma = GetMaterial(n, coord, 3, vPrims); + if (sigma) + EffMat[3] += delta_ny / sigma; + else + EffMat[3] = 0; + length+=delta_ny; + } + + //shift up + ++loc_pos[n]; + if (GetCellCenterMaterialAvgCoord(loc_pos,coord)) + { + delta_ny = GetNodeWidth(n,loc_pos,true); + EffMat[2] += delta_ny / GetMaterial(n, coord, 2, vPrims); + sigma = GetMaterial(n, coord, 3, vPrims); + if (sigma) + EffMat[3] += delta_ny / sigma; + else + EffMat[3] = 0; + length+=delta_ny; + } + + EffMat[2] = length * __MUE0__ / EffMat[2]; + if (EffMat[3]) EffMat[3]=length / EffMat[3]; + + for (int n=0; n<4; ++n) + if (isnan(EffMat[n]) || isinf(EffMat[n])) + { + cerr << "Operator::" << __func__ << ": Error, an effective material parameter is not a valid result, this should NOT have happend... exit..." << endl; + cerr << ny << "@" << n << " : " << pos[0] << "," << pos[1] << "," << pos[2] << endl; + exit(0); + } + return true; +} + +bool Operator::AverageMatQuarterCell(int ny, const unsigned int* pos, double* EffMat, vector<CSPrimitives*> vPrims) const +{ + int n=ny; + double coord[3]; + double shiftCoord[3]; + int nP = (n+1)%3; + int nPP = (n+2)%3; + coord[0] = discLines[0][pos[0]]; + coord[1] = discLines[1][pos[1]]; + coord[2] = discLines[2][pos[2]]; + double delta=GetRawDiscDelta(n,pos[n]); + double deltaP=GetRawDiscDelta(nP,pos[nP]); + double deltaPP=GetRawDiscDelta(nPP,pos[nPP]); + double delta_M=GetRawDiscDelta(n,pos[n]-1); + double deltaP_M=GetRawDiscDelta(nP,pos[nP]-1); + double deltaPP_M=GetRawDiscDelta(nPP,pos[nPP]-1); + + int loc_pos[3] = {(int)pos[0],(int)pos[1],(int)pos[2]}; + double A_n; + double area = 0; + + //******************************* epsilon,kappa averaging *****************************// + //shift up-right + shiftCoord[n] = coord[n]+delta*0.5; + shiftCoord[nP] = coord[nP]+deltaP*0.25; + shiftCoord[nPP] = coord[nPP]+deltaPP*0.25; + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] = GetMaterial(n, shiftCoord, 0, vPrims)*A_n; + EffMat[1] = GetMaterial(n, shiftCoord, 1, vPrims)*A_n; + area+=A_n; + + //shift up-left + shiftCoord[n] = coord[n]+delta*0.5; + shiftCoord[nP] = coord[nP]-deltaP_M*0.25; + shiftCoord[nPP] = coord[nPP]+deltaPP*0.25; + + --loc_pos[nP]; + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] += GetMaterial(n, shiftCoord, 0, vPrims)*A_n; + EffMat[1] += GetMaterial(n, shiftCoord, 1, vPrims)*A_n; + area+=A_n; + + //shift down-right + shiftCoord[n] = coord[n]+delta*0.5; + shiftCoord[nP] = coord[nP]+deltaP*0.25; + shiftCoord[nPP] = coord[nPP]-deltaPP_M*0.25; + ++loc_pos[nP]; + --loc_pos[nPP]; + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] += GetMaterial(n, shiftCoord, 0, vPrims)*A_n; + EffMat[1] += GetMaterial(n, shiftCoord, 1, vPrims)*A_n; + area+=A_n; + + //shift down-left + shiftCoord[n] = coord[n]+delta*0.5; + shiftCoord[nP] = coord[nP]-deltaP_M*0.25; + shiftCoord[nPP] = coord[nPP]-deltaPP_M*0.25; + --loc_pos[nP]; + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] += GetMaterial(n, shiftCoord, 0, vPrims)*A_n; + EffMat[1] += GetMaterial(n, shiftCoord, 1, vPrims)*A_n; + area+=A_n; + + EffMat[0]*=__EPS0__/area; + EffMat[1]/=area; + + //******************************* mu,sigma averaging *****************************// + loc_pos[0]=pos[0]; + loc_pos[1]=pos[1]; + loc_pos[2]=pos[2]; + double length=0; + + //shift down + shiftCoord[n] = coord[n]-delta_M*0.25; + shiftCoord[nP] = coord[nP]+deltaP*0.5; + shiftCoord[nPP] = coord[nPP]+deltaPP*0.5; + --loc_pos[n]; + double delta_ny = GetNodeWidth(n,loc_pos,true); + EffMat[2] = delta_ny / GetMaterial(n, shiftCoord, 2, vPrims); + double sigma = GetMaterial(n, shiftCoord, 3, vPrims); + if (sigma) + EffMat[3] = delta_ny / sigma; + else + EffMat[3] = 0; + length=delta_ny; + + //shift up + shiftCoord[n] = coord[n]+delta*0.25; + shiftCoord[nP] = coord[nP]+deltaP*0.5; + shiftCoord[nPP] = coord[nPP]+deltaPP*0.5; + ++loc_pos[n]; + delta_ny = GetNodeWidth(n,loc_pos,true); + EffMat[2] += delta_ny / GetMaterial(n, shiftCoord, 2, vPrims); + sigma = GetMaterial(n, shiftCoord, 3, vPrims); + if (sigma) + EffMat[3] += delta_ny / sigma; + else + EffMat[3] = 0; + length+=delta_ny; + + EffMat[2] = length * __MUE0__ / EffMat[2]; + if (EffMat[3]) EffMat[3]=length / EffMat[3]; + + for (int n=0; n<4; ++n) + if (isnan(EffMat[n]) || isinf(EffMat[n])) + { + cerr << "Operator::" << __func__ << ": Error, An effective material parameter is not a valid result, this should NOT have happend... exit..." << endl; + cerr << ny << "@" << n << " : " << pos[0] << "," << pos[1] << "," << pos[2] << endl; + exit(0); + } + + return true; +} + +bool Operator::Calc_EffMatPos(int ny, const unsigned int* pos, double* EffMat, vector<CSPrimitives *> vPrims) const +{ + switch (m_MatAverageMethod) + { + case QuarterCell: + return AverageMatQuarterCell(ny, pos, EffMat, vPrims); + case CentralCell: + return AverageMatCellCenter(ny, pos, EffMat, vPrims); + default: + cerr << "Operator:: " << __func__ << ": Error, unknown material averaging method... exit" << endl; + exit(1); + } + return false; +} + +bool Operator::Calc_LumpedElements() +{ + vector<CSProperties*> props = CSX->GetPropertyByType(CSProperties::LUMPED_ELEMENT); + for (size_t i=0;i<props.size();++i) + { + CSPropLumpedElement* PLE = dynamic_cast<CSPropLumpedElement*>(props.at(i)); + if (PLE==NULL) + return false; //sanity check: this should never happen! + vector<CSPrimitives*> prims = PLE->GetAllPrimitives(); + for (size_t bn=0;bn<prims.size();++bn) + { + CSPrimBox* box = dynamic_cast<CSPrimBox*>(prims.at(bn)); + if (box) + { //calculate lumped element parameter + + double C = PLE->GetCapacity(); + if (C<=0) + C = NAN; + double R = PLE->GetResistance(); + if (R<0) + R = NAN; + + if ((isnan(R)) && (isnan(C))) + { + cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element R or C not specified! skipping. " + << " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl; + continue; + } + + int ny = PLE->GetDirection(); + if ((ny<0) || (ny>2)) + { + cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element direction is invalid! skipping. " + << " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl; + continue; + } + int nyP = (ny+1)%3; + int nyPP = (ny+2)%3; + + unsigned int uiStart[3]; + unsigned int uiStop[3]; + // snap to the native coordinate system + int Snap_Dimension = Operator::SnapBox2Mesh(box->GetStartCoord()->GetCoords(m_MeshType), box->GetStopCoord()->GetCoords(m_MeshType), uiStart, uiStop, false, true); + if (Snap_Dimension<=0) + { + if (Snap_Dimension>=-1) + cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element snapping failed! Dimension is: " << Snap_Dimension << " skipping. " + << " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl; + // Snap_Dimension == -2 means outside the simulation domain --> no special warning, but box probably marked as unused! + continue; + } + + if (uiStart[ny]==uiStop[ny]) + { + cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element with zero (snapped) length is invalid! skipping. " + << " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl; + continue; + } + + //calculate geometric property for this lumped element + unsigned int pos[3]; + double unitGC=0; + int ipos=0; + for (pos[ny]=uiStart[ny];pos[ny]<uiStop[ny];++pos[ny]) + { + double unitGC_Plane=0; + for (pos[nyP]=uiStart[nyP];pos[nyP]<=uiStop[nyP];++pos[nyP]) + { + for (pos[nyPP]=uiStart[nyPP];pos[nyPP]<=uiStop[nyPP];++pos[nyPP]) + { + // capacity/conductivity in parallel: add values + unitGC_Plane += GetEdgeArea(ny,pos)/GetEdgeLength(ny,pos); + } + } + + //capacity/conductivity in series: add reciprocal values + unitGC += 1/unitGC_Plane; + } + unitGC = 1/unitGC; + + bool caps = PLE->GetCaps(); + double kappa = 0; + double epsilon = 0; + if (R>0) + kappa = 1 / R / unitGC; + if (C>0) + { + epsilon = C / unitGC; + + if (epsilon< __EPS0__) + { + cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element capacity is too small for its size! skipping. " + << " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl; + C = 0; + } + } + + for (pos[ny]=uiStart[ny];pos[ny]<uiStop[ny];++pos[ny]) + { + for (pos[nyP]=uiStart[nyP];pos[nyP]<=uiStop[nyP];++pos[nyP]) + { + for (pos[nyPP]=uiStart[nyPP];pos[nyPP]<=uiStop[nyPP];++pos[nyPP]) + { + ipos = MainOp->SetPos(pos[0],pos[1],pos[2]); + if (C>0) + EC_C[ny][ipos] = epsilon * GetEdgeArea(ny,pos)/GetEdgeLength(ny,pos); + if (R>0) + EC_G[ny][ipos] = kappa * GetEdgeArea(ny,pos)/GetEdgeLength(ny,pos); + + if (R==0) //make lumped element a PEC if resistance is zero + { + SetVV(ny,pos[0],pos[1],pos[2], 0 ); + SetVI(ny,pos[0],pos[1],pos[2], 0 ); + } + else //recalculate operator inside the lumped element + Calc_ECOperatorPos(ny,pos); + } + } + } + + // setup metal caps + if (caps) + { + for (pos[nyP]=uiStart[nyP];pos[nyP]<=uiStop[nyP];++pos[nyP]) + { + for (pos[nyPP]=uiStart[nyPP];pos[nyPP]<=uiStop[nyPP];++pos[nyPP]) + { + pos[ny]=uiStart[ny]; + if (pos[nyP]<uiStop[nyP]) + { + SetVV(nyP,pos[0],pos[1],pos[2], 0 ); + SetVI(nyP,pos[0],pos[1],pos[2], 0 ); + ++m_Nr_PEC[nyP]; + } + + if (pos[nyPP]<uiStop[nyPP]) + { + SetVV(nyPP,pos[0],pos[1],pos[2], 0 ); + SetVI(nyPP,pos[0],pos[1],pos[2], 0 ); + ++m_Nr_PEC[nyPP]; + } + + pos[ny]=uiStop[ny]; + if (pos[nyP]<uiStop[nyP]) + { + SetVV(nyP,pos[0],pos[1],pos[2], 0 ); + SetVI(nyP,pos[0],pos[1],pos[2], 0 ); + ++m_Nr_PEC[nyP]; + } + + if (pos[nyPP]<uiStop[nyPP]) + { + SetVV(nyPP,pos[0],pos[1],pos[2], 0 ); + SetVI(nyPP,pos[0],pos[1],pos[2], 0 ); + ++m_Nr_PEC[nyPP]; + } + } + } + } + box->SetPrimitiveUsed(true); + + } + else + cerr << "Operator::Calc_LumpedElements(): Warning: Primitves other than boxes are not supported for lumped elements! skipping " + << prims.at(bn)->GetTypeName() << " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl; + } + } + return true; +} + +void Operator::Init_EC() +{ + for (int n=0; n<3; ++n) + { + //init x-cell-array + delete[] EC_C[n]; + delete[] EC_G[n]; + delete[] EC_L[n]; + delete[] EC_R[n]; + EC_C[n] = new FDTD_FLOAT[MainOp->GetSize()]; + EC_G[n] = new FDTD_FLOAT[MainOp->GetSize()]; + EC_L[n] = new FDTD_FLOAT[MainOp->GetSize()]; + EC_R[n] = new FDTD_FLOAT[MainOp->GetSize()]; + for (unsigned int i=0; i<MainOp->GetSize(); i++) //init all + { + EC_C[n][i]=0; + EC_G[n][i]=0; + EC_L[n][i]=0; + EC_R[n][i]=0; + } + } +} + +bool Operator::Calc_EC() +{ + if (CSX==NULL) + { + cerr << "CartOperator::Calc_EC: CSX not given or invalid!!!" << endl; + return false; + } + + MainOp->SetPos(0,0,0); + Calc_EC_Range(0,numLines[0]-1); + return true; +} + +vector<CSPrimitives*> Operator::GetPrimitivesBoundBox(int posX, int posY, int posZ, CSProperties::PropertyType type) const +{ + double boundBox[6]; + int BBpos[3] = {posX, posY, posZ}; + for (int n=0;n<3;++n) + { + if (BBpos[n]<0) + { + boundBox[2*n] = this->GetDiscLine(n,0); + boundBox[2*n+1] = this->GetDiscLine(n,numLines[n]-1); + } + else + { + boundBox[2*n] = this->GetDiscLine(n, max(0, BBpos[n]-1)); + boundBox[2*n+1] = this->GetDiscLine(n, min(int(numLines[n])-1, BBpos[n]+1)); + } + } + + vector<CSPrimitives*> vPrim = this->CSX->GetPrimitivesByBoundBox(boundBox, true, type); + return vPrim; +} + +void Operator::Calc_EC_Range(unsigned int xStart, unsigned int xStop) +{ +// vector<CSPrimitives*> vPrims = this->CSX->GetAllPrimitives(true, CSProperties::MATERIAL); + unsigned int ipos; + unsigned int pos[3]; + double inEC[4]; + for (pos[0]=xStart; pos[0]<=xStop; ++pos[0]) + { + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + vector<CSPrimitives*> vPrims = this->GetPrimitivesBoundBox(pos[0], pos[1], -1, CSProperties::MATERIAL); + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + ipos = MainOp->GetPos(pos[0],pos[1],pos[2]); + for (int n=0; n<3; ++n) + { + Calc_ECPos(n,pos,inEC,vPrims); + EC_C[n][ipos]=inEC[0]; + EC_G[n][ipos]=inEC[1]; + EC_L[n][ipos]=inEC[2]; + EC_R[n][ipos]=inEC[3]; + } + } + } + } +} + +void Operator::SetTimestepFactor(double factor) +{ + if ((factor<=0) || (factor>1)) + { + cerr << "Operator::SetTimestepFactor: Warning, invalid timestep factor, skipping!" << endl; + return; + } + + cout << "Operator::SetTimestepFactor: Setting timestep factor to " << factor << endl; + m_TimeStepFactor=factor; +} + +double Operator::CalcTimestep() +{ + if (m_TimeStepVar==3) + return CalcTimestep_Var3(); //the biggest one for cartesian meshes + + //variant 1 is default + return CalcTimestep_Var1(); +} + +////Berechnung nach Andreas Rennings Dissertation 2008, Seite 66, Formel 4.52 +double Operator::CalcTimestep_Var1() +{ + m_Used_TS_Name = string("Rennings_1"); +// cout << "Operator::CalcTimestep(): Using timestep algorithm by Andreas Rennings, Dissertation @ University Duisburg-Essen, 2008, pp. 66, eq. 4.52" << endl; + dT=1e200; + double newT; + unsigned int pos[3]; + unsigned int smallest_pos[3] = {0, 0, 0}; + unsigned int smallest_n = 0; + unsigned int ipos; + unsigned int ipos_PM; + unsigned int ipos_PPM; + MainOp->SetReflection2Cell(); + for (int n=0; n<3; ++n) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + ipos = MainOp->SetPos(pos[0],pos[1],pos[2]); + ipos_PM = MainOp->Shift(nP,-1); + MainOp->ResetShift(); + ipos_PPM= MainOp->Shift(nPP,-1); + MainOp->ResetShift(); + newT = 2/sqrt( ( 4/EC_L[nP][ipos] + 4/EC_L[nP][ipos_PPM] + 4/EC_L[nPP][ipos] + 4/EC_L[nPP][ipos_PM]) / EC_C[n][ipos] ); + if ((newT<dT) && (newT>0.0)) + { + dT=newT; + smallest_pos[0]=pos[0];smallest_pos[1]=pos[1];smallest_pos[2]=pos[2]; + smallest_n = n; + } + } + } + } + } + if (dT==0) + { + cerr << "Operator::CalcTimestep: Timestep is zero... this is not supposed to happen!!! exit!" << endl; + exit(3); + } + if (g_settings.GetVerboseLevel()>1) + { + cout << "Operator::CalcTimestep_Var1: Smallest timestep (" << dT << "s) found at position: " << smallest_n << " : " << smallest_pos[0] << ";" << smallest_pos[1] << ";" << smallest_pos[2] << endl; + } + return 0; +} + +double min(double* val, unsigned int count) +{ + if (count==0) + return 0.0; + double min = val[0]; + for (unsigned int n=1; n<count; ++n) + if (val[n]<min) + min = val[n]; + return min; +} + +//Berechnung nach Andreas Rennings Dissertation 2008, Seite 76 ff, Formel 4.77 ff +double Operator::CalcTimestep_Var3() +{ + dT=1e200; + m_Used_TS_Name = string("Rennings_2"); +// cout << "Operator::CalcTimestep(): Using timestep algorithm by Andreas Rennings, Dissertation @ University Duisburg-Essen, 2008, pp. 76, eq. 4.77 ff." << endl; + double newT; + unsigned int pos[3]; + unsigned int smallest_pos[3] = {0, 0, 0}; + unsigned int smallest_n = 0; + unsigned int ipos; + double w_total=0; + double wqp=0,wt1=0,wt2=0; + double wt_4[4]={0,0,0,0}; + MainOp->SetReflection2Cell(); + for (int n=0; n<3; ++n) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + MainOp->ResetShift(); + ipos = MainOp->SetPos(pos[0],pos[1],pos[2]); + wqp = 1/(EC_L[nPP][ipos]*EC_C[n][MainOp->GetShiftedPos(nP ,1)]) + 1/(EC_L[nPP][ipos]*EC_C[n][ipos]); + wqp += 1/(EC_L[nP ][ipos]*EC_C[n][MainOp->GetShiftedPos(nPP,1)]) + 1/(EC_L[nP ][ipos]*EC_C[n][ipos]); + ipos = MainOp->Shift(nP,-1); + wqp += 1/(EC_L[nPP][ipos]*EC_C[n][MainOp->GetShiftedPos(nP ,1)]) + 1/(EC_L[nPP][ipos]*EC_C[n][ipos]); + ipos = MainOp->Shift(nPP,-1); + wqp += 1/(EC_L[nP ][ipos]*EC_C[n][MainOp->GetShiftedPos(nPP,1)]) + 1/(EC_L[nP ][ipos]*EC_C[n][ipos]); + + MainOp->ResetShift(); + ipos = MainOp->SetPos(pos[0],pos[1],pos[2]); + wt_4[0] = 1/(EC_L[nPP][ipos] *EC_C[nP ][ipos]); + wt_4[1] = 1/(EC_L[nPP][MainOp->GetShiftedPos(nP ,-1)] *EC_C[nP ][ipos]); + wt_4[2] = 1/(EC_L[nP ][ipos] *EC_C[nPP][ipos]); + wt_4[3] = 1/(EC_L[nP ][MainOp->GetShiftedPos(nPP,-1)] *EC_C[nPP][ipos]); + + wt1 = wt_4[0]+wt_4[1]+wt_4[2]+wt_4[3] - 2*min(wt_4,4); + + MainOp->ResetShift(); + ipos = MainOp->SetPos(pos[0],pos[1],pos[2]); + wt_4[0] = 1/(EC_L[nPP][ipos] *EC_C[nP ][MainOp->GetShiftedPos(n,1)]); + wt_4[1] = 1/(EC_L[nPP][MainOp->GetShiftedPos(nP ,-1)] *EC_C[nP ][MainOp->GetShiftedPos(n,1)]); + wt_4[2] = 1/(EC_L[nP ][ipos] *EC_C[nPP][MainOp->GetShiftedPos(n,1)]); + wt_4[3] = 1/(EC_L[nP ][MainOp->GetShiftedPos(nPP,-1)] *EC_C[nPP][MainOp->GetShiftedPos(n,1)]); + + wt2 = wt_4[0]+wt_4[1]+wt_4[2]+wt_4[3] - 2*min(wt_4,4); + + w_total = wqp + wt1 + wt2; + newT = 2/sqrt( w_total ); + if ((newT<dT) && (newT>0.0)) + { + dT=newT; + smallest_pos[0]=pos[0];smallest_pos[1]=pos[1];smallest_pos[2]=pos[2]; + smallest_n = n; + } + } + } + } + } + if (dT==0) + { + cerr << "Operator::CalcTimestep: Timestep is zero... this is not supposed to happen!!! exit!" << endl; + exit(3); + } + if (g_settings.GetVerboseLevel()>1) + { + cout << "Operator::CalcTimestep_Var3: Smallest timestep (" << dT << "s) found at position: " << smallest_n << " : " << smallest_pos[0] << ";" << smallest_pos[1] << ";" << smallest_pos[2] << endl; + } + return 0; +} + +bool Operator::CalcPEC() +{ + m_Nr_PEC[0]=0; + m_Nr_PEC[1]=0; + m_Nr_PEC[2]=0; + + CalcPEC_Range(0,numLines[0]-1,m_Nr_PEC); + + CalcPEC_Curves(); + + return true; +} + +void Operator::CalcPEC_Range(unsigned int startX, unsigned int stopX, unsigned int* counter) +{ + double coord[3]; + unsigned int pos[3]; + for (pos[0]=startX; pos[0]<=stopX; ++pos[0]) + { + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + vector<CSPrimitives*> vPrims = this->GetPrimitivesBoundBox(pos[0], pos[1], -1, (CSProperties::PropertyType)(CSProperties::MATERIAL | CSProperties::METAL)); + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + for (int n=0; n<3; ++n) + { + GetYeeCoords(n,pos,coord,false); + CSProperties* prop = CSX->GetPropertyByCoordPriority(coord, vPrims, true); +// CSProperties* old_prop = CSX->GetPropertyByCoordPriority(coord, (CSProperties::PropertyType)(CSProperties::MATERIAL | CSProperties::METAL), true); +// if (old_prop!=prop) +// { +// cerr << "CalcPEC_Range: " << old_prop << " vs " << prop << endl; +// exit(-1); +// } + if (prop) + { + if (prop->GetType()==CSProperties::METAL) //set to PEC + { + SetVV(n,pos[0],pos[1],pos[2], 0 ); + SetVI(n,pos[0],pos[1],pos[2], 0 ); + ++counter[n]; + } + } + } + } + } + } +} + +void Operator::CalcPEC_Curves() +{ + //special treatment for primitives of type curve (treated as wires) + double p1[3]; + double p2[3]; + Grid_Path path; + vector<CSProperties*> vec_prop = CSX->GetPropertyByType(CSProperties::METAL); + for (size_t p=0; p<vec_prop.size(); ++p) + { + CSProperties* prop = vec_prop.at(p); + for (size_t n=0; n<prop->GetQtyPrimitives(); ++n) + { + CSPrimitives* prim = prop->GetPrimitive(n); + CSPrimCurve* curv = prim->ToCurve(); + if (curv) + { + for (size_t i=1; i<curv->GetNumberOfPoints(); ++i) + { + curv->GetPoint(i-1,p1,m_MeshType); + curv->GetPoint(i,p2,m_MeshType); + path = FindPath(p1,p2); + if (path.dir.size()>0) + prim->SetPrimitiveUsed(true); + for (size_t t=0; t<path.dir.size(); ++t) + { + SetVV(path.dir.at(t),path.posPath[0].at(t),path.posPath[1].at(t),path.posPath[2].at(t), 0 ); + SetVI(path.dir.at(t),path.posPath[0].at(t),path.posPath[1].at(t),path.posPath[2].at(t), 0 ); + ++m_Nr_PEC[path.dir.at(t)]; + } + } + } + } + } +} + +Operator_Ext_Excitation* Operator::GetExcitationExtension() const +{ + //search for excitation extension + Operator_Ext_Excitation* Op_Ext_Exc=0; + for (size_t n=0; n<m_Op_exts.size(); ++n) + { + Op_Ext_Exc = dynamic_cast<Operator_Ext_Excitation*>(m_Op_exts.at(n)); + if (Op_Ext_Exc) + break; + } + return Op_Ext_Exc; +} + +void Operator::AddExtension(Operator_Extension* op_ext) +{ + m_Op_exts.push_back(op_ext); +} + +void Operator::DeleteExtension(Operator_Extension* op_ext) +{ + for (size_t n=0;n<m_Op_exts.size();++n) + { + if (m_Op_exts.at(n)==op_ext) + { + m_Op_exts.erase(m_Op_exts.begin()+n); + return; + } + } +} + +double Operator::CalcNumericPhaseVelocity(unsigned int start[3], unsigned int stop[3], double propDir[3], float freq) const +{ + double average_mesh_disc[3]; + double c0 = __C0__/sqrt(GetBackgroundEpsR()*GetBackgroundMueR()); + + //calculate average mesh deltas + for (int n=0;n<3;++n) + { + average_mesh_disc[n] = fabs(GetDiscLine(n,start[n])-GetDiscLine(n,stop[n]))*GetGridDelta() / (fabs(stop[n]-start[n])); + } + + // if propagation is in a Cartesian direction, return analytic solution + for (int n=0;n<3;++n) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + if ((fabs(propDir[n])==1) && (propDir[nP]==0) && (propDir[nPP]==0)) + { + double kx = asin(average_mesh_disc[0]/c0/dT*sin(2*PI*freq*dT/2))*2/average_mesh_disc[0]; + return 2*PI*freq/kx; + } + } + + // else, do an newton iterative estimation + double k0=2*PI*freq/c0; + double k=k0; + double RHS = pow(sin(2*PI*freq*dT/2)/c0/dT,2); + double fk=1,fdk=0; + double old_phv=0; + double phv=c0; + double err_est = 1e-6; + int it_count=0; + while (fabs(old_phv-phv)>err_est) + { + ++it_count; + old_phv=phv; + fk=0; + fdk=0; + for (int n=0;n<3;++n) + { + fk+= pow(sin(propDir[n]*k*average_mesh_disc[n]/2)/average_mesh_disc[n],2); + fdk+= propDir[n]*sin(propDir[n]*k*average_mesh_disc[n]/2)*cos(propDir[n]*k*average_mesh_disc[n]/2)/average_mesh_disc[n]; + } + fk -= RHS; + k-=fk/fdk; + + // do not allow a speed greater than c0 due to a numerical inaccuracy + if (k<k0) + k=k0; + + phv=2*PI*freq/k; + + //abort if iteration count is getting to high! + if (it_count>99) + { + cerr << "Operator::CalcNumericPhaseVelocity: Error, newton iteration estimation can't find a solution!!" << endl; + break; + } + } + + if (g_settings.GetVerboseLevel()>1) + cerr << "Operator::CalcNumericPhaseVelocity: Newton iteration estimated solution: " << phv/__C0__ << "*c0 in " << it_count << " iterations." << endl; + + return phv; +} diff --git a/openEMS/FDTD/operator.h b/openEMS/FDTD/operator.h new file mode 100644 index 0000000..8fc0409 --- /dev/null +++ b/openEMS/FDTD/operator.h @@ -0,0 +1,287 @@ +/* +* 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_H +#define OPERATOR_H + +#include "tools/AdrOp.h" +#include "tools/constants.h" +#include "excitation.h" +#include "Common/operator_base.h" + +class Operator_Extension; +class Operator_Ext_Excitation; +class Engine; +class TiXmlElement; + +//! Basic FDTD-operator +class Operator : public Operator_Base +{ + friend class Engine; + friend class Engine_Interface_FDTD; + friend class Operator_Ext_LorentzMaterial; //we need to find a way around this... friend class Operator_Extension only would be nice + friend class Operator_Ext_ConductingSheet; //we need to find a way around this... friend class Operator_Extension only would be nice + friend class Operator_Ext_PML_SF_Plane; + friend class Operator_Ext_Excitation; + friend class Operator_Ext_UPML; + friend class Operator_Ext_Cylinder; +public: + enum DebugFlags {None=0,debugMaterial=1,debugOperator=2,debugPEC=4}; + + enum MatAverageMethods {QuarterCell=0, CentralCell=1}; + + //! Create a new operator + static Operator* New(); + virtual ~Operator(); + + virtual Engine* CreateEngine(); + virtual Engine* GetEngine() const {return m_Engine;} + + virtual bool SetGeometryCSX(ContinuousStructure* geo); + + virtual int CalcECOperator( DebugFlags debugFlags = None ); + + // the next four functions need to be reimplemented in a derived class + inline virtual FDTD_FLOAT GetVV( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return vv[n][x][y][z]; } + inline virtual FDTD_FLOAT GetVI( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return vi[n][x][y][z]; } + inline virtual FDTD_FLOAT GetII( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return ii[n][x][y][z]; } + inline virtual FDTD_FLOAT GetIV( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return iv[n][x][y][z]; } + + // convenient access functions + inline virtual FDTD_FLOAT GetVV( unsigned int n, unsigned int pos[3] ) const { return GetVV(n,pos[0],pos[1],pos[2]); } + inline virtual FDTD_FLOAT GetVI( unsigned int n, unsigned int pos[3] ) const { return GetVI(n,pos[0],pos[1],pos[2]); } + inline virtual FDTD_FLOAT GetII( unsigned int n, unsigned int pos[3] ) const { return GetII(n,pos[0],pos[1],pos[2]); } + inline virtual FDTD_FLOAT GetIV( unsigned int n, unsigned int pos[3] ) const { return GetIV(n,pos[0],pos[1],pos[2]); } + + // the next four functions need to be reimplemented in a derived class + inline virtual void SetVV( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { vv[n][x][y][z] = value; } + inline virtual void SetVI( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { vi[n][x][y][z] = value; } + inline virtual void SetII( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { ii[n][x][y][z] = value; } + inline virtual void SetIV( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { iv[n][x][y][z] = value; } + + virtual void ApplyElectricBC(bool* dirs); //applied by default to all boundaries + virtual void ApplyMagneticBC(bool* dirs); + + virtual void SetBCSize(int dir, int size) {m_BC_Size[dir]=size;} + virtual int GetBCSize(int dir) {return m_BC_Size[dir];} + + //! Set a forced timestep to use by the operator + virtual void SetTimestep(double ts) {dT = ts;} + virtual void SetTimestepFactor(double factor); + bool GetTimestepValid() const {return !m_InvaildTimestep;} + + //! Choose a time step method (0=auto, 1=CFL, 3=Rennings) + void SetTimeStepMethod(int var) {m_TimeStepVar=var;} + + //! Set the material averaging method /sa MatAverageMethods + void SetMaterialAvgMethod(MatAverageMethods method); + + //! Set material averaging method to the advanced quarter cell material interpolation (default) + void SetQuarterCellMaterialAvg() {m_MatAverageMethod=QuarterCell;} + + //! Set operator to assume a constant material inside a cell (material probing in the cell center) + void SetCellConstantMaterial() {m_MatAverageMethod=CentralCell;} + + virtual double GetNumberCells() const; + + virtual unsigned int GetNumberOfNyquistTimesteps() const {return m_Exc->GetNyquistNum();} + + virtual unsigned int GetNumberOfLines(int ny, bool full=false) const {UNUSED(full);return numLines[ny];} + + virtual void ShowStat() const; + virtual void ShowExtStat() const; + + virtual double GetGridDelta() const {return gridDelta;} + + //! Get the disc line in \a n direction (in drawing units) + virtual double GetDiscLine(int n, unsigned int pos, bool dualMesh=false) const; + + //! Get the disc line delta in \a n direction (in drawing units) + virtual double GetDiscDelta(int n, unsigned int pos, bool dualMesh=false) const; + + //! Get the coordinates for a given node index and component, according to the yee-algorithm. Returns true if inside the FDTD domain. + virtual bool GetYeeCoords(int ny, unsigned int pos[3], double* coords, bool dualMesh) const; + + virtual bool GetNodeCoords(const unsigned int pos[3], double* coords, bool dualMesh=false, CoordinateSystem c_system=UNDEFINED_CS) const; + + //! Get the node width for a given direction \a n and a given mesh position \a pos + virtual double GetNodeWidth(int ny, const unsigned int pos[3], bool dualMesh = false) const {return GetEdgeLength(ny,pos,!dualMesh);} + //! Get the node width for a given direction \a n and a given mesh position \a pos + virtual double GetNodeWidth(int ny, const int pos[3], bool dualMesh = false) const; + + //! Get the node area for a given direction \a n and a given mesh position \a pos + virtual double GetNodeArea(int ny, const unsigned int pos[3], bool dualMesh = false) const; + //! Get the node area for a given direction \a n and a given mesh position \a pos + virtual double GetNodeArea(int ny, const int pos[3], bool dualMesh = false) const; + + //! Get the length of an FDTD edge (unit is meter). + virtual double GetEdgeLength(int ny, const unsigned int pos[3], bool dualMesh = false) const; + + //! Get the volume of an FDTD cell + virtual double GetCellVolume(const unsigned int pos[3], bool dualMesh = false) const; + + //! Get the area around an edge for a given direction \a n and a given mesh posisition \a pos + /*! + This will return the area around an edge with a given direction, measured at the middle of the edge. + In a cartesian mesh this is equal to the NodeArea, may be different in other coordinate systems. + */ + virtual double GetEdgeArea(int ny, const unsigned int pos[3], bool dualMesh = false) const {return GetNodeArea(ny,pos,dualMesh);} + + virtual unsigned int SnapToMeshLine(int ny, double coord, bool &inside, bool dualMesh=false, bool fullMesh=false) const; + + //! Snap the given coodinates to mesh indices + virtual bool SnapToMesh(const double* coord, unsigned int* uicoord, bool dualMesh=false, bool fullMesh=false, bool* inside=NULL) const; + + //! Snap a given box to the FDTD mesh + virtual int SnapBox2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh=false, bool fullMesh=false, int SnapMethod=0, bool* bStartIn=NULL, bool* bStopIn=NULL) const; + + //! Snap a given line to the operator mesh + /*! + \param[in] start coorindate of the line + \param[in] stop coorindate of the line + \param[out] uiStart the snapped line-start coorindate index + \param[out] uiStop the snapped line-stop coorindate index + \param[in] dualMesh snap to main or dual mesh (default is main mesh) + \return returns a status, 0 = success, 1 = start outside, 2 = stop outside, 3 = both outside + */ + virtual int SnapLine2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh=false, bool fullMesh=false) const; + + virtual void AddExtension(Operator_Extension* op_ext); + virtual void DeleteExtension(Operator_Extension* op_ext); + virtual size_t GetNumberOfExtentions() const {return m_Op_exts.size();} + virtual Operator_Extension* GetExtension(size_t index) const {return m_Op_exts.at(index);} + + virtual void CleanupMaterialStorage(); + + virtual double GetDiscMaterial(int type, int ny, const unsigned int pos[3]) const; + + //! Get the cell center coordinate usable for material averaging (Warning, may not be the yee cell center) + virtual bool GetCellCenterMaterialAvgCoord(const int pos[3], double coord[3]) const; + + virtual void SetExcitationSignal(Excitation* exc); + virtual Excitation* GetExcitationSignal() const {return m_Exc;} + + Operator_Ext_Excitation* GetExcitationExtension() const; + + virtual double CalcNumericPhaseVelocity(unsigned int start[3], unsigned int stop[3], double propDir[3], float freq) const; + + virtual vector<CSPrimitives*> GetPrimitivesBoundBox(int posX, int posY, int posZ, CSProperties::PropertyType type=CSProperties::ANY) const; + +protected: + //! use New() for creating a new Operator + Operator(); + + virtual void Init(); + void Delete(); + virtual void Reset(); + virtual void InitOperator(); + virtual void InitDataStorage(); + + virtual bool SetupCSXGrid(CSRectGrid* grid); + + virtual Grid_Path FindPath(double start[], double stop[]); + + // debug + virtual void DumpOperator2File(string filename); + virtual void DumpMaterial2File(string filename); + virtual void DumpPEC2File( string filename, unsigned int *range = NULL ); + + unsigned int m_Nr_PEC[3]; //count PEC edges + virtual bool CalcPEC(); + virtual void CalcPEC_Range(unsigned int startX, unsigned int stopX, unsigned int* counter); //internal to CalcPEC + virtual void CalcPEC_Curves(); //internal to CalcPEC + + //Calc timestep only internal use + int m_TimeStepVar; + double m_TimeStepFactor; + virtual double CalcTimestep(); + double opt_dT; + bool m_InvaildTimestep; + string m_Used_TS_Name; + + double CalcTimestep_Var1(); + double CalcTimestep_Var3(); + + //! Calculate the FDTD equivalent circuit parameter for the given position and direction ny. \sa Calc_EffMat_Pos + virtual bool Calc_ECPos(int ny, const unsigned int* pos, double* EC, vector<CSPrimitives *> vPrims) const; + + //! Get the FDTD raw disc delta, needed by Calc_EffMatPos() \sa Calc_EffMatPos + /*! + Get the raw disc delta for a given position and direction. + The result will be positive if a disc delta inside the simulation domain is requested. + The result will be the negative value of the first or last disc delta respectivly if the position is outside the field domain. + */ + virtual double GetRawDiscDelta(int ny, const int pos) const; + + //! Get the material at a given coordinate, direction and type from CSX (internal use only) + virtual double GetMaterial(int ny, const double coords[3], int MatType, vector<CSPrimitives*> vPrims, bool markAsUsed=true) const; + + MatAverageMethods m_MatAverageMethod; + + //! Calculate the effective/averaged material properties at the given position and direction ny. + virtual bool Calc_EffMatPos(int ny, const unsigned int* pos, double* EffMat, vector<CSPrimitives*> vPrims) const; + + virtual bool AverageMatCellCenter(int ny, const unsigned int* pos, double* EffMat, vector<CSPrimitives*> vPrims) const; + virtual bool AverageMatQuarterCell(int ny, const unsigned int* pos, double* EffMat, vector<CSPrimitives*> vPrims) const; + + //! Calc operator at certain \a pos + virtual void Calc_ECOperatorPos(int n, unsigned int* pos); + + //! Calculate and setup lumped elements + virtual bool Calc_LumpedElements(); + + //! Store the size of the applied boundary conditions + int m_BC_Size[6]; + + //store material properties for post-processing + float**** m_epsR; + float**** m_kappa; + float**** m_mueR; + float**** m_sigma; + + //EC elements, internal only! + virtual void Init_EC(); + virtual bool Calc_EC(); + virtual void Calc_EC_Range(unsigned int xStart, unsigned int xStop); + FDTD_FLOAT* EC_C[3]; + FDTD_FLOAT* EC_G[3]; + FDTD_FLOAT* EC_L[3]; + FDTD_FLOAT* EC_R[3]; + + AdrOp* MainOp; + + vector<Operator_Extension*> m_Op_exts; + + Engine* m_Engine; + + // excitation classes + Excitation* m_Exc; // excitation time signal class +// Operator_Ext_Excitation* m_Op_Ext_Exc; // excitation extension + + // engine/post-proc needs access +public: + //EC operator + FDTD_FLOAT**** vv; //calc new voltage from old voltage + FDTD_FLOAT**** vi; //calc new voltage from old current + FDTD_FLOAT**** ii; //calc new current from old current + FDTD_FLOAT**** iv; //calc new current from old voltage +}; + +inline Operator::DebugFlags operator|( Operator::DebugFlags a, Operator::DebugFlags b ) { return static_cast<Operator::DebugFlags>(static_cast<int>(a) | static_cast<int>(b)); } +inline Operator::DebugFlags& operator|=( Operator::DebugFlags& a, const Operator::DebugFlags& b ) { return a = a | b; } + +#endif // OPERATOR_H diff --git a/openEMS/FDTD/operator_cylinder.cpp b/openEMS/FDTD/operator_cylinder.cpp new file mode 100644 index 0000000..342415f --- /dev/null +++ b/openEMS/FDTD/operator_cylinder.cpp @@ -0,0 +1,576 @@ +/* +* 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.h" +#include "engine_cylinder.h" +#include "Common/processfields.h" +#include "operator_cylinder.h" +#include "extensions/operator_extension.h" +#include "extensions/operator_ext_cylinder.h" +#include "tools/useful.h" + +Operator_Cylinder* Operator_Cylinder::New(unsigned int numThreads) +{ + cout << "Create cylindrical FDTD operator" << endl; + Operator_Cylinder* op = new Operator_Cylinder(); + op->setNumThreads(numThreads); + op->Init(); + return op; +} + +Operator_Cylinder::Operator_Cylinder() : Operator_Multithread() +{ + m_MeshType = CYLINDRICAL; + m_Cyl_Ext = NULL; +} + +Operator_Cylinder::~Operator_Cylinder() +{ +} + + +Engine* Operator_Cylinder::CreateEngine() +{ + //! create a special cylindrical-engine + m_Engine = Engine_Cylinder::New(this, m_numThreads); + return m_Engine; +} + +void Operator_Cylinder::Init() +{ + CC_closedAlpha = false; + CC_R0_included = false; + Operator_Multithread::Init(); +} + +double Operator_Cylinder::GetRawDiscDelta(int ny, const int pos) const +{ + if (CC_closedAlpha && ny==1 && pos==-1) + return (discLines[1][numLines[1]-2] - discLines[1][numLines[1]-3]); + if (CC_closedAlpha && ny==1 && (pos==(int)numLines[ny]-1)) + return (discLines[1][2] - discLines[1][1]); + + return Operator_Multithread::GetRawDiscDelta(ny,pos); +} + +double Operator_Cylinder::GetMaterial(int ny, const double* coords, int MatType, vector<CSPrimitives*> vPrims, bool markAsUsed) const +{ + double l_coords[] = {coords[0],coords[1],coords[2]}; + if (CC_closedAlpha && (coords[1]>GetDiscLine(1,0,false)+2*PI)) + l_coords[1]-=2*PI; + if (CC_closedAlpha && (coords[1]<GetDiscLine(1,0,false))) + l_coords[1] += 2*PI; + return Operator_Multithread::GetMaterial(ny,l_coords,MatType,vPrims,markAsUsed); +} + +int Operator_Cylinder::CalcECOperator( DebugFlags debugFlags ) +{ + // debugs only work with the native vector dumps + bool natDump = g_settings.NativeFieldDumps(); + g_settings.SetNativeFieldDumps(true); + int rc = Operator_Multithread::CalcECOperator(debugFlags); + // reset original settings + g_settings.SetNativeFieldDumps(natDump); + return rc; +} + +double Operator_Cylinder::CalcTimestep() +{ + if (discLines[0][0]==0.0) + // use conservative timestep for a mesh including the r==0 singularity + m_TimeStepVar = 1; + + return Operator::CalcTimestep(); +} + +inline unsigned int Operator_Cylinder::GetNumberOfLines(int ny, bool full) const +{ + if (full) + return Operator_Multithread::GetNumberOfLines(ny, full); + + //this is necessary for a correct field processing... cylindrical engine has to reset this by adding +1 + if (CC_closedAlpha && ny==1) + return Operator_Multithread::GetNumberOfLines(ny, true)-2; + + return Operator_Multithread::GetNumberOfLines(ny, full); +} + +string Operator_Cylinder::GetDirName(int ny) const +{ + if (ny==0) return "rho"; + if (ny==1) return "alpha"; + if (ny==2) return "z"; + return ""; +} + +bool Operator_Cylinder::GetYeeCoords(int ny, unsigned int pos[3], double* coords, bool dualMesh) const +{ + bool ret = Operator_Multithread::GetYeeCoords(ny,pos,coords,dualMesh); + + if (CC_closedAlpha && (coords[1]>=GetDiscLine(1,0,false)+2*PI)) + coords[1]-=2*PI; + if (CC_closedAlpha && (coords[1]<GetDiscLine(1,0,false))) + coords[1]+=2*PI; + + return ret; +} + +double Operator_Cylinder::GetNodeWidth(int ny, const unsigned int pos[3], bool dualMesh) const +{ + if ((ny<0) || (ny>2)) return 0.0; + if (pos[ny]>=numLines[ny]) return 0.0; + double width = Operator_Multithread::GetEdgeLength(ny,pos,!dualMesh); + if (ny==1) + width *= GetDiscLine(0,pos[0],dualMesh); + return width; +} + +double Operator_Cylinder::GetNodeWidth(int ny, const int pos[3], bool dualMesh) const +{ + if ( (pos[0]<0) || (pos[1]<0 && CC_closedAlpha==false) || (pos[2]<0) ) + return 0.0; + + unsigned int uiPos[]={(unsigned int)pos[0],(unsigned int)pos[1],(unsigned int)pos[2]}; + if (pos[1]<0 && CC_closedAlpha==true) + uiPos[1]+=numLines[1]-2; + + return GetNodeWidth(ny, uiPos, dualMesh); +} + +double Operator_Cylinder::GetNodeArea(int ny, const unsigned int pos[3], bool dualMesh) const +{ + if (pos[ny]>=numLines[ny]) return 0.0; + if (pos[0]>=numLines[0]) return 0.0; + if (ny==2) + { + double da = Operator_Multithread::GetEdgeLength(1,pos,dualMesh)/gridDelta; + double r1,r2; + + if (dualMesh) + { + r1 = GetDiscLine(0,pos[0],false)*gridDelta; + r2 = r1 + GetEdgeLength(0,pos,false); + } + else + { + r2 = GetDiscLine(0,pos[0],!dualMesh)*gridDelta; + r1 = r2 - GetEdgeLength(0,pos,true); + } + + if (r1<=0) + return da/2 * pow(r2,2); + else + return da/2* (pow(r2,2) - pow(r1,2)); + } + + return Operator_Multithread::GetNodeArea(ny,pos,dualMesh); +} + +double Operator_Cylinder::GetNodeArea(int ny, const int pos[3], bool dualMesh) const +{ + if ( (pos[0]<0) || (pos[1]<0 && CC_closedAlpha==false) || (pos[2]<0) ) + return 0.0; + + unsigned int uiPos[]={(unsigned int)pos[0],(unsigned int)pos[1],(unsigned int)pos[2]}; + if (pos[1]<0 && CC_closedAlpha==true) + uiPos[1]+=numLines[1]-2; + + return GetNodeArea(ny, uiPos, dualMesh); +} + +double Operator_Cylinder::GetEdgeLength(int ny, const unsigned int pos[3], bool dualMesh) const +{ + double length = Operator_Multithread::GetEdgeLength(ny,pos,dualMesh); + if (ny!=1) + return length; + return length * GetDiscLine(0,pos[0],dualMesh); +} + +double Operator_Cylinder::GetCellVolume(const unsigned int pos[3], bool dualMesh) const +{ + return GetEdgeArea(2,pos,dualMesh)*GetEdgeLength(2,pos,dualMesh); +} + +double Operator_Cylinder::GetEdgeArea(int ny, const unsigned int pos[3], bool dualMesh) const +{ + if (ny!=0) + return GetNodeArea(ny,pos,dualMesh); + + return GetEdgeLength(1,pos,!dualMesh) * GetEdgeLength(2,pos,!dualMesh); +} + +double Operator_Cylinder::FitToAlphaRange(double a_coord, bool fullMesh) const +{ + double min = GetDiscLine(1,0); + double max = GetDiscLine(1,GetNumberOfLines(1, fullMesh)-1); + if ((a_coord>=min) && (a_coord<=max)) + return a_coord; + while (a_coord<min) + { + a_coord+=2*PI; + if (a_coord>max) + return a_coord-2*PI; + if (a_coord>min) + return a_coord; + } + while (a_coord>max) + { + a_coord-=2*PI; + if (a_coord<min) + return a_coord+2*PI; + if (a_coord<max) + return a_coord; + } + // this cannot happen + return a_coord; +} + +int Operator_Cylinder::MapAlphaIndex2Range(int pos) const +{ + if (!CC_closedAlpha) + return pos; + if (pos<0) + return (int)numLines[1]+pos-2; + else if (pos>=(int)numLines[1]-2) + return pos-(int)numLines[1]+2; + else + return pos; +} + +bool Operator_Cylinder::GetCellCenterMaterialAvgCoord(const int pos[3], double coord[3]) const +{ + if (!CC_closedAlpha || ((pos[1]>=0) && (pos[1]<(int)numLines[1]-2))) + { + return Operator_Multithread::GetCellCenterMaterialAvgCoord(pos, coord); + } + if ((pos[0]<0) || (pos[2]<0)) + return false; + int l_pos[3] = {pos[0], 0, pos[2]}; + l_pos[1] = MapAlphaIndex2Range(pos[1]); + return Operator_Multithread::GetCellCenterMaterialAvgCoord(l_pos, coord); +} + +unsigned int Operator_Cylinder::SnapToMeshLine(int ny, double coord, bool &inside, bool dualMesh, bool fullMesh) const +{ + if (ny==1) + coord=FitToAlphaRange(coord); + return Operator_Multithread::SnapToMeshLine(ny, coord, inside, dualMesh, fullMesh); +} + +int Operator_Cylinder::SnapBox2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh, bool fullMesh, int SnapMethod, bool* bStartIn, bool* bStopIn) const +{ + double a_min = GetDiscLine(1,0); + double a_max = GetDiscLine(1,GetNumberOfLines(1,fullMesh)-1); + + double a_size = stop[1] - start[1]; + double a_center = FitToAlphaRange(0.5*(stop[1]+start[1])); + double a_start = a_center-a_size/2; + double a_stop = a_start + a_size; + if (a_stop>a_max) + a_stop=a_max; + if (a_stop<a_min) + a_stop=a_min; + if (a_start>a_max) + a_start=a_max; + if (a_start<a_min) + a_start=a_min; + + double l_start[3] = {start[0], a_start, start[2]}; + double l_stop[3] = {stop[0] , a_stop , stop[2] }; + return Operator_Multithread::SnapBox2Mesh(l_start, l_stop, uiStart, uiStop, dualMesh, fullMesh, SnapMethod, bStartIn, bStopIn); +} + +int Operator_Cylinder::SnapLine2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh, bool fullMesh) const +{ + int ret = Operator_Multithread::SnapLine2Mesh(start, stop, uiStart, uiStop, dualMesh, fullMesh); + + if ((stop[1]>start[1]) && (uiStop[1]<uiStart[1]) && (uiStop[1]==0)) + uiStop[1] = GetNumberOfLines(1, fullMesh)-1-(int)CC_closedAlpha; + if ((stop[1]<start[1]) && (uiStop[1]>uiStart[1]) && (uiStop[1]==GetNumberOfLines(1, fullMesh)-1-(int)CC_closedAlpha)) + uiStop[1] = 0; + + return ret; +} + + +Grid_Path Operator_Cylinder::FindPath(double start[], double stop[]) +{ + double l_start[3]; + double l_stop[3]; + + for (int n=0;n<3;++n) + { + l_start[n] = start[n]; + l_stop[n] = stop[n]; + } + + while (fabs(l_stop[1]-l_start[1])>PI) + { + if (l_stop[1]>l_start[1]) + l_stop[1]-=2*PI; + else + l_stop[1]+=2*PI; + } + + double help=0; + if (l_start[1]>l_stop[1]) + { + for (int n=0;n<3;++n) + { + help = l_start[n]; + l_start[n] = l_stop[n]; + l_stop[n] = help; + } + } + + double a_start = FitToAlphaRange(l_start[1]); + double a_stop = FitToAlphaRange(l_stop[1]); + + if (a_stop >= a_start) + { + l_start[1] = a_start; + l_stop[1] = a_stop; + return Operator_Multithread::FindPath(l_start, l_stop); + } + + // if a-stop fitted to disc range is now smaller than a-start, it must step over the a-bounds... + + Grid_Path path; + for (int n=0;n<3;++n) + { + if ((l_start[n]<GetDiscLine(n,0)) && (l_stop[n]<GetDiscLine(n,0))) + return path; //lower bound violation + if ((l_start[n]>GetDiscLine(n,GetNumberOfLines(n,true)-1)) && (l_stop[n]>GetDiscLine(n,GetNumberOfLines(n,true)-1))) + return path; //upper bound violation + } + + if (g_settings.GetVerboseLevel()>2) + cerr << __func__ << ": A path was leaving the alpha-direction mesh..." << endl; + + // this section comes into play, if the line moves over the angulare mesh-end/start + // we try to have one part of the path on both "ends" of the mesh and stitch them together + + Grid_Path path1; + Grid_Path path2; + + // calculate the intersection of the line with the a-max boundary + double p0[3],p1[3],p2[3]; + for (int n=0;n<3;++n) + { + p0[n] = GetDiscLine(n,0); + p1[n] = p0[n]; + p2[n] = p0[n]; + } + p0[1] = GetDiscLine(1,GetNumberOfLines(1,true)-1-(int)CC_closedAlpha); + p1[1] = p0[1]; + p2[1] = p0[1]; + p1[0] = discLines[0][numLines[0]-1]; + p2[2] = discLines[2][numLines[2]-1]; + + TransformCoordSystem(p0,p0,m_MeshType,CARTESIAN); + TransformCoordSystem(p1,p1,m_MeshType,CARTESIAN); + TransformCoordSystem(p2,p2,m_MeshType,CARTESIAN); + + double c_start[3],c_stop[3]; + TransformCoordSystem(l_start,c_start,m_MeshType,CARTESIAN); + TransformCoordSystem(l_stop,c_stop,m_MeshType,CARTESIAN); + double intersect[3]; + double dist; + int ret = LinePlaneIntersection(p0,p1,p2,c_start,c_stop,intersect,dist); + if (ret<0) + { + cerr << __func__ << ": Error, unable to calculate intersection, this should not happen!" << endl; + return path; // return empty path; + } + + if (ret==0) + { + TransformCoordSystem(intersect,intersect,CARTESIAN,m_MeshType); + intersect[1] = GetDiscLine(1,GetNumberOfLines(1,true)-1-(int)CC_closedAlpha); + l_start[1] = FitToAlphaRange(l_start[1]); + path1 = Operator::FindPath(l_start, intersect); + if (g_settings.GetVerboseLevel()>2) + cerr << __func__ << ": Intersection top: " << intersect[0] << "," << intersect[1] << "," << intersect[2] << endl; + } //otherwise the path was not intersecting the upper a-bound... + + if (CC_closedAlpha==false) + { + for (int n=0;n<3;++n) + { + p0[n] = GetDiscLine(n,0); + p1[n] = p0[n]; + p2[n] = p0[n]; + } + p1[0] = discLines[0][numLines[0]-1]; + p2[2] = discLines[2][numLines[2]-1]; + + TransformCoordSystem(p0,p0,m_MeshType,CARTESIAN); + TransformCoordSystem(p1,p1,m_MeshType,CARTESIAN); + TransformCoordSystem(p2,p2,m_MeshType,CARTESIAN); + + TransformCoordSystem(l_start,c_start,m_MeshType,CARTESIAN); + TransformCoordSystem(l_stop,c_stop,m_MeshType,CARTESIAN); + + ret = LinePlaneIntersection(p0,p1,p2,c_start,c_stop,intersect,dist); + TransformCoordSystem(intersect,intersect,CARTESIAN,m_MeshType); + } + + if (ret==0) + { + intersect[1] = GetDiscLine(1,0); + l_stop[1] = FitToAlphaRange(l_stop[1]); + path2 = Operator::FindPath(intersect, l_stop); + if (g_settings.GetVerboseLevel()>2) + cerr << __func__ << ": Intersection bottom: " << intersect[0] << "," << intersect[1] << "," << intersect[2] << endl; + } + + //combine path + for (size_t t=0; t<path1.dir.size(); ++t) + { + path.posPath[0].push_back(path1.posPath[0].at(t)); + path.posPath[1].push_back(path1.posPath[1].at(t)); + path.posPath[2].push_back(path1.posPath[2].at(t)); + path.dir.push_back(path1.dir.at(t)); + } + for (size_t t=0; t<path2.dir.size(); ++t) + { + path.posPath[0].push_back(path2.posPath[0].at(t)); + path.posPath[1].push_back(path2.posPath[1].at(t)); + path.posPath[2].push_back(path2.posPath[2].at(t)); + path.dir.push_back(path2.dir.at(t)); + } + + if (CC_closedAlpha==true) + for (size_t t=0; t<path.dir.size(); ++t) + { + if ( ((path.dir.at(t)==0) || (path.dir.at(t)==2)) && (path.posPath[1].at(t)==0)) + path.posPath[1].at(t) = numLines[1]-2; + } + + return path; +} + +bool Operator_Cylinder::SetupCSXGrid(CSRectGrid* grid) +{ + unsigned int alphaNum; + double* alphaLines = NULL; + alphaLines = grid->GetLines(1,alphaLines,alphaNum,true); + + double minmaxA = fabs(alphaLines[alphaNum-1]-alphaLines[0]); + if (fabs(minmaxA-2*PI) < OPERATOR_CYLINDER_CLOSED_ALPHA_THRESHOLD) + { + if (g_settings.GetVerboseLevel()>0) + cout << "Operator_Cylinder::SetupCSXGrid: Alpha is a full 2*PI => closed Cylinder..." << endl; + CC_closedAlpha = true; + grid->SetLine(1,alphaNum-1,2*PI+alphaLines[0]); + grid->AddDiscLine(1,2*PI+alphaLines[1]); + } + else if (minmaxA>2*PI) + { + cerr << "Operator_Cylinder::SetupCSXGrid: Alpha Max-Min must not be larger than 2*PI!!!" << endl; + Reset(); + return false; + } + else + { + CC_closedAlpha=false; + } + + CC_R0_included = false; + if (grid->GetLine(0,0)<0) + { + cerr << "Operator_Cylinder::SetupCSXGrid: r<0 not allowed in Cylinder Coordinates!!!" << endl; + Reset(); + return false; + } + else if (grid->GetLine(0,0)==0.0) + { + if (g_settings.GetVerboseLevel()>0) + cout << "Operator_Cylinder::SetupCSXGrid: r=0 included..." << endl; + CC_R0_included = CC_closedAlpha; //needed for correct ec-calculation, deactivate if closed cylinder is false... --> E_r = 0 anyways + } + +#ifdef MPI_SUPPORT + // Setup an MPI split in alpha direction for a closed cylinder + CC_MPI_Alpha = false; + if ((m_NeighborUp[1]>=0) || (m_NeighborDown[1]>=0)) //check for MPI split in alpha direction + { + double minmaxA = 2*PI;// fabs(m_OrigDiscLines[1][m_OrigNumLines[1]-1]-m_OrigDiscLines[1][0]); + if (fabs(minmaxA-2*PI) < OPERATOR_CYLINDER_CLOSED_ALPHA_THRESHOLD) //check for closed alpha MPI split + { + CC_MPI_Alpha = true; + if (m_OrigDiscLines[0][0]==0) + { + cerr << "Operator_Cylinder::SetupCSXGrid: Error: MPI split in alpha direction for closed cylinder including r==0 is currently not supported! Exit!" << endl; + exit(-2); + } + + if (m_NeighborUp[1]<0) //check if this process is at the alpha-end + { + grid->SetLine(1,alphaNum-1,2*PI+m_OrigDiscLines[1][0]); + grid->AddDiscLine(1,2*PI+m_OrigDiscLines[1][1]); + + SetNeighborUp(1,m_ProcTable[m_ProcTablePos[0]][0][m_ProcTablePos[2]]); + } + + if (m_NeighborDown[1]<0) //check if this process is at the alpha-start + { + SetNeighborDown(1,m_ProcTable[m_ProcTablePos[0]][m_SplitNumber[1]-1][m_ProcTablePos[2]]); + } + + //Note: the process table will not reflect this up/down neighbors necessary for a closed cylinder + } + } +#endif + + if (Operator_Multithread::SetupCSXGrid(grid)==false) + return false; + + if (CC_closedAlpha || CC_R0_included) + { + m_Cyl_Ext = new Operator_Ext_Cylinder(this); + this->AddExtension(m_Cyl_Ext); + } + + return true; +} + +void Operator_Cylinder::ApplyMagneticBC(bool* dirs) +{ + if (dirs==NULL) return; + if (CC_closedAlpha) + { + dirs[2]=0; + dirs[3]=0; //no PMC in alpha directions... + } + if (CC_R0_included) + { + dirs[0]=0; //no PMC in r_min directions... + } + Operator_Multithread::ApplyMagneticBC(dirs); +} + +void Operator_Cylinder::AddExtension(Operator_Extension* op_ext) +{ + if (op_ext->IsCylinderCoordsSave(CC_closedAlpha, CC_R0_included)) + Operator_Multithread::AddExtension(op_ext); + else + { + cerr << "Operator_Cylinder::AddExtension: Warning: Operator extension \"" << op_ext->GetExtensionName() << "\" is not compatible with cylinder-coords!! skipping...!" << endl; + delete op_ext; + } +} diff --git a/openEMS/FDTD/operator_cylinder.h b/openEMS/FDTD/operator_cylinder.h new file mode 100644 index 0000000..152f618 --- /dev/null +++ b/openEMS/FDTD/operator_cylinder.h @@ -0,0 +1,118 @@ +/* +* 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_CYLINDER_H +#define OPERATOR_CYLINDER_H + +#define OPERATOR_CYLINDER_CLOSED_ALPHA_THRESHOLD 1e-6 + +#include "operator_multithread.h" + +class Operator_Ext_Cylinder; + +//! This class creates an operator for a cylindrical FDTD. +/*! +This class creates an operator for a cylindrical FDTD. No special engine is necessary, +all special cases e.g. a closed alpha mesh or an included r=0 case is treated by an operator/engine extension \sa operator_ext_cylinder. +*/ +class Operator_Cylinder : public Operator_Multithread +{ + friend class Operator_CylinderMultiGrid; + friend class Operator_Ext_Cylinder; + friend class Operator_Ext_LorentzMaterial; +public: + static Operator_Cylinder* New(unsigned int numThreads = 0); + virtual ~Operator_Cylinder(); + + virtual void ApplyMagneticBC(bool* dirs); + + virtual unsigned int GetNumberOfLines(int ny, bool full=false) const; + + //! Get the name for the given direction: 0 -> rho, 1 -> alpha, 2 -> z + virtual string GetDirName(int ny) const; + + //! Get the coordinates for a given node index and component, according to the cylindrical yee-algorithm. Returns true if inside the FDTD domain. + virtual bool GetYeeCoords(int ny, unsigned int pos[3], double* coords, bool dualMesh) const; + + //! Get the node width for a given direction \a n and a given mesh posisition \a pos + virtual double GetNodeWidth(int ny, const unsigned int pos[3], bool dualMesh = false) const; + //! Get the node width for a given direction \a n and a given mesh posisition \a pos + virtual double GetNodeWidth(int ny, const int pos[3], bool dualMesh = false) const; + + //! Get the node area for a given direction \a n and a given mesh posisition \a pos + virtual double GetNodeArea(int n, const unsigned int* pos, bool dualMesh=false) const; + //! Get the node area for a given direction \a n and a given mesh posisition \a pos + virtual double GetNodeArea(int ny, const int pos[3], bool dualMesh = false) const; + + //! Get the length of an FDTD edge, including radius corrected alpha-mesh width. + virtual double GetEdgeLength(int ny, const unsigned int pos[3], bool dualMesh = false) const; + + //! Get the volume of an FDTD cell + virtual double GetCellVolume(const unsigned int pos[3], bool dualMesh = false) const; + + //! Get the area around an edge for a given direction \a n and a given mesh posisition \a pos + /*! + This will return the area around an edge with a given direction, measured at the middle of the edge. + In a cartesian mesh this is equal to the NodeArea, may be different in other coordinate systems. + */ + virtual double GetEdgeArea(int ny, const unsigned int pos[3], bool dualMesh = false) const; + + virtual double FitToAlphaRange(double a_coord, bool fullMesh=false) const; + + //! Map a negative or out of range index in alpha direction back into the closed alpha mesh + virtual int MapAlphaIndex2Range(int pos) const; + + virtual bool GetCellCenterMaterialAvgCoord(const int pos[3], double coord[3]) const; + + virtual unsigned int SnapToMeshLine(int ny, double coord, bool &inside, bool dualMesh=false, bool fullMesh=false) const; + + //! Snap a given box to the FDTD mesh + virtual int SnapBox2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh=false, bool fullMesh=false, int SnapMethod=0, bool* bStartIn=NULL, bool* bStopIn=NULL) const; + + virtual int SnapLine2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh=false, bool fullMesh=false) const; + + bool GetClosedAlpha() const {return CC_closedAlpha;} + bool GetR0Included() const {return CC_R0_included;} + + virtual void AddExtension(Operator_Extension* op_ext); + + virtual Engine* CreateEngine(); + +protected: + Operator_Cylinder(); + virtual void Init(); + + virtual bool SetupCSXGrid(CSRectGrid* grid); + + virtual Grid_Path FindPath(double start[], double stop[]); + + virtual double GetRawDiscDelta(int ny, const int pos) const; + + virtual double GetMaterial(int ny, const double coords[3], int MatType, vector<CSPrimitives*> vPrims, bool markAsUsed=true) const; + + virtual int CalcECOperator( DebugFlags debugFlags = None ); + virtual double CalcTimestep(); + bool CC_closedAlpha; + bool CC_R0_included; + Operator_Ext_Cylinder* m_Cyl_Ext; + +#ifdef MPI_SUPPORT + bool CC_MPI_Alpha; +#endif +}; + +#endif // OPERATOR_CYLINDER_H diff --git a/openEMS/FDTD/operator_cylindermultigrid.cpp b/openEMS/FDTD/operator_cylindermultigrid.cpp new file mode 100644 index 0000000..88f9f82 --- /dev/null +++ b/openEMS/FDTD/operator_cylindermultigrid.cpp @@ -0,0 +1,569 @@ +/* +* 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_cylindermultigrid.h" +#include "engine_cylindermultigrid.h" +#include "extensions/operator_ext_cylinder.h" +#include "tools/useful.h" +#include "CSUseful.h" + +Operator_CylinderMultiGrid::Operator_CylinderMultiGrid(vector<double> Split_Radii, unsigned int level) : Operator_Cylinder() +{ + m_Split_Radii = Split_Radii; + m_Split_Rad = m_Split_Radii.back(); + m_Split_Radii.pop_back(); + m_MultiGridLevel = level; +} + +Operator_CylinderMultiGrid::~Operator_CylinderMultiGrid() +{ + Delete(); +} + +Operator_CylinderMultiGrid* Operator_CylinderMultiGrid::New(vector<double> Split_Radii, unsigned int numThreads, unsigned int level) +{ + if ((Split_Radii.size()==0) || (Split_Radii.size()>CYLIDINDERMULTIGRID_LIMIT)) + { + cerr << "Operator_CylinderMultiGrid::New: Warning: Number of multigrids invalid! Split-Number: " << Split_Radii.size() << endl; + return NULL; + } + cout << "Create cylindrical multi grid FDTD operator " << endl; + Operator_CylinderMultiGrid* op = new Operator_CylinderMultiGrid(Split_Radii, level); + op->setNumThreads(numThreads); + op->Init(); + + return op; +} + +Engine* Operator_CylinderMultiGrid::CreateEngine() +{ + m_Engine = Engine_CylinderMultiGrid::New(this,m_numThreads); + return m_Engine; +} + +double Operator_CylinderMultiGrid::GetNumberCells() const +{ + if (numLines) + return (numLines[0]-m_Split_Pos)*(numLines[1])*(numLines[2]) + m_InnerOp->GetNumberCells(); + return 0; +} + +bool Operator_CylinderMultiGrid::SetupCSXGrid(CSRectGrid* grid) +{ + if (Operator_Cylinder::SetupCSXGrid(grid)==false) + return false; + + // make this multigrid use the larger timestep by method 3, since no r==0 singularity can be part of this engine + m_TimeStepVar = 3; + + if ((numLines[1]-CC_closedAlpha)%2 != 1) + { + cerr << "Operator_CylinderMultiGrid::SetupCSXGrid: Error, number of line in alpha direction must be odd... found: " << numLines[1] << endl; + exit(0); + } + + m_Split_Pos = 0; + for (unsigned int n=0; n<numLines[0]; ++n) + { + if (m_Split_Rad < discLines[0][n]) + { + m_Split_Pos = n; + if (g_settings.GetVerboseLevel()>0) + cout << "Operator_CylinderMultiGrid::SetupCSXGrid: Found mesh split position @" << m_Split_Pos << endl; + m_Split_Rad = discLines[0][n]; + break; + } + } + if ((m_Split_Pos<4) || (m_Split_Pos>numLines[0]-4)) + { + cerr << "Operator_CylinderMultiGrid::SetupCSXGrid: Error, split invalid..." << endl; + return false; + } + return true; +} + +bool Operator_CylinderMultiGrid::SetGeometryCSX(ContinuousStructure* geo) +{ + if (Operator_Cylinder::SetGeometryCSX(geo)==false) + return false; + + CSRectGrid* grid = geo->GetGrid(); + + grid->ClearLines(0); + grid->ClearLines(1); + for (unsigned int n=0; n<m_Split_Pos ; ++n) + grid->AddDiscLine(0,discLines[0][n]); + for (unsigned int n=0; n<numLines[1]; n+=2) + grid->AddDiscLine(1,discLines[1][n]); + + if (m_InnerOp->SetGeometryCSX(CSX)==false) + return false; + + //restore grid to original mesh + grid->ClearLines(0); + grid->ClearLines(1); + for (unsigned int n=0; n<numLines[0]; ++n) + grid->AddDiscLine(0,discLines[0][n]); + for (unsigned int n=0; n<numLines[1]; ++n) + grid->AddDiscLine(1,discLines[1][n]); + + return true; +} + +void Operator_CylinderMultiGrid::Init() +{ + Operator_Cylinder::Init(); + + if (m_Split_Radii.empty()) + m_InnerOp = Operator_Cylinder::New(m_numThreads); + else + m_InnerOp = Operator_CylinderMultiGrid::New(m_Split_Radii,m_numThreads, m_MultiGridLevel+1); + + for (int n=0;n<2;++n) + { + m_interpol_pos_v_2p[n] = NULL; + f4_interpol_v_2p[n]=NULL; + m_interpol_pos_v_2pp[n] = NULL; + f4_interpol_v_2pp[n]=NULL; + + m_interpol_pos_i_2p[n] = NULL; + f4_interpol_i_2p[n]=NULL; + m_interpol_pos_i_2pp[n] = NULL; + f4_interpol_i_2pp[n]=NULL; + } +} + +bool Operator_CylinderMultiGrid::GetYeeCoords(int ny, unsigned int pos[3], double* coords, bool dualMesh) const +{ + bool ret = Operator_Cylinder::GetYeeCoords(ny,pos,coords,dualMesh); + + if (pos[0]<(m_Split_Pos-1)) + ret = false; + + return ret; +} + +#ifdef MPI_SUPPORT +void Operator_CylinderMultiGrid::SetTag(int tag) +{ + m_MyTag = tag; + m_InnerOp->SetTag(tag+1); +} + +void Operator_CylinderMultiGrid::SetNeighborUp(int ny, int id) +{ + if (ny==0) + { + cerr << "Operator_CylinderMultiGrid::SetNeighborUp: Error: MPI segregation in radial direction not supported for a cylindircal multigrid. Exit!"; + MPI_Barrier(MPI_COMM_WORLD); + exit(-1); + } + Operator_Cylinder::SetNeighborUp(ny,id); + m_InnerOp->SetNeighborUp(ny,id); +} + +void Operator_CylinderMultiGrid::SetNeighborDown(int ny, int id) +{ + if (ny==0) + { + cerr << "Operator_CylinderMultiGrid::SetNeighborDown: Error: MPI segregation in radial direction not supported for a cylindircal multigrid. Exit!"; + MPI_Barrier(MPI_COMM_WORLD); + exit(-1); + } + Operator_Cylinder::SetNeighborDown(ny,id); + m_InnerOp->SetNeighborDown(ny,id); +} +#endif + +void Operator_CylinderMultiGrid::CalcStartStopLines(unsigned int &numThreads, vector<unsigned int> &start, vector<unsigned int> &stop) const +{ + vector<unsigned int> jpt = AssignJobs2Threads(numLines[0]- m_Split_Pos + 1, numThreads, true); + + numThreads = jpt.size(); + + start.resize(numThreads); + stop.resize(numThreads); + + start.at(0)= m_Split_Pos-1; + stop.at(0)= jpt.at(0)-1 + m_Split_Pos-1; + + for (unsigned int n=1; n<numThreads; n++) + { + start.at(n) = stop.at(n-1)+1; + stop.at(n) = start.at(n) + jpt.at(n) - 1; + } +} + + +void Operator_CylinderMultiGrid::FillMissingDataStorage() +{ + unsigned int pos[3]; + double EffMat[4]; + for (int ny=0; ny<3; ++ny) + { + for (pos[0]=0; pos[0]<m_Split_Pos-1; ++pos[0]) + { + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + vector<CSPrimitives*> vPrims = this->GetPrimitivesBoundBox(pos[0], pos[1], -1, CSProperties::MATERIAL); + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + Calc_EffMatPos(ny,pos,EffMat,vPrims); + + if (m_epsR) + m_epsR[ny][pos[0]][pos[1]][pos[2]] = EffMat[0]; + if (m_kappa) + m_kappa[ny][pos[0]][pos[1]][pos[2]] = EffMat[1]; + if (m_mueR) + m_mueR[ny][pos[0]][pos[1]][pos[2]] = EffMat[2]; + if (m_sigma) + m_sigma[ny][pos[0]][pos[1]][pos[2]] = EffMat[3]; + } + } + } + } +} + +bool Operator_CylinderMultiGrid::GetCellCenterMaterialAvgCoord(const int pos[3], double coord[3]) const +{ + if (Operator_Cylinder::GetCellCenterMaterialAvgCoord(pos, coord)==false) + return false; + + if (pos[0]>=((int)m_Split_Pos)) + return true; + + int pos_a = MapAlphaIndex2Range(pos[1])/2; + if ((pos_a<0) || (pos_a>=(int)m_InnerOp->numLines[1])) + return false; + coord[1] = m_InnerOp->GetDiscLine(1,pos_a,true); + return true; +} + +int Operator_CylinderMultiGrid::CalcECOperator( DebugFlags debugFlags ) +{ + int retCode=0; + if (dT) + m_InnerOp->SetTimestep(dT); + + //calc inner child first + m_InnerOp->CalcECOperator(); + + dT = m_InnerOp->GetTimestep(); + + retCode = Operator_Cylinder::CalcECOperator( debugFlags ); + if (GetTimestepValid()==false) + { + cerr << "Operator_CylinderMultiGrid::CalcECOperator(): Warning, timestep invalid... resetting..." << endl; + dT = opt_dT; + m_InnerOp->SetTimestep(dT); + m_InnerOp->CalcECOperator(); + retCode = Operator_Cylinder::CalcECOperator( debugFlags ); + } + + SetupInterpolation(); + + //the data storage will only be filled up to m_Split_Pos-1, fill the remaining area here... + FillMissingDataStorage(); + return retCode; +} + +void Operator_CylinderMultiGrid::DumpPEC2File( string filename, unsigned int *range) +{ + if (range!=NULL) + return Operator_Cylinder::DumpPEC2File(filename, range); + + range = new unsigned int[6]; + for (int n=0;n<3;++n) + { + range[2*n] = 0; + range[2*n+1] = numLines[n]-1; + } + range[0] = m_Split_Pos-1; + Operator_Cylinder::DumpPEC2File(filename + "_S" + ConvertInt(m_MultiGridLevel), range); + delete[] range; + range=NULL; + + if (dynamic_cast<Operator_CylinderMultiGrid*>(m_InnerOp)) + m_InnerOp->DumpPEC2File(filename); + else // base cylindrical grid + m_InnerOp->DumpPEC2File(filename + "_S" + ConvertInt(m_MultiGridLevel+1)); +} + +void Operator_CylinderMultiGrid::SetupInterpolation() +{ + // n==0 --> interpolation in r&z-direction + // n==1 --> interpolation in a-direction + for (int n=0;n<2;++n) + { + delete[] m_interpol_pos_v_2p[n]; + m_interpol_pos_v_2p[n] = new unsigned int[numLines[1]]; + Delete1DArray_v4sf(f4_interpol_v_2p[n]); + f4_interpol_v_2p[n]=Create1DArray_v4sf(numLines[1]); + + delete[] m_interpol_pos_v_2pp[n]; + m_interpol_pos_v_2pp[n] = new unsigned int[numLines[1]]; + Delete1DArray_v4sf(f4_interpol_v_2pp[n]); + f4_interpol_v_2pp[n]=Create1DArray_v4sf(numLines[1]); + + delete[] m_interpol_pos_i_2p[n]; + m_interpol_pos_i_2p[n] = new unsigned int[numLines[1]]; + Delete1DArray_v4sf(f4_interpol_i_2p[n]); + f4_interpol_i_2p[n]=Create1DArray_v4sf(numLines[1]); + + delete[] m_interpol_pos_i_2pp[n]; + m_interpol_pos_i_2pp[n] = new unsigned int[numLines[1]]; + Delete1DArray_v4sf(f4_interpol_i_2pp[n]); + f4_interpol_i_2pp[n]=Create1DArray_v4sf(numLines[1]); + } + + bool isOdd, isEven; + for (unsigned int a_n=0; a_n<numLines[1]; ++a_n) + { + isOdd = (a_n%2); + isEven = !isOdd; + + /* current interpolation position for r,z direction + this sub_grid 2p sub_grid 2pp + 0 <-- 0 (-1) 0 + 1 <-- 0 1 + 2 <-- 1 0 + 3 <-- 1 2 + 4 <-- 2 1 + 5 <-- 2 3 + ... + */ + m_interpol_pos_i_2p[0][a_n] = a_n/2; + m_interpol_pos_i_2pp[0][a_n] = a_n/2 + isOdd - isEven; + if ((a_n==0) && CC_closedAlpha) + m_interpol_pos_i_2pp[0][a_n] = m_InnerOp->numLines[1]-3; + else if ((a_n==0) && !CC_closedAlpha) + m_interpol_pos_i_2pp[0][a_n] = 0; + + //setup some special treatments for not closed alpha mesh + if ((a_n==numLines[1]-2) && !CC_closedAlpha) + m_interpol_pos_i_2pp[0][a_n] = a_n/2 - 1; + if ((a_n==numLines[1]-1) && !CC_closedAlpha) + m_interpol_pos_i_2p[0][a_n] = m_interpol_pos_i_2pp[0][a_n] = a_n/2; + + double dl_p=m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2p[0][a_n],true); + double dl_pp=m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2pp[0][a_n],true); + if ((a_n==0) && CC_closedAlpha) + dl_pp -= 2*PI; + + for (int v=0;v<4;++v) + { + if (m_interpol_pos_i_2p[0][a_n]==m_interpol_pos_i_2pp[0][a_n]) + f4_interpol_i_2p[0][a_n].f[v] = 1.0; + else + { + f4_interpol_i_2p[0][a_n].f[v] = (dl_pp-GetDiscLine(1,a_n,true)) / (dl_pp-dl_p); + f4_interpol_i_2pp[0][a_n].f[v] = (GetDiscLine(1,a_n,true)-dl_p) / (dl_pp-dl_p); + } + } + + /* voltage interpolation position for r,z direction + this sub_grid 2p sub_grid 2pp + 0 <-- 0 0 + 1 <-- 0 1 + 2 <-- 1 1 + 3 <-- 1 2 + 4 <-- 2 2 + 5 <-- 2 3 + ... + */ + m_interpol_pos_v_2p[0][a_n] = a_n/2; + m_interpol_pos_v_2pp[0][a_n] = a_n/2 + isOdd; + + dl_p=m_InnerOp->GetDiscLine(1,m_interpol_pos_v_2p[0][a_n],false); + dl_pp=m_InnerOp->GetDiscLine(1,m_interpol_pos_v_2pp[0][a_n],false); + + for (int v=0;v<4;++v) + { + if (m_interpol_pos_v_2p[0][a_n]==m_interpol_pos_v_2pp[0][a_n]) + f4_interpol_v_2p[0][a_n].f[v] = 1.0; + else + { + f4_interpol_v_2p[0][a_n].f[v] = (dl_pp-GetDiscLine(1,a_n,false)) / (dl_pp-dl_p); + f4_interpol_v_2pp[0][a_n].f[v] = (GetDiscLine(1,a_n,false)-dl_p) / (dl_pp-dl_p); + } + } + + /* current interpolation position for the alpha direction + this sub_grid 2p sub_grid 2pp + 0 <-- 0 0 + 1 <-- 0 1 + 2 <-- 1 1 + 3 <-- 1 2 + 4 <-- 2 2 + 5 <-- 2 3 + ... + */ + m_interpol_pos_i_2p[1][a_n] = a_n/2; + m_interpol_pos_i_2pp[1][a_n] = a_n/2 + isOdd; + + //setup some special treatments for not closed alpha mesh + if ((a_n==1) && !CC_closedAlpha) + m_interpol_pos_i_2p[1][a_n] = 2; + if ((a_n==numLines[1]-2) && !CC_closedAlpha) + m_interpol_pos_i_2pp[1][a_n] = a_n/2 - 1; + + for (int v=0;v<4;++v) + { + if (m_interpol_pos_i_2p[1][a_n]==m_interpol_pos_i_2pp[1][a_n]) + f4_interpol_i_2p[1][a_n].f[v] = GetDiscDelta(1,a_n,true)/m_InnerOp->GetDiscDelta(1,m_interpol_pos_i_2p[1][a_n],true); + else + { + f4_interpol_i_2p[1][a_n].f[v] = (m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2pp[1][a_n],false)-GetDiscLine(1,a_n,false)) / + (m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2pp[1][a_n],false)-m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2p[1][a_n],false)); + f4_interpol_i_2p[1][a_n].f[v] *= GetDiscDelta(1,a_n,true)/m_InnerOp->GetDiscDelta(1,m_interpol_pos_i_2p[1][a_n],true); + + f4_interpol_i_2pp[1][a_n].f[v] = (GetDiscLine(1,a_n,false)-m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2p[1][a_n],false)) / + (m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2pp[1][a_n],false)-m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2p[1][a_n],false)); + f4_interpol_i_2pp[1][a_n].f[v] *= GetDiscDelta(1,a_n,true)/m_InnerOp->GetDiscDelta(1,m_interpol_pos_i_2pp[1][a_n],true); + } + } + + /* voltage interpolation position for the alpha direction + this sub_grid 2p sub_grid 2pp + 0 <-- 0 (-1) 0 + 1 <-- 0 1 + 2 <-- 1 0 + 3 <-- 1 2 + 4 <-- 2 1 + 5 <-- 2 3 + ... + */ + m_interpol_pos_v_2p[1][a_n] = a_n/2; + m_interpol_pos_v_2pp[1][a_n] = a_n/2 + isOdd - isEven; + + if ((a_n==0) && CC_closedAlpha) + m_interpol_pos_v_2pp[1][a_n] = m_InnerOp->numLines[1]-3; + else if ((a_n==0) && !CC_closedAlpha) + m_interpol_pos_v_2pp[1][a_n] = 1; + + //setup some special treatments for not closed alpha mesh + if ((a_n==numLines[1]-2) && !CC_closedAlpha) + m_interpol_pos_v_2pp[1][a_n] = a_n/2 - 1; + if ((a_n==numLines[1]-1) && !CC_closedAlpha) + { + m_interpol_pos_v_2p[1][a_n] = 0; + m_interpol_pos_v_2pp[1][a_n] = 0; + } + + dl_p=m_InnerOp->GetDiscLine(1,m_interpol_pos_v_2p[1][a_n],true); + dl_pp=m_InnerOp->GetDiscLine(1,m_interpol_pos_v_2pp[1][a_n],true); + + for (int v=0;v<4;++v) + { + if (m_interpol_pos_v_2p[1][a_n]==m_interpol_pos_v_2pp[1][a_n]) + f4_interpol_v_2p[1][a_n].f[v] = f4_interpol_v_2pp[1][a_n].f[v] = 0; + else + { + f4_interpol_v_2p[1][a_n].f[v] = (dl_pp-GetDiscLine(1,a_n,true)) / (dl_pp-dl_p); + f4_interpol_v_2p[1][a_n].f[v] *= GetDiscDelta(1,a_n,false)/m_InnerOp->GetDiscDelta(1,m_interpol_pos_v_2p[1][a_n],false); + + f4_interpol_v_2pp[1][a_n].f[v] = (GetDiscLine(1,a_n,true)-dl_p) / (dl_pp-dl_p); + f4_interpol_v_2pp[1][a_n].f[v] *= GetDiscDelta(1,a_n,false)/m_InnerOp->GetDiscDelta(1,m_interpol_pos_v_2pp[1][a_n],false); + } + } + } +} + +void Operator_CylinderMultiGrid::SetExcitationSignal(Excitation* exc) +{ + m_InnerOp->SetExcitationSignal(exc); + Operator_Cylinder::SetExcitationSignal(exc); +} + +void Operator_CylinderMultiGrid::Delete() +{ + delete m_InnerOp; + m_InnerOp=0; + + for (int n=0;n<2;++n) + { + delete[] m_interpol_pos_v_2p[n]; + m_interpol_pos_v_2p[n]=NULL; + Delete1DArray_v4sf(f4_interpol_v_2p[n]); + f4_interpol_v_2p[n]=NULL; + delete[] m_interpol_pos_v_2pp[n]; + m_interpol_pos_v_2pp[n]=NULL; + Delete1DArray_v4sf(f4_interpol_v_2pp[n]); + f4_interpol_v_2pp[n]=NULL; + + delete[] m_interpol_pos_i_2p[n]; + m_interpol_pos_i_2p[n]=NULL; + Delete1DArray_v4sf(f4_interpol_i_2p[n]); + f4_interpol_i_2p[n]=NULL; + delete[] m_interpol_pos_i_2pp[n]; + m_interpol_pos_i_2pp[n]=NULL; + Delete1DArray_v4sf(f4_interpol_i_2pp[n]); + f4_interpol_i_2pp[n]=NULL; + } +} + +void Operator_CylinderMultiGrid::Reset() +{ + Delete(); + Operator_Cylinder::Reset(); +} + +void Operator_CylinderMultiGrid::SetBoundaryCondition(int* BCs) +{ + Operator_Cylinder::SetBoundaryCondition(BCs); + int oldBC = BCs[1]; + BCs[1] = 0; //always PEC in +r-direction + m_InnerOp->SetBoundaryCondition(BCs); + BCs[1] = oldBC; +} + +void Operator_CylinderMultiGrid::AddExtension(Operator_Extension* op_ext) +{ + //check whether extension is save to use in multi-grid + if (op_ext->IsCylindricalMultiGridSave(false)==false) + { + cerr << "Operator_CylinderMultiGrid::AddExtension: Warning: Operator extension \"" << op_ext->GetExtensionName() << "\" is not compatible with cylindrical multi-grids!! skipping...!" << endl; + delete op_ext; + return; + } + + Operator_Cylinder::AddExtension(op_ext); + + // cylinder extension does not need to be cloned, it will be created by each operator of its own... + if (dynamic_cast<Operator_Ext_Cylinder*>(op_ext)) + return; + + //check whether extension is save to use in child multi-grid + if (op_ext->IsCylindricalMultiGridSave(true)) + { + Operator_Extension* child_Ext = op_ext->Clone(m_InnerOp); + if (child_Ext==NULL) + { + cerr << "Operator_CylinderMultiGrid::AddExtension: Warning, extension: " << op_ext->GetExtensionName() << " can not be cloned for the child operator. Skipping Extension... " << endl; + return; + } + //give the copy to child + m_InnerOp->AddExtension(child_Ext); + } +} + +void Operator_CylinderMultiGrid::ShowStat() const +{ + m_InnerOp->ShowStat(); + m_InnerOp->ShowExtStat(); + Operator_Cylinder::ShowStat(); +} diff --git a/openEMS/FDTD/operator_cylindermultigrid.h b/openEMS/FDTD/operator_cylindermultigrid.h new file mode 100644 index 0000000..57481f1 --- /dev/null +++ b/openEMS/FDTD/operator_cylindermultigrid.h @@ -0,0 +1,109 @@ +/* +* 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_CYLINDERMULTIGRID_H +#define OPERATOR_CYLINDERMULTIGRID_H + +#define CYLIDINDERMULTIGRID_LIMIT 20 + +#include "operator_cylinder.h" + +//! This is a cylindrical FDTD operator using a simple multi-grid approach. +/*! + This cylindrical multi-grid operator itself is not calculating any real operator, instead it is hosting two separate "child" operators of type "Operator_Cylinder". + This operator class (or the corresponding engine) will perform the interpolation and connection between these two child-operator/engines. + One of the child operators itself may be another multi-grid operator to allow for a cascaded multi-grid approach. + */ +class Operator_CylinderMultiGrid : public Operator_Cylinder +{ + friend class Engine_CylinderMultiGrid; +public: + static Operator_CylinderMultiGrid* New(vector<double> Split_Radii, unsigned int numThreads = 0, unsigned int level = 0); + virtual ~Operator_CylinderMultiGrid(); + + virtual double GetNumberCells() const; + + virtual Engine* CreateEngine(); + + virtual bool SetGeometryCSX(ContinuousStructure* geo); + + //! Get the coordinates for a given node index and component, according to the cylindrical yee-algorithm. Returns true if inside the FDTD domain. + virtual bool GetYeeCoords(int ny, unsigned int pos[3], double* coords, bool dualMesh) const; + + virtual unsigned int GetSplitPos() const {return m_Split_Pos;} + + virtual void SetBoundaryCondition(int* BCs); + + virtual void AddExtension(Operator_Extension* op_ext); + + //! Get the multi grid level of this operator, e.g. 0 is main grid --> no parent grid + int GetMultiGridLevel() const {return m_MultiGridLevel;} + + Operator_Cylinder* GetInnerOperator() const {return m_InnerOp;} + + virtual void SetExcitationSignal(Excitation* exc); + + virtual void ShowStat() const; + + //! Get the cell center coordinate usable for material averaging (Warning, may not be the yee cell center) + virtual bool GetCellCenterMaterialAvgCoord(const int pos[3], double coord[3]) const; + +#ifdef MPI_SUPPORT + virtual void SetTag(int tag); + virtual void SetNeighborUp(int ny, int id); + virtual void SetNeighborDown(int ny, int id); +#endif + +protected: + Operator_CylinderMultiGrid(vector<double> Split_Radii, unsigned int level); + virtual void Init(); + void Delete(); + virtual void Reset(); + + virtual bool SetupCSXGrid(CSRectGrid* grid); + + virtual int CalcECOperator( DebugFlags debugFlags = None ); + + virtual void DumpPEC2File( string filename, unsigned int *range = NULL ); + + //! The material data storage in the sub-grid area's will not be filled by the base-operator. Check and do this here! + void FillMissingDataStorage(); + + unsigned int m_MultiGridLevel; + double m_Split_Rad; + vector<double> m_Split_Radii; + unsigned int m_Split_Pos; + + Operator_Cylinder* m_InnerOp; + + // sub-grid to base interpolation coefficients + unsigned int* m_interpol_pos_v_2p[2]; + f4vector* f4_interpol_v_2p[2]; + unsigned int* m_interpol_pos_v_2pp[2]; + f4vector* f4_interpol_v_2pp[2]; + + unsigned int* m_interpol_pos_i_2p[2]; + f4vector* f4_interpol_i_2p[2]; + unsigned int* m_interpol_pos_i_2pp[2]; + f4vector* f4_interpol_i_2pp[2]; + + void SetupInterpolation(); + + virtual void CalcStartStopLines(unsigned int &numThreads, vector<unsigned int> &start, vector<unsigned int> &stop) const; +}; + +#endif // OPERATOR_CYLINDERMULTIGRID_H diff --git a/openEMS/FDTD/operator_mpi.cpp b/openEMS/FDTD/operator_mpi.cpp new file mode 100644 index 0000000..432f5d7 --- /dev/null +++ b/openEMS/FDTD/operator_mpi.cpp @@ -0,0 +1,209 @@ +/* +* Copyright (C) 2011 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_mpi.h" +#include "operator_sse_compressed.h" +#include "engine_sse_compressed.h" +#include "engine_mpi.h" +#include "extensions/operator_extension.h" +#include "tools/array_ops.h" +#include "tools/useful.h" +#include "mpi.h" + +Operator_MPI* Operator_MPI::New() +{ + cout << "Create FDTD operator (compressed SSE + MPI)" << endl; + Operator_MPI* op = new Operator_MPI(); + op->Init(); + return op; +} + +Operator_MPI::Operator_MPI() : Operator_SSE_Compressed() +{ + m_NumProc = MPI::COMM_WORLD.Get_size(); + + //enabled only if more than one process is active + m_MPI_Enabled = m_NumProc>1; +} + +Operator_MPI::~Operator_MPI() +{ + Delete(); +} + +double Operator_MPI::CalcTimestep() +{ + double ret = Operator::CalcTimestep(); + + if (!m_MPI_Enabled) + return ret; + + double local_dT = dT; + //find the smallest time-step requestes by all processings + MPI_Reduce(&local_dT, &dT, 1, MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD); + //send the smallest time-step to all + MPI_Bcast(&dT, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + return ret; +} + +void Operator_MPI::SetBoundaryCondition(int* BCs) +{ + if (!m_MPI_Enabled) + return Operator_SSE_Compressed::SetBoundaryCondition(BCs); + + //set boundary conditions on MPI interfaces to PEC, ApplyElectricBC will handle proper interface handling... + for (int n=0;n<3;++n) + { + if (m_NeighborUp[n]>=0) + BCs[2*n+1] = 0; + if (m_NeighborDown[n]>=0) + BCs[2*n] = 0; + } + Operator_SSE_Compressed::SetBoundaryCondition(BCs); +} + +Engine* Operator_MPI::CreateEngine() +{ + if (m_MPI_Enabled) + m_Engine = Engine_MPI::New(this); + else + m_Engine = Engine_SSE_Compressed::New(this); + return m_Engine; +} + +void Operator_MPI::SetNeighborUp(int ny, int id) +{ + if ((ny<0) || (ny>2)) + return; + m_NeighborUp[ny]=id; +} + +void Operator_MPI::SetNeighborDown(int ny, int id) +{ + if ((ny<0) || (ny>2)) + return; + m_NeighborDown[ny]=id; +} + +void Operator_MPI::Init() +{ + Operator_SSE_Compressed::Init(); + + m_MyTag = 0; + + for (int i=0;i<3;++i) + { + m_NeighborUp[i]=-1; + m_NeighborDown[i]=-1; + m_OrigDiscLines[i]=NULL; + } + + m_ProcTable = NULL; + m_SplitNumber[0]=0; + m_SplitNumber[1]=0; + m_SplitNumber[2]=0; + + int namelen; + m_NumProc = MPI::COMM_WORLD.Get_size(); + m_MyID = MPI::COMM_WORLD.Get_rank(); + + m_Processor_Name = new char[MPI_MAX_PROCESSOR_NAME]; + MPI::Get_processor_name(m_Processor_Name,namelen); + + if ((m_MPI_Enabled) && (g_settings.GetVerboseLevel()>0)) + cerr << "Operator_MPI::Init(): Running on " << m_Processor_Name << endl; +} + +void Operator_MPI::Delete() +{ + delete[] m_Processor_Name; + m_Processor_Name = NULL; + for (int i=0;i<3;++i) + { + delete[] m_OrigDiscLines[i]; + m_OrigDiscLines[i] = NULL; + } + Delete3DArray(m_ProcTable,m_SplitNumber); + m_ProcTable=NULL; +} + +void Operator_MPI::Reset() +{ + Delete(); + Operator_SSE_Compressed::Reset(); +} + +void Operator_MPI::SetOriginalMesh(CSRectGrid* orig_Mesh) +{ + for (int n=0;n<3;++n) + { + delete[] m_OrigDiscLines[n]; + m_OrigDiscLines[n] = orig_Mesh->GetLines(n,NULL,m_OrigNumLines[n]); + } +} + +unsigned int Operator_MPI::GetNumberOfLines(int ny, bool fullMesh) const +{ + if (fullMesh) + return Operator_SSE_Compressed::GetNumberOfLines(ny,fullMesh); + + if ((!m_MPI_Enabled) || (m_NeighborUp[ny]<0)) + return Operator_SSE_Compressed::GetNumberOfLines(ny,fullMesh); + + return Operator_SSE_Compressed::GetNumberOfLines(ny)-1; +} + +void Operator_MPI::AddExtension(Operator_Extension* op_ext) +{ + if (m_MPI_Enabled==false) + return Operator_SSE_Compressed::AddExtension(op_ext); + + if (op_ext->IsMPISave()) + Operator_SSE_Compressed::AddExtension(op_ext); + else + { + cerr << "Operator_MPI::AddExtension: Warning: Operator extension \"" << op_ext->GetExtensionName() << "\" is not compatible with MPI!! skipping...!" << endl; + delete op_ext; + } +} + + +string Operator_MPI::PrependRank(string name) +{ + stringstream out_name; + if (m_MPI_Enabled) + out_name << "ID" << m_MyID << "_" << name; + else + out_name << name; + return out_name.str(); +} + +void Operator_MPI::DumpOperator2File(string filename) +{ + Operator_SSE_Compressed::DumpOperator2File(PrependRank(filename)); +} + +void Operator_MPI::DumpMaterial2File(string filename) +{ + Operator_SSE_Compressed::DumpMaterial2File(PrependRank(filename)); +} + +void Operator_MPI::DumpPEC2File(string filename , unsigned int *range) +{ + Operator_SSE_Compressed::DumpPEC2File(PrependRank(filename), range); +} diff --git a/openEMS/FDTD/operator_mpi.h b/openEMS/FDTD/operator_mpi.h new file mode 100644 index 0000000..c09616e --- /dev/null +++ b/openEMS/FDTD/operator_mpi.h @@ -0,0 +1,90 @@ +/* +* Copyright (C) 2011 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_MPI_H +#define OPERATOR_MPI_H + +#include "operator_sse_compressed.h" + +class Operator_MPI : public Operator_SSE_Compressed +{ + friend class Engine_MPI; +public: + //! Create a new operator + static Operator_MPI* New(); + virtual ~Operator_MPI(); + + bool GetMPIEnabled() const {return m_MPI_Enabled;} + + virtual void SetBoundaryCondition(int* BCs); + + virtual Engine* CreateEngine(); + + virtual void SetTag(int tag) {m_MyTag=tag;} + + //! Set the number of splits for a given direction. This also defines the size of the process table. \sa SetProcessTable + virtual void SetSplitNumbers(int ny, unsigned int splits) {m_SplitNumber[ny]=splits;} + //! Set the table containing a list of all MPI rank ID's and there mesh affiliation. \sa SetProcessTablePosition + virtual void SetProcessTable(unsigned int*** procTable) {m_ProcTable=procTable;} + //! Save the position for this rank in the process table. \sa SetProcessTable + virtual void SetProcessTablePosition(int ny, unsigned int pos) {m_ProcTablePos[ny]=pos;} + + virtual void SetNeighborUp(int ny, int id); + virtual void SetNeighborDown(int ny, int id); + + //! Set the lower original mesh position + virtual void SetSplitPos(int ny, unsigned int pos) {m_SplitPos[ny]=pos;} + virtual void SetOriginalMesh(CSRectGrid* orig_Mesh); + + virtual unsigned int GetNumberOfLines(int ny, bool fullMesh=false) const; + + virtual void AddExtension(Operator_Extension* op_ext); + +protected: + Operator_MPI(); + bool m_MPI_Enabled; + virtual void Init(); + void Delete(); + virtual void Reset(); + + virtual double CalcTimestep(); + + unsigned int m_MyID; + unsigned int m_NumProc; + int m_MyTag; + char* m_Processor_Name; + + //the up and down neighbors, -1 if non for the given direction + int m_NeighborUp[3]; + int m_NeighborDown[3]; + + unsigned int m_SplitNumber[3]; + unsigned int m_ProcTablePos[3]; + unsigned int*** m_ProcTable; + + double* m_OrigDiscLines[3]; + unsigned int m_OrigNumLines[3]; + unsigned int m_SplitPos[3]; + + string PrependRank(string name); + + virtual void DumpOperator2File(string filename); + virtual void DumpMaterial2File(string filename); + virtual void DumpPEC2File( string filename, unsigned int *range = NULL ); +}; + +#endif // OPERATOR_MPI_H diff --git a/openEMS/FDTD/operator_multithread.cpp b/openEMS/FDTD/operator_multithread.cpp new file mode 100644 index 0000000..9a602a6 --- /dev/null +++ b/openEMS/FDTD/operator_multithread.cpp @@ -0,0 +1,203 @@ +/* +* 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_multithread.h" +#include "engine_multithread.h" +#include "tools/useful.h" + +Operator_Multithread* Operator_Multithread::New(unsigned int numThreads) +{ + cout << "Create FDTD operator (compressed SSE + multi-threading)" << endl; + Operator_Multithread* op = new Operator_Multithread(); + op->setNumThreads(numThreads); + op->Init(); + return op; +} + +Operator_Multithread::~Operator_Multithread() +{ + Delete(); +} + +void Operator_Multithread::setNumThreads( unsigned int numThreads ) +{ + m_numThreads = numThreads; +} + +Engine* Operator_Multithread::CreateEngine() +{ + m_Engine = Engine_Multithread::New(this,m_numThreads); + return m_Engine; +} + +Operator_Multithread::Operator_Multithread() : OPERATOR_MULTITHREAD_BASE() +{ + m_CalcEC_Start=NULL; + m_CalcEC_Stop=NULL; + + m_CalcPEC_Start=NULL; + m_CalcPEC_Stop=NULL; +} + +void Operator_Multithread::Init() +{ + OPERATOR_MULTITHREAD_BASE::Init(); + + m_CalcEC_Start=NULL; + m_CalcEC_Stop=NULL; + + m_CalcPEC_Start=NULL; + m_CalcPEC_Stop=NULL; +} + +void Operator_Multithread::Delete() +{ + m_thread_group.join_all(); + + delete m_CalcEC_Start; + m_CalcEC_Start=NULL; + delete m_CalcEC_Stop; + m_CalcEC_Stop=NULL; + + delete m_CalcPEC_Start; + m_CalcPEC_Start=NULL; + delete m_CalcPEC_Stop; + m_CalcPEC_Stop=NULL; +} + +void Operator_Multithread::Reset() +{ + Delete(); + OPERATOR_MULTITHREAD_BASE::Reset(); +} + +void Operator_Multithread::CalcStartStopLines(unsigned int &numThreads, vector<unsigned int> &start, vector<unsigned int> &stop) const +{ + vector<unsigned int> jpt = AssignJobs2Threads(numLines[0], numThreads, true); + + numThreads = jpt.size(); + + start.resize(numThreads); + stop.resize(numThreads); + + start.at(0)=0; + stop.at(0)=jpt.at(0)-1; + + for (unsigned int n=1; n<numThreads; n++) + { + start.at(n) = stop.at(n-1)+1; + stop.at(n) = start.at(n) + jpt.at(n) - 1; + } +} + +int Operator_Multithread::CalcECOperator( DebugFlags debugFlags ) +{ + if (m_numThreads == 0) + m_numThreads = boost::thread::hardware_concurrency(); + + vector<unsigned int> m_Start_Lines; + vector<unsigned int> m_Stop_Lines; + CalcStartStopLines( m_numThreads, m_Start_Lines, m_Stop_Lines ); + + if (g_settings.GetVerboseLevel()>0) + cout << "Multithreaded operator using " << m_numThreads << " threads." << std::endl; + + m_thread_group.join_all(); + delete m_CalcEC_Start; + m_CalcEC_Start = new boost::barrier(m_numThreads+1); // numThread workers + 1 controller + delete m_CalcEC_Stop; + m_CalcEC_Stop = new boost::barrier(m_numThreads+1); // numThread workers + 1 controller + + delete m_CalcPEC_Start; + m_CalcPEC_Start = new boost::barrier(m_numThreads+1); // numThread workers + 1 controller + delete m_CalcPEC_Stop; + m_CalcPEC_Stop = new boost::barrier(m_numThreads+1); // numThread workers + 1 controller + + for (unsigned int n=0; n<m_numThreads; n++) + { + boost::thread *t = new boost::thread( Operator_Thread(this,m_Start_Lines.at(n),m_Stop_Lines.at(n),n) ); + m_thread_group.add_thread( t ); + } + + return OPERATOR_MULTITHREAD_BASE::CalcECOperator( debugFlags ); +} + +bool Operator_Multithread::Calc_EC() +{ + if (CSX==NULL) + { + cerr << "CartOperator::Calc_EC: CSX not given or invalid!!!" << endl; + return false; + } + + MainOp->SetPos(0,0,0); + + m_CalcEC_Start->wait(); + + m_CalcEC_Stop->wait(); + + return true; +} + +bool Operator_Multithread::CalcPEC() +{ + m_Nr_PEC[0]=0; + m_Nr_PEC[1]=0; + m_Nr_PEC[2]=0; + + m_Nr_PEC_thread = new unsigned int[m_numThreads][3]; + + m_CalcPEC_Start->wait(); + + m_CalcPEC_Stop->wait(); + + for (unsigned int t=0; t<m_numThreads; ++t) + for (int n=0; n<3; ++n) + m_Nr_PEC[n]+=m_Nr_PEC_thread[t][n]; + + CalcPEC_Curves(); + + delete[] m_Nr_PEC_thread; + + return true; +} + + +Operator_Thread::Operator_Thread( Operator_Multithread* ptr, unsigned int start, unsigned int stop, unsigned int threadID ) +{ + m_start=start; + m_stop=stop; + m_threadID=threadID; + m_OpPtr = ptr; +} + +void Operator_Thread::operator()() +{ + //************** calculate EC (Calc_EC) ***********************// + m_OpPtr->m_CalcEC_Start->wait(); + m_OpPtr->Calc_EC_Range(m_start,m_stop); + m_OpPtr->m_CalcEC_Stop->wait(); + + //************** calculate EC (Calc_EC) ***********************// + m_OpPtr->m_CalcPEC_Start->wait(); + for (int n=0; n<3; ++n) + m_OpPtr->m_Nr_PEC_thread[m_threadID][n] = 0; + + m_OpPtr->CalcPEC_Range(m_start,m_stop,m_OpPtr->m_Nr_PEC_thread[m_threadID]); + m_OpPtr->m_CalcPEC_Stop->wait(); +} + diff --git a/openEMS/FDTD/operator_multithread.h b/openEMS/FDTD/operator_multithread.h new file mode 100644 index 0000000..65f4748 --- /dev/null +++ b/openEMS/FDTD/operator_multithread.h @@ -0,0 +1,89 @@ +/* +* 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_MULTITHREAD_H +#define OPERATOR_MULTITHREAD_H + +#include "operator_sse_compressed.h" + +#include <boost/thread.hpp> + +#ifdef MPI_SUPPORT + #define OPERATOR_MULTITHREAD_BASE Operator_MPI + #include "operator_mpi.h" +#else + #define OPERATOR_MULTITHREAD_BASE Operator_SSE_Compressed +#endif + +class Operator_Multithread : public OPERATOR_MULTITHREAD_BASE +{ + friend class Engine_Multithread; + friend class Operator_Thread; +public: + //! Create a new operator + static Operator_Multithread* New(unsigned int numThreads = 0); + virtual ~Operator_Multithread(); + + virtual void setNumThreads( unsigned int numThreads ); + + virtual Engine* CreateEngine(); + +protected: + Operator_Multithread(); + virtual void Init(); + void Delete(); + virtual void Reset(); + + virtual bool Calc_EC(); //this method is using multi-threading + + unsigned int (*m_Nr_PEC_thread)[3]; //count PEC edges per thread + virtual bool CalcPEC(); //this method is using multi-threading + + virtual int CalcECOperator( DebugFlags debugFlags = None ); + + //Calc_EC barrier + boost::barrier* m_CalcEC_Start; + boost::barrier* m_CalcEC_Stop; + //CalcPEC barrier + boost::barrier* m_CalcPEC_Start; + boost::barrier* m_CalcPEC_Stop; + + boost::thread_group m_thread_group; + unsigned int m_numThreads; // number of worker threads + + //! Calculate the start/stop lines for the multithreading operator and engine. + /*! + It depends on the number of threads and number of lines to simulate. + This method is also used by the multithreading engine! + This method may also reduce the usable number of thread in case of too few lines or otherwise bad utilization. + */ + virtual void CalcStartStopLines(unsigned int &numThreads, vector<unsigned int> &start, vector<unsigned int> &stop) const; +}; + +class Operator_Thread +{ +public: + Operator_Thread( Operator_Multithread* ptr, unsigned int start, unsigned int stop, unsigned int threadID ); + void operator()(); + +protected: + unsigned int m_start, m_stop, m_threadID; + Operator_Multithread *m_OpPtr; +}; + + +#endif // OPERATOR_MULTITHREAD_H diff --git a/openEMS/FDTD/operator_sse.cpp b/openEMS/FDTD/operator_sse.cpp new file mode 100644 index 0000000..8a1b21b --- /dev/null +++ b/openEMS/FDTD/operator_sse.cpp @@ -0,0 +1,91 @@ +/* +* Copyright (C) 2010 Sebastian Held (Sebastian.Held@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_sse.h" +#include "operator_sse.h" +#include "tools/array_ops.h" +//#include "processfields.h" + +Operator_sse* Operator_sse::New() +{ + cout << "Create FDTD operator (SSE)" << endl; + Operator_sse* op = new Operator_sse(); + op->Init(); + return op; +} + +Operator_sse::Operator_sse() : Operator() +{ + f4_vv = 0; + f4_vi = 0; + f4_iv = 0; + f4_ii = 0; +} + +Operator_sse::~Operator_sse() +{ + Delete(); +} + +Engine* Operator_sse::CreateEngine() const +{ + //! create a special sse-engine + Engine_sse* eng = Engine_sse::New(this); + return eng; +} + +void Operator_sse::Init() +{ + Operator::Init(); + f4_vv = 0; + f4_vi = 0; + f4_iv = 0; + f4_ii = 0; +} + +void Operator_sse::Delete() +{ + Delete_N_3DArray_v4sf(f4_vv,numLines); + Delete_N_3DArray_v4sf(f4_vi,numLines); + Delete_N_3DArray_v4sf(f4_iv,numLines); + Delete_N_3DArray_v4sf(f4_ii,numLines); + f4_vv = 0; + f4_vi = 0; + f4_iv = 0; + f4_ii = 0; +} + +void Operator_sse::Reset() +{ + Delete(); + Operator::Reset(); +} + + +void Operator_sse::InitOperator() +{ + Delete_N_3DArray_v4sf(f4_vv,numLines); + Delete_N_3DArray_v4sf(f4_vi,numLines); + Delete_N_3DArray_v4sf(f4_iv,numLines); + Delete_N_3DArray_v4sf(f4_ii,numLines); + f4_vv = Create_N_3DArray_v4sf(numLines); + f4_vi = Create_N_3DArray_v4sf(numLines); + f4_iv = Create_N_3DArray_v4sf(numLines); + f4_ii = Create_N_3DArray_v4sf(numLines); + + numVectors = ceil((double)numLines[2]/4.0); +} diff --git a/openEMS/FDTD/operator_sse.h b/openEMS/FDTD/operator_sse.h new file mode 100644 index 0000000..317ea72 --- /dev/null +++ b/openEMS/FDTD/operator_sse.h @@ -0,0 +1,63 @@ +/* +* Copyright (C) 2010 Sebastian Held (Sebastian.Held@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_SSE_H +#define OPERATOR_SSE_H + +#include "operator.h" +#include "tools/array_ops.h" + +class Operator_sse : public Operator +{ + friend class Engine_Interface_SSE_FDTD; +public: + //! Create a new operator + static Operator_sse* New(); + virtual ~Operator_sse(); + + virtual Engine* CreateEngine() const; + + inline virtual FDTD_FLOAT GetVV( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return f4_vv[n][x][y][z%numVectors].f[z/numVectors]; } + inline virtual FDTD_FLOAT GetVI( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return f4_vi[n][x][y][z%numVectors].f[z/numVectors]; } + inline virtual FDTD_FLOAT GetII( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return f4_ii[n][x][y][z%numVectors].f[z/numVectors]; } + inline virtual FDTD_FLOAT GetIV( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return f4_iv[n][x][y][z%numVectors].f[z/numVectors]; } + + inline virtual void SetVV( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { f4_vv[n][x][y][z%numVectors].f[z/numVectors] = value; } + inline virtual void SetVI( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { f4_vi[n][x][y][z%numVectors].f[z/numVectors] = value; } + inline virtual void SetII( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { f4_ii[n][x][y][z%numVectors].f[z/numVectors] = value; } + inline virtual void SetIV( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { f4_iv[n][x][y][z%numVectors].f[z/numVectors] = value; } + +protected: + //! use New() for creating a new Operator + Operator_sse(); + + virtual void Init(); + void Delete(); + virtual void Reset(); + virtual void InitOperator(); + + unsigned int numVectors; + + // engine/post-proc needs access +public: + f4vector**** f4_vv; //calc new voltage from old voltage + f4vector**** f4_vi; //calc new voltage from old current + f4vector**** f4_iv; //calc new current from old current + f4vector**** f4_ii; //calc new current from old voltage +}; + +#endif // OPERATOR_SSE_H diff --git a/openEMS/FDTD/operator_sse_compressed.cpp b/openEMS/FDTD/operator_sse_compressed.cpp new file mode 100644 index 0000000..5214892 --- /dev/null +++ b/openEMS/FDTD/operator_sse_compressed.cpp @@ -0,0 +1,251 @@ +/* +* 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_sse_compressed.h" +#include "engine_sse_compressed.h" +#include "engine_sse.h" +#include "tools/array_ops.h" + +#include <map> +#include <cstring> + +Operator_SSE_Compressed* Operator_SSE_Compressed::New() +{ + cout << "Create FDTD operator (compressed SSE)" << endl; + Operator_SSE_Compressed* op = new Operator_SSE_Compressed(); + op->Init(); + return op; +} + +Operator_SSE_Compressed::Operator_SSE_Compressed() : Operator_sse() +{ + m_Op_index = NULL; + m_Use_Compression = false; +} + +Operator_SSE_Compressed::~Operator_SSE_Compressed() +{ + Delete(); +} + +Engine* Operator_SSE_Compressed::CreateEngine() const +{ + if (!m_Use_Compression) + { + //! create a default sse-engine + Engine_sse* eng = Engine_sse::New(this); + return eng; + } + Engine_SSE_Compressed* eng = Engine_SSE_Compressed::New(this); + return eng; +} + +int Operator_SSE_Compressed::CalcECOperator( DebugFlags debugFlags ) +{ + int ErrCode = Operator_sse::CalcECOperator( debugFlags ); + m_Use_Compression = false; + m_Use_Compression = CompressOperator(); + + return ErrCode; +} + +void Operator_SSE_Compressed::Init() +{ + Operator_sse::Init(); + m_Use_Compression = false; + m_Op_index = NULL; +} + +void Operator_SSE_Compressed::Delete() +{ + if (m_Op_index) + { + Delete3DArray<unsigned int>( m_Op_index, numLines ); + m_Op_index = 0; + } + + m_Use_Compression = false; + for (int n=0; n<3; n++) + { + f4_vv_Compressed[n].clear(); + f4_vi_Compressed[n].clear(); + f4_iv_Compressed[n].clear(); + f4_ii_Compressed[n].clear(); + } +} + +void Operator_SSE_Compressed::Reset() +{ + Delete(); + Operator_sse::Reset(); +} + +void Operator_SSE_Compressed::InitOperator() +{ + //cleanup compression + m_Use_Compression = false; + for (int n=0; n<3; n++) + { + f4_vv_Compressed[n].clear(); + f4_vi_Compressed[n].clear(); + f4_iv_Compressed[n].clear(); + f4_ii_Compressed[n].clear(); + } + + Operator_sse::InitOperator(); + m_Op_index = Create3DArray<unsigned int>( numLines ); +} + +void Operator_SSE_Compressed::ShowStat() const +{ + Operator_sse::ShowStat(); + + cout << "SSE compression enabled\t: " << (m_Use_Compression?"yes":"no") << endl; + cout << "Unique SSE operators\t: " << f4_vv_Compressed->size() << endl; + cout << "-----------------------------------" << endl; +} + +bool Operator_SSE_Compressed::CompressOperator() +{ + if (g_settings.GetVerboseLevel()>0) + cout << "Compressing the FDTD operator... this may take a while..." << endl; + + map<SSE_coeff,unsigned int> lookUpMap; + + unsigned int pos[3]; + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + for (pos[2]=0; pos[2]<numVectors; ++pos[2]) + { + f4vector vv[3] = { f4_vv[0][pos[0]][pos[1]][pos[2]], f4_vv[1][pos[0]][pos[1]][pos[2]], f4_vv[2][pos[0]][pos[1]][pos[2]] }; + f4vector vi[3] = { f4_vi[0][pos[0]][pos[1]][pos[2]], f4_vi[1][pos[0]][pos[1]][pos[2]], f4_vi[2][pos[0]][pos[1]][pos[2]] }; + f4vector iv[3] = { f4_iv[0][pos[0]][pos[1]][pos[2]], f4_iv[1][pos[0]][pos[1]][pos[2]], f4_iv[2][pos[0]][pos[1]][pos[2]] }; + f4vector ii[3] = { f4_ii[0][pos[0]][pos[1]][pos[2]], f4_ii[1][pos[0]][pos[1]][pos[2]], f4_ii[2][pos[0]][pos[1]][pos[2]] }; + SSE_coeff c( vv, vi, iv, ii ); + + map<SSE_coeff,unsigned int>::iterator it; + it = lookUpMap.find(c); + if (it == lookUpMap.end()) + { + // not found -> insert + unsigned int index = f4_vv_Compressed[0].size(); + for (int n=0; n<3; n++) + { + f4_vv_Compressed[n].push_back( vv[n] ); + f4_vi_Compressed[n].push_back( vi[n] ); + f4_iv_Compressed[n].push_back( iv[n] ); + f4_ii_Compressed[n].push_back( ii[n] ); + } + lookUpMap[c] = index; + m_Op_index[pos[0]][pos[1]][pos[2]] = index; + } + else + { + // this operator is already in the list + unsigned int index = (*it).second; + m_Op_index[pos[0]][pos[1]][pos[2]] = index; + } + } + } + } + + Delete_N_3DArray_v4sf(f4_vv,numLines); + Delete_N_3DArray_v4sf(f4_vi,numLines); + Delete_N_3DArray_v4sf(f4_iv,numLines); + Delete_N_3DArray_v4sf(f4_ii,numLines); + f4_vv = 0; + f4_vi = 0; + f4_iv = 0; + f4_ii = 0; + + return true; +} + + + + +// ---------------------------------------------------------------------------- + +SSE_coeff::SSE_coeff( f4vector vv[3], f4vector vi[3], f4vector iv[3], f4vector ii[3] ) +{ + for (int n=0; n<3; n++) + { + m_vv[n] = vv[n]; + m_vi[n] = vi[n]; + m_iv[n] = iv[n]; + m_ii[n] = ii[n]; + } +} + +bool SSE_coeff::operator==( const SSE_coeff& other ) const +{ + for (int n=0; n<3; n++) + { + if (memcmp( &(m_vv[n]), &(other.m_vv[n]), sizeof(f4vector) ) != 0) return false; + if (memcmp( &(m_vi[n]), &(other.m_vi[n]), sizeof(f4vector) ) != 0) return false; + if (memcmp( &(m_iv[n]), &(other.m_iv[n]), sizeof(f4vector) ) != 0) return false; + if (memcmp( &(m_ii[n]), &(other.m_ii[n]), sizeof(f4vector) ) != 0) return false; + } + return true; +} +bool SSE_coeff::operator!=( const SSE_coeff& other ) const +{ + return !(*this == other); +} +bool SSE_coeff::operator<( const SSE_coeff& other ) const +{ + for (int n=0; n<3; n++) + { + for (int c=0; c<4; c++) + { + if (m_vv[n].f[c] > other.m_vv[n].f[c]) return false; + if (m_vv[n].f[c] < other.m_vv[n].f[c]) return true; + if (m_vi[n].f[c] > other.m_vi[n].f[c]) return false; + if (m_vi[n].f[c] < other.m_vi[n].f[c]) return true; + if (m_iv[n].f[c] > other.m_iv[n].f[c]) return false; + if (m_iv[n].f[c] < other.m_iv[n].f[c]) return true; + if (m_ii[n].f[c] > other.m_ii[n].f[c]) return false; + if (m_ii[n].f[c] < other.m_ii[n].f[c]) return true; + } + } + return false; +} + +void SSE_coeff::print( ostream& stream ) const +{ + stream << "SSE_coeff: (" << endl; + for (int n=0; n<3; n++) + { + stream << "n=" << n << ":" << endl; + stream << "vv="; + for (int c=0; c<4; c++) + stream << m_vv[n].f[c] << " "; + stream << endl << "vi="; + for (int c=0; c<4; c++) + stream << m_vi[n].f[c] << " "; + stream << endl << "iv="; + for (int c=0; c<4; c++) + stream << m_iv[n].f[c] << " "; + stream << endl << "ii="; + for (int c=0; c<4; c++) + stream << m_ii[n].f[c] << " "; + stream << endl; + } + stream << ")" << endl; +} diff --git a/openEMS/FDTD/operator_sse_compressed.h b/openEMS/FDTD/operator_sse_compressed.h new file mode 100644 index 0000000..5d3454f --- /dev/null +++ b/openEMS/FDTD/operator_sse_compressed.h @@ -0,0 +1,84 @@ +/* +* 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_SSE_COMPRESSED_H +#define OPERATOR_SSE_COMPRESSED_H + +#include "operator_sse.h" +#include "tools/aligned_allocator.h" + +class SSE_coeff +{ +public: + SSE_coeff( f4vector vv[3], f4vector vi[3], f4vector iv[3], f4vector ii[3] ); + bool operator==( const SSE_coeff& ) const; + bool operator!=( const SSE_coeff& ) const; + bool operator<( const SSE_coeff& ) const; + void print( ostream& stream ) const; +protected: + f4vector m_vv[3]; + f4vector m_vi[3]; + f4vector m_iv[3]; + f4vector m_ii[3]; +}; + +class Operator_SSE_Compressed : public Operator_sse +{ +public: + //! Create a new operator + static Operator_SSE_Compressed* New(); + virtual ~Operator_SSE_Compressed(); + + virtual Engine* CreateEngine() const; + + inline virtual FDTD_FLOAT GetVV( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { if (m_Use_Compression) return f4_vv_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors]; else return Operator_sse::GetVV(n,x,y,z);} + inline virtual FDTD_FLOAT GetVI( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { if (m_Use_Compression) return f4_vi_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors]; else return Operator_sse::GetVI(n,x,y,z);} + inline virtual FDTD_FLOAT GetII( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { if (m_Use_Compression) return f4_ii_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors]; else return Operator_sse::GetII(n,x,y,z);} + inline virtual FDTD_FLOAT GetIV( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { if (m_Use_Compression) return f4_iv_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors]; else return Operator_sse::GetIV(n,x,y,z);} + + inline virtual void SetVV( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { if (m_Use_Compression) f4_vv_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors] = value; else Operator_sse::SetVV(n,x,y,z,value);} + inline virtual void SetVI( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { if (m_Use_Compression) f4_vi_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors] = value; else Operator_sse::SetVI(n,x,y,z,value);} + inline virtual void SetII( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { if (m_Use_Compression) f4_ii_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors] = value; else Operator_sse::SetII(n,x,y,z,value);} + inline virtual void SetIV( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { if (m_Use_Compression) f4_iv_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors] = value; else Operator_sse::SetIV(n,x,y,z,value);} + + virtual void ShowStat() const; + + bool CompressOperator(); + +protected: + Operator_SSE_Compressed(); + + bool m_Use_Compression; + + virtual void Init(); + void Delete(); + virtual void Reset(); + virtual void InitOperator(); + + virtual int CalcECOperator( DebugFlags debugFlags = None ); + + // engine needs access +public: + unsigned int*** m_Op_index; + vector<f4vector,aligned_allocator<f4vector> > f4_vv_Compressed[3]; //!< coefficient: calc new voltage from old voltage + vector<f4vector,aligned_allocator<f4vector> > f4_vi_Compressed[3]; //!< coefficient: calc new voltage from old current + vector<f4vector,aligned_allocator<f4vector> > f4_iv_Compressed[3]; //!< coefficient: calc new current from old voltage + vector<f4vector,aligned_allocator<f4vector> > f4_ii_Compressed[3]; //!< coefficient: calc new current from old current + +}; + +#endif // OPERATOR_SSE_Compressed_H |