diff options
author | Ruben Undheim <ruben.undheim@gmail.com> | 2016-07-05 18:02:38 +0200 |
---|---|---|
committer | Ruben Undheim <ruben.undheim@gmail.com> | 2016-07-05 18:02:38 +0200 |
commit | ef962f6008f25ab7cbd4ca21bcc72b97a1e2d76f (patch) | |
tree | 8149bee93d1a3f91d4503bfb3853adac4af0a85e /openEMS/Common |
Imported Upstream version 0.0.34
Diffstat (limited to 'openEMS/Common')
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 |