summaryrefslogtreecommitdiff
path: root/openEMS/FDTD
diff options
context:
space:
mode:
authorRuben Undheim <ruben.undheim@gmail.com>2016-07-05 18:02:38 +0200
committerRuben Undheim <ruben.undheim@gmail.com>2016-07-05 18:02:38 +0200
commitef962f6008f25ab7cbd4ca21bcc72b97a1e2d76f (patch)
tree8149bee93d1a3f91d4503bfb3853adac4af0a85e /openEMS/FDTD
Imported Upstream version 0.0.34
Diffstat (limited to 'openEMS/FDTD')
-rw-r--r--openEMS/FDTD/CMakeLists.txt30
-rw-r--r--openEMS/FDTD/engine.cpp232
-rw-r--r--openEMS/FDTD/engine.h104
-rw-r--r--openEMS/FDTD/engine_cylinder.cpp38
-rw-r--r--openEMS/FDTD/engine_cylinder.h36
-rw-r--r--openEMS/FDTD/engine_cylindermultigrid.cpp226
-rw-r--r--openEMS/FDTD/engine_cylindermultigrid.h85
-rw-r--r--openEMS/FDTD/engine_interface_cylindrical_fdtd.cpp64
-rw-r--r--openEMS/FDTD/engine_interface_cylindrical_fdtd.h39
-rw-r--r--openEMS/FDTD/engine_interface_fdtd.cpp274
-rw-r--r--openEMS/FDTD/engine_interface_fdtd.h65
-rw-r--r--openEMS/FDTD/engine_interface_sse_fdtd.cpp69
-rw-r--r--openEMS/FDTD/engine_interface_sse_fdtd.h38
-rw-r--r--openEMS/FDTD/engine_mpi.cpp211
-rw-r--r--openEMS/FDTD/engine_mpi.h57
-rw-r--r--openEMS/FDTD/engine_multithread.cpp343
-rw-r--r--openEMS/FDTD/engine_multithread.h127
-rw-r--r--openEMS/FDTD/engine_sse.cpp176
-rw-r--r--openEMS/FDTD/engine_sse.h60
-rw-r--r--openEMS/FDTD/engine_sse_compressed.cpp163
-rw-r--r--openEMS/FDTD/engine_sse_compressed.h38
-rw-r--r--openEMS/FDTD/excitation.cpp304
-rw-r--r--openEMS/FDTD/excitation.h115
-rw-r--r--openEMS/FDTD/extensions/CMakeLists.txt32
-rw-r--r--openEMS/FDTD/extensions/OptimizeCondSheetParameter.m107
-rw-r--r--openEMS/FDTD/extensions/cond_sheet_parameter.h14
-rw-r--r--openEMS/FDTD/extensions/engine_ext_cylinder.cpp101
-rw-r--r--openEMS/FDTD/extensions/engine_ext_cylinder.h49
-rw-r--r--openEMS/FDTD/extensions/engine_ext_cylindermultigrid.cpp165
-rw-r--r--openEMS/FDTD/extensions/engine_ext_cylindermultigrid.h58
-rw-r--r--openEMS/FDTD/extensions/engine_ext_dispersive.cpp162
-rw-r--r--openEMS/FDTD/extensions/engine_ext_dispersive.h51
-rw-r--r--openEMS/FDTD/extensions/engine_ext_excitation.cpp170
-rw-r--r--openEMS/FDTD/extensions/engine_ext_excitation.h40
-rw-r--r--openEMS/FDTD/extensions/engine_ext_lorentzmaterial.cpp322
-rw-r--r--openEMS/FDTD/extensions/engine_ext_lorentzmaterial.h48
-rw-r--r--openEMS/FDTD/extensions/engine_ext_mur_abc.cpp263
-rw-r--r--openEMS/FDTD/extensions/engine_ext_mur_abc.h63
-rw-r--r--openEMS/FDTD/extensions/engine_ext_steadystate.cpp112
-rw-r--r--openEMS/FDTD/extensions/engine_ext_steadystate.h51
-rw-r--r--openEMS/FDTD/extensions/engine_ext_tfsf.cpp215
-rw-r--r--openEMS/FDTD/extensions/engine_ext_tfsf.h40
-rw-r--r--openEMS/FDTD/extensions/engine_ext_upml.cpp493
-rw-r--r--openEMS/FDTD/extensions/engine_ext_upml.h55
-rw-r--r--openEMS/FDTD/extensions/engine_extension.cpp95
-rw-r--r--openEMS/FDTD/extensions/engine_extension.h88
-rw-r--r--openEMS/FDTD/extensions/operator_ext_conductingsheet.cpp261
-rw-r--r--openEMS/FDTD/extensions/operator_ext_conductingsheet.h51
-rw-r--r--openEMS/FDTD/extensions/operator_ext_cylinder.cpp114
-rw-r--r--openEMS/FDTD/extensions/operator_ext_cylinder.h60
-rw-r--r--openEMS/FDTD/extensions/operator_ext_dispersive.cpp78
-rw-r--r--openEMS/FDTD/extensions/operator_ext_dispersive.h56
-rw-r--r--openEMS/FDTD/extensions/operator_ext_excitation.cpp372
-rw-r--r--openEMS/FDTD/extensions/operator_ext_excitation.h84
-rw-r--r--openEMS/FDTD/extensions/operator_ext_lorentzmaterial.cpp453
-rw-r--r--openEMS/FDTD/extensions/operator_ext_lorentzmaterial.h62
-rw-r--r--openEMS/FDTD/extensions/operator_ext_mur_abc.cpp210
-rw-r--r--openEMS/FDTD/extensions/operator_ext_mur_abc.h68
-rw-r--r--openEMS/FDTD/extensions/operator_ext_steadystate.cpp104
-rw-r--r--openEMS/FDTD/extensions/operator_ext_steadystate.h61
-rw-r--r--openEMS/FDTD/extensions/operator_ext_tfsf.cpp429
-rw-r--r--openEMS/FDTD/extensions/operator_ext_tfsf.h82
-rw-r--r--openEMS/FDTD/extensions/operator_ext_upml.cpp478
-rw-r--r--openEMS/FDTD/extensions/operator_ext_upml.h106
-rw-r--r--openEMS/FDTD/extensions/operator_extension.cpp54
-rw-r--r--openEMS/FDTD/extensions/operator_extension.h87
-rw-r--r--openEMS/FDTD/openems_fdtd_mpi.cpp545
-rw-r--r--openEMS/FDTD/openems_fdtd_mpi.h72
-rw-r--r--openEMS/FDTD/operator.cpp2131
-rw-r--r--openEMS/FDTD/operator.h287
-rw-r--r--openEMS/FDTD/operator_cylinder.cpp576
-rw-r--r--openEMS/FDTD/operator_cylinder.h118
-rw-r--r--openEMS/FDTD/operator_cylindermultigrid.cpp569
-rw-r--r--openEMS/FDTD/operator_cylindermultigrid.h109
-rw-r--r--openEMS/FDTD/operator_mpi.cpp209
-rw-r--r--openEMS/FDTD/operator_mpi.h90
-rw-r--r--openEMS/FDTD/operator_multithread.cpp203
-rw-r--r--openEMS/FDTD/operator_multithread.h89
-rw-r--r--openEMS/FDTD/operator_sse.cpp91
-rw-r--r--openEMS/FDTD/operator_sse.h63
-rw-r--r--openEMS/FDTD/operator_sse_compressed.cpp251
-rw-r--r--openEMS/FDTD/operator_sse_compressed.h84
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