summaryrefslogtreecommitdiff
path: root/openEMS/Common
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/Common
Imported Upstream version 0.0.34
Diffstat (limited to 'openEMS/Common')
-rw-r--r--openEMS/Common/CMakeLists.txt23
-rw-r--r--openEMS/Common/engine_interface_base.cpp39
-rw-r--r--openEMS/Common/engine_interface_base.h88
-rw-r--r--openEMS/Common/operator_base.cpp154
-rw-r--r--openEMS/Common/operator_base.h179
-rw-r--r--openEMS/Common/processcurrent.cpp168
-rw-r--r--openEMS/Common/processcurrent.h41
-rw-r--r--openEMS/Common/processfieldprobe.cpp92
-rw-r--r--openEMS/Common/processfieldprobe.h43
-rw-r--r--openEMS/Common/processfields.cpp341
-rw-r--r--openEMS/Common/processfields.h104
-rw-r--r--openEMS/Common/processfields_fd.cpp225
-rw-r--r--openEMS/Common/processfields_fd.h43
-rw-r--r--openEMS/Common/processfields_sar.cpp335
-rw-r--r--openEMS/Common/processfields_sar.h61
-rw-r--r--openEMS/Common/processfields_td.cpp91
-rw-r--r--openEMS/Common/processfields_td.h42
-rw-r--r--openEMS/Common/processing.cpp372
-rw-r--r--openEMS/Common/processing.h204
-rw-r--r--openEMS/Common/processintegral.cpp177
-rw-r--r--openEMS/Common/processintegral.h71
-rw-r--r--openEMS/Common/processmodematch.cpp265
-rw-r--r--openEMS/Common/processmodematch.h68
-rw-r--r--openEMS/Common/processvoltage.cpp40
-rw-r--r--openEMS/Common/processvoltage.h39
-rw-r--r--openEMS/Common/readme.txt6
26 files changed, 3311 insertions, 0 deletions
diff --git a/openEMS/Common/CMakeLists.txt b/openEMS/Common/CMakeLists.txt
new file mode 100644
index 0000000..004b35e
--- /dev/null
+++ b/openEMS/Common/CMakeLists.txt
@@ -0,0 +1,23 @@
+
+#INCLUDE_DIRECTORIES( ${openEMS_SOURCE_DIR} )
+
+set(SOURCES
+ ${SOURCES}
+ ${CMAKE_CURRENT_SOURCE_DIR}/engine_interface_base.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/operator_base.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/processcurrent.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/processfieldprobe.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/processfields.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/processfields_fd.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/processfields_sar.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/processfields_td.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/processing.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/processintegral.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/processmodematch.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/processvoltage.cpp
+ PARENT_SCOPE
+)
+
+# Common lib
+#add_library( Common STATIC ${SOURCES} )
+
diff --git a/openEMS/Common/engine_interface_base.cpp b/openEMS/Common/engine_interface_base.cpp
new file mode 100644
index 0000000..4db393c
--- /dev/null
+++ b/openEMS/Common/engine_interface_base.cpp
@@ -0,0 +1,39 @@
+/*
+* 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_base.h"
+#include "string"
+
+Engine_Interface_Base::Engine_Interface_Base(Operator_Base* base_op)
+{
+ m_Op_Base = base_op;
+ m_InterpolType = NO_INTERPOLATION;
+}
+
+std::string Engine_Interface_Base::GetInterpolationNameByType(InterpolationType mode)
+{
+ switch (mode)
+ {
+ case NO_INTERPOLATION:
+ return std::string("None");
+ case NODE_INTERPOLATE:
+ return std::string("Node");
+ case CELL_INTERPOLATE:
+ return std::string("Cell");
+ }
+ return std::string();
+}
diff --git a/openEMS/Common/engine_interface_base.h b/openEMS/Common/engine_interface_base.h
new file mode 100644
index 0000000..6ce466b
--- /dev/null
+++ b/openEMS/Common/engine_interface_base.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_INTERFACE_BASE_H
+#define ENGINE_INTERFACE_BASE_H
+
+#include "tools/global.h"
+
+class Operator_Base;
+
+//! This is the abstact base for all Engine Interface classes.
+/*!
+ This is the abstact base for all Engine Interface classes. It will provide unified access to the field information of the corresponding engine.
+ All processing methods should only access this base class.
+*/
+class Engine_Interface_Base
+{
+public:
+ enum InterpolationType { NO_INTERPOLATION, NODE_INTERPOLATE, CELL_INTERPOLATE };
+
+ virtual ~Engine_Interface_Base() {;} //!< provide a virtual destructor to correctly delete derived objects
+
+ //! Set the operator used for this engine interface.
+ virtual void SetOperator(Operator_Base* base_op) {m_Op_Base=base_op;}
+ //! Get the operator used for this engine interface.
+ virtual const Operator_Base* GetOperator() const {return m_Op_Base;}
+
+ //! Set the current interpolation type \sa GetInterpolationType
+ void SetInterpolationType(InterpolationType type) {m_InterpolType=type;}
+ //! Set the current interpolation type \sa GetInterpolationType
+ void SetInterpolationType(int type) {m_InterpolType=(InterpolationType)type;}
+ //! Get the current interpolation type as string \sa SetInterpolationType GetInterpolationType GetInterpolationNameByType
+ std::string GetInterpolationTypeString() {return GetInterpolationNameByType(m_InterpolType);}
+ //! Get the current interpolation type \sa SetInterpolationType
+ InterpolationType GetInterpolationType() {return m_InterpolType;}
+
+ //! Get the (interpolated) electric field at \p pos. \sa SetInterpolationType
+ virtual double* GetEField(const unsigned int* pos, double* out) const =0;
+ //! Get the (interpolated) magnetic field at \p pos. \sa SetInterpolationType
+ virtual double* GetHField(const unsigned int* pos, double* out) const =0;
+ //! Get the (interpolated) electric current density field at \p pos. \sa SetInterpolationType
+ virtual double* GetJField(const unsigned int* pos, double* out) const =0;
+ //! Get the total current density field by rot(H) at \p pos. \sa SetInterpolationType
+ virtual double* GetRotHField(const unsigned int* pos, double* out) const =0;
+
+ //! Calculate the electric field integral along a given line
+ virtual double CalcVoltageIntegral(const unsigned int* start, const unsigned int* stop) const =0;
+
+ //! Convert the interpolation type into a string.
+ static std::string GetInterpolationNameByType(InterpolationType mode);
+
+ //! Get the current simulation time
+ virtual double GetTime(bool dualTime=false) const =0;
+
+ //! Get the current number of timesteps
+ virtual unsigned int GetNumberOfTimesteps() const =0;
+
+ //! Calc (roughly) the total energy
+ /*!
+ This method only calculates a very rough estimate of the total energy in the simulation domain.
+ The result may even be roughly proportional to the real system energy only.
+ Primary goal is speed, not accuracy.
+ */
+ virtual double CalcFastEnergy() const =0;
+
+protected:
+ Engine_Interface_Base(Operator_Base* base_op);
+
+ Operator_Base* m_Op_Base;
+
+ InterpolationType m_InterpolType;
+};
+
+#endif // ENGINE_INTERFACE_BASE_H
diff --git a/openEMS/Common/operator_base.cpp b/openEMS/Common/operator_base.cpp
new file mode 100644
index 0000000..e5d26f5
--- /dev/null
+++ b/openEMS/Common/operator_base.cpp
@@ -0,0 +1,154 @@
+/*
+* 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_base.h"
+
+using namespace std;
+
+Operator_Base::Operator_Base()
+{
+ Init();
+ m_MeshType = CARTESIAN;
+ m_StoreMaterial[0]=false;
+ m_StoreMaterial[1]=false;
+ m_StoreMaterial[2]=false;
+ m_StoreMaterial[3]=false;
+}
+
+Operator_Base::~Operator_Base()
+{
+ Delete();
+}
+
+bool Operator_Base::SetGeometryCSX(ContinuousStructure* geo)
+{
+ if (geo==NULL) return false;
+ CSX = geo;
+
+ return true;
+}
+
+std::string Operator_Base::GetDirName(int ny) const
+{
+ if (ny==0) return "x";
+ if (ny==1) return "y";
+ if (ny==2) return "z";
+ return "";
+}
+
+void Operator_Base::Init()
+{
+ CSX = NULL;
+
+ dT = 0;
+ for (int n=0; n<3; ++n)
+ discLines[n]=NULL;
+ for (int n=0; n<6; ++n)
+ m_BC[n]=0;
+
+ SetBackgroundMaterial(1,1,0,0);
+}
+
+void Operator_Base::Delete()
+{
+ for (int n=0; n<3; ++n)
+ {
+ delete[] discLines[n];
+ discLines[n]=0;
+ }
+ for (int n=0; n<6; ++n)
+ m_BC[n]=0;
+ dT = 0;
+}
+
+void Operator_Base::Reset()
+{
+ Delete();
+}
+
+void Operator_Base::SetMaterialStoreFlags(int type, bool val)
+{
+ if ((type<0) || (type>4))
+ return;
+ m_StoreMaterial[type]=val;
+}
+
+bool Operator_Base::GetCellCenterMaterialAvgCoord(const unsigned int pos[3], double coord[3]) const
+{
+ int ipos[3] = {(int)pos[0], (int)pos[1], (int)pos[2]};
+ return GetCellCenterMaterialAvgCoord(ipos, coord);
+}
+
+void Operator_Base::SetBackgroundMaterial(double epsR, double mueR, double kappa, double sigma, double density)
+{
+ SetBackgroundEpsR(epsR);
+ SetBackgroundMueR(mueR);
+ SetBackgroundKappa(kappa);
+ SetBackgroundSigma(sigma);
+ SetBackgroundDensity(density);
+}
+
+void Operator_Base::SetBackgroundEpsR(double val)
+{
+ if (val<1)
+ {
+ cerr << __func__ << ": Warning, a relative electric permittivity <1 it not supported, skipping" << endl;
+ return;
+ }
+ m_BG_epsR=val;
+}
+
+void Operator_Base::SetBackgroundMueR(double val)
+{
+ if (val<1)
+ {
+ cerr << __func__ << ": Warning, a relative magnetic permeability <1 it not supported, skipping" << endl;
+ return;
+ }
+ m_BG_mueR=val;
+}
+
+void Operator_Base::SetBackgroundKappa(double val)
+{
+ if (val<0)
+ {
+ cerr << __func__ << ": Warning, an electric conductivity <0 it not supported, skipping" << endl;
+ return;
+ }
+ m_BG_kappa=val;
+}
+
+void Operator_Base::SetBackgroundSigma(double val)
+{
+ if (val<0)
+ {
+ cerr << __func__ << ": Warning, an artifival magnetic conductivity <0 it not supported, skipping" << endl;
+ return;
+ }
+ m_BG_sigma=val;
+}
+
+
+void Operator_Base::SetBackgroundDensity(double val)
+{
+ if (val<0)
+ {
+ cerr << __func__ << ": Warning, a mass density <0 it not supported, skipping" << endl;
+ return;
+ }
+ m_BG_density=val;
+}
diff --git a/openEMS/Common/operator_base.h b/openEMS/Common/operator_base.h
new file mode 100644
index 0000000..cfbd40b
--- /dev/null
+++ b/openEMS/Common/operator_base.h
@@ -0,0 +1,179 @@
+/*
+* 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_BASE_H
+#define OPERATOR_BASE_H
+
+#include "ContinuousStructure.h"
+#include "tools/global.h"
+#include "Common/processing.h"
+#include "string"
+
+typedef struct
+{
+ std::vector<unsigned int> posPath[3];
+ std::vector<unsigned short> dir;
+} Grid_Path;
+
+//! Abstract base-class for a common operator
+class Operator_Base
+{
+public:
+ virtual ~Operator_Base();
+
+ virtual bool SetGeometryCSX(ContinuousStructure* geo);
+ virtual ContinuousStructure* GetGeometryCSX() const {return CSX;}
+
+ //! Get the timestep used by this operator
+ virtual double GetTimestep() const {return dT;}
+
+ //! Get the number of cells or nodes defined by this operator
+ virtual double GetNumberCells() const =0;
+
+ //! Get the number of timesteps satisfying the nyquist condition (may depend on the excitation)
+ virtual unsigned int GetNumberOfNyquistTimesteps() const =0;
+
+ //! Returns the number of lines as needed for post-processing etc.
+ virtual unsigned int GetNumberOfLines(int ny, bool full=false) const =0;
+
+ //! Get the name for the given direction: 0 -> x, 1 -> y, 2 -> z
+ virtual std::string GetDirName(int ny) const;
+
+ //! Get the grid drawing unit in m
+ virtual double GetGridDelta() const =0;
+
+ //! Get the disc line in \a n direction (in drawing units)
+ virtual double GetDiscLine(int n, unsigned int pos, bool dualMesh=false) const =0;
+
+ //! Get the disc line delta in \a n direction (in drawing units)
+ virtual double GetDiscDelta(int n, unsigned int pos, bool dualMesh=false) const =0;
+
+ //! 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 =0;
+
+ //! 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 =0;
+
+ //! Get the length of an FDTD edge (unit is meter).
+ virtual double GetEdgeLength(int ny, const unsigned int pos[3], bool dualMesh = false) const =0;
+
+ //! 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 =0;
+
+ //! Get the volume of an FDTD cell
+ virtual double GetCellVolume(const unsigned int pos[3], bool dualMesh = false) const =0;
+
+ //! Snap the given coodinates to mesh indices, return box dimension
+ virtual bool SnapToMesh(const double* coord, unsigned int* uicoord, bool dualMesh=false, bool fullMesh=false, bool* inside=NULL) const =0;
+
+ //! Snap a given box to the operator mesh, uiStart will be always <= uiStop
+ /*!
+ \param[in] start the box-start coorindate
+ \param[in] stop the box-stopt coorindate
+ \param[out] uiStart the snapped box-start coorindate index
+ \param[out] uiStop the snapped box-stop coorindate index
+ \param[in] dualMesh snap to main or dual mesh (default is main mesh)
+ \param[in] SnapMethod Snapping method, 0=snap to closest line, 1/(2)=snap such that given box is inside (outside) the snapped lines
+ \return returns the box dimension or -1 if box is not inside the simulation domain
+ */
+ 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 =0;
+
+ //! Set the boundary conditions
+ virtual void SetBoundaryCondition(int* BCs) {for (int n=0; n<6; ++n) m_BC[n]=BCs[n];}
+
+ //! Set flags to store material data for post-processing
+ virtual void SetMaterialStoreFlags(int type, bool val);
+
+ //! Check storage flags and cleanup
+ virtual void CleanupMaterialStorage() = 0;
+
+ //! Get stored discrete material (if storage is enabled).
+ virtual double GetDiscMaterial(int type, int ny, const unsigned int pos[3]) const = 0;
+
+ //! Get the cell center coordinate usable for material averaging (Warning, may not be the yee cell center)
+ bool GetCellCenterMaterialAvgCoord(const unsigned int pos[3], double coord[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 = 0;
+
+ virtual std::vector<CSPrimitives*> GetPrimitivesBoundBox(int posX, int posY, int posZ, CSProperties::PropertyType type=CSProperties::ANY) const = 0;
+
+ //! Set the background material (default is vacuum)
+ virtual void SetBackgroundMaterial(double epsR=0, double mueR=0, double kappa=0, double sigma=0, double density=0);
+
+ //! Get background rel. electric permittivity
+ double GetBackgroundEpsR() const {return m_BG_epsR;}
+ //! Set background rel. electric permittivity
+ void SetBackgroundEpsR(double val);
+
+ //! Get background rel. magnetic permeability
+ double GetBackgroundMueR() const {return m_BG_mueR;}
+ //! Set background rel. magnetic permeability
+ void SetBackgroundMueR(double val);
+
+ //! Get background electric conductivity
+ double GetBackgroundKappa() const {return m_BG_kappa;}
+ //! Set background electric conductivity
+ void SetBackgroundKappa(double val);
+
+ //! Get background magnetic conductivity (artificial)
+ double GetBackgroundSigma() const {return m_BG_sigma;}
+ //! Set background magnetic conductivity (artificial)
+ void SetBackgroundSigma(double val);
+
+ //! Get background mass density
+ double GetBackgroundDensity() const {return m_BG_density;}
+ //! Set background mass density
+ void SetBackgroundDensity(double val);
+
+protected:
+ Operator_Base();
+
+ ContinuousStructure* CSX;
+
+ virtual void Init();
+ //! Cleanup data and reset
+ void Delete();
+ virtual void Reset();
+
+ //! boundary conditions
+ int m_BC[6];
+
+ //! The operator timestep
+ double dT;
+
+ //! bool flag array to store material data for post-processing
+ bool m_StoreMaterial[4];
+
+ //! background materials
+ double m_BG_epsR;
+ double m_BG_mueR;
+ double m_BG_kappa;
+ double m_BG_sigma;
+ double m_BG_density;
+
+ CoordinateSystem m_MeshType;
+ unsigned int numLines[3];
+ double* discLines[3];
+ double gridDelta;
+};
+
+#endif // OPERATOR_BASE_H
diff --git a/openEMS/Common/processcurrent.cpp b/openEMS/Common/processcurrent.cpp
new file mode 100644
index 0000000..8c35bf0
--- /dev/null
+++ b/openEMS/Common/processcurrent.cpp
@@ -0,0 +1,168 @@
+/*
+* 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/global.h"
+#include "processcurrent.h"
+#include "FDTD/engine_interface_fdtd.h"
+#include <iomanip>
+
+ProcessCurrent::ProcessCurrent(Engine_Interface_Base* eng_if) : ProcessIntegral(eng_if)
+{
+ m_SnapMethod=1;
+}
+
+ProcessCurrent::~ProcessCurrent()
+{
+}
+
+string ProcessCurrent::GetIntegralName(int row) const
+{
+ if (row==0)
+ return "current";
+ return "unknown";
+}
+
+void ProcessCurrent::DefineStartStopCoord(double* dstart, double* dstop)
+{
+ ProcessIntegral::DefineStartStopCoord(dstart, dstop);
+
+ if ((m_normDir<0) || (m_normDir>2))
+ {
+ if (m_Dimension!=2)
+ {
+ cerr << "ProcessCurrent::DefineStartStopCoord(): Warning Current Integration Box \"" << m_filename << "\" is not a surface (found dimension: " << m_Dimension << ") nor has it set a valid normal direction! --> disabled" << endl;
+ SetEnable(false);
+ return;
+ }
+
+ for (int n=0; n<3; ++n)
+ {
+ if (stop[n] == start[n])
+ m_normDir = n;
+ }
+ }
+ else
+ {
+ //expand dimension to 2 if possible
+ m_Dimension = 0;
+ for (int n=0; n<3; ++n)
+ {
+ if (n==m_normDir)
+ continue;
+ if (dstart[n]==dstop[n])
+ {
+ if ((Op->GetDiscLine( n, start[n], true ) > dstart[n]) && (start[n]>0))
+ --start[n];
+ if ((Op->GetDiscLine( n, start[n], true ) < dstart[n]) && (stop[n]<Op->GetNumberOfLines(n)-1))
+ ++stop[n];
+ }
+ if (stop[n] > start[n])
+ ++m_Dimension;
+ }
+ }
+
+ if (start[m_normDir]!=stop[m_normDir])
+ {
+ cerr << "ProcessCurrent::DefineStartStopCoord(): Warning Current Integration Box \"" << m_filename << "\" has an expansion in normal direction! --> disabled" << endl;
+ SetEnable(false);
+ return;
+ }
+
+ if ((m_normDir<0) || (m_normDir>2))
+ {
+ cerr << "ProcessCurrent::DefineStartStopCoord(): Warning Current Integration Box \"" << m_filename << "\" has an invalid normal direction --> disabled" << endl;
+ SetEnable(false);
+ return;
+ }
+}
+
+double ProcessCurrent::CalcIntegral()
+{
+ FDTD_FLOAT current=0;
+
+ Engine_Interface_FDTD* EI_FDTD = dynamic_cast<Engine_Interface_FDTD*>(m_Eng_Interface);
+
+ if (EI_FDTD)
+ {
+ const Engine* Eng = EI_FDTD->GetFDTDEngine();
+
+
+ switch (m_normDir)
+ {
+ case 0:
+ //y-current
+ if (m_stop_inside[0] && m_start_inside[2])
+ for (unsigned int i=start[1]+1; i<=stop[1]; ++i)
+ current+=Eng->GetCurr(1,stop[0],i,start[2]);
+ //z-current
+ if (m_stop_inside[0] && m_stop_inside[1])
+ for (unsigned int i=start[2]+1; i<=stop[2]; ++i)
+ current+=Eng->GetCurr(2,stop[0],stop[1],i);
+ //y-current
+ if (m_start_inside[0] && m_stop_inside[2])
+ for (unsigned int i=start[1]+1; i<=stop[1]; ++i)
+ current-=Eng->GetCurr(1,start[0],i,stop[2]);
+ //z-current
+ if (m_start_inside[0] && m_start_inside[1])
+ for (unsigned int i=start[2]+1; i<=stop[2]; ++i)
+ current-=Eng->GetCurr(2,start[0],start[1],i);
+ break;
+ case 1:
+ //z-current
+ if (m_start_inside[0] && m_start_inside[1])
+ for (unsigned int i=start[2]+1; i<=stop[2]; ++i)
+ current+=Eng->GetCurr(2,start[0],start[1],i);
+ //x-current
+ if (m_stop_inside[1] && m_stop_inside[2])
+ for (unsigned int i=start[0]+1; i<=stop[0]; ++i)
+ current+=Eng->GetCurr(0,i,stop[1],stop[2]);
+ //z-current
+ if (m_stop_inside[0] && m_stop_inside[1])
+ for (unsigned int i=start[2]+1; i<=stop[2]; ++i)
+ current-=Eng->GetCurr(2,stop[0],stop[1],i);
+ //x-current
+ if (m_start_inside[1] && m_start_inside[2])
+ for (unsigned int i=start[0]+1; i<=stop[0]; ++i)
+ current-=Eng->GetCurr(0,i,start[1],start[2]);
+ break;
+ case 2:
+ //x-current
+ if (m_start_inside[1] && m_start_inside[2])
+ for (unsigned int i=start[0]+1; i<=stop[0]; ++i)
+ current+=Eng->GetCurr(0,i,start[1],start[2]);
+ //y-current
+ if (m_stop_inside[0] && m_start_inside[2])
+ for (unsigned int i=start[1]+1; i<=stop[1]; ++i)
+ current+=Eng->GetCurr(1,stop[0],i,start[2]);
+ //x-current
+ if (m_stop_inside[1] && m_stop_inside[2])
+ for (unsigned int i=start[0]+1; i<=stop[0]; ++i)
+ current-=Eng->GetCurr(0,i,stop[1],stop[2]);
+ //y-current
+ if (m_start_inside[0] && m_stop_inside[2])
+ for (unsigned int i=start[1]+1; i<=stop[1]; ++i)
+ current-=Eng->GetCurr(1,start[0],i,stop[2]);
+ break;
+ default:
+ //this cannot happen...
+ return 0.0;
+ break;
+ }
+ }
+
+ return current;
+}
diff --git a/openEMS/Common/processcurrent.h b/openEMS/Common/processcurrent.h
new file mode 100644
index 0000000..5152b92
--- /dev/null
+++ b/openEMS/Common/processcurrent.h
@@ -0,0 +1,41 @@
+/*
+* 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 PROCESSCURRENT_H
+#define PROCESSCURRENT_H
+
+#include "processintegral.h"
+
+class ProcessCurrent : public ProcessIntegral
+{
+public:
+ ProcessCurrent(Engine_Interface_Base* eng_if);
+ virtual ~ProcessCurrent();
+
+ virtual std::string GetProcessingName() const {return "current integration";}
+
+ virtual std::string GetIntegralName(int row) const;
+
+ virtual void DefineStartStopCoord(double* dstart, double* dstop);
+
+ //! Integrate currents flowing through an area
+ virtual double CalcIntegral();
+
+protected:
+};
+
+#endif // PROCESSCURRENT_H
diff --git a/openEMS/Common/processfieldprobe.cpp b/openEMS/Common/processfieldprobe.cpp
new file mode 100644
index 0000000..c456a22
--- /dev/null
+++ b/openEMS/Common/processfieldprobe.cpp
@@ -0,0 +1,92 @@
+/*
+* 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 "processfieldprobe.h"
+
+using namespace std;
+
+ProcessFieldProbe::ProcessFieldProbe(Engine_Interface_Base* eng_if, int type) : ProcessIntegral(eng_if)
+{
+ SetFieldType(type);
+}
+
+ProcessFieldProbe::~ProcessFieldProbe()
+{
+
+}
+
+string ProcessFieldProbe::GetProcessingName() const
+{
+ if (m_ModeFieldType==0)
+ return "electric field probe";
+ if (m_ModeFieldType==1)
+ return "magnetic field probe";
+ return "unknown field probe";
+}
+
+string ProcessFieldProbe::GetIntegralName(int row) const
+{
+ if (row==0)
+ {
+ if (m_ModeFieldType==0)
+ return "Ex/(V/m)";
+ if (m_ModeFieldType==1)
+ return "Hx/(A/m)";
+ }
+ if (row==1)
+ {
+ if (m_ModeFieldType==0)
+ return "Ey/(V/m)";
+ if (m_ModeFieldType==1)
+ return "Hy/(A/m)";
+ }
+ if (row==2)
+ {
+ if (m_ModeFieldType==0)
+ return "Ez/(V/m)";
+ if (m_ModeFieldType==1)
+ return "Hz/(A/m)";
+ }
+ return "unknown";
+}
+
+void ProcessFieldProbe::SetFieldType(int type)
+{
+ if ((type<0) || (type>1))
+ {
+ cerr << "ProcessFieldProbe::SetFieldType: Error: unknown field type... skipping" << endl;
+ Enabled=false;
+ }
+ m_ModeFieldType = type;
+}
+
+double* ProcessFieldProbe::CalcMultipleIntegrals()
+{
+ m_Eng_Interface->SetInterpolationType(Engine_Interface_Base::NO_INTERPOLATION);
+
+ switch (m_ModeFieldType)
+ {
+ case 0:
+ default:
+ m_Eng_Interface->GetEField(start,m_Results);
+ break;
+ case 1:
+ m_Eng_Interface->GetHField(start,m_Results);
+ break;
+ }
+ return m_Results;
+}
diff --git a/openEMS/Common/processfieldprobe.h b/openEMS/Common/processfieldprobe.h
new file mode 100644
index 0000000..342eba4
--- /dev/null
+++ b/openEMS/Common/processfieldprobe.h
@@ -0,0 +1,43 @@
+/*
+* 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 PROCESSFIELDPROBE_H
+#define PROCESSFIELDPROBE_H
+
+#include "processintegral.h"
+
+class ProcessFieldProbe : public ProcessIntegral
+{
+public:
+ ProcessFieldProbe(Engine_Interface_Base* eng_if, int type=0);
+ virtual ~ProcessFieldProbe();
+
+ virtual std::string GetProcessingName() const;
+
+ virtual std::string GetIntegralName(int row) const;
+
+ //! Set the field type (0 electric field, 1 magnetic field)
+ void SetFieldType(int type);
+
+ virtual int GetNumberOfIntegrals() const {return 3;}
+ virtual double* CalcMultipleIntegrals();
+
+protected:
+ int m_ModeFieldType;
+};
+
+#endif // PROCESSFIELDPROBE_H
diff --git a/openEMS/Common/processfields.cpp b/openEMS/Common/processfields.cpp
new file mode 100644
index 0000000..f52fc14
--- /dev/null
+++ b/openEMS/Common/processfields.cpp
@@ -0,0 +1,341 @@
+/*
+* 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 <iomanip>
+#include "tools/global.h"
+#include "tools/vtk_file_writer.h"
+#include "tools/hdf5_file_writer.h"
+#include "processfields.h"
+#include "FDTD/engine_interface_fdtd.h"
+
+ProcessFields::ProcessFields(Engine_Interface_Base* eng_if) : Processing(eng_if)
+{
+ m_DumpType = E_FIELD_DUMP;
+ // vtk-file is default
+ m_fileType = VTK_FILETYPE;
+ m_SampleType = NONE;
+ m_Vtk_Dump_File = NULL;
+ m_HDF5_Dump_File = NULL;
+ SetPrecision(6);
+ m_dualTime = false;
+
+ // dump box should be always inside the snapped lines
+ m_SnapMethod = 1;
+
+ for (int n=0; n<3; ++n)
+ {
+ numLines[n]=0;
+ posLines[n]=NULL;
+ discLines[n]=NULL;
+ subSample[n]=1;
+ optResolution[n]=0;
+ }
+}
+
+ProcessFields::~ProcessFields()
+{
+ delete m_Vtk_Dump_File;
+ m_Vtk_Dump_File = NULL;
+ for (int n=0; n<3; ++n)
+ {
+ delete[] posLines[n];
+ posLines[n]=NULL;
+ delete[] discLines[n];
+ discLines[n]=NULL;
+ }
+}
+
+string ProcessFields::GetFieldNameByType(DumpType type)
+{
+ switch (type)
+ {
+ case E_FIELD_DUMP:
+ return "E-Field";
+ case H_FIELD_DUMP:
+ return "H-Field";
+ case J_FIELD_DUMP:
+ return "J-Field";
+ case ROTH_FIELD_DUMP:
+ return "RotH-Field";
+ case SAR_LOCAL_DUMP:
+ return "SAR-local";
+ case SAR_1G_DUMP:
+ return "SAR_1g";
+ case SAR_10G_DUMP:
+ return "SAR_10g";
+ case SAR_RAW_DATA:
+ return "SAR_raw_data";
+ }
+ return "unknown field";
+}
+
+bool ProcessFields::NeedConductivity() const
+{
+ switch (m_DumpType)
+ {
+ case J_FIELD_DUMP:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
+void ProcessFields::InitProcess()
+{
+ if (Enabled==false) return;
+
+ CalcMeshPos();
+
+ if (m_fileType==VTK_FILETYPE)
+ {
+ delete m_Vtk_Dump_File;
+ m_Vtk_Dump_File = new VTK_File_Writer(m_filename,(int)m_Mesh_Type);
+
+ #ifdef OUTPUT_IN_DRAWINGUNITS
+ double discScaling = 1;
+ #else
+ double discScaling = Op->GetGridDelta();
+ #endif
+ m_Vtk_Dump_File->SetMeshLines(discLines,numLines,discScaling);
+ m_Vtk_Dump_File->SetNativeDump(g_settings.NativeFieldDumps());
+ }
+ if (m_fileType==HDF5_FILETYPE)
+ {
+ delete m_HDF5_Dump_File;
+ m_HDF5_Dump_File = new HDF5_File_Writer(m_filename+".h5");
+
+ #ifdef OUTPUT_IN_DRAWINGUNITS
+ double discScaling = 1;
+ #else
+ double discScaling = Op->GetGridDelta();
+ #endif
+ m_HDF5_Dump_File->WriteRectMesh(numLines,discLines,(int)m_Mesh_Type,discScaling);
+
+ m_HDF5_Dump_File->WriteAtrribute("/","openEMS_HDF5_version",0.2);
+ }
+}
+
+void ProcessFields::SetDumpMode(Engine_Interface_Base::InterpolationType mode)
+{
+ m_Eng_Interface->SetInterpolationType(mode);
+ if (mode==Engine_Interface_Base::CELL_INTERPOLATE)
+ m_dualMesh=true;
+ else if (mode==Engine_Interface_Base::NODE_INTERPOLATE)
+ m_dualMesh=false;
+ //else keep the preset/user defined case
+}
+
+void ProcessFields::DefineStartStopCoord(double* dstart, double* dstop)
+{
+ Processing::DefineStartStopCoord(dstart,dstop);
+
+ // normalize order of start and stop
+ for (int n=0; n<3; ++n)
+ {
+ if (start[n]>stop[n])
+ {
+ unsigned int help = start[n];
+ start[n]=stop[n];
+ stop[n]=help;
+ }
+ }
+}
+
+double ProcessFields::CalcTotalEnergyEstimate() const
+{
+ return m_Eng_Interface->CalcFastEnergy();
+}
+
+void ProcessFields::SetSubSampling(unsigned int subSampleRate, int dir)
+{
+ if (dir>2) return;
+ if (dir<0)
+ {
+ subSample[0]=subSampleRate;
+ subSample[1]=subSampleRate;
+ subSample[2]=subSampleRate;
+ }
+ else subSample[dir]=subSampleRate;
+ m_SampleType = SUBSAMPLE;
+}
+
+void ProcessFields::SetOptResolution(double optRes, int dir)
+{
+ if (dir>2) return;
+ if (dir<0)
+ {
+ optResolution[0]=optRes;
+ optResolution[1]=optRes;
+ optResolution[2]=optRes;
+ }
+ else optResolution[dir]=optRes;
+ m_SampleType = OPT_RESOLUTION;
+}
+
+void ProcessFields::CalcMeshPos()
+{
+ if ((m_SampleType==SUBSAMPLE) || (m_SampleType==NONE))
+ {
+ vector<unsigned int> tmp_pos;
+
+ for (int n=0; n<3; ++n)
+ {
+ // construct new discLines
+ tmp_pos.clear();
+ for (unsigned int i=start[n]; i<=stop[n]; i+=subSample[n])
+ tmp_pos.push_back(i);
+
+ numLines[n] = tmp_pos.size();
+ delete[] discLines[n];
+ discLines[n] = new double[numLines[n]];
+ delete[] posLines[n];
+ posLines[n] = new unsigned int[numLines[n]];
+ for (unsigned int i=0; i<numLines[n]; ++i)
+ {
+ posLines[n][i] = tmp_pos.at(i);
+ discLines[n][i] = Op->GetDiscLine(n,tmp_pos.at(i),m_dualMesh);
+ }
+ }
+ }
+ if ((m_SampleType==OPT_RESOLUTION))
+ {
+ vector<unsigned int> tmp_pos;
+ double oldPos=0;
+ for (int n=0; n<3; ++n)
+ {
+ // construct new discLines
+ tmp_pos.clear();
+ tmp_pos.push_back(start[n]);
+ oldPos=Op->GetDiscLine(n,start[n],m_dualMesh);
+ if (stop[n]==0)
+ tmp_pos.push_back(stop[n]);
+ else
+ for (unsigned int i=start[n]+1; i<=stop[n]-1; ++i)
+ {
+ if ( (Op->GetDiscLine(n,i+1,m_dualMesh)-oldPos) >= optResolution[n])
+ {
+ tmp_pos.push_back(i);
+ oldPos=Op->GetDiscLine(n,i,m_dualMesh);
+ }
+ }
+ if (start[n]!=stop[n])
+ tmp_pos.push_back(stop[n]);
+ numLines[n] = tmp_pos.size();
+ delete[] discLines[n];
+ discLines[n] = new double[numLines[n]];
+ delete[] posLines[n];
+ posLines[n] = new unsigned int[numLines[n]];
+ for (unsigned int i=0; i<numLines[n]; ++i)
+ {
+ posLines[n][i] = tmp_pos.at(i);
+ discLines[n][i] = Op->GetDiscLine(n,tmp_pos.at(i),m_dualMesh);
+ }
+ }
+ }
+}
+
+FDTD_FLOAT**** ProcessFields::CalcField()
+{
+ unsigned int pos[3];
+ double out[3];
+ //create array
+ FDTD_FLOAT**** field = Create_N_3DArray<FDTD_FLOAT>(numLines);
+ switch (m_DumpType)
+ {
+ case E_FIELD_DUMP:
+ for (unsigned int i=0; i<numLines[0]; ++i)
+ {
+ pos[0]=posLines[0][i];
+ for (unsigned int j=0; j<numLines[1]; ++j)
+ {
+ pos[1]=posLines[1][j];
+ for (unsigned int k=0; k<numLines[2]; ++k)
+ {
+ pos[2]=posLines[2][k];
+
+ m_Eng_Interface->GetEField(pos,out);
+ field[0][i][j][k] = out[0];
+ field[1][i][j][k] = out[1];
+ field[2][i][j][k] = out[2];
+ }
+ }
+ }
+ return field;
+ case H_FIELD_DUMP:
+ for (unsigned int i=0; i<numLines[0]; ++i)
+ {
+ pos[0]=posLines[0][i];
+ for (unsigned int j=0; j<numLines[1]; ++j)
+ {
+ pos[1]=posLines[1][j];
+ for (unsigned int k=0; k<numLines[2]; ++k)
+ {
+ pos[2]=posLines[2][k];
+
+ m_Eng_Interface->GetHField(pos,out);
+ field[0][i][j][k] = out[0];
+ field[1][i][j][k] = out[1];
+ field[2][i][j][k] = out[2];
+ }
+ }
+ }
+ return field;
+ case J_FIELD_DUMP:
+ for (unsigned int i=0; i<numLines[0]; ++i)
+ {
+ pos[0]=posLines[0][i];
+ for (unsigned int j=0; j<numLines[1]; ++j)
+ {
+ pos[1]=posLines[1][j];
+ for (unsigned int k=0; k<numLines[2]; ++k)
+ {
+ pos[2]=posLines[2][k];
+
+ m_Eng_Interface->GetJField(pos,out);
+ field[0][i][j][k] = out[0];
+ field[1][i][j][k] = out[1];
+ field[2][i][j][k] = out[2];
+ }
+ }
+ }
+ return field;
+ case ROTH_FIELD_DUMP:
+ for (unsigned int i=0; i<numLines[0]; ++i)
+ {
+ pos[0]=posLines[0][i];
+ for (unsigned int j=0; j<numLines[1]; ++j)
+ {
+ pos[1]=posLines[1][j];
+ for (unsigned int k=0; k<numLines[2]; ++k)
+ {
+ pos[2]=posLines[2][k];
+
+ m_Eng_Interface->GetRotHField(pos,out);
+ field[0][i][j][k] = out[0];
+ field[1][i][j][k] = out[1];
+ field[2][i][j][k] = out[2];
+ }
+ }
+ }
+ return field;
+ default:
+ cerr << "ProcessFields::CalcField(): Error, unknown dump type..." << endl;
+ return field;
+ }
+}
+
diff --git a/openEMS/Common/processfields.h b/openEMS/Common/processfields.h
new file mode 100644
index 0000000..3d4085b
--- /dev/null
+++ b/openEMS/Common/processfields.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 PROCESSFIELDS_H
+#define PROCESSFIELDS_H
+
+#include "processing.h"
+#include "tools/array_ops.h"
+
+#define __VTK_DATA_TYPE__ "double"
+
+class VTK_File_Writer;
+class HDF5_File_Writer;
+
+class ProcessFields : public Processing
+{
+public:
+ ProcessFields(Engine_Interface_Base* eng_if);
+ virtual ~ProcessFields();
+
+ //! File type definition.
+ enum FileType { VTK_FILETYPE, HDF5_FILETYPE};
+
+ //! Dump type definitions.
+ /*!
+ Current dump types are electric field (E_FIELD_DUMP), magnetic field (H_FIELD_DUMP),
+ (conduction) electric current density (kappa*E) (J_FIELD_DUMP) and total current density (rotH)
+ */
+ enum DumpType { E_FIELD_DUMP=0, H_FIELD_DUMP=1, J_FIELD_DUMP=2, ROTH_FIELD_DUMP=3, SAR_LOCAL_DUMP=20, SAR_1G_DUMP=21, SAR_10G_DUMP=22, SAR_RAW_DATA=29};
+
+ virtual std::string GetProcessingName() const {return "common field processing";}
+
+ virtual void InitProcess();
+
+ virtual void DefineStartStopCoord(double* dstart, double* dstop);
+
+ //! Define a field dump sub sampling rate for a given direction (default: \a dir = -1 means all directions)
+ virtual void SetSubSampling(unsigned int subSampleRate, int dir=-1);
+
+ //! Define a field dump optimal resolution for a given direction (default: \a dir = -1 means all directions)
+ virtual void SetOptResolution(double optRes, int dir=-1);
+
+ //! Set the filename for a hdf5 data group file (HDF5 FileType only) \sa SetFileType()
+ void SetFileName(std::string fn) {m_filename=fn;}
+ std::string SetFileName() const {return m_filename;}
+
+ //! Define the Dump-Mode
+ void SetDumpMode(Engine_Interface_Base::InterpolationType mode);
+ //! This methode will dump all fields on a main cell node using 2 E-field and 4 H-fields per direction.
+ void SetDumpMode2Node() {SetDumpMode(Engine_Interface_Base::NODE_INTERPOLATE);}
+ //! This methode will dump all fields in the center of a main cell (dual-node) using 4 E-field and 2 H-fields per direction.
+ void SetDumpMode2Cell() {SetDumpMode(Engine_Interface_Base::CELL_INTERPOLATE);}
+
+ //! Set dump type: 0 for E-fields, 1 for H-fields, 2 for D-fields, 3 for B-fields, 4 for J-fields, etc...
+ virtual void SetDumpType(DumpType type) {m_DumpType=type;}
+
+ double CalcTotalEnergyEstimate() const;
+
+ void SetFileType(FileType fileType) {m_fileType=fileType;}
+
+ static std::string GetFieldNameByType(DumpType type);
+
+ virtual bool NeedConductivity() const;
+
+protected:
+ DumpType m_DumpType;
+ FileType m_fileType;
+
+ VTK_File_Writer* m_Vtk_Dump_File;
+ HDF5_File_Writer* m_HDF5_Dump_File;
+
+ enum SampleType {NONE, SUBSAMPLE, OPT_RESOLUTION} m_SampleType;
+ virtual void CalcMeshPos();
+
+ //! field dump sub-sampling (if enabled)
+ unsigned int subSample[3];
+
+ //! field dump optimal resolution (if enabled)
+ double optResolution[3];
+
+ //! dump mesh information
+ unsigned int numLines[3]; //number of lines to dump
+ unsigned int* posLines[3]; //grid positions to dump
+ double* discLines[3]; //mesh disc lines to dump
+
+ //! Calculate and return the defined field. Caller has to cleanup the array.
+ FDTD_FLOAT**** CalcField();
+};
+
+#endif // PROCESSFIELDS_H
diff --git a/openEMS/Common/processfields_fd.cpp b/openEMS/Common/processfields_fd.cpp
new file mode 100644
index 0000000..ca59b2b
--- /dev/null
+++ b/openEMS/Common/processfields_fd.cpp
@@ -0,0 +1,225 @@
+/*
+* 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 "processfields_fd.h"
+#include "Common/operator_base.h"
+#include "tools/vtk_file_writer.h"
+#include "tools/hdf5_file_writer.h"
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+using namespace std;
+
+ProcessFieldsFD::ProcessFieldsFD(Engine_Interface_Base* eng_if) : ProcessFields(eng_if)
+{
+}
+
+ProcessFieldsFD::~ProcessFieldsFD()
+{
+ for (size_t n = 0; n<m_FD_Fields.size(); ++n)
+ {
+ Delete_N_3DArray(m_FD_Fields.at(n),numLines);
+ }
+ m_FD_Fields.clear();
+}
+
+void ProcessFieldsFD::InitProcess()
+{
+ if (Enabled==false) return;
+
+ if (m_FD_Samples.size()==0)
+ {
+ cerr << "ProcessFieldsFD::InitProcess: No frequencies found... skipping this dump!" << endl;
+ Enabled=false;
+ return;
+ }
+
+ //setup the hdf5 file
+ ProcessFields::InitProcess();
+
+ if (m_Vtk_Dump_File)
+ m_Vtk_Dump_File->SetHeader(string("openEMS FD Field Dump -- Interpolation: ")+m_Eng_Interface->GetInterpolationTypeString());
+
+ if (m_HDF5_Dump_File)
+ {
+ m_HDF5_Dump_File->SetCurrentGroup("/FieldData/FD");
+ m_HDF5_Dump_File->WriteAtrribute("/FieldData/FD","frequency",m_FD_Samples);
+ }
+
+ //create data structures...
+ for (size_t n = 0; n<m_FD_Samples.size(); ++n)
+ {
+ std::complex<float>**** field_fd = Create_N_3DArray<std::complex<float> >(numLines);
+ m_FD_Fields.push_back(field_fd);
+ }
+}
+
+int ProcessFieldsFD::Process()
+{
+ if (Enabled==false) return -1;
+ if (CheckTimestep()==false) return GetNextInterval();
+
+ if ((m_FD_Interval==0) || (m_Eng_Interface->GetNumberOfTimesteps()%m_FD_Interval!=0))
+ return GetNextInterval();
+
+ FDTD_FLOAT**** field_td = CalcField();
+ std::complex<float>**** field_fd = NULL;
+
+ double T = m_Eng_Interface->GetTime(m_dualTime);
+ unsigned int pos[3];
+ for (size_t n = 0; n<m_FD_Samples.size(); ++n)
+ {
+ std::complex<float> exp_jwt_2_dt = std::exp( (std::complex<float>)(-2.0 * _I * M_PI * m_FD_Samples.at(n) * T) );
+ exp_jwt_2_dt *= 2; // *2 for single-sided spectrum
+ exp_jwt_2_dt *= Op->GetTimestep() * m_FD_Interval; // multiply with timestep-interval
+ field_fd = m_FD_Fields.at(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])
+ {
+ field_fd[0][pos[0]][pos[1]][pos[2]] += field_td[0][pos[0]][pos[1]][pos[2]] * exp_jwt_2_dt;
+ field_fd[1][pos[0]][pos[1]][pos[2]] += field_td[1][pos[0]][pos[1]][pos[2]] * exp_jwt_2_dt;
+ field_fd[2][pos[0]][pos[1]][pos[2]] += field_td[2][pos[0]][pos[1]][pos[2]] * exp_jwt_2_dt;
+ }
+ }
+ }
+ }
+ Delete_N_3DArray<FDTD_FLOAT>(field_td,numLines);
+ ++m_FD_SampleCount;
+ return GetNextInterval();
+}
+
+void ProcessFieldsFD::PostProcess()
+{
+ DumpFDData();
+}
+
+void ProcessFieldsFD::DumpFDData()
+{
+ if (m_fileType==VTK_FILETYPE)
+ {
+ unsigned int pos[3];
+ FDTD_FLOAT**** field = Create_N_3DArray<float>(numLines);
+ std::complex<float>**** field_fd = NULL;
+ double angle=0;
+ int Nr_Ph = 21;
+
+ for (size_t n = 0; n<m_FD_Samples.size(); ++n)
+ {
+ //dump multiple phase to vtk-files
+ for (int p=0; p<Nr_Ph; ++p)
+ {
+ angle = 2.0 * M_PI * p / Nr_Ph;
+ std::complex<float> exp_jwt = std::exp( (std::complex<float>)( _I * angle) );
+ field_fd = m_FD_Fields.at(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])
+ {
+ field[0][pos[0]][pos[1]][pos[2]] = real(field_fd[0][pos[0]][pos[1]][pos[2]] * exp_jwt);
+ field[1][pos[0]][pos[1]][pos[2]] = real(field_fd[1][pos[0]][pos[1]][pos[2]] * exp_jwt);
+ field[2][pos[0]][pos[1]][pos[2]] = real(field_fd[2][pos[0]][pos[1]][pos[2]] * exp_jwt);
+ }
+ }
+ }
+ stringstream ss;
+ ss << m_filename << fixed << "_f=" << m_FD_Samples.at(n) << "_p=" << std::setw( 3 ) << std::setfill( '0' ) <<(int)(angle * 180 / M_PI);
+
+ m_Vtk_Dump_File->SetFilename(ss.str());
+ m_Vtk_Dump_File->ClearAllFields();
+ m_Vtk_Dump_File->AddVectorField(GetFieldNameByType(m_DumpType),field);
+ if (m_Vtk_Dump_File->Write()==false)
+ cerr << "ProcessFieldsFD::Process: can't dump to file... abort! " << endl;
+ }
+
+ {
+ //dump magnitude to vtk-files
+ 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])
+ {
+ field[0][pos[0]][pos[1]][pos[2]] = abs(field_fd[0][pos[0]][pos[1]][pos[2]]);
+ field[1][pos[0]][pos[1]][pos[2]] = abs(field_fd[1][pos[0]][pos[1]][pos[2]]);
+ field[2][pos[0]][pos[1]][pos[2]] = abs(field_fd[2][pos[0]][pos[1]][pos[2]]);
+ }
+ }
+ }
+ stringstream ss;
+ ss << m_filename << fixed << "_f=" << m_FD_Samples.at(n) << "_abs";
+ m_Vtk_Dump_File->SetFilename(ss.str());
+ m_Vtk_Dump_File->ClearAllFields();
+ m_Vtk_Dump_File->AddVectorField(GetFieldNameByType(m_DumpType),field);
+ if (m_Vtk_Dump_File->Write()==false)
+ cerr << "ProcessFieldsFD::Process: can't dump to file... abort! " << endl;
+ }
+
+ {
+ //dump phase to vtk-files
+ 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])
+ {
+ field[0][pos[0]][pos[1]][pos[2]] = arg(field_fd[0][pos[0]][pos[1]][pos[2]]);
+ field[1][pos[0]][pos[1]][pos[2]] = arg(field_fd[1][pos[0]][pos[1]][pos[2]]);
+ field[2][pos[0]][pos[1]][pos[2]] = arg(field_fd[2][pos[0]][pos[1]][pos[2]]);
+ }
+ }
+ }
+ stringstream ss;
+ ss << m_filename << fixed << "_f=" << m_FD_Samples.at(n) << "_arg";
+ m_Vtk_Dump_File->SetFilename(ss.str());
+ m_Vtk_Dump_File->ClearAllFields();
+ m_Vtk_Dump_File->AddVectorField(GetFieldNameByType(m_DumpType),field);
+ if (m_Vtk_Dump_File->Write()==false)
+ cerr << "ProcessFieldsFD::Process: can't dump to file... abort! " << endl;
+ }
+ }
+ Delete_N_3DArray(field,numLines);
+ return;
+ }
+
+ if (m_fileType==HDF5_FILETYPE)
+ {
+ for (size_t n = 0; n<m_FD_Samples.size(); ++n)
+ {
+ stringstream ss;
+ ss << "f" << n;
+ size_t datasize[]={numLines[0],numLines[1],numLines[2]};
+ if (m_HDF5_Dump_File->WriteVectorField(ss.str(), m_FD_Fields.at(n), datasize)==false)
+ cerr << "ProcessFieldsFD::Process: can't dump to file...! " << endl;
+
+ //legacy support, use /FieldData/FD frequency-Attribute in the future
+ float freq[1] = {(float)m_FD_Samples.at(n)};
+ if (m_HDF5_Dump_File->WriteAtrribute("/FieldData/FD/"+ss.str()+"_real","frequency",freq,1)==false)
+ cerr << "ProcessFieldsFD::Process: can't dump to file...! " << endl;
+ if (m_HDF5_Dump_File->WriteAtrribute("/FieldData/FD/"+ss.str()+"_imag","frequency",freq,1)==false)
+ cerr << "ProcessFieldsFD::Process: can't dump to file...! " << endl;
+ }
+ return;
+ }
+
+ cerr << "ProcessFieldsFD::Process: unknown File-Type" << endl;
+}
diff --git a/openEMS/Common/processfields_fd.h b/openEMS/Common/processfields_fd.h
new file mode 100644
index 0000000..2049cc3
--- /dev/null
+++ b/openEMS/Common/processfields_fd.h
@@ -0,0 +1,43 @@
+/*
+* 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 PROCESSFIELDS_FD_H
+#define PROCESSFIELDS_FD_H
+
+#include "processfields.h"
+
+class ProcessFieldsFD : public ProcessFields
+{
+public:
+ ProcessFieldsFD(Engine_Interface_Base* eng_if);
+ virtual ~ProcessFieldsFD();
+
+ virtual std::string GetProcessingName() const {return "frequency domain field dump";}
+
+ virtual void InitProcess();
+
+ virtual int Process();
+ virtual void PostProcess();
+
+protected:
+ virtual void DumpFDData();
+
+ //! frequency domain field storage
+ std::vector<std::complex<float>****> m_FD_Fields;
+};
+
+#endif // PROCESSFIELDS_FD_H
diff --git a/openEMS/Common/processfields_sar.cpp b/openEMS/Common/processfields_sar.cpp
new file mode 100644
index 0000000..9bbdab2
--- /dev/null
+++ b/openEMS/Common/processfields_sar.cpp
@@ -0,0 +1,335 @@
+/*
+* 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 "processfields_sar.h"
+#include "operator_base.h"
+#include "tools/vtk_file_writer.h"
+#include "tools/hdf5_file_writer.h"
+#include "tools/sar_calculation.h"
+
+#include "CSPropMaterial.h"
+
+using namespace std;
+
+ProcessFieldsSAR::ProcessFieldsSAR(Engine_Interface_Base* eng_if) : ProcessFieldsFD(eng_if)
+{
+ m_UseCellKappa = true;
+ m_SAR_method = "Simple";
+}
+
+ProcessFieldsSAR::~ProcessFieldsSAR()
+{
+ for (size_t n = 0; n<m_E_FD_Fields.size(); ++n)
+ Delete_N_3DArray(m_E_FD_Fields.at(n),numLines);
+ m_E_FD_Fields.clear();
+
+ for (size_t n = 0; n<m_J_FD_Fields.size(); ++n)
+ Delete_N_3DArray(m_J_FD_Fields.at(n),numLines);
+ m_J_FD_Fields.clear();
+}
+
+void ProcessFieldsSAR::SetDumpType(DumpType type)
+{
+ if (type==SAR_RAW_DATA)
+ m_UseCellKappa = true;
+ ProcessFieldsFD::SetDumpType(type);
+}
+
+bool ProcessFieldsSAR::NeedConductivity() const
+{
+ return !m_UseCellKappa;
+}
+
+void ProcessFieldsSAR::SetSubSampling(unsigned int subSampleRate, int dir)
+{
+ UNUSED(subSampleRate);UNUSED(dir);
+ cerr << "ProcessFieldsSAR::SetSubSampling: Warning: Defining a sub-sampling for SAR calculation is not allowed!!! Skipped!" << endl;
+}
+
+void ProcessFieldsSAR::SetOptResolution(double optRes, int dir)
+{
+ UNUSED(optRes);UNUSED(dir);
+ cerr << "ProcessFieldsSAR::SetOptResolution: Warning: Defining a sub-sampling for SAR calculation is not allowed!!! Skipped!" << endl;
+}
+
+void ProcessFieldsSAR::InitProcess()
+{
+ if ((m_DumpType!=SAR_LOCAL_DUMP) && (m_DumpType!=SAR_1G_DUMP) && (m_DumpType!=SAR_10G_DUMP) && (m_DumpType!=SAR_RAW_DATA))
+ {
+ Enabled=false;
+ cerr << "ProcessFieldsSAR::InitProcess(): Error, wrong dump type... this should not happen... skipping!" << endl;
+ return;
+ }
+ if (m_Eng_Interface->GetInterpolationType()!=Engine_Interface_Base::CELL_INTERPOLATE)
+ {
+ cerr << "ProcessFieldsSAR::InitProcess(): Warning, interpolation type is not supported, resetting to CELL!" << endl;
+ SetDumpMode2Cell();
+ }
+
+ if ((m_DumpType==SAR_RAW_DATA) && (m_fileType!=HDF5_FILETYPE))
+ {
+ Enabled=false;
+ cerr << "ProcessFieldsSAR::InitProcess(): Error, wrong file type for dumping raw SAR data! skipping" << endl;
+ return;
+
+ }
+
+ ProcessFieldsFD::InitProcess();
+
+ if (Enabled==false) return;
+
+ //create data structures...
+ for (size_t n = 0; n<m_FD_Samples.size(); ++n)
+ {
+ m_E_FD_Fields.push_back(Create_N_3DArray<std::complex<float> >(numLines));
+ if (!m_UseCellKappa)
+ m_J_FD_Fields.push_back(Create_N_3DArray<std::complex<float> >(numLines));
+ }
+}
+
+int ProcessFieldsSAR::Process()
+{
+ if (Enabled==false) return -1;
+ if (CheckTimestep()==false) return GetNextInterval();
+
+ if ((m_FD_Interval==0) || (m_Eng_Interface->GetNumberOfTimesteps()%m_FD_Interval!=0))
+ return GetNextInterval();
+
+ std::complex<float>**** field_fd = NULL;
+ unsigned int pos[3];
+ double T;
+ FDTD_FLOAT**** field_td=NULL;
+
+ //save dump type
+ DumpType save_dump_type = m_DumpType;
+
+ // calc E-field
+ m_DumpType = E_FIELD_DUMP;
+ field_td = CalcField();
+ T = m_Eng_Interface->GetTime(m_dualTime);
+ for (size_t n = 0; n<m_FD_Samples.size(); ++n)
+ {
+ std::complex<float> exp_jwt_2_dt = std::exp( (std::complex<float>)(-2.0 * _I * M_PI * m_FD_Samples.at(n) * T) );
+ exp_jwt_2_dt *= 2; // *2 for single-sided spectrum
+ exp_jwt_2_dt *= Op->GetTimestep() * m_FD_Interval; // multiply with timestep-interval
+ field_fd = m_E_FD_Fields.at(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])
+ {
+ field_fd[0][pos[0]][pos[1]][pos[2]] += field_td[0][pos[0]][pos[1]][pos[2]] * exp_jwt_2_dt;
+ field_fd[1][pos[0]][pos[1]][pos[2]] += field_td[1][pos[0]][pos[1]][pos[2]] * exp_jwt_2_dt;
+ field_fd[2][pos[0]][pos[1]][pos[2]] += field_td[2][pos[0]][pos[1]][pos[2]] * exp_jwt_2_dt;
+ }
+ }
+ }
+ }
+ Delete_N_3DArray<FDTD_FLOAT>(field_td,numLines);
+
+ // calc J-field
+ if (!m_UseCellKappa)
+ {
+ m_DumpType = J_FIELD_DUMP;
+ field_td = CalcField();
+ T = m_Eng_Interface->GetTime(m_dualTime);
+ for (size_t n = 0; n<m_FD_Samples.size(); ++n)
+ {
+ std::complex<float> exp_jwt_2_dt = std::exp( (std::complex<float>)(-2.0 * _I * M_PI * m_FD_Samples.at(n) * T) );
+ exp_jwt_2_dt *= 2; // *2 for single-sided spectrum
+ exp_jwt_2_dt *= Op->GetTimestep() * m_FD_Interval; // multiply with timestep-interval
+ field_fd = m_J_FD_Fields.at(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])
+ {
+ field_fd[0][pos[0]][pos[1]][pos[2]] += field_td[0][pos[0]][pos[1]][pos[2]] * exp_jwt_2_dt;
+ field_fd[1][pos[0]][pos[1]][pos[2]] += field_td[1][pos[0]][pos[1]][pos[2]] * exp_jwt_2_dt;
+ field_fd[2][pos[0]][pos[1]][pos[2]] += field_td[2][pos[0]][pos[1]][pos[2]] * exp_jwt_2_dt;
+ }
+ }
+ }
+ }
+ Delete_N_3DArray<FDTD_FLOAT>(field_td,numLines);
+ }
+
+ //reset dump type
+ m_DumpType = save_dump_type;
+
+ ++m_FD_SampleCount;
+ return GetNextInterval();
+}
+
+void ProcessFieldsSAR::DumpFDData()
+{
+ if (Enabled==false) return;
+ unsigned int pos[3];
+ unsigned int orig_pos[3];
+ float*** SAR = Create3DArray<float>(numLines);
+ double coord[3];
+ ContinuousStructure* CSX = Op->GetGeometryCSX();
+ CSProperties* prop = NULL;
+ CSPropMaterial* matProp = NULL;
+
+ double power;
+
+ float*** cell_volume = Create3DArray<float>(numLines);
+ float*** cell_density = Create3DArray<float>(numLines);
+ float*** cell_kappa = NULL;
+ if (m_UseCellKappa)
+ cell_kappa = Create3DArray<float>(numLines);
+
+ bool found_UnIsotropic=false;
+
+ // calculate volumes and masses for all cells
+ for (pos[0]=0; pos[0]<numLines[0]; ++pos[0])
+ {
+ orig_pos[0] = posLines[0][pos[0]];
+ for (pos[1]=0; pos[1]<numLines[1]; ++pos[1])
+ {
+ orig_pos[1] = posLines[1][pos[1]];
+ vector<CSPrimitives*> vPrims = Op->GetPrimitivesBoundBox(orig_pos[0], orig_pos[1], -1, CSProperties::MATERIAL);
+ for (pos[2]=0; pos[2]<numLines[2]; ++pos[2])
+ {
+ orig_pos[2] = posLines[2][pos[2]];
+
+ cell_volume[pos[0]][pos[1]][pos[2]] = Op->GetCellVolume(orig_pos);
+ cell_density[pos[0]][pos[1]][pos[2]] = 0.0;
+
+ Op->GetCellCenterMaterialAvgCoord(orig_pos, coord);
+ prop = CSX->GetPropertyByCoordPriority(coord, vPrims);
+// prop = CSX->GetPropertyByCoordPriority(coord,CSProperties::MATERIAL);
+ if (prop!=0)
+ {
+ matProp = dynamic_cast<CSPropMaterial*>(prop);
+ if (matProp)
+ {
+ found_UnIsotropic |= !matProp->GetIsotropy();
+ cell_density[pos[0]][pos[1]][pos[2]] = matProp->GetDensityWeighted(coord);
+ if (m_UseCellKappa)
+ cell_kappa[pos[0]][pos[1]][pos[2]] = matProp->GetKappaWeighted(0,coord);
+ }
+ }
+ }
+ }
+ }
+ if (found_UnIsotropic)
+ cerr << "ProcessFieldsSAR::DumpFDData(): Warning, found unisotropic material in SAR calculation... this is unsupported!" << endl;
+
+ float* cellWidth[3];
+ for (int n=0;n<3;++n)
+ {
+ cellWidth[n]=new float[numLines[n]];
+ for (unsigned int i=0;i<numLines[n];++i)
+ cellWidth[n][i]=Op->GetDiscDelta(n,posLines[n][i])*Op->GetGridDelta();
+ }
+
+ if (m_DumpType == SAR_RAW_DATA)
+ {
+ if (m_fileType!=HDF5_FILETYPE)
+ {
+ cerr << "ProcessFieldsSAR::DumpFDData(): Error, wrong file type, this should not happen!!! skipped" << endl;
+ return;
+ }
+
+ size_t datasize[]={numLines[0],numLines[1],numLines[2]};
+ for (size_t n = 0; n<m_FD_Samples.size(); ++n)
+ {
+ stringstream ss;
+ ss << "f" << n;
+ if (m_HDF5_Dump_File->WriteVectorField(ss.str(), m_E_FD_Fields.at(n), datasize)==false)
+ cerr << "ProcessFieldsSAR::DumpFDData: can't dump to file...! " << endl;
+ }
+
+ m_HDF5_Dump_File->SetCurrentGroup("/CellData");
+ if (m_UseCellKappa==false)
+ cerr << "ProcessFieldsSAR::DumpFDData: Error, cell conductivity data not available, this should not happen... skipping! " << endl;
+ else if (m_HDF5_Dump_File->WriteScalarField("Conductivity", cell_kappa, datasize)==false)
+ cerr << "ProcessFieldsSAR::DumpFDData: can't dump to file...! " << endl;
+ if (m_HDF5_Dump_File->WriteScalarField("Density", cell_density, datasize)==false)
+ cerr << "ProcessFieldsSAR::DumpFDData: can't dump to file...! " << endl;
+ if (m_HDF5_Dump_File->WriteScalarField("Volume", cell_volume, datasize)==false)
+ cerr << "ProcessFieldsSAR::DumpFDData: can't dump to file...! " << endl;
+ }
+ else
+ {
+ SAR_Calculation SAR_Calc;
+ SAR_Calc.SetAveragingMethod(m_SAR_method, g_settings.GetVerboseLevel()==0);
+ SAR_Calc.SetDebugLevel(g_settings.GetVerboseLevel());
+ SAR_Calc.SetNumLines(numLines);
+ if (m_DumpType == SAR_LOCAL_DUMP)
+ SAR_Calc.SetAveragingMass(0);
+ else if (m_DumpType == SAR_1G_DUMP)
+ SAR_Calc.SetAveragingMass(1e-3);
+ else if (m_DumpType == SAR_10G_DUMP)
+ SAR_Calc.SetAveragingMass(10e-3);
+ else
+ {
+ cerr << "ProcessFieldsSAR::DumpFDData: unknown SAR dump type...!" << endl;
+ }
+ SAR_Calc.SetCellDensities(cell_density);
+ SAR_Calc.SetCellWidth(cellWidth);
+ SAR_Calc.SetCellVolumes(cell_volume);
+ SAR_Calc.SetCellCondictivity(cell_kappa); // cell_kappa will be NULL if m_UseCellKappa is false
+
+ for (size_t n = 0; n<m_FD_Samples.size(); ++n)
+ {
+ SAR_Calc.SetEField(m_E_FD_Fields.at(n));
+ if (!m_UseCellKappa)
+ SAR_Calc.SetJField(m_J_FD_Fields.at(n));
+ power = SAR_Calc.CalcSARPower();
+ SAR_Calc.CalcSAR(SAR);
+
+ if (m_fileType==VTK_FILETYPE)
+ {
+ stringstream ss;
+ ss << m_filename << fixed << "_f=" << m_FD_Samples.at(n);
+
+ m_Vtk_Dump_File->SetFilename(ss.str());
+ m_Vtk_Dump_File->ClearAllFields();
+ m_Vtk_Dump_File->AddScalarField(GetFieldNameByType(m_DumpType),SAR);
+ if (m_Vtk_Dump_File->Write()==false)
+ cerr << "ProcessFieldsSAR::DumpFDData: can't dump to file...! " << endl;
+ }
+ else if (m_fileType==HDF5_FILETYPE)
+ {
+ stringstream ss;
+ ss << "f" << n;
+ size_t datasize[]={numLines[0],numLines[1],numLines[2]};
+ if (m_HDF5_Dump_File->WriteScalarField(ss.str(), SAR, datasize)==false)
+ cerr << "ProcessFieldsSAR::DumpFDData: can't dump to file...! " << endl;
+ float freq[1] = {(float)m_FD_Samples.at(n)};
+ if (m_HDF5_Dump_File->WriteAtrribute("/FieldData/FD/"+ss.str(),"frequency",freq,1)==false)
+ cerr << "ProcessFieldsSAR::DumpFDData: can't dump to file...! " << endl;
+ float pow[1] = {(float)power};
+ if (m_HDF5_Dump_File->WriteAtrribute("/FieldData/FD/"+ss.str(),"power",pow,1)==false)
+ cerr << "ProcessFieldsSAR::DumpFDData: can't dump to file...! " << endl;
+ }
+ else
+ cerr << "ProcessFieldsSAR::DumpFDData: unknown File-Type" << endl;
+ }
+ }
+ for (int n=0;n<3;++n)
+ delete[] cellWidth[n];
+ Delete3DArray(cell_volume,numLines);
+ Delete3DArray(cell_density,numLines);
+ Delete3DArray(cell_kappa,numLines);
+ Delete3DArray(SAR,numLines);
+}
diff --git a/openEMS/Common/processfields_sar.h b/openEMS/Common/processfields_sar.h
new file mode 100644
index 0000000..289100d
--- /dev/null
+++ b/openEMS/Common/processfields_sar.h
@@ -0,0 +1,61 @@
+/*
+* 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 PROCESSFIELDS_SAR_H
+#define PROCESSFIELDS_SAR_H
+
+#include "processfields_fd.h"
+
+class ProcessFieldsSAR : public ProcessFieldsFD
+{
+public:
+ ProcessFieldsSAR(Engine_Interface_Base* eng_if);
+ virtual ~ProcessFieldsSAR();
+
+ virtual void SetDumpType(DumpType type);
+
+ virtual bool NeedConductivity() const;
+
+ virtual std::string GetProcessingName() const {return "SAR dump";}
+
+ virtual void InitProcess();
+
+ virtual int Process();
+
+ virtual void SetSubSampling(unsigned int subSampleRate, int dir=-1);
+
+ virtual void SetOptResolution(double optRes, int dir=-1);
+
+ //! Set to true for using the conductivity found at the center of a cell, or false for E*J instead
+ virtual void SetUseCellConductivity(bool val) {m_UseCellKappa=val;}
+
+ virtual void SetSARAveragingMethod(std::string method) {m_SAR_method=method;}
+
+protected:
+ virtual void DumpFDData();
+
+ bool m_UseCellKappa;
+
+ std::string m_SAR_method;
+
+ //! frequency domain electric field storage
+ std::vector<std::complex<float>****> m_E_FD_Fields;
+ //! frequency domain current density storage
+ std::vector<std::complex<float>****> m_J_FD_Fields;
+};
+
+#endif // PROCESSFIELDS_SAR_H
diff --git a/openEMS/Common/processfields_td.cpp b/openEMS/Common/processfields_td.cpp
new file mode 100644
index 0000000..d67e48b
--- /dev/null
+++ b/openEMS/Common/processfields_td.cpp
@@ -0,0 +1,91 @@
+/*
+* 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 "processfields_td.h"
+#include "Common/operator_base.h"
+#include "tools/vtk_file_writer.h"
+#include "tools/hdf5_file_writer.h"
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+using namespace std;
+
+ProcessFieldsTD::ProcessFieldsTD(Engine_Interface_Base* eng_if) : ProcessFields(eng_if)
+{
+ pad_length = 8;
+}
+
+ProcessFieldsTD::~ProcessFieldsTD()
+{
+}
+
+void ProcessFieldsTD::InitProcess()
+{
+ if (Enabled==false) return;
+
+ ProcessFields::InitProcess();
+
+ if (m_Vtk_Dump_File)
+ m_Vtk_Dump_File->SetHeader(string("openEMS TD Field Dump -- Interpolation: ")+m_Eng_Interface->GetInterpolationTypeString());
+
+ if (m_HDF5_Dump_File)
+ m_HDF5_Dump_File->SetCurrentGroup("/FieldData/TD");
+}
+
+int ProcessFieldsTD::Process()
+{
+ if (Enabled==false) return -1;
+ if (CheckTimestep()==false) return GetNextInterval();
+
+ string filename = m_filename;
+
+ float**** field = CalcField();
+ bool success = true;
+
+ if (m_fileType==VTK_FILETYPE)
+ {
+ m_Vtk_Dump_File->SetTimestep(m_Eng_Interface->GetNumberOfTimesteps());
+ m_Vtk_Dump_File->ClearAllFields();
+ m_Vtk_Dump_File->AddVectorField(GetFieldNameByType(m_DumpType),field);
+ success &= m_Vtk_Dump_File->Write();
+ }
+ else if (m_fileType==HDF5_FILETYPE)
+ {
+ stringstream ss;
+ ss << std::setw( pad_length ) << std::setfill( '0' ) << m_Eng_Interface->GetNumberOfTimesteps();
+ size_t datasize[]={numLines[0],numLines[1],numLines[2]};
+ success &= m_HDF5_Dump_File->WriteVectorField(ss.str(), field, datasize);
+ float time[1] = {(float)m_Eng_Interface->GetTime(m_dualTime)};
+ success &= m_HDF5_Dump_File->WriteAtrribute("/FieldData/TD/"+ss.str(),"time",time,1);
+ }
+ else
+ {
+ success = false;
+ cerr << "ProcessFieldsTD::Process: unknown File-Type" << endl;
+ }
+
+ Delete_N_3DArray<FDTD_FLOAT>(field,numLines);
+
+ if (success==false)
+ {
+ SetEnable(false);
+ cerr << "ProcessFieldsTD::Process: can't dump to file... disabled! " << endl;
+ }
+
+ return GetNextInterval();
+}
diff --git a/openEMS/Common/processfields_td.h b/openEMS/Common/processfields_td.h
new file mode 100644
index 0000000..91c4c04
--- /dev/null
+++ b/openEMS/Common/processfields_td.h
@@ -0,0 +1,42 @@
+/*
+* 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 PROCESSFIELDS_TD_H
+#define PROCESSFIELDS_TD_H
+
+#include "processfields.h"
+
+class ProcessFieldsTD : public ProcessFields
+{
+public:
+ ProcessFieldsTD(Engine_Interface_Base* eng_if);
+ virtual ~ProcessFieldsTD();
+
+ virtual std::string GetProcessingName() const {return "time domain field dump";}
+
+ virtual void InitProcess();
+
+ virtual int Process();
+
+ //! Set the length of the filename timestep pad filled with zeros (default is 8)
+ void SetPadLength(int val) {pad_length=val;};
+
+protected:
+ int pad_length;
+};
+
+#endif // PROCESSFIELDS_TD_H
diff --git a/openEMS/Common/processing.cpp b/openEMS/Common/processing.cpp
new file mode 100644
index 0000000..a444d9d
--- /dev/null
+++ b/openEMS/Common/processing.cpp
@@ -0,0 +1,372 @@
+/*
+* Copyright (C) 2010-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 "tools/global.h"
+#include "tools/useful.h"
+#include "Common/operator_base.h"
+#include <algorithm>
+#include "processing.h"
+#include <climits>
+
+using namespace std;
+
+Processing::Processing(Engine_Interface_Base* eng_if)
+{
+ m_Eng_Interface = NULL;
+ SetEngineInterface(eng_if);
+
+ Enabled = true;
+ m_PS_pos = 0;
+ SetPrecision(12);
+ ProcessInterval=0;
+ m_FD_SampleCount=0;
+ m_FD_Interval=0;
+ m_weight=1;
+ m_Flush = false;
+ m_dualMesh = false;
+ m_dualTime = false;
+ m_SnapMethod = 0;
+ m_Mesh_Type = CARTESIAN_MESH;
+
+ startTS=0;
+ stopTS =UINT_MAX;
+ for (int n=0;n<3;++n)
+ {
+ start[n]=0;
+ stop[n]=0;
+ }
+}
+
+Processing::~Processing()
+{
+ SetEngineInterface(NULL);
+ file.close();
+}
+
+void Processing::Reset()
+{
+ m_PS_pos=0;
+}
+
+void Processing::SetEngineInterface(Engine_Interface_Base* eng_if)
+{
+ delete m_Eng_Interface;
+ m_Eng_Interface = eng_if;
+ if (m_Eng_Interface)
+ Op=m_Eng_Interface->GetOperator();
+ else
+ Op=NULL;
+}
+
+void Processing::SetName(string val, int number)
+{
+ stringstream ss;
+ ss << val << "_" << number;
+ SetName(ss.str());
+}
+
+bool Processing::CheckTimestep()
+{
+ unsigned int ts = m_Eng_Interface->GetNumberOfTimesteps();
+ if (ts<startTS || ts>stopTS)
+ return false;
+ if (m_ProcessSteps.size()>m_PS_pos)
+ {
+ if (m_ProcessSteps.at(m_PS_pos)==ts)
+ {
+ ++m_PS_pos;
+ return true;
+ }
+ }
+ if (ProcessInterval)
+ {
+ if (ts%ProcessInterval==0) return true;
+ }
+
+ if (m_FD_Interval)
+ {
+ if (ts%m_FD_Interval==0) return true;
+ }
+ return false;
+}
+
+int Processing::GetNextInterval() const
+{
+ if (Enabled==false) return -1;
+ int next=INT_MAX;
+ int ts = (int)m_Eng_Interface->GetNumberOfTimesteps();
+ if (m_ProcessSteps.size()>m_PS_pos)
+ {
+ next = (int)m_ProcessSteps.at(m_PS_pos)-ts;
+ }
+ if (ProcessInterval!=0)
+ {
+ int next_Interval = (int)ProcessInterval - ts%ProcessInterval;
+ if (next_Interval<next)
+ next = next_Interval;
+ }
+
+ //check for FD sample interval
+ if (m_FD_Interval!=0)
+ {
+ int next_Interval = (int)m_FD_Interval - ts%m_FD_Interval;
+ if (next_Interval<next)
+ next = next_Interval;
+ }
+
+ return next;
+}
+
+void Processing::AddStep(unsigned int step)
+{
+ if (m_ProcessSteps.size()==0)
+ m_ProcessSteps.push_back(step);
+ else if (find(m_ProcessSteps.begin(), m_ProcessSteps.end(),step)==m_ProcessSteps.end())
+ m_ProcessSteps.push_back(step);
+}
+
+void Processing::AddSteps(vector<unsigned int> steps)
+{
+ for (size_t n=0; n<steps.size(); ++n)
+ {
+ AddStep(steps.at(n));
+ }
+}
+
+void Processing::AddFrequency(double freq)
+{
+ unsigned int nyquistTS = CalcNyquistNum(freq,Op->GetTimestep());
+
+ if (nyquistTS == 0)
+ {
+ cerr << "Processing::AddFrequency: Requested frequency " << freq << " is too high for the current timestep used... skipping..." << endl;
+ return;
+ }
+ else if (nyquistTS<Op->GetNumberOfNyquistTimesteps())
+ {
+ cerr << "Processing::AddFrequency: Warning: Requested frequency " << freq << " is higher than maximum excited frequency..." << endl;
+ }
+
+ if (m_FD_Interval==0)
+ m_FD_Interval = Op->GetNumberOfNyquistTimesteps();
+ if (m_FD_Interval>nyquistTS)
+ m_FD_Interval = nyquistTS;
+
+ m_FD_Samples.push_back(freq);
+}
+
+void Processing::AddFrequency(vector<double> *freqs)
+{
+ for (size_t n=0; n<freqs->size(); ++n)
+ {
+ AddFrequency(freqs->at(n));
+ }
+}
+
+void Processing::DefineStartStopCoord(double* dstart, double* dstop)
+{
+ m_Dimension = Op->SnapBox2Mesh(dstart,dstop,start,stop,m_dualMesh,false,m_SnapMethod, m_start_inside, m_stop_inside);
+ if (m_Dimension<0)
+ {
+ cerr << "Processing::DefineStartStopCoord: Warning in " << m_Name << " (" << GetProcessingName() << ") : Box is outside the field domain!! Disabling" << endl;
+ Enabled = false;
+ return;
+ }
+}
+
+void Processing::ShowSnappedCoords()
+{
+ cerr << m_Name << ": snapped ";
+ if (m_dualMesh)
+ cerr << "dual";
+ else
+ cerr << "primary";
+ cerr << " coords: (" << Op->GetDiscLine( 0, start[0], m_dualMesh ) << ","
+ << Op->GetDiscLine( 1, start[1], m_dualMesh ) << "," << Op->GetDiscLine( 2, start[2], m_dualMesh ) << ") -> ("
+ << Op->GetDiscLine( 0, stop[0], m_dualMesh ) << ","<< Op->GetDiscLine( 1, stop[1], m_dualMesh ) << ","
+ << Op->GetDiscLine( 2, stop[2], m_dualMesh ) << ")";
+ cerr << " [" << start[0] << "," << start[1] << "," << start[2] << "] -> ["
+ << stop[0] << "," << stop[1] << "," << stop[2] << "]" << endl;
+}
+
+void Processing::SetProcessStartStopTime(double start, double stop)
+{
+ double dT = Op->GetTimestep();
+ startTS = 0;
+ stopTS = UINT_MAX;
+ if (start>0)
+ startTS = floor(start/dT);
+ if (stop>0)
+ stopTS = ceil(stop/dT);
+ if (stopTS<=startTS)
+ {
+ cerr << "Processing::SetProcessStartStopTimestep: Invalid start/stop values! Disabling!" << endl;
+ startTS = 0;
+ stopTS = UINT_MAX;
+ }
+}
+
+void Processing::OpenFile( string outfile )
+{
+ if (file.is_open())
+ file.close();
+
+ file.open( outfile.c_str() );
+ if (!file.is_open())
+ cerr << "Can't open file: " << outfile << endl;
+
+ m_filename = outfile;
+}
+
+void Processing::PostProcess()
+{
+ FlushData();
+}
+
+void Processing::DumpBox2File( string vtkfilenameprefix, bool dualMesh ) const
+{
+ string vtkfilename = vtkfilenameprefix + m_filename + ".vtk";
+
+ ofstream file( vtkfilename.c_str() );
+ if (!file.is_open())
+ {
+ cerr << "Processing::DumpBoxes2File(): Can't open file: " << vtkfilename << endl;
+ return;
+ }
+
+ // normalize coordinates
+ double s1[3], s2[3];
+ for (int i=0; i<3; i++)
+ {
+ s1[i] = min(Op->GetDiscLine(i,start[i],dualMesh),Op->GetDiscLine(i,stop[i],dualMesh));
+ s2[i] = max(Op->GetDiscLine(i,start[i],dualMesh),Op->GetDiscLine(i,stop[i],dualMesh));
+ }
+
+ // fix degenerate box/plane -> line (paraview display problem)
+ if (((s1[0] == s2[0]) && (s1[1] == s2[1])) || ((s1[0] == s2[0]) && (s1[2] == s2[2])) || ((s1[2] == s2[2]) && (s1[1] == s2[1])))
+ {
+ // line are not displayed correctly -> enlarge
+ for (int i=0; i<3; i++)
+ {
+ double delta = min( Op->GetEdgeLength( i, start,dualMesh ), Op->GetEdgeLength( i, stop,dualMesh ) ) / Op->GetGridDelta() / 4.0;
+ s1[i] -= delta;
+ s2[i] += delta;
+ }
+ }
+
+ // rescale coordinates
+#ifndef OUTPUT_IN_DRAWINGUNITS
+ double scaling = Op->GetGridDelta();
+ for (int i=0; i<3; i++)
+ {
+ s1[i] *= scaling;
+ s2[i] *= scaling;
+ }
+#endif
+
+ file << "# vtk DataFile Version 2.0" << endl;
+ file << "" << endl;
+ file << "ASCII" << endl;
+ file << "DATASET POLYDATA" << endl;
+
+ file << "POINTS 8 float" << endl;
+ file << s1[0] << " " << s1[1] << " " << s1[2] << endl;
+ file << s2[0] << " " << s1[1] << " " << s1[2] << endl;
+ file << s2[0] << " " << s2[1] << " " << s1[2] << endl;
+ file << s1[0] << " " << s2[1] << " " << s1[2] << endl;
+ file << s1[0] << " " << s1[1] << " " << s2[2] << endl;
+ file << s2[0] << " " << s1[1] << " " << s2[2] << endl;
+ file << s2[0] << " " << s2[1] << " " << s2[2] << endl;
+ file << s1[0] << " " << s2[1] << " " << s2[2] << endl;
+
+ file << "POLYGONS 6 30" << endl;
+ file << "4 0 1 2 3" << endl;
+ file << "4 4 5 6 7" << endl;
+ file << "4 7 6 2 3" << endl;
+ file << "4 4 5 1 0" << endl;
+ file << "4 0 4 7 3" << endl;
+ file << "4 5 6 2 1" << endl;
+
+ file.close();
+}
+
+void ProcessingArray::AddProcessing(Processing* proc)
+{
+ ProcessArray.push_back(proc);
+}
+
+void ProcessingArray::InitAll()
+{
+ for (size_t i=0; i<ProcessArray.size(); ++i)
+ {
+ ProcessArray.at(i)->InitProcess();
+ }
+}
+
+void ProcessingArray::FlushNext()
+{
+ for (size_t i=0; i<ProcessArray.size(); ++i)
+ {
+ ProcessArray.at(i)->FlushNext();
+ }
+}
+
+void ProcessingArray::Reset()
+{
+ for (size_t i=0; i<ProcessArray.size(); ++i)
+ {
+ ProcessArray.at(i)->Reset();
+ }
+}
+
+void ProcessingArray::DeleteAll()
+{
+ for (size_t i=0; i<ProcessArray.size(); ++i)
+ {
+ delete ProcessArray.at(i);
+ }
+ ProcessArray.clear();
+}
+
+void ProcessingArray::PreProcess()
+{
+ for (size_t i=0; i<ProcessArray.size(); ++i) ProcessArray.at(i)->PreProcess();
+}
+
+int ProcessingArray::Process()
+{
+ int nextProcess=maxInterval;
+ //this could be done nicely in parallel??
+ for (size_t i=0; i<ProcessArray.size(); ++i)
+ {
+ int step = ProcessArray.at(i)->Process();
+ if ((step>0) && (step<nextProcess))
+ nextProcess=step;
+ }
+ return nextProcess;
+}
+
+void ProcessingArray::PostProcess()
+{
+ for (size_t i=0; i<ProcessArray.size(); ++i) ProcessArray.at(i)->PostProcess();
+}
+
+void ProcessingArray::DumpBoxes2File( string vtkfilenameprefix ) const
+{
+ for (size_t i=0; i<ProcessArray.size(); ++i)
+ ProcessArray.at(i)->DumpBox2File( vtkfilenameprefix );
+}
diff --git a/openEMS/Common/processing.h b/openEMS/Common/processing.h
new file mode 100644
index 0000000..2042706
--- /dev/null
+++ b/openEMS/Common/processing.h
@@ -0,0 +1,204 @@
+/*
+* Copyright (C) 2010-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 PROCESSING_H
+#define PROCESSING_H
+
+#include <complex>
+typedef std::complex<double> double_complex;
+#define _I double_complex(0.0,1.0)
+
+#include <iostream>
+#include <fstream>
+#include <cmath>
+#include <stdio.h>
+#include <stdlib.h>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include "Common/engine_interface_base.h"
+
+class Operator_Base;
+
+class Processing
+{
+public:
+ virtual ~Processing();
+
+ enum MeshType { CARTESIAN_MESH, CYLINDRICAL_MESH};
+
+ //! Set the interface to the engine. Each processing needs its own engine interface. This class will take ownership and cleanup the interface on deletion!
+ void SetEngineInterface(Engine_Interface_Base* eng_if);
+
+ virtual void SetName(std::string val) {m_Name=val;}
+ virtual void SetName(std::string val, int number);
+ virtual std::string GetName() const {return m_Name;}
+
+ //! Get the name for this processing, will be used in file description.
+ virtual std::string GetProcessingName() const = 0;
+
+ virtual void InitProcess() {};
+ virtual void Reset();
+
+ virtual void DefineStartStopCoord(double* dstart, double* dstop);
+
+ virtual void ShowSnappedCoords();
+
+ void SetProcessInterval(unsigned int interval) {ProcessInterval=std::max((unsigned int)1,interval);}
+ void SetProcessStartStopTime(double start, double stop);
+
+ void AddStep(unsigned int step);
+ void AddSteps(std::vector<unsigned int> steps);
+
+ void AddFrequency(double freq);
+ void AddFrequency(std::vector<double> *freqs);
+
+ bool CheckTimestep();
+
+ //! Process data prior to the simulation run.
+ virtual void PreProcess() {};
+
+ //! Process data during simulation run.
+ virtual int Process() {return GetNextInterval();}
+
+ //! Process data after simulation has finished.
+ virtual void PostProcess();
+
+ //! If disabled, Process() will do nothing...
+ virtual void SetEnable(bool val) {Enabled=val;}
+ //! If disabled, Process() will do nothing...
+ virtual bool GetEnable() const {return Enabled;}
+
+ virtual void SetWeight(double weight) {m_weight=weight;}
+ virtual double GetWeight() {return m_weight;}
+
+ //! Invoke this flag to flush all stored data to disk
+ virtual void FlushNext() {m_Flush = true;}
+ virtual void FlushData() {};
+
+ void SetMeshType(MeshType meshType) {m_Mesh_Type=meshType;}
+
+ //! Set the dump precision
+ void SetPrecision(unsigned int val) {m_precision = val;}
+
+ //! Dump probe geometry to file (will obay main or dual mesh property)
+ virtual void DumpBox2File(std::string vtkfilenameprefix) const {DumpBox2File(vtkfilenameprefix,m_dualMesh);}
+
+ //! Dump probe geometry to file
+ virtual void DumpBox2File(std::string vtkfilenameprefix, bool dualMesh) const;
+
+ virtual void SetDualMesh(bool val) {m_dualMesh=val;}
+ virtual void SetDualTime(bool val) {m_dualTime=val;}
+
+protected:
+ Processing(Engine_Interface_Base* eng_if);
+ Engine_Interface_Base* m_Eng_Interface;
+ const Operator_Base* Op;
+ MeshType m_Mesh_Type;
+
+ unsigned int m_precision;
+
+ std::string m_Name;
+
+ bool m_Flush;
+
+ double m_weight;
+
+ bool Enabled;
+
+ int GetNextInterval() const;
+ unsigned int ProcessInterval;
+
+ size_t m_PS_pos; //! current position in list of processing steps
+ std::vector<unsigned int> m_ProcessSteps; //! list of processing steps
+
+ //! Vector of frequency samples
+ std::vector<double> m_FD_Samples;
+ //! Number of samples already processed
+ unsigned int m_FD_SampleCount;
+ //! Sampling interval needed for the FD_Samples
+ unsigned int m_FD_Interval;
+
+ //! define if given coords are on main or dualMesh (default is false)
+ bool m_dualMesh;
+
+ //! define if given processing uses the dual time concept (default is false);
+ bool m_dualTime;
+
+ //! define the snap method used for this processing
+ int m_SnapMethod;
+
+ //! dimension of the snapped box
+ int m_Dimension;
+
+ //! define/store snapped start/stop coords as mesh index
+ unsigned int start[3];
+ unsigned int stop[3];
+
+ //! start/stop timestep
+ unsigned int startTS, stopTS;
+
+ //! define/store if snapped start/stop coords are inside the field domain
+ bool m_start_inside[3];
+ bool m_stop_inside[3];
+
+ std::ofstream file;
+ std::string m_filename;
+
+ virtual void OpenFile(std::string outfile);
+};
+
+class ProcessingArray
+{
+public:
+ ProcessingArray(unsigned int maximalInterval) {maxInterval=maximalInterval;}
+ ~ProcessingArray() {};
+
+ void AddProcessing(Processing* proc);
+
+ void InitAll();
+
+ //! Invoke this flag to flush all stored data to disk for all processings on next Process()
+ void FlushNext();
+
+ void Reset();
+
+ //! Deletes all given processing's, can be helpful, but use carefull!!!
+ void DeleteAll();
+
+ //! Invoke PreProcess() on all Processings.
+ void PreProcess();
+
+ //! Invoke Process() on all Processings. Will return the smallest next iteration interval.
+ int Process();
+
+ //! Invoke PostProcess() on all Processings.
+ void PostProcess();
+
+ void DumpBoxes2File(std::string vtkfilenameprefix ) const;
+
+ size_t GetNumberOfProcessings() const {return ProcessArray.size();}
+
+ Processing* GetProcessing(size_t number) {return ProcessArray.at(number);}
+
+protected:
+ unsigned int maxInterval;
+ std::vector<Processing*> ProcessArray;
+};
+
+#endif // PROCESSING_H
diff --git a/openEMS/Common/processintegral.cpp b/openEMS/Common/processintegral.cpp
new file mode 100644
index 0000000..b64b479
--- /dev/null
+++ b/openEMS/Common/processintegral.cpp
@@ -0,0 +1,177 @@
+/*
+* 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 "processintegral.h"
+#include "Common/operator_base.h"
+#include "time.h"
+#include <iomanip>
+
+using namespace std;
+
+ProcessIntegral::ProcessIntegral(Engine_Interface_Base* eng_if) : Processing(eng_if)
+{
+ m_Results=NULL;
+ m_FD_Results=NULL;
+ m_normDir = -1;
+}
+
+ProcessIntegral::~ProcessIntegral()
+{
+ delete[] m_Results;
+ delete[] m_FD_Results;
+ m_Results = NULL;
+ m_FD_Results = NULL;
+}
+
+
+void ProcessIntegral::InitProcess()
+{
+ delete[] m_Results; m_Results = NULL;
+ delete[] m_FD_Results; m_FD_Results = NULL;
+
+ if (!Enabled)
+ return;
+
+ m_Results = new double[GetNumberOfIntegrals()];
+ m_FD_Results = new vector<double_complex>[GetNumberOfIntegrals()];
+
+ m_filename = m_Name;
+ OpenFile(m_filename);
+
+ //write header
+ time_t rawTime;
+ time(&rawTime);
+ file << "% time-domain " << GetProcessingName() << " by openEMS " << GIT_VERSION << " @" << ctime(&rawTime);
+ file << "% start-coordinates: ("
+ << Op->GetDiscLine(0,start[0])*Op->GetGridDelta() << ","
+ << Op->GetDiscLine(1,start[1])*Op->GetGridDelta() << ","
+ << Op->GetDiscLine(2,start[2])*Op->GetGridDelta() << ") m -> [" << start[0] << "," << start[1] << "," << start[2] << "]" << endl;
+ file << "% stop-coordinates: ("
+ << Op->GetDiscLine(0,stop[0])*Op->GetGridDelta() << ","
+ << Op->GetDiscLine(1,stop[1])*Op->GetGridDelta() << ","
+ << Op->GetDiscLine(2,stop[2])*Op->GetGridDelta() << ") m -> [" << stop[0] << "," << stop[1] << "," << stop[2] << "]" << endl;
+ file << "% t/s";
+ for (int n=0;n<GetNumberOfIntegrals();++n)
+ {
+ file << "\t" << GetIntegralName(n);
+ }
+ file << endl;
+
+ for (int i=0;i<GetNumberOfIntegrals();++i)
+ {
+ for (size_t n=0; n<m_FD_Samples.size(); ++n)
+ {
+ m_FD_Results[i].push_back(0);
+ }
+ }
+}
+
+void ProcessIntegral::FlushData()
+{
+ if (!Enabled)
+ return;
+ if (m_FD_Samples.size())
+ Dump_FD_Data(1.0,m_filename + "_FD");
+}
+
+
+void ProcessIntegral::Dump_FD_Data(double factor, string filename)
+{
+ if (m_FD_Samples.size()==0)
+ return;
+ ofstream file;
+ file.open( filename.c_str() );
+ if (!file.is_open())
+ cerr << "ProcessIntegral::Dump_FD_Data: Error: Can't open file: " << filename << endl;
+
+ //write header
+ time_t rawTime;
+ time(&rawTime);
+ file << "% frequency-domain " << GetProcessingName() << " by openEMS " << GIT_VERSION << " @" << ctime(&rawTime);
+ file << "% start-coordinates: ("
+ << Op->GetDiscLine(0,start[0])*Op->GetGridDelta() << ","
+ << Op->GetDiscLine(1,start[1])*Op->GetGridDelta() << ","
+ << Op->GetDiscLine(2,start[2])*Op->GetGridDelta() << ") m -> [" << start[0] << "," << start[1] << "," << start[2] << "]" << endl;
+ file << "% stop-coordinates: ("
+ << Op->GetDiscLine(0,stop[0])*Op->GetGridDelta() << ","
+ << Op->GetDiscLine(1,stop[1])*Op->GetGridDelta() << ","
+ << Op->GetDiscLine(2,stop[2])*Op->GetGridDelta() << ") m -> [" << stop[0] << "," << stop[1] << "," << stop[2] << "]" << endl;
+ file << "% f/Hz";
+ for (int n=0;n<GetNumberOfIntegrals();++n)
+ {
+ file << "\t" << GetIntegralName(n) << "\t";
+ }
+ file << endl << "%";
+ for (int i = 0; i < GetNumberOfIntegrals();++i)
+ file << "\treal\timag";
+ file << endl;
+
+ for (size_t n=0; n<m_FD_Samples.size(); ++n)
+ {
+ file << m_FD_Samples.at(n) ;
+ for (int i = 0; i < GetNumberOfIntegrals();++i)
+ file << "\t" << std::real(m_FD_Results[i].at(n))*factor << "\t" << std::imag(m_FD_Results[i].at(n))*factor;
+ file << "\n";
+ }
+
+ file.close();
+}
+
+int ProcessIntegral::Process()
+{
+ if (Enabled==false) return -1;
+ if (CheckTimestep()==false) return GetNextInterval();
+
+ CalcMultipleIntegrals();
+ int NrInt = GetNumberOfIntegrals();
+ double time = m_Eng_Interface->GetTime(m_dualTime);
+
+ if (ProcessInterval)
+ {
+ if (m_Eng_Interface->GetNumberOfTimesteps()%ProcessInterval==0)
+ {
+ file << setprecision(m_precision) << time;
+ for (int n=0; n<NrInt; ++n)
+ file << "\t" << m_Results[n] * m_weight;
+ file << endl;
+ }
+ }
+
+ if (m_FD_Interval)
+ {
+ if (m_Eng_Interface->GetNumberOfTimesteps()%m_FD_Interval==0)
+ {
+ for (size_t n=0; n<m_FD_Samples.size(); ++n)
+ {
+ for (int i=0; i<NrInt; ++i)
+ m_FD_Results[i].at(n) += (double)m_Results[i] * m_weight * std::exp( -2.0 * _I * M_PI * m_FD_Samples.at(n) * time ) * 2.0 * Op->GetTimestep() * (double)m_FD_Interval;
+ }
+ ++m_FD_SampleCount;
+ if (m_Flush)
+ FlushData();
+ m_Flush = false;
+ }
+ }
+
+ return GetNextInterval();
+}
+
+double* ProcessIntegral::CalcMultipleIntegrals()
+{
+ m_Results[0] = CalcIntegral();
+ return m_Results;
+}
diff --git a/openEMS/Common/processintegral.h b/openEMS/Common/processintegral.h
new file mode 100644
index 0000000..1bddfd6
--- /dev/null
+++ b/openEMS/Common/processintegral.h
@@ -0,0 +1,71 @@
+/*
+* 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 PROCESSINTEGRAL_H
+#define PROCESSINTEGRAL_H
+
+#include "processing.h"
+
+//! Abstract base class for integral parameter processing
+/*!
+ \todo Weighting is applied equally to all integral parameter --> todo: weighting for each result individually
+ */
+class ProcessIntegral : public Processing
+{
+public:
+ virtual ~ProcessIntegral();
+
+ virtual void InitProcess();
+
+ virtual std::string GetProcessingName() const = 0;
+
+ virtual void GetNormalDir(int nd) {m_normDir=nd;}
+
+ //! Flush FD data to disk
+ virtual void FlushData();
+
+ //! This method can calculate multiple integral parameter and must be overloaded for each derived class. \sa GetNumberOfIntegrals
+ /*!
+ This method will store its integral results internally with a size given by GetNumberOfIntegrals()
+ It will return the result for the CalcIntegral() as default.
+ */
+ virtual double* CalcMultipleIntegrals();
+
+ //! Get the name of the integral for the given row. The names will be used in the file header.
+ virtual std::string GetIntegralName(int row) const = 0;
+
+ //! Number of calculated results produced by this integral processing. \sa CalcMultipleIntegrals
+ virtual int GetNumberOfIntegrals() const {return 1;}
+
+ //! This method should calculate the integral parameter and must be overloaded for each derived class
+ virtual double CalcIntegral() {return 0;}
+
+ //! This method will write the TD and FD dump files using CalcIntegral() to calculate the integral parameter
+ virtual int Process();
+
+protected:
+ ProcessIntegral(Engine_Interface_Base* eng_if);
+
+ void Dump_FD_Data(double factor, std::string filename);
+
+ std::vector<double_complex> *m_FD_Results;
+ double *m_Results;
+
+ int m_normDir; // normal direction as required by some integral processings
+};
+
+#endif // PROCESSINTEGRAL_H
diff --git a/openEMS/Common/processmodematch.cpp b/openEMS/Common/processmodematch.cpp
new file mode 100644
index 0000000..9c71c7a
--- /dev/null
+++ b/openEMS/Common/processmodematch.cpp
@@ -0,0 +1,265 @@
+/*
+* 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 "processmodematch.h"
+#include "CSFunctionParser.h"
+#include "Common/operator_base.h"
+#include "tools/array_ops.h"
+
+using namespace std;
+
+ProcessModeMatch::ProcessModeMatch(Engine_Interface_Base* eng_if) : ProcessIntegral(eng_if)
+{
+ for (int n=0; n<2; ++n)
+ {
+ m_ModeParser[n] = new CSFunctionParser();
+ m_ModeDist[n] = NULL;
+ }
+ delete[] m_Results;
+ m_Results = new double[2];
+}
+
+ProcessModeMatch::~ProcessModeMatch()
+{
+ for (int n=0; n<2; ++n)
+ {
+ delete m_ModeParser[n];
+ m_ModeParser[n] = NULL;
+ }
+ Reset();
+}
+
+string ProcessModeMatch::GetIntegralName(int row) const
+{
+ if (row==0)
+ {
+ if (m_ModeFieldType==0)
+ return "voltage";
+ if (m_ModeFieldType==1)
+ return "current";
+ }
+ if (row==1)
+ {
+ return "mode_purity";
+ }
+ return "unknown";
+}
+
+string ProcessModeMatch::GetProcessingName() const
+{
+ if (m_ModeFieldType==0)
+ return "voltage mode matching";
+ if (m_ModeFieldType==1)
+ return "current mode matching";
+ return "unknown mode matching";
+}
+
+void ProcessModeMatch::InitProcess()
+{
+ if (!Enabled) return;
+
+ if (m_Eng_Interface==NULL)
+ {
+ cerr << "ProcessModeMatch::InitProcess: Error, Engine_Interface is NULL, abort mode mathcing..." << endl;
+ Enabled=false;
+ return;
+ }
+ m_Eng_Interface->SetInterpolationType(Engine_Interface_Base::NODE_INTERPOLATE);
+
+ int Dump_Dim=0;
+ m_ny = -1;
+ for (int n=0; n<3; ++n)
+ {
+ if (start[n]>stop[n])
+ {
+ unsigned int help=start[n];
+ start[n]=stop[n];
+ stop[n]=help;
+ }
+
+ //exclude boundaries from mode-matching
+ if (start[n]==0)
+ ++start[n];
+ if (stop[n]==Op->GetNumberOfLines(n)-1)
+ --stop[n];
+
+ if (stop[n]!=start[n])
+ ++Dump_Dim;
+
+ if (stop[n] == start[n])
+ m_ny = n;
+ }
+
+ if ((Dump_Dim!=2) || (m_ny<0))
+ {
+ cerr << "ProcessModeMatch::InitProcess(): Warning Mode Matching Integration Box \"" << m_filename << "\" is not a surface (found dimension: " << Dump_Dim << ")" << endl;
+ SetEnable(false);
+ Reset();
+ return;
+ }
+
+ int nP = (m_ny+1)%3;
+ int nPP = (m_ny+2)%3;
+ m_numLines[0] = stop[nP] - start[nP] + 1;
+ m_numLines[1] = stop[nPP] - start[nPP] + 1;
+
+ for (int n=0; n<2; ++n)
+ {
+ int ny = (m_ny+n+1)%3;
+ int res = m_ModeParser[n]->Parse(m_ModeFunction[ny], "x,y,z,rho,a,r,t");
+ if (res >= 0)
+ {
+ cerr << "ProcessModeMatch::InitProcess(): Warning, an error occured parsing the mode matching function (see below) ..." << endl;
+ cerr << m_ModeFunction[ny] << "\n" << string(res, ' ') << "^\n" << m_ModeParser[n]->ErrorMsg() << "\n";
+ SetEnable(false);
+ Reset();
+ }
+ }
+
+ for (int n=0; n<2; ++n)
+ {
+ m_ModeDist[n] = Create2DArray<double>(m_numLines);
+ }
+
+ unsigned int pos[3] = {0,0,0};
+ double discLine[3] = {0,0,0};
+ double gridDelta = 1; // 1 -> mode-matching function is definied in drawing units...
+ double var[7];
+ pos[m_ny] = start[m_ny];
+ discLine[m_ny] = Op->GetDiscLine(m_ny,pos[m_ny],m_dualMesh);
+ double norm = 0;
+ double area = 0;
+ for (unsigned int posP = 0; posP<m_numLines[0]; ++posP)
+ {
+ pos[nP] = start[nP] + posP;
+ discLine[nP] = Op->GetDiscLine(nP,pos[nP],m_dualMesh);
+ for (unsigned int posPP = 0; posPP<m_numLines[1]; ++posPP)
+ {
+ pos[nPP] = start[nPP] + posPP;
+ discLine[nPP] = Op->GetDiscLine(nPP,pos[nPP],m_dualMesh);
+
+ var[0] = discLine[0] * gridDelta; // x
+ var[1] = discLine[1] * gridDelta; // y
+ var[2] = discLine[2] * gridDelta; // z
+ var[3] = sqrt(discLine[0]*discLine[0] + discLine[1]*discLine[1]) * gridDelta; // rho = sqrt(x^2 + y^2)
+ var[4] = atan2(discLine[1], discLine[0]); // a = atan(y,x)
+ var[5] = sqrt(pow(discLine[0],2)+pow(discLine[1],2)+pow(discLine[2],2)) * gridDelta; // r
+ var[6] = asin(1)-atan(var[2]/var[3]); //theta (t)
+
+ if (m_Mesh_Type == CYLINDRICAL_MESH)
+ {
+ var[3] = discLine[0] * gridDelta; // rho
+ var[4] = discLine[1]; // a
+ var[0] = discLine[0] * cos(discLine[1]) * gridDelta; // x = r*cos(a)
+ var[1] = discLine[0] * sin(discLine[1]) * gridDelta; // y = r*sin(a)
+ var[5] = sqrt(pow(discLine[0],2)+pow(discLine[2],2)) * gridDelta; // r
+ var[6] = asin(1)-atan(var[2]/var[3]); //theta (t)
+ }
+ area = Op->GetNodeArea(m_ny,pos,m_dualMesh);
+ for (int n=0; n<2; ++n)
+ {
+ m_ModeDist[n][posP][posPP] = m_ModeParser[n]->Eval(var); //calc mode template
+ if ((isnan(m_ModeDist[n][posP][posPP])) || (isinf(m_ModeDist[n][posP][posPP])))
+ m_ModeDist[n][posP][posPP] = 0.0;
+ norm += pow(m_ModeDist[n][posP][posPP],2) * area;
+ }
+// cerr << discLine[0] << " " << discLine[1] << " : " << m_ModeDist[0][posP][posPP] << " , " << m_ModeDist[1][posP][posPP] << endl;
+ }
+ }
+
+ norm = sqrt(norm);
+// cerr << norm << endl;
+ // normalize template function...
+ for (unsigned int posP = 0; posP<m_numLines[0]; ++posP)
+ for (unsigned int posPP = 0; posPP<m_numLines[1]; ++posPP)
+ {
+ for (int n=0; n<2; ++n)
+ {
+ m_ModeDist[n][posP][posPP] /= norm;
+ }
+// cerr << posP << " " << posPP << " : " << m_ModeDist[0][posP][posPP] << " , " << m_ModeDist[1][posP][posPP] << endl;
+ }
+
+ ProcessIntegral::InitProcess();
+}
+
+void ProcessModeMatch::Reset()
+{
+ ProcessIntegral::Reset();
+ for (int n=0; n<2; ++n)
+ {
+ Delete2DArray<double>(m_ModeDist[n],m_numLines);
+ m_ModeDist[n] = NULL;
+ }
+}
+
+
+void ProcessModeMatch::SetModeFunction(int ny, string function)
+{
+ if ((ny<0) || (ny>2)) return;
+ m_ModeFunction[ny] = function;
+}
+
+void ProcessModeMatch::SetFieldType(int type)
+{
+ m_ModeFieldType = type;
+ if ((type<0) || (type>1))
+ cerr << "ProcessModeMatch::SetFieldType: Warning, unknown field type..." << endl;
+}
+
+double* ProcessModeMatch::CalcMultipleIntegrals()
+{
+ double value = 0;
+ double field = 0;
+ double purity = 0;
+ double area = 0;
+
+ int nP = (m_ny+1)%3;
+ int nPP = (m_ny+2)%3;
+
+ unsigned int pos[3] = {0,0,0};
+ pos[m_ny] = start[m_ny];
+
+ double out[3]={0,0,0};
+
+ for (unsigned int posP = 0; posP<m_numLines[0]; ++posP)
+ {
+ pos[nP] = start[nP] + posP;
+ for (unsigned int posPP = 0; posPP<m_numLines[1]; ++posPP)
+ {
+ pos[nPP] = start[nPP] + posPP;
+ area = Op->GetNodeArea(m_ny,pos,m_dualMesh);
+ if (m_ModeFieldType==0)
+ m_Eng_Interface->GetEField(pos,out);
+ if (m_ModeFieldType==1)
+ m_Eng_Interface->GetHField(pos,out);
+
+ for (int n=0; n<2; ++n)
+ {
+ field = out[(m_ny+n+1)%3];
+ value += field * m_ModeDist[n][posP][posPP] * area;
+ purity += field*field * area;
+ }
+ }
+ }
+ if (purity!=0)
+ m_Results[1] = value*value/purity;
+ else
+ m_Results[1] = 0;
+ m_Results[0] = value;
+ return m_Results;
+}
diff --git a/openEMS/Common/processmodematch.h b/openEMS/Common/processmodematch.h
new file mode 100644
index 0000000..0bb03b7
--- /dev/null
+++ b/openEMS/Common/processmodematch.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 PROCESSMODEMATCH_H
+#define PROCESSMODEMATCH_H
+
+#include "processintegral.h"
+
+class CSFunctionParser;
+
+//! Processing class to match a mode to a given analytic function and return the integral value.
+/*!
+ The analytric function has to be definied in drawing units.
+ It will return the integral value and the mode purity as a secondary value.
+ */
+class ProcessModeMatch : public ProcessIntegral
+{
+public:
+ ProcessModeMatch(Engine_Interface_Base* eng_if);
+ virtual ~ProcessModeMatch();
+
+ virtual std::string GetProcessingName() const;
+
+ virtual std::string GetIntegralName(int row) const;
+
+ virtual void InitProcess();
+ virtual void Reset();
+
+ //! Set the field type (0 electric field, 1 magnetic field)
+ void SetFieldType(int type);
+ //! Set the mode function in the given direction ny. For example: SetModeFunction(0,"cos(pi/1000*x)*sin(pi/500*y)");
+ void SetModeFunction(int ny, std::string function);
+
+ virtual int GetNumberOfIntegrals() const {return 2;}
+ virtual double* CalcMultipleIntegrals();
+
+protected:
+ //normal direction of the mode plane
+ int m_ny;
+
+ int m_ModeFieldType;
+
+ double GetField(int ny, const unsigned int pos[3]);
+ double GetEField(int ny, const unsigned int pos[3]);
+ double GetHField(int ny, const unsigned int pos[3]);
+
+ std::string m_ModeFunction[3];
+ CSFunctionParser* m_ModeParser[2];
+
+ unsigned int m_numLines[2];
+ double** m_ModeDist[2];
+};
+
+#endif // PROCESSMODEMATCH_H
diff --git a/openEMS/Common/processvoltage.cpp b/openEMS/Common/processvoltage.cpp
new file mode 100644
index 0000000..6875b03
--- /dev/null
+++ b/openEMS/Common/processvoltage.cpp
@@ -0,0 +1,40 @@
+/*
+* 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 "processvoltage.h"
+#include <iomanip>
+
+ProcessVoltage::ProcessVoltage(Engine_Interface_Base* eng_if) : ProcessIntegral(eng_if)
+{
+}
+
+ProcessVoltage::~ProcessVoltage()
+{
+}
+
+std::string ProcessVoltage::GetIntegralName(int row) const
+{
+ if (row==0)
+ return "voltage";
+ return "unknown";
+}
+
+double ProcessVoltage::CalcIntegral()
+{
+ //integrate voltages from start to stop on a line
+ return m_Eng_Interface->CalcVoltageIntegral(start,stop);
+}
diff --git a/openEMS/Common/processvoltage.h b/openEMS/Common/processvoltage.h
new file mode 100644
index 0000000..509ddbf
--- /dev/null
+++ b/openEMS/Common/processvoltage.h
@@ -0,0 +1,39 @@
+/*
+* 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 PROCESSVOLTAGE_H
+#define PROCESSVOLTAGE_H
+
+#include "processintegral.h"
+
+//! Process voltage along a line from start to stop coordinates. ATM integration along the axis e.g.: in x, then y then z direction (Future: diagonal integration)
+class ProcessVoltage : public ProcessIntegral
+{
+public:
+ ProcessVoltage(Engine_Interface_Base* eng_if);
+ virtual ~ProcessVoltage();
+
+ virtual std::string GetProcessingName() const {return "voltage integration";}
+
+ virtual std::string GetIntegralName(int row) const;
+
+ virtual double CalcIntegral();
+
+protected:
+};
+
+#endif // PROCESSVOLTAGE_H
diff --git a/openEMS/Common/readme.txt b/openEMS/Common/readme.txt
new file mode 100644
index 0000000..8c62be8
--- /dev/null
+++ b/openEMS/Common/readme.txt
@@ -0,0 +1,6 @@
+readme for openEMS/Common
+
+- This folder contains all classes common for all numerical solver included in openEMS (currently only EC-FDTD)
+ - Operator-Base class
+ - Engine-Interface classes
+ - Common processing classes