diff options
Diffstat (limited to 'openEMS/tools')
-rw-r--r-- | openEMS/tools/AdrOp.cpp | 554 | ||||
-rw-r--r-- | openEMS/tools/AdrOp.h | 149 | ||||
-rw-r--r-- | openEMS/tools/CMakeLists.txt | 28 | ||||
-rw-r--r-- | openEMS/tools/ErrorMsg.cpp | 98 | ||||
-rw-r--r-- | openEMS/tools/ErrorMsg.h | 50 | ||||
-rw-r--r-- | openEMS/tools/ExpenseLog.cpp | 145 | ||||
-rw-r--r-- | openEMS/tools/ExpenseLog.h | 92 | ||||
-rw-r--r-- | openEMS/tools/aligned_allocator.h | 173 | ||||
-rw-r--r-- | openEMS/tools/array_ops.cpp | 144 | ||||
-rw-r--r-- | openEMS/tools/array_ops.h | 196 | ||||
-rw-r--r-- | openEMS/tools/constants.h | 29 | ||||
-rw-r--r-- | openEMS/tools/global.cpp | 78 | ||||
-rw-r--r-- | openEMS/tools/global.h | 65 | ||||
-rw-r--r-- | openEMS/tools/hdf5_file_reader.cpp | 689 | ||||
-rw-r--r-- | openEMS/tools/hdf5_file_reader.h | 78 | ||||
-rw-r--r-- | openEMS/tools/hdf5_file_writer.cpp | 515 | ||||
-rw-r--r-- | openEMS/tools/hdf5_file_writer.h | 68 | ||||
-rw-r--r-- | openEMS/tools/sar_calculation.cpp | 656 | ||||
-rw-r--r-- | openEMS/tools/sar_calculation.h | 122 | ||||
-rw-r--r-- | openEMS/tools/useful.cpp | 185 | ||||
-rw-r--r-- | openEMS/tools/useful.h | 44 | ||||
-rw-r--r-- | openEMS/tools/vtk_file_writer.cpp | 340 | ||||
-rw-r--r-- | openEMS/tools/vtk_file_writer.h | 94 |
23 files changed, 4592 insertions, 0 deletions
diff --git a/openEMS/tools/AdrOp.cpp b/openEMS/tools/AdrOp.cpp new file mode 100644 index 0000000..228f8de --- /dev/null +++ b/openEMS/tools/AdrOp.cpp @@ -0,0 +1,554 @@ +/*
+* 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 "AdrOp.h"
+
+using namespace std;
+
+AdrOp::AdrOp(unsigned int muiImax, unsigned int muiJmax, unsigned int muiKmax, unsigned int muiLmax)
+{
+ //error-handling...
+ error = new ErrorMsg(9);
+ if (error==NULL)
+ {
+ fprintf(stderr,"Memory allocation failed!! exiting...");
+ exit(1);
+ }
+ error->SetMsg(1,"Adress Operator: Memory allocation failed!! exiting...");
+ error->SetMsg(2,"Adress Operator: Invalid Adress requested!! exiting...");
+ error->SetMsg(3,"Adress Operator: Invalid Position set!! exiting...");
+ error->SetMsg(4,"Adress Operator: Invalid jump or passing end of iteration!! exiting...");
+ error->SetMsg(5,"Adress Operator: 4D not yet implemented!! exiting...");
+ error->SetMsg(6,"Adress Operator: Position not set!! exiting...");
+ error->SetMsg(7,"Adress Operator: Cells not added to Adress Operator!! exiting...");
+ error->SetMsg(8,"Adress Operator: Invalid Node!! exiting...");
+ error->SetMsg(9,"Adress Operator: Grid invalid!! exiting...");
+
+ //if (muiImax<0) muiImax=0;
+ //if (muiJmax<0) muiJmax=0;
+ //if (muiKmax<0) muiKmax=0;
+ //if (muiLmax<0) muiLmax=0;
+
+ uiDimension=0;
+ if (muiImax>0) uiDimension++;
+ else exit(-1);
+ if (muiJmax>0) uiDimension++;
+ else exit(-2);
+ if (muiKmax>0) uiDimension++;
+ if ( (muiLmax>0) && (muiKmax>0) ) uiDimension++;
+// cout << "\n-----Adress Operator created: Dimension: " << uiDimension << "----" <<endl;
+ uiImax=muiImax;
+ uiJmax=muiJmax;
+ uiKmax=muiKmax;
+ uiLmax=muiLmax=0;
+ if (uiDimension==2) uiSize=uiImax*uiJmax;
+ else if (uiDimension==3) uiSize=uiImax*uiJmax*uiKmax;
+ else if (uiDimension==4) uiSize=uiImax*uiJmax*uiKmax*uiLmax;
+ else uiSize=0;
+ bPosSet=false;
+ if (uiDimension==4) error->Error(5);
+ iIshift=iJshift=iKshift=0;
+ reflect=false;
+ uiTypeOffset=0;
+ clCellAdr=NULL;
+ dGrid[0]=NULL;
+ dGrid[1]=NULL;
+ dGrid[2]=NULL;
+ dGrid[3]=NULL;
+ dDeltaUnit=1;
+ bDebug=false;
+}
+
+AdrOp::AdrOp(AdrOp* origOP)
+{
+ clCellAdr=NULL;
+ error=NULL; // has to be done!!!
+
+ uiDimension=origOP->uiDimension;
+ uiSize=origOP->uiSize;
+ uiImax=origOP->uiImax;
+ uiJmax=origOP->uiJmax;
+ uiKmax=origOP->uiKmax;
+ uiLmax=origOP->uiLmax;
+ uiIpos=origOP->uiIpos;
+ uiJpos=origOP->uiJpos;
+ uiKpos=origOP->uiKpos;
+ uiLpos=origOP->uiLpos;
+ for (int ii=0; ii<4; ++ii) dGrid[ii]=origOP->dGrid[ii];
+ dDeltaUnit=origOP->dDeltaUnit;
+ iIshift=origOP->iIshift;
+ iJshift=origOP->iJshift;
+ iKshift=origOP->iKshift;
+ for (int ii=0; ii<3; ++ii) iCellShift[ii]=origOP->iCellShift[ii];
+ i=origOP->i;
+ j=origOP->j;
+ k=origOP->k;
+ l=origOP->l;
+ reflect=origOP->reflect;
+ uiTypeOffset=origOP->uiTypeOffset;
+
+ bPosSet=origOP->bPosSet;
+ bDebug=origOP->bDebug;
+// return;
+ if (origOP->clCellAdr!=NULL) clCellAdr= new AdrOp(origOP->clCellAdr);
+}
+
+AdrOp::~AdrOp()
+{
+// cerr << "\n------Adress Operator deconstructed-----\n" << endl;
+ delete error;
+ error=NULL;
+ delete clCellAdr;
+ clCellAdr=NULL;
+}
+
+unsigned int AdrOp::SetPos(unsigned int muiIpos, unsigned int muiJpos, unsigned int muiKpos, unsigned int muiLpos)
+{
+ if (bDebug) fprintf(stderr,"AdrOp Debug:: SetPos(%d,%d,%d,%d) Max(%d,%d,%d,%d) \n",muiIpos,muiJpos,muiKpos,muiLpos,uiImax,uiJmax,uiKmax,uiLmax);
+ bPosSet=false;
+ if (muiIpos<uiImax) uiIpos=muiIpos;
+ else error->Error(3);
+ if (muiJpos<uiJmax) uiJpos=muiJpos;
+ else error->Error(3);
+ if ((muiKpos>=uiKmax) && (uiDimension>2)) error->Error(3);
+ else if (uiDimension>2) uiKpos=muiKpos;
+ if ((muiLpos>=uiLmax) && (uiDimension>3)) error->Error(3);
+ else if (uiDimension>3) uiLpos=muiLpos;
+ bPosSet=true;
+// cerr << "Position i:" << uiIpos << " j: " << uiJpos << " k: " << uiKpos << " l: " << 0 << " MAX: i:" << uiImax << " j: " << uiJmax << " k: " << uiKmax << endl; //debug
+ ADRESSEXPENSE(0,0,0,0,uiDimension+1,18)
+ return GetPos();
+}
+
+bool AdrOp::SetPosChecked(unsigned int muiIpos, unsigned int muiJpos, unsigned int muiKpos, unsigned int muiLpos)
+{
+ bPosSet=true;
+ if (muiIpos<uiImax) uiIpos=muiIpos;
+ else bPosSet=false;
+ if (muiJpos<uiJmax) uiJpos=muiJpos;
+ else bPosSet=false;
+ if ((muiKpos>=uiKmax) && (uiDimension>2)) bPosSet=false;
+ else if (uiDimension>2) uiKpos=muiKpos;
+ if ((muiLpos>=uiLmax) && (uiDimension>3)) bPosSet=false;
+ else if (uiDimension>3) uiLpos=muiLpos;
+ ADRESSEXPENSE(0,0,0,0,uiDimension+1,18)
+ return bPosSet;
+}
+
+void AdrOp::SetGrid(double *gridI,double *gridJ,double *gridK,double *gridL)
+{
+ dGrid[0]=gridI;
+ dGrid[1]=gridJ;
+ dGrid[2]=gridK;
+ dGrid[3]=gridL;
+ ADRESSEXPENSE(0,0,0,0,4,0)
+}
+
+bool AdrOp::CheckPos(unsigned int muiIpos, unsigned int muiJpos, unsigned int muiKpos, unsigned int muiLpos)
+{
+ bPosSet=true;
+ if ((muiIpos>=uiImax)) bPosSet=false;
+ if ((muiJpos>=uiJmax)) bPosSet=false;
+ if ((muiKpos>=uiKmax) && (uiDimension>2)) bPosSet=false;
+ if ((muiLpos>=uiLmax) && (uiDimension>3)) bPosSet=false;
+ ADRESSEXPENSE(0,0,0,0,uiDimension+1,18)
+ return bPosSet;
+}
+
+bool AdrOp::CheckRelativePos(int muiIrel,int muiJrel,int muiKrel, int muiLrel)
+{
+ bPosSet=true;
+ if ((muiIrel+(int)uiIpos<0) || (muiIrel+(int)uiIpos>=(int)uiImax)) bPosSet=false;
+ if ((muiJrel+(int)uiJpos<0) || (muiJrel+(int)uiJpos>=(int)uiJmax)) bPosSet=false;
+ if (((muiKrel+(int)uiKpos<0) || (muiKrel+(int)uiKpos>=(int)uiKmax)) && (uiDimension>2)) bPosSet=false;
+ if (((muiLrel+(int)uiLpos<0) || (muiLrel+(int)uiLpos>=(int)uiLmax)) && (uiDimension>3)) bPosSet=false;
+ ADRESSEXPENSE(2*uiDimension,0,0,0,uiDimension+1,18)
+ return bPosSet;
+}
+
+unsigned int AdrOp::GetPos(int muiIrel, int muiJrel, int muiKrel, int /*muiLrel*/)
+{
+ if (bPosSet==false) error->Error(6);
+ if (reflect)
+ {
+#if EXPENSE_LOG==1
+ if (muiIrel+(int)uiIpos<0) ADRESSEXPENSE(2,1,0,0,1,0)
+ if (muiIrel+(int)uiIpos>(int)uiImax-1) ADRESSEXPENSE(4,1,0,0,1,0)
+ if (muiJrel+(int)uiJpos<0) ADRESSEXPENSE(2,1,0,0,1,0)
+ if (muiJrel+(int)uiJpos>(int)uiJmax-1) ADRESSEXPENSE(4,1,0,0,1,0)
+ if (muiKrel+(int)uiKpos<0) ADRESSEXPENSE(2,1,0,0,1,0)
+ if (muiKrel+(int)uiKpos>(int)uiKmax-1) ADRESSEXPENSE(4,1,0,0,1,0)
+#endif
+
+ if (muiIrel+(int)uiIpos<0) muiIrel=-2*uiIpos-muiIrel-uiTypeOffset;
+ if (muiIrel+(int)uiIpos>(int)uiImax-1) muiIrel=2*(uiImax-1-uiIpos)-muiIrel+uiTypeOffset;
+ if (muiJrel+(int)uiJpos<0) muiJrel=-2*uiJpos-muiJrel-uiTypeOffset;
+ if (muiJrel+(int)uiJpos>(int)uiJmax-1) muiJrel=2*(uiJmax-1-uiJpos)-muiJrel+uiTypeOffset;
+ if (muiKrel+(int)uiKpos<0) muiKrel=-2*uiKpos-muiKrel-uiTypeOffset;
+ if (muiKrel+(int)uiKpos>(int)uiKmax-1) muiKrel=2*(uiKmax-1-uiKpos)-muiKrel+uiTypeOffset;
+ }
+ if (uiDimension==2)
+ {
+ ADRESSEXPENSE(7,1,0,0,0,7)
+ if ( (muiIrel+uiIpos<uiImax) && (muiJrel+uiJpos<uiJmax) )
+ return (muiIrel+uiIpos)+(muiJrel+uiJpos)*uiImax;
+ else error->Error(2);
+ return 0;
+ }
+ else if (uiDimension==3)
+ {
+ ADRESSEXPENSE(9,3,0,0,0,11)
+ if ( (muiIrel+uiIpos<uiImax) && (muiJrel+uiJpos<uiJmax) && (muiKrel+uiKpos<uiKmax) )
+ return (muiIrel+uiIpos) + (muiJrel+uiJpos)*uiImax + (muiKrel+uiKpos)*uiJmax*uiImax;
+ else error->Error(2);
+ return 0;
+ }
+ else return 0;
+}
+
+unsigned int AdrOp::GetPosFromNode(int ny, unsigned int uiNode)
+{
+ while (ny<0) ny+=uiDimension;
+ ny=ny%uiDimension;
+ unsigned int help=uiNode,i=0,j=0,k=0,l=0;
+ i=help%uiImax;
+ help=help/uiImax;
+ j=help%uiJmax;
+ help=help/uiJmax;
+ if (uiKmax>0)
+ {
+ k=help%uiKmax;
+ help=help/uiKmax;
+ l=help;
+ }
+ if (!CheckPos(i,j,k,l)) error->Error(8);
+ ADRESSEXPENSE(0,7,0,0,13,4)
+ switch (ny)
+ {
+ case 0:
+ {
+ return i;
+ break;
+ }
+ case 1:
+ {
+ return j;
+ break;
+ }
+ case 2:
+ {
+ return k;
+ break;
+ }
+ case 3:
+ {
+ return l;
+ break;
+ }
+ }
+ return 0;
+}
+
+double AdrOp::GetNodeVolume(unsigned int uiNode)
+{
+ for (unsigned int n=0; n<uiDimension; n++) if (dGrid[n]==NULL) error->Error(9);
+ double dVol=1;
+ unsigned int uiMax[4]={uiImax,uiJmax,uiKmax,uiLmax};
+ unsigned int uiPos[4]={GetPosFromNode(0,uiNode),GetPosFromNode(1,uiNode),GetPosFromNode(2,uiNode),GetPosFromNode(3,uiNode)};
+ for (unsigned int n=0; n<uiDimension; n++)
+ {
+ if ((uiPos[n]>0) && (uiPos[n]<uiMax[n]-1))
+ {
+ dVol*=0.5*dDeltaUnit*(dGrid[n][uiPos[n]+1]-dGrid[n][uiPos[n]-1]);
+ ADRESSEXPENSE(4,0,1,3,0,4)
+ }
+ else if ((uiPos[n]==0) && (uiPos[n]<uiMax[n]-1))
+ {
+ dVol*=dDeltaUnit*(dGrid[n][uiPos[n]+1]-dGrid[n][uiPos[n]]);
+ ADRESSEXPENSE(3,0,1,2,0,4)
+ }
+ else if ((uiPos[n]>0) && (uiPos[n]==uiMax[n]-1))
+ {
+ dVol*=dDeltaUnit*(dGrid[n][uiPos[n]]-dGrid[n][uiPos[n]-1]);
+ ADRESSEXPENSE(3,0,1,2,0,4)
+ }
+ }
+ return dVol;
+}
+
+double AdrOp::GetIndexWidth(int ny, int index)
+{
+ for (unsigned int n=0; n<uiDimension; n++) if (dGrid[n]==NULL) error->Error(9);
+ double width=0;
+ while (ny<0) ny+=uiDimension;
+ ny=ny%uiDimension;
+ unsigned int uiMax[4]={uiImax,uiJmax,uiKmax,uiLmax};
+ if ((index>0) && (index<(int)uiMax[ny]-1)) width= (dGrid[ny][index+1]-dGrid[ny][index-1])/2*dDeltaUnit;
+ else if ((index==0) && (index<(int)uiMax[ny]-1)) width=(dGrid[ny][index+1]-dGrid[ny][index])*dDeltaUnit;
+ else if ((index>0) && (index==(int)uiMax[ny]-1)) width=(dGrid[ny][index]-dGrid[ny][index-1])*dDeltaUnit;
+ else width= 0;
+ return width;
+}
+
+double AdrOp::GetIndexCoord(int ny, int index)
+{
+ for (unsigned int n=0; n<uiDimension; n++) if (dGrid[n]==NULL) error->Error(9);
+ while (ny<0) ny+=uiDimension;
+ ny=ny%uiDimension;
+ unsigned int uiMax[4]={uiImax,uiJmax,uiKmax,uiLmax};
+ if (index<0) index=0;
+ if (index>=(int)uiMax[ny]) index=uiMax[ny]-1;
+ return dGrid[ny][index]*dDeltaUnit;
+}
+
+double AdrOp::GetIndexDelta(int ny, int index)
+{
+ if (index<0) return GetIndexCoord(ny, 0) - GetIndexCoord(ny, 1);
+ unsigned int uiMax[4]={uiImax,uiJmax,uiKmax,uiLmax};
+ if (index>=(int)uiMax[ny]-1) return GetIndexCoord(ny, (int)uiMax[ny]-2) - GetIndexCoord(ny, (int)uiMax[ny]-1);
+ return GetIndexCoord(ny, index+1) - GetIndexCoord(ny, index);
+}
+
+
+unsigned int AdrOp::Shift(int ny, int step)
+{
+ if (bPosSet==false) error->Error(6);
+ while (ny<0) ny+=uiDimension;
+ ny=ny%uiDimension;
+ switch (ny)
+ {
+ case 0:
+ {
+ iIshift=step;
+// if ((int)uiIpos+step<0) iIshift=-2*uiIpos-iIshift;
+// else if ((int)uiIpos+step>=(int)uiImax) iIshift=-1*iIshift+2*(uiImax-1-uiIpos);
+ break;
+ }
+ case 1:
+ {
+ iJshift=step;
+// if ((int)uiJpos+iJshift<0) iJshift=-2*uiJpos-iJshift;
+// else if ((int)uiJpos+iJshift>=(int)uiJmax) iJshift=-1*iJshift+2*(uiJmax-1-uiJpos);
+ break;
+ }
+ case 2:
+ {
+ iKshift=step;
+// if ((int)uiKpos+iKshift<0) iKshift=-2*uiKpos-iKshift;
+// else if ((int)uiKpos+iKshift>=(int)uiKmax) iKshift=-1*iKshift+2*(uiKmax-1-uiKpos);
+ break;
+ }
+ }
+ ADRESSEXPENSE(1,1,0,0,2,3)
+ return GetPos(iIshift,iJshift,iKshift);
+}
+
+bool AdrOp::CheckShift(int ny, int step)
+{
+ while (ny<0) ny+=uiDimension;
+ ny=ny%uiDimension;
+ int shift[3]={0,0,0};
+ shift[ny]=step;
+ if (this->CheckPos(uiIpos+shift[0],uiJpos+shift[1],uiKpos+shift[2]))
+ {
+ this->Shift(ny,step);
+ return true;
+ }
+ else return false;
+}
+
+unsigned int AdrOp::GetShiftedPos(int ny, int step)
+{
+ if ((ny<0) || (ny>2))
+ return GetPos(iIshift,iJshift,iKshift);
+ int pos[3] = {iIshift, iJshift, iKshift};
+ pos[ny]+=step;
+ return GetPos(pos[0],pos[1],pos[2]);
+}
+
+void AdrOp::ResetShift()
+{
+ iIshift=iJshift=iKshift=0;
+}
+
+unsigned int AdrOp::Iterate(int jump)
+{
+ if (abs(jump)>=(int)uiImax) error->Error(4);
+ i=uiIpos+jump;
+ if (i>=uiImax)
+ {
+ i=i-uiImax;
+ j=uiJpos+1;
+ if (j>=uiJmax)
+ {
+ j=0;
+ if (uiDimension==3)
+ {
+ k=uiKpos+1;
+ if (k>=uiKmax) k=0;
+ uiKpos=k;
+ }
+ }
+ uiIpos=i;
+ uiJpos=j;
+ return GetPos();
+ }
+ else
+ {
+ uiIpos=i;
+ return GetPos();
+ }
+}
+
+unsigned int AdrOp::GetSize()
+{
+ return uiSize;
+}
+
+
+void AdrOp::SetReflection2Node()
+{
+ reflect=true;
+ uiTypeOffset=0;
+}
+
+void AdrOp::SetReflection2Cell()
+{
+ reflect=true;
+ uiTypeOffset=1;
+}
+
+void AdrOp::SetReflectionOff()
+{
+ reflect=false;
+}
+
+AdrOp* AdrOp::AddCellAdrOp()
+{
+ if (clCellAdr!=NULL) return clCellAdr;
+ if (uiDimension==3) clCellAdr = new AdrOp(uiImax-1,uiJmax-1,uiKmax-1);
+ else if (uiDimension==2) clCellAdr = new AdrOp(uiImax-1,uiJmax-1);
+ else clCellAdr=NULL;
+ if (clCellAdr!=NULL)
+ {
+ clCellAdr->SetPos(0,0,0);
+ clCellAdr->SetReflection2Cell();
+ }
+ iCellShift[0]=iCellShift[1]=iCellShift[2]=0;
+ return clCellAdr;
+}
+
+AdrOp* AdrOp::DeleteCellAdrOp()
+{
+ delete clCellAdr;
+ clCellAdr=NULL;
+ return NULL;
+}
+
+unsigned int AdrOp::ShiftCell(int ny, int step)
+{
+ if (clCellAdr==NULL) error->Error(7);
+ while (ny<0) ny+=uiDimension;
+ ny=ny%uiDimension;
+ iCellShift[ny]=step;
+ ADRESSEXPENSE(3,1,0,0,1,2)
+ return clCellAdr->GetPos(uiIpos+iCellShift[0],uiJpos+iCellShift[1],uiKpos+iCellShift[2]);
+}
+
+bool AdrOp::ShiftCellCheck(int ny, int step)
+{
+ return clCellAdr->CheckShift(ny,step);
+}
+
+void AdrOp::ResetCellShift()
+{
+ if (clCellAdr==NULL) error->Error(7);
+ iCellShift[0]=iCellShift[1]=iCellShift[2]=0;
+}
+
+unsigned int AdrOp::GetCellPos(bool incShift)
+{
+ if (bPosSet==false) error->Error(6);
+ if (clCellAdr==NULL) error->Error(7);
+#if EXPENSE_LOG==1
+ if (incShift) ADRESSEXPENSE(3,0,0,0,0,2)
+#endif
+ if (incShift) return clCellAdr->GetPos(uiIpos+iCellShift[0],uiJpos+iCellShift[1],uiKpos+iCellShift[2]);
+ else return clCellAdr->GetPos(uiIpos,uiJpos,uiKpos);
+}
+
+unsigned int AdrOp::GetCellPos(int i, int j, int k)
+{
+ if (bPosSet==false) error->Error(6);
+ return clCellAdr->GetPos(uiIpos+i,uiJpos+j,uiKpos+k);
+}
+
+
+double AdrOp::GetShiftCellVolume(int ny, int step)
+{
+ for (unsigned int n=0; n<uiDimension; n++) if (dGrid[n]==NULL) error->Error(9);
+ int uiMax[4]={(int)uiImax-1,(int)uiJmax-1,(int)uiKmax-1,(int)uiLmax-1};
+ while (ny<0) ny+=uiDimension;
+ ny=ny%uiDimension;
+ iCellShift[ny]=step;
+ int uiPos[4]={(int)uiIpos+iCellShift[0],(int)uiJpos+iCellShift[1],(int)uiKpos+iCellShift[2]};
+ double dVol=1;
+ for (unsigned int n=0; n<uiDimension; ++n)
+ {
+ if (uiMax[n]>0)
+ {
+ while ((uiPos[n]<0) || (uiPos[n]>=uiMax[n]))
+ {
+ if (uiPos[n]<0) uiPos[n]=-1*uiPos[n]-1;
+ else if (uiPos[n]>=uiMax[n]) uiPos[n]=uiMax[n]-(uiPos[n]-uiMax[n]+1);
+ }
+ dVol*=(dGrid[n][uiPos[n]+1]-dGrid[n][uiPos[n]])*dDeltaUnit;
+ }
+ }
+ return dVol;
+}
+
+
+deltaAdrOp::deltaAdrOp(unsigned int max)
+{
+ uiMax=max;
+}
+
+deltaAdrOp::~deltaAdrOp()
+{
+}
+
+void deltaAdrOp::SetMax(unsigned int max)
+{
+ uiMax=max;
+}
+
+unsigned int deltaAdrOp::GetAdr(int pos)
+{
+ if (uiMax==1) return 0;
+ if (pos<0) pos=pos*-1;
+ else if (pos>(int)uiMax-1) pos=2*(uiMax-1)-pos+1;
+ if ((pos<0) || (pos>(int)uiMax-1))
+ {
+ fprintf(stderr," Error exiting... ");
+ getchar();
+ exit(-1);
+ }
+ return pos;
+}
+
+
diff --git a/openEMS/tools/AdrOp.h b/openEMS/tools/AdrOp.h new file mode 100644 index 0000000..e4a690b --- /dev/null +++ b/openEMS/tools/AdrOp.h @@ -0,0 +1,149 @@ +/* +* 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/>. +*/ + +/*! +\class AdrOp +\author Thorsten Liebig +\version $Revision: 1.10 $ +\date $Date: 2006/10/29 18:50:44 $ +*/ + +#ifndef ADROP_H +#define ADROP_H + +#include <iostream> +#include <stdio.h> +#include <stdlib.h> +#include <vector> +#include "ExpenseLog.h" +#include "ErrorMsg.h" + +class AdrOp +{ +public: + ///Constructor, define dimension/size here + AdrOp(unsigned int muiImax, unsigned int muiYmax, unsigned int muiKmax=0, unsigned int muiLmax=0); + ///Copy-Constructor + AdrOp(AdrOp* origOP); + ///Deconstructor + virtual ~AdrOp(); + ///Set the current n-dim position, get 1-dim array position as return value + /*!A position has to be set or all other methodes will case error! \n The methode will exit with error message if invalid position is set! \sa ErrorMsg */ + unsigned int SetPos(unsigned int muiIpos, unsigned int muiJpos, unsigned int muiKpos=0, unsigned int muiLpos=0); + + bool SetPosChecked(unsigned int muiIpos, unsigned int muiJpos, unsigned int muiKpos=0, unsigned int muiLpos=0); + + void SetGrid(double *gridI,double *gridJ,double *gridK=NULL,double *gridL=NULL); + void SetGridDelta(double delta) {this->dDeltaUnit=delta;}; + + bool CheckPos(unsigned int muiIpos, unsigned int muiJpos, unsigned int muiKpos=0, unsigned int muiLpos=0); + bool CheckRelativePos(int muiIrel=0,int muiJrel=0,int muiKrel=0, int muiLrel=0); + ///will return current 1-dim position, in addition to a relative n-dim shift + /*!In case of crossing the boundaries, activate reflection or an error will be invoked\sa SetReflection2Node \sa SetReflection2Cell \sa SetReflectionOff */ + unsigned int GetPos(int muiIrel=0,int muiJrel=0,int muiKrel=0, int muiLrel=0); + + double GetNodeVolume(unsigned int uiNode); + + double GetIndexWidth(int ny, int index); + double GetIndexCoord(int ny, int index); + ///Get the gird delta at the given index of direction ny. (if index<0 return negative value as index=0 would give, if index>=max-1 returns negative value as index=max-2 would give) + double GetIndexDelta(int ny, int index); + +// double GetCellVolume(unsigned int uiCell); + + unsigned int GetPosFromNode(int ny, unsigned int uiNode); + ///Set a shift in ny direction (e.g. 0 for i-direction) + /*!Shift set by this methode will be ignored by methode GetPos*/ + unsigned int Shift(int ny, int step); + ///Set a checked shift in ny direction (e.g. 0 for i-direction) + /*!Shift set by this methode will be ignored by methode GetPos*/ + bool CheckShift(int ny, int step); + ///Returns the current 1-dim position including shift by methode "Shift" + additional (transitory) shift + unsigned int GetShiftedPos(int ny=-1, int step=0); + ///Reset shift set by "Shift"-methode + void ResetShift(); + ///Iterates through AdrOp; --- obsolete --- + unsigned int Iterate(int jump=1); + ///Retruns size of array + unsigned int GetSize(); + ///Set mode to reflect by node + /*!1D-example (6 nodes): \image html node_reflect.PNG order: 0,1,2,3,4,5,4,3,...*/ + void SetReflection2Node(); + ///Set mode to reflect by cell + /*!1D-example (5 cells): \image html cell_reflect.PNG order: 0,1,2,3,4,4,3,...*/ + void SetReflection2Cell(); + ///Deactivate reflection (default) + void SetReflectionOff(); + ///Add a cell adress operator (dimensions: i-1 j-1 k-1 l-1) + /*!\image html cells_nodes.png */ + AdrOp* AddCellAdrOp(); + + AdrOp* GetCellAdrOp() {return clCellAdr;}; + + ///Deconstructed cell adress operator if no longer needed + AdrOp* DeleteCellAdrOp(); + ///Shift cell in ny dircetion; cell reflection is active + unsigned int ShiftCell(int ny, int step); + ///Shift cell in ny dircetion; cell reflection is active; return check + bool ShiftCellCheck(int ny, int step); + ///Reset cell shift + void ResetCellShift(); + ///Get current cell position from cell adress operator + unsigned int GetCellPos(bool incShift=true); + ///Get cell position from cell adress operator + unsigned int GetCellPos(int i, int j, int k=0); + //get volume of cell; incl shift + double GetShiftCellVolume(int ny, int step); + + + void SetDebugOn() {this->bDebug=true;}; + void SetDebugOff() {this->bDebug=false;}; + +protected: + AdrOp *clCellAdr; + unsigned int uiDimension; + unsigned int uiSize; + unsigned int uiImax,uiJmax,uiKmax,uiLmax; + unsigned int uiIpos, uiJpos, uiKpos, uiLpos; + double *dGrid[4]; + double dDeltaUnit; + int iIshift, iJshift, iKshift; + int iCellShift[3]; + unsigned int i,j,k,l; + bool reflect; + unsigned int uiTypeOffset; + + bool bPosSet; + bool bDebug; + ErrorMsg *error; +}; + + +class deltaAdrOp +{ +public: + deltaAdrOp(unsigned int max=0); + virtual ~deltaAdrOp(); + void SetMax(unsigned int max); + unsigned int GetAdr(int pos); + +protected: + unsigned int uiMax; +}; + + +#endif // ADROP_H diff --git a/openEMS/tools/CMakeLists.txt b/openEMS/tools/CMakeLists.txt new file mode 100644 index 0000000..8b62b8a --- /dev/null +++ b/openEMS/tools/CMakeLists.txt @@ -0,0 +1,28 @@ + +set(SOURCES + ${SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/AdrOp.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ErrorMsg.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/array_ops.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/global.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/hdf5_file_reader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/hdf5_file_writer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sar_calculation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/useful.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/vtk_file_writer.cpp + PARENT_SCOPE +) + +#set(HEADERS +# constants.h +# array_ops.h +# global.h +# useful.h +# aligned_allocator.h +# hdf5_file_reader.h +# hdf5_file_writer.h +#) + +# tools lib +#add_library(tools STATIC ${SOURCES} ) + diff --git a/openEMS/tools/ErrorMsg.cpp b/openEMS/tools/ErrorMsg.cpp new file mode 100644 index 0000000..9a1974c --- /dev/null +++ b/openEMS/tools/ErrorMsg.cpp @@ -0,0 +1,98 @@ +/* +* 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "ErrorMsg.h" + +ErrorMsg::ErrorMsg(unsigned int NoMessage) +{ + NoMsg=NoMessage; + if (NoMsg>0) Msg = new char*[NoMsg]; + if (Msg==NULL) + { + fprintf(stderr,"Memory allocation failed!! exiting..."); + exit(1); + } + for (unsigned int i=0; i<NoMsg; i++) Msg[i]=NULL; +} + +ErrorMsg::~ErrorMsg() +{ + for (unsigned int i=0; i<NoMsg; i++) + { + delete[] Msg[i]; + Msg[i]=NULL; + }; + delete[] Msg; + Msg=NULL; +} + +void ErrorMsg::SetMsg(unsigned int nr, const char *Message) +{ + if ((nr<1) || (nr>NoMsg) || (Message==NULL)) ownError(); + Msg[nr-1] = new char[strlen(Message)+1]; + if (Msg[nr-1]==NULL) + { + fprintf(stderr,"Memory allocation failed!! exiting..."); + exit(1); + } + Msg[nr-1]=strcpy(Msg[nr-1],Message); +} + +void ErrorMsg::Error(unsigned int nr,char *chAddMsg) +{ + if ((nr>0) && (nr<=NoMsg)) + { + if (Msg[nr-1]!=NULL) fprintf(stderr,"%s",Msg[nr-1]); + else fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); + if (chAddMsg!=NULL) fprintf(stderr,"%s",chAddMsg); + getchar(); + exit(nr); + } + else + { + fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); + getchar(); + exit(nr); + } +} + +void ErrorMsg::Error(unsigned int nr,int addNr) +{ + if ((nr>0) && (nr<=NoMsg)) + { + if (Msg[nr-1]!=NULL) fprintf(stderr,"%s",Msg[nr-1]); + else fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); + fprintf(stderr,"%d",addNr); + getchar(); + exit(nr); + } + else + { + fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); + getchar(); + exit(nr); + } +} + +void ErrorMsg::ownError(void) +{ + fprintf(stdout," Error occured by using Error Message class!! ... exiting..."); + exit(-1); +} diff --git a/openEMS/tools/ErrorMsg.h b/openEMS/tools/ErrorMsg.h new file mode 100644 index 0000000..fa63c93 --- /dev/null +++ b/openEMS/tools/ErrorMsg.h @@ -0,0 +1,50 @@ +/* +* 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/>. +*/ + +/*! +\class ErrorMsg +\author Thorsten Liebig +\version $Revision: 1.2 $ +\date $Date: 2006/01/25 11:47:07 $ +*/ + +#ifndef _ERRORMSG_H_ +#define _ERRORMSG_H_ + +class ErrorMsg +{ +public: + ///Constructor defines number of error messages + ErrorMsg(unsigned int NoMessage=0); + ///Deconstructor + virtual ~ErrorMsg(); + ///Methode for defining error messages + /*! \param nr Number of defining error message \param *Message Set error message string \sa Error */ + void SetMsg(unsigned int nr, const char *Message); + ///Call an error message. Will exit the program! + /*! \param nr Number of called error message. default is 0 \sa SetMsg*/ + void Error(unsigned int nr=0,char *chAddMsg=0); + + void Error(unsigned int nr,int addNr); + +protected: + void ownError(void); + unsigned int NoMsg; + char **Msg; +}; + +#endif //_ERRORMSG_H_ diff --git a/openEMS/tools/ExpenseLog.cpp b/openEMS/tools/ExpenseLog.cpp new file mode 100644 index 0000000..95a0d4c --- /dev/null +++ b/openEMS/tools/ExpenseLog.cpp @@ -0,0 +1,145 @@ +#include "ExpenseLog.h" + +ExpenseModule::ExpenseModule(const char* moduleName) +{ + chModuleName=moduleName; + uiDoubleAdditions=uiDoubleMultiplications=uiIntAdditions=uiIntMultiplications=uiAssignments=uiBoolOp=0; + uiMrdDA=uiMrdDM=uiMrdIA=uiMrdIM=uiMrdAssign=uiMrdBO=0; +} + +ExpenseModule::~ExpenseModule() {}; + +void ExpenseModule::Clear() +{ + uiDoubleAdditions=uiDoubleMultiplications=uiIntAdditions=uiIntMultiplications=uiAssignments=uiBoolOp=0; + uiMrdDA=uiMrdDM=uiMrdIA=uiMrdIM=uiMrdAssign=uiMrdBO=0; +} + +void ExpenseModule::AddDoubleAdditons(unsigned int number) +{ + uiDoubleAdditions+=number; + if (uiDoubleAdditions>=MRD) + { + uiDoubleAdditions-=MRD; + ++uiMrdDA; + } +} + +void ExpenseModule::AddDoubleMultiplications(unsigned int number) +{ + uiDoubleMultiplications+=number; + if (uiDoubleMultiplications>=MRD) + { + uiDoubleMultiplications-=MRD; + ++uiMrdDM; + } +} + +void ExpenseModule::AddIntAdditons(unsigned int number) +{ + uiIntAdditions+=number; + if (uiIntAdditions>=MRD) + { + uiIntAdditions-=MRD; + ++uiMrdIA; + } +} + +void ExpenseModule::AddIntMultiplications(unsigned int number) +{ + uiIntMultiplications+=number; + if (uiIntMultiplications>=MRD) + { + uiIntMultiplications-=MRD; + ++uiMrdIM; + } +} + +void ExpenseModule::AddAssignments(unsigned int number) +{ + uiAssignments+=number; + if (uiAssignments>=MRD) + { + uiAssignments-=MRD; + ++uiMrdAssign; + } +} + +void ExpenseModule::AddBoolOperations(unsigned int number) +{ + uiBoolOp+=number; + if (uiBoolOp>=MRD) + { + uiBoolOp-=MRD; + ++uiMrdBO; + } +} + +void ExpenseModule::AddOperations(unsigned int IntAdd, unsigned int IntMul, unsigned int DoubleAdd, unsigned int DoubleMul, unsigned int Assigns, unsigned int BoolOp) +{ + this->AddIntAdditons(IntAdd); + this->AddIntMultiplications(IntMul); + this->AddDoubleAdditons(DoubleAdd); + this->AddDoubleMultiplications(DoubleMul); + this->AddAssignments(Assigns); + this->AddBoolOperations(BoolOp); +} + +void ExpenseModule::PrintfSelf(FILE* file) +{ + fprintf(file,"\n***********\n Module: %s\n Additions:\n Double: %3.0d%9d\tInteger: %3.0d%9d",chModuleName,uiMrdDA,uiDoubleAdditions,uiMrdIA,uiIntAdditions); + fprintf(file,"\n\n Multiplications:\n Double: %3.0d%9d\tInteger: %3.0d%9d\n",uiMrdDM,uiDoubleMultiplications,uiMrdIM,uiIntMultiplications); + fprintf(file,"\n Assignments: %3.0d%9d\tBool Operations: %3.0d%9d\n",uiMrdAssign,uiAssignments,uiMrdBO,uiBoolOp); + fprintf(file,"\n***********\n"); +} + + + + +/***********************************************************************************************************************/ + +ExpenseLog::ExpenseLog(void) +{ +} + +ExpenseLog::~ExpenseLog(void) +{ + for (size_t i=0; i<vModules.size(); ++i) + { + delete vModules.at(i); + vModules.at(i)=NULL; + } + vModules.clear(); +} + +ExpenseModule* ExpenseLog::AddModule(const char* name) +{ + ExpenseModule* newModule = new ExpenseModule(name); + vModules.push_back(newModule); + return newModule; +} + +void ExpenseLog::PrintAll(FILE *file) +{ + double totalAdd=0,totalMul=0,totalBool=0,totalAssign=0; + fprintf(stderr,"\n ----------------\n Expense Log PrintOut\n Nr of Modules: %d\n",vModules.size()); + for (size_t i=0; i<vModules.size(); ++i) + { + totalAdd+=((double)vModules.at(i)->uiIntAdditions+(double)vModules.at(i)->uiDoubleAdditions) + 1e9*((double)vModules.at(i)->uiMrdIA+(double)vModules.at(i)->uiMrdIA); + totalMul+=((double)vModules.at(i)->uiIntMultiplications+(double)vModules.at(i)->uiDoubleMultiplications) + 1e9*(double)(vModules.at(i)->uiMrdIM+vModules.at(i)->uiMrdIM); + totalBool+=(double)vModules.at(i)->uiBoolOp + 1e9*(double)vModules.at(i)->uiMrdBO; + totalAssign+=(double)vModules.at(i)->uiAssignments + 1e9*(double)vModules.at(i)->uiMrdAssign; + vModules.at(i)->PrintfSelf(file); + } + fprintf(stderr," Total:\n Additions: %e Multiplications: %e\n Bool Operations: %e Assignments: %e\n",totalAdd,totalMul,totalBool,totalAssign); + fprintf(stderr,"\n ----------------\n"); +} + +void ExpenseLog::ClearAll() +{ + for (size_t i=0; i<vModules.size(); ++i) + { + vModules.at(i)->Clear(); + } +} + diff --git a/openEMS/tools/ExpenseLog.h b/openEMS/tools/ExpenseLog.h new file mode 100644 index 0000000..f8cc1ba --- /dev/null +++ b/openEMS/tools/ExpenseLog.h @@ -0,0 +1,92 @@ +#pragma once +#include <stdio.h> +#include <stdlib.h> +#include <vector> + +using namespace std; + +#define EXPENSE_LOG 0 +#define MRD 1000000000 + +#if EXPENSE_LOG==1 + +#define EXPENSE_DEFINE \ +ExpenseLog EL; \ +ExpenseModule* EngineExpense=EL.AddModule("Static Engine Expenses"); \ +ExpenseModule* PPExpense=EL.AddModule("Static Post Processing"); \ +ExpenseModule* AdrOpExpense=EL.AddModule("Adress Operator"); +#define EXTERN_EXPENSE_DEFINE extern ExpenseLog EL; +#define ENGINEEXPENSE_DEFINE extern ExpenseModule* EngineExpense; +#define POSTPROCEXPENSE_DEFINE extern ExpenseModule* PPExpense; +#define ADREXPENSE_DEFINE extern ExpenseModule* AdrOpExpense; +#define ENGINEEXPENSE(IA,IM,DA,DM,AS,BO) EngineExpense->AddOperations((IA),(IM),(DA),(DM),(AS),(BO)); +#define POSTPROCEXPENSE(IA,IM,DA,DM,AS,BO) PPExpense->AddOperations((IA),(IM),(DA),(DM),(AS),(BO)); +#define ADRESSEXPENSE(IA,IM,DA,DM,AS,BO) AdrOpExpense->AddOperations((IA),(IM),(DA),(DM),(AS),(BO)); +#define EXPENSEPRINT EL.PrintAll(stderr); +#define EXPENSECLEAR EL.ClearAll(); +#else + +#define EXPENSE_DEFINE +#define EXTERN_EXPENSE_DEFINE +#define ENGINEEXPENSE_DEFINE +#define POSTPROCEXPENSE_DEFINE +#define ADREXPENSE_DEFINE +#define ENGINEEXPENSE(IA,IM,DA,DM,AS,BO) +#define POSTPROCEXPENSE(IA,IM,DA,DM,AS,BO) +#define ADRESSEXPENSE(IA,IM,DA,DM,AS,BO) +#define EXPENSEPRINT +#define EXPENSECLEAR +#endif + +class ExpenseModule +{ + friend class ExpenseLog; +public: + ExpenseModule(const char* moduleName); + ~ExpenseModule(); + + void Clear(); + + void AddDoubleAdditons(unsigned int number); + void AddDoubleMultiplications(unsigned int number); + + void AddIntAdditons(unsigned int number); + void AddIntMultiplications(unsigned int number); + + void AddAssignments(unsigned int number); + void AddBoolOperations(unsigned int number); + + void AddOperations(unsigned int IntAdd, unsigned int IntMul, unsigned int DoubleAdd, unsigned int DoubleMul, unsigned int Assigns, unsigned int BoolOp); + + void PrintfSelf(FILE* file=stdout); + +protected: + const char* chModuleName; + unsigned int uiDoubleAdditions; + unsigned int uiDoubleMultiplications; + unsigned int uiIntAdditions; + unsigned int uiIntMultiplications; + unsigned int uiAssignments; + unsigned int uiBoolOp; + unsigned int uiMrdDA; + unsigned int uiMrdDM; + unsigned int uiMrdIA; + unsigned int uiMrdIM; + unsigned int uiMrdAssign; + unsigned int uiMrdBO; +}; + +class ExpenseLog +{ +public: + ExpenseLog(void); + ~ExpenseLog(void); + + ExpenseModule* AddModule(const char* name); + void PrintAll(FILE *file=stdout); + void ClearAll(); +protected: + vector<ExpenseModule*> vModules; +}; + + diff --git a/openEMS/tools/aligned_allocator.h b/openEMS/tools/aligned_allocator.h new file mode 100644 index 0000000..efabe7d --- /dev/null +++ b/openEMS/tools/aligned_allocator.h @@ -0,0 +1,173 @@ +/* +* Copyright (C) 2010 Sebastian Held (sebastian.held@gmx.de) +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +// based on http://blogs.msdn.com/b/vcblog/archive/2008/08/28/the-aligned_allocator.aspx +// from Stephan T. Lavavej + + +// The following headers are required for all allocators. +#include <stddef.h> // Required for size_t and ptrdiff_t and NULL +#include <new> // Required for placement new and std::bad_alloc +#include <stdexcept> // Required for std::length_error + + +#ifdef WIN32 +#define __MSVCRT_VERSION__ 0x0700 +#include <malloc.h> +#define MEMALIGN( array, alignment, size ) !(*array = _aligned_malloc( size, alignment )) +#define FREE( array ) _aligned_free( array ) +#else +#define MEMALIGN( array, alignment, size ) posix_memalign( array, alignment, size ) +#define FREE( array ) free( array ) +#endif + + +template <typename T> class aligned_allocator +{ +public: + // The following will be the same for virtually all allocators. + typedef T * pointer; + typedef const T * const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + T * address(T& r) const + { + return &r; + } + + const T * address(const T& s) const + { + return &s; + } + + size_t max_size() const + { + // The following has been carefully written to be independent of + // the definition of size_t and to avoid signed/unsigned warnings. + return (static_cast<size_t>(0) - static_cast<size_t>(1)) / sizeof(T); + } + + // The following must be the same for all allocators. + template <typename U> struct rebind + { + typedef aligned_allocator<U> other; + }; + + bool operator!=(const aligned_allocator& other) const + { + return !(*this == other); + } + + void construct(T * const p, const T& t) const + { + void * const pv = static_cast<void *>(p); + new (pv) T(t); + } + + void destroy(T * const p) const; // Defined below. + + // Returns true if and only if storage allocated from *this + // can be deallocated from other, and vice versa. + // Always returns true for stateless allocators. + bool operator==(const aligned_allocator& other) const + { + return true; + } + + // Default constructor, copy constructor, rebinding constructor, and destructor. + // Empty for stateless allocators. + aligned_allocator() { } + aligned_allocator(const aligned_allocator&) { } + template <typename U> aligned_allocator(const aligned_allocator<U>&) { } + ~aligned_allocator() { } + + // The following will be different for each allocator. + T * allocate(const size_t n) const + { +// std::cout << "Allocating " << n << (n == 1 ? " object" : "objects") << " of size " << sizeof(T) << "." << std::endl; + // The return value of allocate(0) is unspecified. + // aligned_allocator returns NULL in order to avoid depending + // on malloc(0)'s implementation-defined behavior + // (the implementation can define malloc(0) to return NULL, + // in which case the bad_alloc check below would fire). + // All allocators can return NULL in this case. + if (n == 0) + { + return NULL; + } + + // All allocators should contain an integer overflow check. + // The Standardization Committee recommends that std::length_error + // be thrown in the case of integer overflow. + if (n > max_size()) + { + throw std::length_error("aligned_allocator<T>::allocate() - Integer overflow."); + } + + // Allocators should throw std::bad_alloc in the case of memory allocation failure. + void * pv; + if (MEMALIGN( &pv, 16, n * sizeof(T))) + throw std::bad_alloc(); + + return static_cast<T *>(pv); + } + + void deallocate(T * const p, const size_t n) const + { +// std::cout << "Deallocating " << n << (n == 1 ? " object" : "objects") << " of size " << sizeof(T) << "." << std::endl; + // aligned_allocator wraps free(). + UNUSED(n); + FREE(p); + } + + // The following will be the same for all allocators that ignore hints. + template <typename U> T * allocate(const size_t n, const U * /* const hint */) const + { + return allocate(n); + } + + // Allocators are not required to be assignable, so + // all allocators should have a private unimplemented + // assignment operator. Note that this will trigger the + // off-by-default (enabled under /Wall) warning C4626 + // "assignment operator could not be generated because a + // base class assignment operator is inaccessible" within + // the STL headers, but that warning is useless. + +private: + aligned_allocator& operator=(const aligned_allocator&); +}; + +// A compiler bug causes it to believe that p->~T() doesn't reference p. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4100) // unreferenced formal parameter +#endif + +// The definition of destroy() must be the same for all allocators. +template <typename T> void aligned_allocator<T>::destroy(T * const p) const +{ + p->~T(); +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/openEMS/tools/array_ops.cpp b/openEMS/tools/array_ops.cpp new file mode 100644 index 0000000..8710b3c --- /dev/null +++ b/openEMS/tools/array_ops.cpp @@ -0,0 +1,144 @@ +/* +* 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 "array_ops.h" +#include <ostream> + +using namespace std; + +#ifdef WIN32 +#define __MSVCRT_VERSION__ 0x0700 +#include <malloc.h> +//(void**)&array, 16, sizeof(typeof(f4vector**))*numLines[0] +#define MEMALIGN( array, alignment, size ) !(*array = _aligned_malloc( size, alignment )) +#define FREE( array ) _aligned_free( array ) +#else +#define MEMALIGN( array, alignment, size ) posix_memalign( array, alignment, size ) +#define FREE( array ) free( array ) +#endif + +void Delete1DArray_v4sf(f4vector* array) +{ + if (array==NULL) return; + FREE( array ); +} + + +void Delete3DArray_v4sf(f4vector*** array, const unsigned int* numLines) +{ + if (array==NULL) return; + unsigned int pos[3]; + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + FREE( array[pos[0]][pos[1]] ); + //delete[] array[pos[0]][pos[1]]; + } + FREE( array[pos[0]] ); + //delete[] array[pos[0]]; + } + FREE( array ); + //delete[] array; +} + +void Delete_N_3DArray_v4sf(f4vector**** array, const unsigned int* numLines) +{ + if (array==NULL) return; + for (int n=0; n<3; ++n) + { + Delete3DArray_v4sf(array[n],numLines); + } + FREE( array ); + //delete[] array; +} + +f4vector* Create1DArray_v4sf(const unsigned int numLines) +{ + f4vector* array=NULL; + if (MEMALIGN( (void**)&array, 16, sizeof(typeof(f4vector))*numLines )) + { + cerr << "cannot allocate aligned memory" << endl; + exit(3); + } + for (unsigned int pos=0; pos<numLines; ++pos) + { + array[pos].f[0] = 0; + array[pos].f[1] = 0; + array[pos].f[2] = 0; + array[pos].f[3] = 0; + } + return array; +} + +//! \brief this function allocates a 3D array, which is aligned to 16 byte +f4vector*** Create3DArray_v4sf(const unsigned int* numLines) +{ + unsigned int numZ = ceil((double)numLines[2]/4.0); + + f4vector*** array=NULL; + unsigned int pos[3]; + if (MEMALIGN( (void**)&array, 16, sizeof(typeof(f4vector**))*numLines[0] )) + { + cerr << "cannot allocate aligned memory" << endl; + exit(3); + } + //array = new f4vector**[numLines[0]]; + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + if (MEMALIGN( (void**)&array[pos[0]], 16, sizeof(typeof(f4vector*))*numLines[1] )) + { + cerr << "cannot allocate aligned memory" << endl; + exit(3); + } + //array[pos[0]] = new f4vector*[numLines[1]]; + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + if (MEMALIGN( (void**)&array[pos[0]][pos[1]], 16, sizeof(typeof(f4vector))*numZ )) + { + cerr << "cannot allocate aligned memory" << endl; + exit(3); + } + //array[pos[0]][pos[1]] = new f4vector[numZ]; + for (pos[2]=0; pos[2]<numZ; ++pos[2]) + { + array[pos[0]][pos[1]][pos[2]].f[0] = 0; + array[pos[0]][pos[1]][pos[2]].f[1] = 0; + array[pos[0]][pos[1]][pos[2]].f[2] = 0; + array[pos[0]][pos[1]][pos[2]].f[3] = 0; + } + } + } + return array; +} + +f4vector**** Create_N_3DArray_v4sf(const unsigned int* numLines) +{ + f4vector**** array=NULL; + if (MEMALIGN( (void**)&array, 16, sizeof(typeof(f4vector***))*3 )) + { + cerr << "cannot allocate aligned memory" << endl; + exit(3); + } + //array = new f4vector***[3]; + for (int n=0; n<3; ++n) + { + array[n]=Create3DArray_v4sf(numLines); + } + return array; +} + diff --git a/openEMS/tools/array_ops.h b/openEMS/tools/array_ops.h new file mode 100644 index 0000000..5c2fd7f --- /dev/null +++ b/openEMS/tools/array_ops.h @@ -0,0 +1,196 @@ +/* +* 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 ARRAY_OPS_H +#define ARRAY_OPS_H + +#ifdef __SIZEOF_FLOAT__ +#if __SIZEOF_FLOAT__ != 4 +#error wrong size of float +#endif +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> +#include <string> +#include <math.h> +#include "constants.h" + +typedef float v4sf __attribute__ ((vector_size (16))); // vector of four single floats +typedef int v4si __attribute__ ((vector_size (4*sizeof(int)))); // vector of four single ints + +union f4vector +{ + v4sf v; + float f[4]; +}; + +void Delete1DArray_v4sf(f4vector* array); +void Delete3DArray_v4sf(f4vector*** array, const unsigned int* numLines); +void Delete_N_3DArray_v4sf(f4vector**** array, const unsigned int* numLines); +f4vector* Create1DArray_v4sf(const unsigned int numLines); +f4vector*** Create3DArray_v4sf(const unsigned int* numLines); +f4vector**** Create_N_3DArray_v4sf(const unsigned int* numLines); + +// ************************************************************************************* +// templates +// ************************************************************************************* +template <typename T> +T** Create2DArray(const unsigned int* numLines) +{ + T** array=NULL; + unsigned int pos[3]; + array = new T*[numLines[0]]; + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + array[pos[0]] = new T[numLines[1]]; + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + array[pos[0]][pos[1]] = 0; + } + } + return array; +} + +template <typename T> +void Delete2DArray(T** array, const unsigned int* numLines) +{ + if (array==NULL) return; + unsigned int pos[3]; + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + delete[] array[pos[0]]; + } + delete[] array; +} + +template <typename T> +inline T& Access_N_3DArray(T**** array, unsigned int n, unsigned int* pos) +{ + return array[n][pos[0]][pos[1]][pos[2]]; +} + +template <typename T> +inline T& Access_N_3DArray(T**** array, unsigned int n, unsigned int x, unsigned int y, unsigned int z ) +{ + return array[n][x][y][z]; +} + +template <typename T> +T*** Create3DArray(const unsigned int* numLines) +{ + T*** array=NULL; + unsigned int pos[3]; + array = new T**[numLines[0]]; + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + array[pos[0]] = new T*[numLines[1]]; + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + array[pos[0]][pos[1]] = new T[numLines[2]]; + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + array[pos[0]][pos[1]][pos[2]] = 0; + } + } + } + return array; +} + +template <typename T> +T*** Copy3DArray(T*** array_in, T*** array_out, const unsigned int* numLines) +{ + if (array_out==NULL) + array_out = Create3DArray<T>(numLines); + unsigned int pos[3]; + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + array_out[pos[0]][pos[1]][pos[2]] = array_in[pos[0]][pos[1]][pos[2]]; + return array_out; +} + +template <typename T> +T**** Create_N_3DArray(const unsigned int* numLines) +{ + T**** array=NULL; + array = new T***[3]; + for (int n=0; n<3; ++n) + { + array[n]=Create3DArray<T>( numLines ); + } + return array; +} + +template <typename T> +T**** Copy_N_3DArray(T**** array_in, T**** array_out, const unsigned int* numLines) +{ + if (array_out==NULL) + array_out = Create_N_3DArray<T>(numLines); + for (int n=0; n<3; ++n) + array_out[n]=Copy3DArray<T>( array_in[n], array_out[n], numLines); + return array_out; +} + +template <typename T> +void Delete3DArray(T*** array, const unsigned int* numLines) +{ + if (!array) return; + unsigned int pos[3]; + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + delete[] array[pos[0]][pos[1]]; + } + delete[] array[pos[0]]; + } + delete[] array; +} + +template <typename T> +void Delete_N_3DArray(T**** array, const unsigned int* numLines) +{ + if (!array) return; + for (int n=0; n<3; ++n) + { + Delete3DArray<T>(array[n],numLines); + } + delete[] array; +} + +template <typename T> +void Dump_N_3DArray2File(std::ostream &file, T**** array, const unsigned int* numLines) +{ + unsigned int pos[3]; + for (pos[0]=0; pos[0]<numLines[0]; ++pos[0]) + { + for (pos[1]=0; pos[1]<numLines[1]; ++pos[1]) + { + for (pos[2]=0; pos[2]<numLines[2]; ++pos[2]) + { + file << pos[0] << "\t" << pos[1] << "\t" << pos[2]; + for (int n=0; n<3; ++n) + file << "\t" << (float)array[n][pos[0]][pos[1]][pos[2]]; + file << std::endl; + } + } + } +} + +#endif // ARRAY_OPS_H diff --git a/openEMS/tools/constants.h b/openEMS/tools/constants.h new file mode 100644 index 0000000..9707fdf --- /dev/null +++ b/openEMS/tools/constants.h @@ -0,0 +1,29 @@ +/* +* 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 CONSTANTS_H +#define CONSTANTS_H + +#define FDTD_FLOAT float + +#define __EPS0__ 8.85418781762e-12 +#define __MUE0__ 1.256637062e-6 +#define __C0__ 299792458 +#define __Z0__ 376.730313461 +#define PI 3.141592653589793238462643383279 + +#endif // CONSTANTS_H diff --git a/openEMS/tools/global.cpp b/openEMS/tools/global.cpp new file mode 100644 index 0000000..3e97fac --- /dev/null +++ b/openEMS/tools/global.cpp @@ -0,0 +1,78 @@ +/* +* Copyright (C) 2010 Sebastian Held <sebastian.held@gmx.de> +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <cstring> +#include <iostream> +#include "global.h" + +using namespace std; + +// create global object +Global g_settings; + +Global::Global() +{ + m_showProbeDiscretization = false; + m_nativeFieldDumps = false; + m_VerboseLevel = 0; +} + +void Global::ShowArguments(ostream& ostr, string front) +{ + ostr << front << "--showProbeDiscretization\tShow probe discretization information" << endl; + ostr << front << "--nativeFieldDumps\t\tDump all fields using the native field components" << endl; + ostr << front << "-v,-vv,-vvv\t\t\tSet debug level: 1 to 3" << endl; +} + +//! \brief This function initializes the object +bool Global::parseCommandLineArgument( const char *argv ) +{ + if (!argv) + return false; + + if (strcmp(argv,"--showProbeDiscretization")==0) + { + cout << "openEMS - showing probe discretization information" << endl; + m_showProbeDiscretization = true; + return true; + } + else if (strcmp(argv,"--nativeFieldDumps")==0) + { + cout << "openEMS - dumping all fields using the native field components" << endl; + m_nativeFieldDumps = true; + return true; + } + else if (strcmp(argv,"-v")==0) + { + cout << "openEMS - verbose level 1" << endl; + m_VerboseLevel = 1; + return true; + } + else if (strcmp(argv,"-vv")==0) + { + cout << "openEMS - verbose level 2" << endl; + m_VerboseLevel = 2; + return true; + } + else if (strcmp(argv,"-vvv")==0) + { + cout << "openEMS - verbose level 3" << endl; + m_VerboseLevel = 3; + return true; + } + return false; +} diff --git a/openEMS/tools/global.h b/openEMS/tools/global.h new file mode 100644 index 0000000..c3bb524 --- /dev/null +++ b/openEMS/tools/global.h @@ -0,0 +1,65 @@ +/* +* Copyright (C) 2010 Sebastian Held <sebastian.held@gmx.de> +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef GLOBAL_H +#define GLOBAL_H + +#include <sstream> + +#define UNUSED(x) (void)(x); + +class Global +{ +public: + Global(); + + //! Show all possible (global) command line arguments + void ShowArguments(std::ostream& ostr, std::string front=std::string()); + + //! Parse the given command line arguments + bool parseCommandLineArgument( const char *argv ); + + bool showProbeDiscretization() const {return m_showProbeDiscretization;} + + //! Returns true if native field dumps are requested... + bool NativeFieldDumps() const {return m_nativeFieldDumps;} + //! Set dumps to use native fields. + void SetNativeFieldDumps(bool val) {m_nativeFieldDumps=val;} + + //! Set the verbose level + void SetVerboseLevel(int level) {m_VerboseLevel=level;m_SavedVerboseLevel=level;} + //! Get the verbose level + int GetVerboseLevel() const {return m_VerboseLevel;} + + //! Set a new verbose level temporarily, restore it with RestoreVerboseLevel() + void SetTempVerboseLevel(int level) {m_SavedVerboseLevel=m_VerboseLevel;m_VerboseLevel=level;} + //! Restore the temporarily overwritten verbose level + void RestoreVerboseLevel() {m_VerboseLevel=m_SavedVerboseLevel;} + +protected: + bool m_showProbeDiscretization; + bool m_nativeFieldDumps; + int m_VerboseLevel; + int m_SavedVerboseLevel; +}; + +extern Global g_settings; + +// declare a parameter as unused +#define UNUSED(x) (void)(x); + +#endif // GLOBAL_H diff --git a/openEMS/tools/hdf5_file_reader.cpp b/openEMS/tools/hdf5_file_reader.cpp new file mode 100644 index 0000000..a6e1359 --- /dev/null +++ b/openEMS/tools/hdf5_file_reader.cpp @@ -0,0 +1,689 @@ +/* +* 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 "hdf5_file_reader.h" +#include "../tools/array_ops.h" +#include <hdf5.h> + +#include <sstream> +#include <iostream> +#include <iomanip> + +using namespace std; + +HDF5_File_Reader::HDF5_File_Reader(string filename) +{ + m_filename = filename; + //suppress hdf5 error output + //H5Eset_auto(NULL, NULL); +} + +HDF5_File_Reader::~HDF5_File_Reader() +{ +} + +bool HDF5_File_Reader::IsValid() +{ + htri_t val = H5Fis_hdf5(m_filename.c_str()); + if (val<0) + { + cerr << "HDF5_File_Reader::IsValid: the given file """ << m_filename << """ is not accessible..." << endl; + return false; + } + if (val==0) + { + cerr << "HDF5_File_Reader::IsValid: the given file """ << m_filename << """ is invalid..." << endl; + return false; + } + if (val==0) + cerr << "HDF5_File_Reader::IsValid: the given file """ << m_filename << """ is valid..." << endl; + return true; +} + +bool HDF5_File_Reader::OpenGroup(hid_t &file, hid_t &group, string groupName) +{ + file = H5Fopen( m_filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT ); + if (file==-1) + { + cerr << "HDF5_File_Reader::OpenGroup: opening the given file """ << m_filename << """ failed" << endl; + return 0; + } + if (H5Lexists(file, groupName.c_str(), H5P_DEFAULT)<=0) + { + H5Fclose(file); + return 0; + } + + group = H5Gopen(file, groupName.c_str(), H5P_DEFAULT ); + if (group<0) + { + cerr << "HDF5_File_Reader::OpenGroup: can't open group """ << groupName << """" << endl; + H5Fclose(file); + return 0; + } + return true; +} + +bool HDF5_File_Reader::ReadAttribute(string grp_name, string attr_name, vector<float> &attr_values) +{ + vector<double> d_attr_values; + if (ReadAttribute(grp_name, attr_name, d_attr_values)==false) + return false; + attr_values.resize(d_attr_values.size(),0); + for (size_t n=0;n<d_attr_values.size();++n) + attr_values.at(n)=d_attr_values.at(n); + return true; +} + +bool HDF5_File_Reader::ReadAttribute(string grp_name, string attr_name, vector<double> &attr_values) +{ + attr_values.clear(); + + hid_t hdf5_file = H5Fopen( m_filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT ); + if (hdf5_file==-1) + { + cerr << "HDF5_File_Reader::OpenGroup: opening the given file """ << m_filename << """ failed" << endl; + return 0; + } + + if (H5Lexists(hdf5_file, grp_name.c_str(), H5P_DEFAULT)<=0) + { + H5Fclose(hdf5_file); + return false; + } + + hid_t attr = H5Aopen_by_name(hdf5_file, grp_name.c_str(), attr_name.c_str(), H5P_DEFAULT, H5P_DEFAULT); + if (attr==-1) + { + cerr << "HDF5_File_Reader::ReadAttribute: Opening the given Attribute: """ << attr_name << """ failed" << endl; + H5Fclose(hdf5_file); + return false; + } + + hid_t type = H5Aget_type(attr); + if (type<0) + { + cerr << "HDF5_File_Reader::ReadAttribute: Dataset type error" << endl; + H5Aclose(attr); + H5Fclose(hdf5_file); + return false; + } + + attr_values.clear(); + if (H5Tget_class(type)==H5T_FLOAT) + { + size_t numVal = H5Aget_storage_size(attr)/H5Tget_size(type); + hid_t datatype=-1; + void *value=NULL; + float *f_value=NULL; + double *d_value=NULL; + if (H5Tget_size(type)==sizeof(float)) + { + f_value = new float[numVal]; + value = f_value; + datatype = H5T_NATIVE_FLOAT; + } + if (H5Tget_size(type)==sizeof(double)) + { + d_value = new double[numVal]; + value = d_value; + datatype = H5T_NATIVE_DOUBLE; + } + if (H5Aread(attr, datatype, value)<0) + { + cerr << "HDF5_File_Reader::ReadAttribute: Reading the given Attribute failed" << endl; + H5Aclose(attr); + H5Fclose(hdf5_file); + return false; + } + if (f_value) + for (size_t n=0;n<numVal;++n) + attr_values.push_back(f_value[n]); + if (d_value) + for (size_t n=0;n<numVal;++n) + attr_values.push_back(d_value[n]); + delete[] f_value; + delete[] d_value; + } + else + { + cerr << "HDF5_File_Reader::ReadAttribute: Attribute type not supported" << endl; + H5Aclose(attr); + H5Fclose(hdf5_file); + return false; + } + H5Aclose(attr); + H5Fclose(hdf5_file); + return true; +} + +bool HDF5_File_Reader::ReadDataSet(string ds_name, hsize_t &nDim, hsize_t* &dims, float* &data) +{ + double* d_data; + if (ReadDataSet(ds_name, nDim, dims, d_data)==false) + return false; + hsize_t data_size = 1; + for (unsigned int d=0;d<nDim;++d) + data_size*=dims[d]; + data = new float[data_size]; + for (size_t n=0;n<data_size;++n) + data[n]=d_data[n]; + delete[] d_data; + return true; +} + +bool HDF5_File_Reader::ReadDataSet(string ds_name, hsize_t &nDim, hsize_t* &dims, double* &data) +{ + if (IsValid()==false) + return false; + + hid_t hdf5_file = H5Fopen( m_filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT ); + if (hdf5_file==-1) + { + cerr << "HDF5_File_Reader::ReadDataSet: opening the given file """ << m_filename << """ failed" << endl; + return false; + } + + hid_t dataset = H5Dopen(hdf5_file, ds_name.c_str(), H5P_DEFAULT ); + if (dataset<0) + { + cerr << "HDF5_File_Reader::ReadDataSet: dataset not found" << endl; + H5Fclose(hdf5_file); + return false; + } + hid_t type = H5Dget_type(dataset); + if (type<0) + { + cerr << "HDF5_File_Reader::ReadDataSet: dataset type error" << endl; + H5Dclose(dataset); + H5Fclose(hdf5_file); + return false; + } + if (H5Tget_class(type)!=H5T_FLOAT) + { + cerr << "HDF5_File_Reader::ReadDataSet: dataset type not a float" << endl; + H5Dclose(dataset); + H5Fclose(hdf5_file); + return false; + } + + hid_t space = H5Dget_space(dataset); + nDim = H5Sget_simple_extent_ndims(space); + dims = new hsize_t[nDim]; + H5Sget_simple_extent_dims(space, dims, NULL ); + hsize_t data_size = 1; + for (unsigned int d=0;d<nDim;++d) + data_size*=dims[d]; + + void *value=NULL; + float *f_value=NULL; + data = new double[data_size]; + if (H5Tget_size(type)==sizeof(float)) + { + f_value = new float[data_size]; + value = f_value; + } + else + value = data; + + if (H5Dread(dataset,type,H5S_ALL,H5S_ALL,H5P_DEFAULT,value)<0) + { + cerr << "HDF5_File_Reader::ReadDataSet: error reading data" << endl; + H5Dclose(dataset); + H5Fclose(hdf5_file); + delete[] data; + delete[] f_value; + data=NULL; + return false; + } + if (f_value) + for (size_t n=0;n<data_size;++n) + data[n]=f_value[n]; + delete[] f_value; + H5Dclose(dataset); + H5Fclose(hdf5_file); + return true; +} + +bool HDF5_File_Reader::ReadMesh(float** lines, unsigned int* numLines, int &meshType) +{ + if (IsValid()==false) + return false; + + hid_t hdf5_file = H5Fopen( m_filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT ); + if (hdf5_file==-1) + { + cerr << "HDF5_File_Reader::ReadMesh: opening the given file """ << m_filename << """ failed" << endl; + return false; + } + + vector<string> Mesh_Names; + if (H5Lexists(hdf5_file, "/Mesh/x", H5P_DEFAULT) && H5Lexists(hdf5_file, "/Mesh/y", H5P_DEFAULT) && H5Lexists(hdf5_file, "/Mesh/z", H5P_DEFAULT)) + { + meshType = 0; + Mesh_Names.push_back("/Mesh/x"); + Mesh_Names.push_back("/Mesh/y"); + Mesh_Names.push_back("/Mesh/z"); + } + else if (H5Lexists(hdf5_file, "/Mesh/rho", H5P_DEFAULT) && H5Lexists(hdf5_file, "/Mesh/alpha", H5P_DEFAULT) && H5Lexists(hdf5_file, "/Mesh/z", H5P_DEFAULT)) + { + meshType = 1; + Mesh_Names.push_back("/Mesh/rho"); + Mesh_Names.push_back("/Mesh/alpha"); + Mesh_Names.push_back("/Mesh/z"); + } + else + { + cerr << "HDF5_File_Reader::ReadMesh: no falid mesh information found" << endl; + H5Fclose(hdf5_file); + return false; + } + + for (int n=0;n<3;++n) + { + hsize_t nDim; + hsize_t* dims=NULL; + float* data=NULL; + ReadDataSet(Mesh_Names.at(n), nDim, dims, data); + if (nDim!=1) + { + cerr << "HDF5_File_Reader::ReadMesh: mesh dimension error" << endl; + delete[] dims; + delete[] data; + H5Fclose(hdf5_file); + return false; + } + numLines[n]=dims[0]; + delete[] dims; + lines[n]=data; + } + H5Fclose(hdf5_file); + return true; +} + +unsigned int HDF5_File_Reader::GetNumTimeSteps() +{ + if (IsValid()==false) + return false; + + hid_t hdf5_file; + hid_t TD_grp; + if (OpenGroup(hdf5_file, TD_grp, "/FieldData/TD")==false) + return false; + + hsize_t numObj; + if (H5Gget_num_objs(TD_grp,&numObj)<0) + { + cerr << "HDF5_File_Reader::GetNumTimeSteps: can't read number of datasets" << endl; + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return 0; + } + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return numObj; +} + +bool HDF5_File_Reader::ReadTimeSteps(vector<unsigned int> ×tep, vector<string> &names) +{ + if (IsValid()==false) + return false; + + hid_t hdf5_file; + hid_t TD_grp; + if (OpenGroup(hdf5_file, TD_grp, "/FieldData/TD")==false) + return false; + + hsize_t numObj; + if (H5Gget_num_objs(TD_grp,&numObj)<0) + { + cerr << "HDF5_File_Reader::ReadTimeSteps: can't read number of datasets" << endl; + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return false; + } + char name[100]; + timestep.clear(); + timestep.resize(numObj,0); + names.clear(); + names.resize(numObj); + for (hsize_t n=0;n<numObj;++n) + { + if (H5Gget_objtype_by_idx(TD_grp, n) != H5G_DATASET) + { + cerr << "HDF5_File_Reader::ReadTimeSteps: invalid timestep found!" << endl; + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return false; + } + H5Gget_objname_by_idx(TD_grp, n, name, 100 ); + istringstream is(name); + unsigned int num; + if (is >> num) + { + timestep.at(n)=num; + names.at(n)=name; + } + else + { + cerr << "HDF5_File_Reader::ReadTimeSteps: invalid timestep format found!" << endl; + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return false; + } + } + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return true; +} + +float**** HDF5_File_Reader::GetTDVectorData(size_t idx, float &time, unsigned int data_size[]) +{ + if (IsValid()==false) + return NULL; + + hid_t hdf5_file; + hid_t TD_grp; + if (OpenGroup(hdf5_file, TD_grp, "/FieldData/TD")==false) + return NULL; + + hsize_t numObj; + if (H5Gget_num_objs(TD_grp,&numObj)<0) + { + cerr << "HDF5_File_Reader::GetTDVectorData: can't read number of datasets" << endl; + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return NULL; + } + if (idx>=numObj) + { + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return NULL; + } + + if (H5Gget_objtype_by_idx(TD_grp, idx) != H5G_DATASET) + { + cerr << "HDF5_File_Reader::GetTDVectorData: invalid timestep found!" << endl; + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return NULL; + } + + char name[100]; + H5Gget_objname_by_idx(TD_grp, idx, name, 100 ); + string ds_name = "/FieldData/TD/" + string(name); + + hid_t attr = H5Aopen_by_name(hdf5_file, ds_name.c_str(), "time", H5P_DEFAULT, H5P_DEFAULT); + if (attr<0) + { + cerr << "HDF5_File_Reader::GetTDVectorData: time attribute not found!" << endl; + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return NULL; + } + if (H5Aread(attr, H5T_NATIVE_FLOAT, &time)<0) + { + cerr << "HDF5_File_Reader::GetTDVectorData: can't read time attribute!" << endl; + H5Aclose(attr); + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return NULL; + } + + hsize_t nDim; + hsize_t* dims=NULL; + double* data=NULL; + ReadDataSet(ds_name, nDim, dims, data); + if (nDim!=4) + { + cerr << "HDF5_File_Reader::GetTDVectorData: data dimension invalid" << endl; + delete[] dims; + H5Aclose(attr); + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return NULL; + } + if (dims[0]!=3) + { + cerr << "HDF5_File_Reader::GetTDVectorData: vector data dimension invalid" << endl; + delete[] dims; + H5Aclose(attr); + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return NULL; + } + data_size[0]=dims[3]; + data_size[1]=dims[2]; + data_size[2]=dims[1]; + delete[] dims; + data_size[3]=3; + size_t pos = 0; + float**** field = Create_N_3DArray<float>(data_size); + for (unsigned int d=0;d<3;++d) + for (unsigned int k=0;k<data_size[2];++k) + for (unsigned int j=0;j<data_size[1];++j) + for (unsigned int i=0;i<data_size[0];++i) + { + field[d][i][j][k]=data[pos++]; + } + delete[] data; + H5Aclose(attr); + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return field; +} + +unsigned int HDF5_File_Reader::GetNumFrequencies() +{ + vector<float> frequencies; + if (ReadFrequencies(frequencies)==false) + return 0; + return frequencies.size(); +} + +bool HDF5_File_Reader::ReadFrequencies(vector<float> &frequencies) +{ + if (IsValid()==false) + return false; + + return ReadAttribute("/FieldData/FD","frequency",frequencies); +} + +bool HDF5_File_Reader::ReadFrequencies(vector<double> &frequencies) +{ + if (IsValid()==false) + return false; + + return ReadAttribute("/FieldData/FD","frequency",frequencies); +} + + +complex<float>**** HDF5_File_Reader::GetFDVectorData(size_t idx, unsigned int data_size[]) +{ + hsize_t nDim; + hsize_t* dims=NULL; + double* data=NULL; + stringstream ds_name; + + // read real values + ds_name << "/FieldData/FD/f" << idx << "_real"; + if (ReadDataSet(ds_name.str(), nDim, dims, data) == false) + return NULL; + if (nDim!=4) + { + cerr << "HDF5_File_Reader::GetFDVectorData: data dimension invalid" << endl; + delete[] dims; + delete[] data; + return NULL; + } + if (dims[0]!=3) + { + cerr << "HDF5_File_Reader::GetFDVectorData: vector data dimension invalid" << endl; + delete[] dims; + delete[] data; + return NULL; + } + data_size[0]=dims[3]; + data_size[1]=dims[2]; + data_size[2]=dims[1]; + delete[] dims; + data_size[3]=3; + size_t pos = 0; + complex<float>**** field = Create_N_3DArray<complex<float> >(data_size); + for (unsigned int d=0;d<3;++d) + for (unsigned int k=0;k<data_size[2];++k) + for (unsigned int j=0;j<data_size[1];++j) + for (unsigned int i=0;i<data_size[0];++i) + { + field[d][i][j][k]=data[pos++]; + } + delete[] data; + + // read imaginary values + ds_name.str(""); + ds_name << "/FieldData/FD/f" << idx << "_imag"; + if (ReadDataSet(ds_name.str(), nDim, dims, data) == false) + { + Delete_N_3DArray<complex<float> >(field, data_size); + return NULL; + } + if (nDim!=4) + { + cerr << "HDF5_File_Reader::GetFDVectorData: data dimension invalid" << endl; + delete[] dims; + delete[] data; + Delete_N_3DArray<complex<float> >(field, data_size); + return NULL; + } + if (dims[0]!=3) + { + cerr << "HDF5_File_Reader::GetFDVectorData: vector data dimension invalid" << endl; + delete[] dims; + delete[] data; + Delete_N_3DArray<complex<float> >(field, data_size); + return NULL; + } + if ((data_size[0]!=dims[3]) || (data_size[1]!=dims[2]) || (data_size[2]!=dims[1])) + { + cerr << "HDF5_File_Reader::GetFDVectorData: data dimension mismatch" << endl; + delete[] dims; + delete[] data; + Delete_N_3DArray<complex<float> >(field, data_size); + return NULL; + } + delete[] dims; + + pos = 0; + complex<double> I(0,1); + for (unsigned int d=0;d<3;++d) + for (unsigned int k=0;k<data_size[2];++k) + for (unsigned int j=0;j<data_size[1];++j) + for (unsigned int i=0;i<data_size[0];++i) + { + field[d][i][j][k]+= I*data[pos++]; + } + delete[] data; + + return field; +} + +bool HDF5_File_Reader::CalcFDVectorData(vector<float> &frequencies, vector<complex<float>****> &FD_data, unsigned int data_size[4]) +{ + FD_data.clear(); + + if (GetNumTimeSteps()<=0) + { + cerr << "HDF5_File_Reader::CalcFDVectorData: error, no TD data found..." << endl; + return false; + } + + float time; + //read first TD data + float**** field = this->GetTDVectorData(0,time,data_size); + if (field==NULL) + { + cerr << "HDF5_File_Reader::CalcFDVectorData: error, no TD data found..." << endl; + return false; + } + + //init + FD_data.resize(frequencies.size(), NULL); + for (size_t fn=0;fn<frequencies.size();++fn) + FD_data.at(fn) = Create_N_3DArray<complex<float> >(data_size); + + size_t ts=0; + unsigned int pos[3]; + complex<float> PI_2_I(0.0,-2.0*M_PI); + complex<float> exp_jwt_2_dt; + float time_diff=0; + float time_old =0; + complex<float>**** field_fd = NULL; + while (field) + { + if ((ts>1) && abs(time_diff - (time - time_old))>1e15) + { + cerr << "HDF5_File_Reader::CalcFDVectorData: time interval error..." << endl; + for (size_t fn=0;fn<frequencies.size();++fn) + Delete_N_3DArray(FD_data.at(fn),data_size); + FD_data.clear(); + return false; + } + time_diff = time - time_old; + for (size_t fn=0;fn<frequencies.size();++fn) + { + exp_jwt_2_dt = exp( (complex<float>)(PI_2_I * frequencies.at(fn) * time) ); + field_fd = FD_data.at(fn); + for (pos[0]=0; pos[0]<data_size[0]; ++pos[0]) + { + for (pos[1]=0; pos[1]<data_size[1]; ++pos[1]) + { + for (pos[2]=0; pos[2]<data_size[2]; ++pos[2]) + { + field_fd[0][pos[0]][pos[1]][pos[2]] += field[0][pos[0]][pos[1]][pos[2]] * exp_jwt_2_dt; + field_fd[1][pos[0]][pos[1]][pos[2]] += field[1][pos[0]][pos[1]][pos[2]] * exp_jwt_2_dt; + field_fd[2][pos[0]][pos[1]][pos[2]] += field[2][pos[0]][pos[1]][pos[2]] * exp_jwt_2_dt; + } + } + } + } + ++ts; + Delete_N_3DArray(field,data_size); + time_old = time; + field = this->GetTDVectorData(ts,time,data_size); + } + + // finalize data + time_diff*=2; + for (size_t fn=0;fn<frequencies.size();++fn) + { + field_fd = FD_data.at(fn); + for (pos[0]=0; pos[0]<data_size[0]; ++pos[0]) + { + for (pos[1]=0; pos[1]<data_size[1]; ++pos[1]) + { + for (pos[2]=0; pos[2]<data_size[2]; ++pos[2]) + { + field_fd[0][pos[0]][pos[1]][pos[2]] *= time_diff; + field_fd[1][pos[0]][pos[1]][pos[2]] *= time_diff; + field_fd[2][pos[0]][pos[1]][pos[2]] *= time_diff; + } + } + } + } + return true; +} diff --git a/openEMS/tools/hdf5_file_reader.h b/openEMS/tools/hdf5_file_reader.h new file mode 100644 index 0000000..f190240 --- /dev/null +++ b/openEMS/tools/hdf5_file_reader.h @@ -0,0 +1,78 @@ +/* +* 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 HDF5_FILE_READER_H +#define HDF5_FILE_READER_H + +#include <string> +#include <vector> +#include <complex> +#include <hdf5.h> + +class HDF5_File_Reader +{ +public: + HDF5_File_Reader(std::string filename); + virtual ~HDF5_File_Reader(); + + bool ReadMesh(float** lines, unsigned int* numLines, int &meshType); + + //! Get the number of timesteps stored at /FieldData/TD/<NUMBER_OF_TS> + unsigned int GetNumTimeSteps(); + bool ReadTimeSteps(std::vector<unsigned int> ×tep, std::vector<std::string> &names); + + /*! + Get time-domain data stored at /FieldData/TD/<NUMBER_OF_TS> + \param[in] idx time step index to extract + \param[out] time time attribute for the given timestep + \param[out] data_size data size found + \return field data found in given timestep, caller must delete array, returns NULL if timestep was not found + */ + float**** GetTDVectorData(size_t idx, float &time, unsigned int data_size[4]); + + unsigned int GetNumFrequencies(); + bool ReadFrequencies(std::vector<float> &frequencies); + bool ReadFrequencies(std::vector<double> &frequencies); + + /*! + Get frequency-domain data stored at "/FieldData/FD/f<idx>_real" and "/FieldData/FD/f<idx>_imag" + \param[in] idx frequency index to extract + \param[out] data_size data size found + \return complex field data found for the given frequency, caller must delete array, returns NULL if frequency was not found + */ + std::complex<float>**** GetFDVectorData(size_t idx, unsigned int data_size[4]); + + /*! + Calculate + */ + bool CalcFDVectorData(std::vector<float> &frequencies, std::vector<std::complex<float>****> &FD_data, unsigned int data_size[4]); + + bool ReadAttribute(std::string grp_name, std::string attr_name, std::vector<double> &attr_values); + bool ReadAttribute(std::string grp_name, std::string attr_name, std::vector<float> &attr_values); + + bool IsValid(); + +protected: + std::string m_filename; + + bool ReadDataSet(std::string ds_name, hsize_t &nDim, hsize_t* &dims, double* &data); + bool ReadDataSet(std::string ds_name, hsize_t &nDim, hsize_t* &dims, float* &data); + + bool OpenGroup(hid_t &file, hid_t &group, std::string groupName); +}; + +#endif // HDF5_FILE_READER_H diff --git a/openEMS/tools/hdf5_file_writer.cpp b/openEMS/tools/hdf5_file_writer.cpp new file mode 100644 index 0000000..e3a2113 --- /dev/null +++ b/openEMS/tools/hdf5_file_writer.cpp @@ -0,0 +1,515 @@ +/* +* 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/>. +*/ + +using namespace std; + +#include "hdf5_file_writer.h" +#include <boost/algorithm/string.hpp> +#include <hdf5.h> + +#include <sstream> +#include <iostream> +#include <iomanip> + +HDF5_File_Writer::HDF5_File_Writer(string filename) +{ + m_filename = filename; + m_Group = "/"; + hid_t hdf5_file = H5Fcreate(m_filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + if (hdf5_file<0) + { + cerr << "HDF5_File_Writer::HDF5_File_Writer: Error, creating the given file """ << m_filename << """ failed" << endl; + } + H5Fclose(hdf5_file); +} + +HDF5_File_Writer::~HDF5_File_Writer() +{ +} + +hid_t HDF5_File_Writer::OpenGroup(hid_t hdf5_file, string group) +{ + if (hdf5_file<0) + { + cerr << "HDF5_File_Writer::CreateGroup: Error, invalid file id" << endl; + return -1; + } + + vector<string> results; + boost::split(results, group, boost::is_any_of("/")); + + hid_t grp=H5Gopen(hdf5_file,"/", H5P_DEFAULT); + if (grp<0) + { + cerr << "HDF5_File_Writer::OpenGroup: Error, opening root group " << endl; + return -1; + } + + for (size_t n=0;n<results.size();++n) + { + hid_t old_grp = grp; + if (!results.at(n).empty()) + { + if (H5Lexists(grp, results.at(n).c_str(), H5P_DEFAULT)) + { + grp = H5Gopen(grp, results.at(n).c_str(), H5P_DEFAULT); + H5Gclose(old_grp); + if (grp<0) + { + cerr << "HDF5_File_Writer::OpenGroup: Error, failed to open existing group" << endl; + return -1; + } + } + else + { + grp = H5Gcreate(grp,results.at(n).c_str(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + H5Gclose(old_grp); + if (grp<0) + { + cerr << "HDF5_File_Writer::OpenGroup: Error, creating group """ << group << """ failed" << endl; + return -1; + } + } + } + } + return grp; +} + +void HDF5_File_Writer::SetCurrentGroup(std::string group, bool createGrp) +{ + m_Group = group; + if (createGrp==false) + return; + + hid_t hdf5_file = H5Fopen( m_filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT ); + if (hdf5_file<0) + { + cerr << "HDF5_File_Writer::SetCurrentGroup: Error, opening the given file """ << m_filename << """ failed" << endl; + return; + } + hid_t hdf5_group = OpenGroup(hdf5_file, m_Group); + if (hdf5_group<0) + cerr << "HDF5_File_Writer::WriteData: Error opening group" << endl; + H5Gclose(hdf5_group); + H5Fclose(hdf5_file); +} + +bool HDF5_File_Writer::WriteRectMesh(unsigned int const* numLines, double const* const* discLines, int MeshType, double scaling) +{ + float* array[3]; + for (int n=0; n<3; ++n) + { + array[n] = new float[numLines[n]]; + for (unsigned int i=0; i<numLines[n]; ++i) + array[n][i]=discLines[n][i]; + + } + bool success = WriteRectMesh(numLines,array,MeshType,scaling); + for (int n=0; n<3; ++n) + delete[] array[n]; + return success; +} + +bool HDF5_File_Writer::WriteRectMesh(unsigned int const* numLines, float const* const* discLines, int MeshType, float scaling) +{ + hid_t hdf5_file = H5Fopen( m_filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT ); + if (hdf5_file<0) + { + cerr << "HDF5_File_Writer::WriteRectMesh: Error, opening the given file """ << m_filename << """ failed" << endl; + return false; + } + + if (H5Lexists(hdf5_file, "/Mesh", H5P_DEFAULT)) + { + cerr << "HDF5_File_Writer::WriteRectMesh: Error, group ""/Mesh"" already exists" << endl; + H5Fclose(hdf5_file); + return false; + } + + hid_t mesh_grp = H5Gcreate(hdf5_file,"/Mesh", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (mesh_grp<0) + { + cerr << "HDF5_File_Writer::WriteRectMesh: Error, creating group ""/Mesh"" failed" << endl; + H5Fclose(hdf5_file); + return false; + } + + string names[] = {"x","y","z"}; + if (MeshType==1) + { + names[0]="rho"; + names[1]="alpha"; + } + if (MeshType==2) + { + names[0]="r"; + names[1]="theta"; + names[2]="phi"; + } + + for (int n=0; n<3; ++n) + { + hsize_t dims[1]={numLines[n]}; + hid_t space = H5Screate_simple(1, dims, NULL); + hid_t dataset = H5Dcreate(mesh_grp, names[n].c_str(), H5T_NATIVE_FLOAT, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + float* array = new float[numLines[n]]; + for (unsigned int i=0; i<numLines[n]; ++i) + { + if ((MeshType==1) && (n==1)) //check for alpha-direction + array[i] = discLines[n][i]; + else if ((MeshType==2) && (n>0)) //check for theta/phi-direction + array[i] = discLines[n][i]; + else + array[i] = discLines[n][i] * scaling; + } + if (H5Dwrite(dataset, H5T_NATIVE_FLOAT, space, H5P_DEFAULT, H5P_DEFAULT, array)) + { + cerr << "HDF5_File_Writer::WriteRectMesh: Error, writing to dataset failed" << endl; + delete[] array; + H5Dclose(dataset); + H5Sclose(space); + H5Gclose(mesh_grp); + H5Fclose(hdf5_file); + return false; + } + delete[] array; + H5Dclose(dataset); + H5Sclose(space); + } + H5Gclose(mesh_grp); + H5Fclose(hdf5_file); + return true; +} + +bool HDF5_File_Writer::WriteScalarField(std::string dataSetName, float const* const* const* field, size_t datasize[3]) +{ + size_t pos = 0; + size_t size = datasize[0]*datasize[1]*datasize[2]; + size_t n_size[3]={datasize[2],datasize[1],datasize[0]}; + float* buffer = new float[size]; + for (size_t k=0;k<datasize[2];++k) + for (size_t j=0;j<datasize[1];++j) + for (size_t i=0;i<datasize[0];++i) + { + buffer[pos++]=field[i][j][k]; + } + bool success = WriteData(dataSetName,buffer,3,n_size); + delete[] buffer; + return success; +} + +bool HDF5_File_Writer::WriteScalarField(std::string dataSetName, double const* const* const* field, size_t datasize[3]) +{ + size_t pos = 0; + size_t size = datasize[0]*datasize[1]*datasize[2]; + size_t n_size[3]={datasize[2],datasize[1],datasize[0]}; + double* buffer = new double[size]; + for (size_t k=0;k<datasize[2];++k) + for (size_t j=0;j<datasize[1];++j) + for (size_t i=0;i<datasize[0];++i) + { + buffer[pos++]=field[i][j][k]; + } + bool success = WriteData(dataSetName,buffer,3,n_size); + delete[] buffer; + return success; +} + +bool HDF5_File_Writer::WriteScalarField(std::string dataSetName, std::complex<float> const* const* const* field, size_t datasize[3]) +{ + size_t pos = 0; + size_t size = datasize[0]*datasize[1]*datasize[2]; + size_t n_size[3]={datasize[2],datasize[1],datasize[0]}; + float* buffer = new float[size]; + for (size_t k=0;k<datasize[2];++k) + for (size_t j=0;j<datasize[1];++j) + for (size_t i=0;i<datasize[0];++i) + { + buffer[pos++]=real(field[i][j][k]); + } + bool success = WriteData(dataSetName + "_real",buffer,3,n_size); + + pos = 0; + for (size_t k=0;k<datasize[2];++k) + for (size_t j=0;j<datasize[1];++j) + for (size_t i=0;i<datasize[0];++i) + { + buffer[pos++]=imag(field[i][j][k]); + } + success &= WriteData(dataSetName + "_imag",buffer,3,n_size); + + delete[] buffer; + return success; +} + +bool HDF5_File_Writer::WriteScalarField(std::string dataSetName, std::complex<double> const* const* const* field, size_t datasize[3]) +{ + size_t pos = 0; + size_t size = datasize[0]*datasize[1]*datasize[2]; + size_t n_size[3]={datasize[2],datasize[1],datasize[0]}; + double* buffer = new double[size]; + for (size_t k=0;k<datasize[2];++k) + for (size_t j=0;j<datasize[1];++j) + for (size_t i=0;i<datasize[0];++i) + { + buffer[pos++]=real(field[i][j][k]); + } + bool success = WriteData(dataSetName + "_real",buffer,3,n_size); + + pos = 0; + for (size_t k=0;k<datasize[2];++k) + for (size_t j=0;j<datasize[1];++j) + for (size_t i=0;i<datasize[0];++i) + { + buffer[pos++]=imag(field[i][j][k]); + } + success &= WriteData(dataSetName + "_imag",buffer,3,n_size); + + delete[] buffer; + return success; +} + +bool HDF5_File_Writer::WriteVectorField(std::string dataSetName, float const* const* const* const* field, size_t datasize[3]) +{ + size_t pos = 0; + size_t size = datasize[0]*datasize[1]*datasize[2]*3; + float* buffer = new float[size]; + for (int n=0;n<3;++n) + for (size_t k=0;k<datasize[2];++k) + for (size_t j=0;j<datasize[1];++j) + for (size_t i=0;i<datasize[0];++i) + { + buffer[pos++]=field[n][i][j][k]; + } + size_t n_size[4]={3,datasize[2],datasize[1],datasize[0]}; + bool success = WriteData(dataSetName,buffer,4,n_size); + delete[] buffer; + return success; +} + +bool HDF5_File_Writer::WriteVectorField(std::string dataSetName, double const* const* const* const* field, size_t datasize[3]) +{ + size_t pos = 0; + size_t size = datasize[0]*datasize[1]*datasize[2]*3; + double* buffer = new double[size]; + for (int n=0;n<3;++n) + for (size_t k=0;k<datasize[2];++k) + for (size_t j=0;j<datasize[1];++j) + for (size_t i=0;i<datasize[0];++i) + { + buffer[pos++]=field[n][i][j][k]; + } + size_t n_size[4]={3,datasize[2],datasize[1],datasize[0]}; + bool success = WriteData(dataSetName,buffer,4,n_size); + delete[] buffer; + return success; +} + +bool HDF5_File_Writer::WriteVectorField(std::string dataSetName, std::complex<float> const* const* const* const* field, size_t datasize[3]) +{ + size_t pos = 0; + size_t size = datasize[0]*datasize[1]*datasize[2]*3; + size_t n_size[4]={3,datasize[2],datasize[1],datasize[0]}; + float* buffer = new float[size]; + for (int n=0;n<3;++n) + for (size_t k=0;k<datasize[2];++k) + for (size_t j=0;j<datasize[1];++j) + for (size_t i=0;i<datasize[0];++i) + { + buffer[pos++]=real(field[n][i][j][k]); + } + bool success = WriteData(dataSetName + "_real",buffer,4,n_size); + + pos = 0; + for (int n=0;n<3;++n) + for (size_t k=0;k<datasize[2];++k) + for (size_t j=0;j<datasize[1];++j) + for (size_t i=0;i<datasize[0];++i) + { + buffer[pos++]=imag(field[n][i][j][k]); + } + success &= WriteData(dataSetName + "_imag",buffer,4,n_size); + + delete[] buffer; + return success; +} + +bool HDF5_File_Writer::WriteVectorField(std::string dataSetName, std::complex<double> const* const* const* const* field, size_t datasize[3]) +{ + size_t pos = 0; + size_t size = datasize[0]*datasize[1]*datasize[2]*3; + size_t n_size[4]={3,datasize[2],datasize[1],datasize[0]}; + double* buffer = new double[size]; + for (int n=0;n<3;++n) + for (size_t k=0;k<datasize[2];++k) + for (size_t j=0;j<datasize[1];++j) + for (size_t i=0;i<datasize[0];++i) + { + buffer[pos++]=real(field[n][i][j][k]); + } + bool success = WriteData(dataSetName + "_real",buffer,4,n_size); + + pos = 0; + for (int n=0;n<3;++n) + for (size_t k=0;k<datasize[2];++k) + for (size_t j=0;j<datasize[1];++j) + for (size_t i=0;i<datasize[0];++i) + { + buffer[pos++]=imag(field[n][i][j][k]); + } + success &= WriteData(dataSetName + "_imag",buffer,4,n_size); + + delete[] buffer; + return success; +} + +bool HDF5_File_Writer::WriteData(std::string dataSetName, float const* field_buf, size_t dim, size_t* datasize) +{ + return WriteData(dataSetName, H5T_NATIVE_FLOAT, field_buf,dim, datasize); +} + +bool HDF5_File_Writer::WriteData(std::string dataSetName, double const* field_buf, size_t dim, size_t* datasize) +{ + return WriteData(dataSetName, H5T_NATIVE_DOUBLE, field_buf,dim, datasize); +} + +bool HDF5_File_Writer::WriteData(std::string dataSetName, hid_t mem_type, void const* field_buf, size_t dim, size_t* datasize) +{ + hid_t hdf5_file = H5Fopen( m_filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT ); + if (hdf5_file<0) + { + cerr << "HDF5_File_Writer::WriteData: Error, opening the given file """ << m_filename << """ failed" << endl; + return false; + } + + hid_t group = OpenGroup(hdf5_file,m_Group); + if (group<0) + { + cerr << "HDF5_File_Writer::WriteData: Error opening group" << endl; + H5Fclose(hdf5_file); + return false; + } + + hsize_t dims[dim]; + for (size_t n=0;n<dim;++n) + dims[n]=datasize[n]; + hid_t space = H5Screate_simple(dim, dims, NULL); + hid_t dataset = H5Dcreate(group, dataSetName.c_str(), mem_type, space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (H5Dwrite(dataset, mem_type, space, H5P_DEFAULT, H5P_DEFAULT, field_buf)) + { + cerr << "HDF5_File_Writer::WriteData: Error, writing to dataset failed" << endl; + H5Dclose(dataset); + H5Sclose(space); + H5Gclose(group); + H5Fclose(hdf5_file); + return false; + } + H5Dclose(dataset); + H5Sclose(space); + H5Gclose(group); + H5Fclose(hdf5_file); + return true; +} + +bool HDF5_File_Writer::WriteAtrribute(std::string locName, std::string attr_name, void const* value, hsize_t size, hid_t mem_type) +{ + hid_t hdf5_file = H5Fopen( m_filename.c_str(), H5F_ACC_RDWR, H5P_DEFAULT ); + if (hdf5_file<0) + { + cerr << "HDF5_File_Writer::WriteAtrribute: Error, opening the given file """ << m_filename << """ failed" << endl; + return false; + } + + if (H5Lexists(hdf5_file, locName.c_str(), H5P_DEFAULT)<0) + { + cerr << "HDF5_File_Writer::WriteAtrribute: Error, failed to find location: """ << locName << """" << endl; + H5Fclose(hdf5_file); + return false; + } + hid_t loc = H5Oopen(hdf5_file, locName.c_str(), H5P_DEFAULT); + if (loc<0) + { + cerr << "HDF5_File_Writer::WriteAtrribute: Error, failed to open location: """ << locName << """" << endl; + H5Fclose(hdf5_file); + return false; + } + + hid_t dataspace_id = H5Screate_simple(1, &size, NULL); + + /* Create a dataset attribute. */ + hid_t attribute_id = H5Acreate(loc, attr_name.c_str(), mem_type, dataspace_id, H5P_DEFAULT, H5P_DEFAULT); + if (attribute_id<0) + { + cerr << "HDF5_File_Writer::WriteAtrribute: Error, failed to create the attrbute" << endl; + H5Sclose(dataspace_id); + H5Oclose(loc); + H5Fclose(hdf5_file); + return false; + } + + /* Write the attribute data. */ + if (H5Awrite(attribute_id, mem_type, value)<0) + { + cerr << "HDF5_File_Writer::WriteAtrribute: Error, failed to write the attrbute" << endl; + H5Aclose(attribute_id); + H5Sclose(dataspace_id); + H5Oclose(loc); + H5Fclose(hdf5_file); + return false; + } + H5Aclose(attribute_id); + H5Sclose(dataspace_id); + H5Oclose(loc); + H5Fclose(hdf5_file); + return true; +} + +bool HDF5_File_Writer::WriteAtrribute(std::string locName, std::string attr_name, float const* value, hsize_t size) +{ + return WriteAtrribute(locName,attr_name, value, size, H5T_NATIVE_FLOAT); +} + +bool HDF5_File_Writer::WriteAtrribute(std::string locName, std::string attr_name, double const* value, hsize_t size) +{ + return WriteAtrribute(locName,attr_name, value, size, H5T_NATIVE_DOUBLE); +} + +bool HDF5_File_Writer::WriteAtrribute(std::string locName, std::string attr_name, vector<float> values) +{ + float val[values.size()]; + for (size_t n=0;n<values.size();++n) + val[n]=values.at(n); + return HDF5_File_Writer::WriteAtrribute(locName, attr_name,val,values.size(),H5T_NATIVE_FLOAT); +} + +bool HDF5_File_Writer::WriteAtrribute(std::string locName, std::string attr_name, vector<double> values) +{ + double val[values.size()]; + for (size_t n=0;n<values.size();++n) + val[n]=values.at(n); + return HDF5_File_Writer::WriteAtrribute(locName, attr_name, val, values.size(), H5T_NATIVE_DOUBLE); +} + +bool HDF5_File_Writer::WriteAtrribute(std::string locName, std::string attr_name, float value) +{ + return HDF5_File_Writer::WriteAtrribute(locName, attr_name,&value,1, H5T_NATIVE_FLOAT); +} + +bool HDF5_File_Writer::WriteAtrribute(std::string locName, std::string attr_name, double value) +{ + return HDF5_File_Writer::WriteAtrribute(locName, attr_name,&value,1, H5T_NATIVE_DOUBLE); +} diff --git a/openEMS/tools/hdf5_file_writer.h b/openEMS/tools/hdf5_file_writer.h new file mode 100644 index 0000000..7ad975c --- /dev/null +++ b/openEMS/tools/hdf5_file_writer.h @@ -0,0 +1,68 @@ +/* +* 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 HDF5_FILE_WRITER_H +#define HDF5_FILE_WRITER_H + +#include <string> +#include <vector> +#include <complex> +#include <hdf5.h> + +class HDF5_File_Writer +{ +public: + HDF5_File_Writer(std::string filename); + ~HDF5_File_Writer(); + + bool WriteRectMesh(unsigned int const* numLines, double const* const* discLines, int MeshType=0, double scaling=1); + bool WriteRectMesh(unsigned int const* numLines, float const* const* discLines, int MeshType=0, float scaling=1); + + bool WriteScalarField(std::string dataSetName, float const* const* const* field, size_t datasize[3]); + bool WriteScalarField(std::string dataSetName, double const* const* const* field, size_t datasize[3]); + + bool WriteScalarField(std::string dataSetName, std::complex<float> const* const* const* field, size_t datasize[3]); + bool WriteScalarField(std::string dataSetName, std::complex<double> const* const* const* field, size_t datasize[3]); + + bool WriteVectorField(std::string dataSetName, float const* const* const* const* field, size_t datasize[3]); + bool WriteVectorField(std::string dataSetName, double const* const* const* const* field, size_t datasize[3]); + + bool WriteVectorField(std::string dataSetName, std::complex<float> const* const* const* const* field, size_t datasize[3]); + bool WriteVectorField(std::string dataSetName, std::complex<double> const* const* const* const* field, size_t datasize[3]); + + bool WriteData(std::string dataSetName, float const* field_buf, size_t dim, size_t* datasize); + bool WriteData(std::string dataSetName, double const* field_buf, size_t dim, size_t* datasize); + + bool WriteAtrribute(std::string locName, std::string attr_name, void const* value, hsize_t size, hid_t mem_type); + bool WriteAtrribute(std::string locName, std::string attr_name, float const* value, hsize_t size); + bool WriteAtrribute(std::string locName, std::string attr_name, double const* value, hsize_t size); + bool WriteAtrribute(std::string locName, std::string attr_name, std::vector<float> values); + bool WriteAtrribute(std::string locName, std::string attr_name, std::vector<double> values); + bool WriteAtrribute(std::string locName, std::string attr_name, float value); + bool WriteAtrribute(std::string locName, std::string attr_name, double value); + + void SetCurrentGroup(std::string group, bool createGrp=true); + +protected: + std::string m_filename; + std::string m_Group; + + hid_t OpenGroup(hid_t hdf5_file, std::string group); + bool WriteData(std::string dataSetName, hid_t mem_type, void const* field_buf, size_t dim, size_t* datasize); +}; + +#endif // HDF5_FILE_WRITER_H diff --git a/openEMS/tools/sar_calculation.cpp b/openEMS/tools/sar_calculation.cpp new file mode 100644 index 0000000..343aa07 --- /dev/null +++ b/openEMS/tools/sar_calculation.cpp @@ -0,0 +1,656 @@ +/* +* Copyright (C) 2012 Thorsten Liebig (Thorsten.Liebig@gmx.de) +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + + +#include "sar_calculation.h" +#include "cfloat" +#include "array_ops.h" +#include "global.h" + +using namespace std; + +SAR_Calculation::SAR_Calculation() +{ + m_Vx_Used = NULL; + m_Vx_Valid = NULL; + m_DebugLevel = 0; + SetAveragingMethod(SIMPLE, true); + Reset(); +} + +void SAR_Calculation::Reset() +{ + Delete3DArray(m_Vx_Used,m_numLines); + m_Vx_Used = NULL; + Delete3DArray(m_Vx_Valid,m_numLines); + m_Vx_Valid = NULL; + + m_avg_mass = 0; + m_numLines[0]=m_numLines[1]=m_numLines[2]=0; + m_cellWidth[0]=m_cellWidth[1]=m_cellWidth[2]=NULL; + + m_cell_volume = NULL; + m_cell_density = NULL; + m_cell_conductivity = NULL; + m_E_field = NULL; + m_J_field = NULL; + + Delete3DArray(m_Vx_Used,m_numLines); + m_Vx_Used = NULL; + Delete3DArray(m_Vx_Valid,m_numLines); + m_Vx_Valid = NULL; +} + +void SAR_Calculation::SetAveragingMethod(string method, bool silent) +{ + if (method.compare("IEEE_C95_3")==0) + return SetAveragingMethod(IEEE_C95_3, silent); + if (method.compare("IEEE_62704")==0) + return SetAveragingMethod(IEEE_62704, silent); + if (method.compare("Simple")==0) + return SetAveragingMethod(SIMPLE, silent); + + cerr << __func__ << ": Error, """ << method << """ is an unknown averaging method..." << endl; + // unknown method, fallback to simple + SetAveragingMethod(SIMPLE, false); +} + +void SAR_Calculation::SetAveragingMethod(SARAveragingMethod method, bool silent) +{ + if (method==IEEE_62704) + { + m_massTolerance = 0.0001; + m_maxMassIterations = 100; + m_maxBGRatio = 0.1; + m_markPartialAsUsed = false; + m_UnusedRelativeVolLimit = 1.05; + m_IgnoreFaceValid = false; + if (!silent) + cerr << __func__ << ": Setting averaging method to IEEE_62704" << endl; + return; + } + else if (method==IEEE_C95_3) + { + m_massTolerance = 0.05; + m_maxMassIterations = 100; + m_maxBGRatio = 1; + m_markPartialAsUsed = true; + m_UnusedRelativeVolLimit = 1; + m_IgnoreFaceValid = false; + if (!silent) + cerr << __func__ << ": Setting averaging method to IEEE_C95_3" << endl; + return; + } + else if (method==SIMPLE) + { + m_massTolerance = 0.05; + m_maxMassIterations = 100; + m_maxBGRatio = 1; + m_markPartialAsUsed = true; + m_UnusedRelativeVolLimit = 1; + m_IgnoreFaceValid = true; + if (!silent) + cerr << __func__ << ": Setting averaging method to SIMPLE" << endl; + return; + } + + cerr << __func__ << ": Error, unknown averaging method..." << endl; + // unknown method, fallback to simple + SetAveragingMethod(SIMPLE, false); +} + +void SAR_Calculation::SetNumLines(unsigned int numLines[3]) +{ + Delete3DArray(m_Vx_Used,m_numLines); + m_Vx_Used = NULL; + Delete3DArray(m_Vx_Valid,m_numLines); + m_Vx_Valid = NULL; + + for (int n=0;n<3;++n) + m_numLines[n]=numLines[n]; +} + +void SAR_Calculation::SetCellWidth(float* cellWidth[3]) +{ + for (int n=0;n<3;++n) + m_cellWidth[n]=cellWidth[n]; +} + +float*** SAR_Calculation::CalcSAR(float*** SAR) +{ + if (CheckValid()==false) + { + cerr << "SAR_Calculation::CalcSAR: SAR calculation is invalid due to missing values... Abort..." << endl; + return NULL; + } + if (m_avg_mass<=0) + return CalcLocalSAR(SAR); + return CalcAveragedSAR(SAR); +} + +bool SAR_Calculation::CheckValid() +{ + for (int n=0;n<3;++n) + if (m_cellWidth[n]==NULL) + return false; + if (m_E_field==NULL) + return false; + if ((m_J_field==NULL) && (m_cell_conductivity==NULL)) + return false; + if (m_cell_density==NULL) + return false; + if (m_avg_mass<0) + return false; + return true; +} + +double SAR_Calculation::CalcSARPower() +{ + if (CheckValid()==false) + { + cerr << "SAR_Calculation::CalcSARPower: SAR calculation is invalid due to missing values... Abort..." << endl; + return 0; + } + double power=0; + unsigned int pos[3]; + for (pos[0]=0; pos[0]<m_numLines[0]; ++pos[0]) + { + for (pos[1]=0; pos[1]<m_numLines[1]; ++pos[1]) + { + for (pos[2]=0; pos[2]<m_numLines[2]; ++pos[2]) + { + power += CalcLocalPowerDensity(pos)*CellVolume(pos); + } + } + } + return power; +} + +double SAR_Calculation::CalcLocalPowerDensity(unsigned int pos[3]) +{ + double l_pow=0; + if (m_cell_conductivity==NULL) + { + l_pow = abs(m_E_field[0][pos[0]][pos[1]][pos[2]]) * abs(m_J_field[0][pos[0]][pos[1]][pos[2]]); + l_pow += abs(m_E_field[1][pos[0]][pos[1]][pos[2]]) * abs(m_J_field[1][pos[0]][pos[1]][pos[2]]); + l_pow += abs(m_E_field[2][pos[0]][pos[1]][pos[2]]) * abs(m_J_field[2][pos[0]][pos[1]][pos[2]]); + } + else + { + l_pow = m_cell_conductivity[pos[0]][pos[1]][pos[2]]*abs(m_E_field[0][pos[0]][pos[1]][pos[2]]) * abs(m_E_field[0][pos[0]][pos[1]][pos[2]]); + l_pow += m_cell_conductivity[pos[0]][pos[1]][pos[2]]*abs(m_E_field[1][pos[0]][pos[1]][pos[2]]) * abs(m_E_field[1][pos[0]][pos[1]][pos[2]]); + l_pow += m_cell_conductivity[pos[0]][pos[1]][pos[2]]*abs(m_E_field[2][pos[0]][pos[1]][pos[2]]) * abs(m_E_field[2][pos[0]][pos[1]][pos[2]]); + } + l_pow*=0.5; + return l_pow; +} + +float*** SAR_Calculation::CalcLocalSAR(float*** SAR) +{ + unsigned int pos[3]; + m_Valid=0; + m_Used=0; + m_Unused=0; + m_AirVoxel=0; + for (pos[0]=0; pos[0]<m_numLines[0]; ++pos[0]) + { + for (pos[1]=0; pos[1]<m_numLines[1]; ++pos[1]) + { + for (pos[2]=0; pos[2]<m_numLines[2]; ++pos[2]) + { + if (m_cell_density[pos[0]][pos[1]][pos[2]]>0) + { + ++m_Valid; + SAR[pos[0]][pos[1]][pos[2]] = CalcLocalPowerDensity(pos)/m_cell_density[pos[0]][pos[1]][pos[2]]; + } + else + { + ++m_AirVoxel; + SAR[pos[0]][pos[1]][pos[2]] = 0; + } + } + } + } + return SAR; +} + +int SAR_Calculation::FindFittingCubicalMass(unsigned int pos[3], float box_size, unsigned int start[3], unsigned int stop[3], + float partial_start[3], float partial_stop[3], double &mass, double &volume, double &bg_ratio, int disabledFace, bool ignoreFaceValid) +{ + unsigned int mass_iterations = 0; + double old_mass=0; + double old_box_size=0; + bool face_valid; + bool mass_valid; + bool voxel_valid; + + //iterate over cubical sizes to find fitting volume to mass + while (mass_iterations<m_maxMassIterations) + { + // calculate cubical mass + face_valid = GetCubicalMass(pos, box_size/2, start, stop, partial_start, partial_stop, mass, volume, bg_ratio, disabledFace); + + // check if found mass is valid + mass_valid = abs(mass-m_avg_mass)<=m_massTolerance*m_avg_mass; + voxel_valid = mass_valid && (face_valid==true) && (bg_ratio<m_maxBGRatio); + + if ((face_valid==false) && (mass<m_avg_mass*(1.0-m_massTolerance)) && (ignoreFaceValid==false)) + { + // this is an invalid cube with a too small total mass --> increasing the box will not yield a valid cube + return 1; + } + else if ((face_valid==false || bg_ratio>=m_maxBGRatio) && (mass_valid)) + { + // this is an invalid cube with a valid total mass + if (ignoreFaceValid) + return 0; + return 2; + } + if (voxel_valid) + { + // valid cube found + return 0; + } + + // if no valid or finally invalid cube is found, calculate an alternaive cube size + if (mass_iterations==0) + { + // on first interation, try a relative resize + old_box_size=box_size; + box_size*=pow(m_avg_mass/mass,1.0/3.0); + } + else + { + // on later interations, try a newton approach + float new_box_size = box_size - (mass-m_avg_mass)/(mass-old_mass)*(box_size-old_box_size); + old_box_size = box_size; + box_size = new_box_size; + } + old_mass=mass; + + ++mass_iterations; + } + + // m_maxMassIterations iterations are exhausted... + return -1; +} + +bool SAR_Calculation::GetCubicalMass(unsigned int pos[3], double box_size, unsigned int start[3], unsigned int stop[3], + float partial_start[3], float partial_stop[3], double &mass, double &volume, double &bg_ratio, int disabledFace) +{ + if ((box_size<=0) || isnan(box_size) || isinf(box_size)) + { + cerr << "SAR_Calculation::GetCubicalMass: critical error: invalid averaging box size!! EXIT" << endl; + exit(-1); + } + bool face_valid=true; + for (int n=0;n<3;++n) + { + // check start position + start[n]=pos[n]; + partial_start[n]=1; + float dist=m_cellWidth[n][pos[n]]/2; + if (disabledFace==2*n) + dist=box_size; + else + { + while (dist<box_size) + { + // box is outside of domain + if (start[n]==0) + { + partial_start[n]=-1; + break; + } + --start[n]; + dist+=m_cellWidth[n][start[n]]; + } + + if (partial_start[n]!=-1) + { // box ends inside stop[n] voxel + partial_start[n]=1-(dist-box_size)/m_cellWidth[n][start[n]]; + } + if ((partial_start[n]!=-1) && (pos[n]==start[n])) + partial_start[n]=2*box_size/m_cellWidth[n][start[n]]; + } + + // check stop position + stop[n]=pos[n]; + partial_stop[n]=1; + dist=m_cellWidth[n][pos[n]]/2; + if (disabledFace==2*n+1) + dist=box_size; + else + { + while (dist<box_size) + { + // box is outside of domain + if (stop[n]==m_numLines[n]-1) + { + partial_stop[n]=-1; + break; + } + ++stop[n]; + dist+=m_cellWidth[n][stop[n]]; + } + + if (partial_stop[n]!=-1) + { // box ends inside stop[n] voxel + partial_stop[n]=1-(dist-box_size)/m_cellWidth[n][stop[n]]; + } + if ((partial_stop[n]!=-1) && (pos[n]==stop[n])) + partial_stop[n]=2*box_size/m_cellWidth[n][stop[n]]; + } + } + + for (int n=0;n<3;++n) + { + if (partial_start[n]==-1) + face_valid=false; + if (partial_stop[n]==-1) + face_valid=false; + } + + mass = 0; + volume = 0; + double bg_volume=0; + double weight[3]; + unsigned int f_pos[3]; + bool face_intersect[6] = {false,false,false,false,false,false}; + for (f_pos[0]=start[0];f_pos[0]<=stop[0];++f_pos[0]) + { + weight[0]=1; + if (f_pos[0]==start[0]) + weight[0]*=abs(partial_start[0]); + if (f_pos[0]==stop[0]) + weight[0]*=abs(partial_stop[0]); + + for (f_pos[1]=start[1];f_pos[1]<=stop[1];++f_pos[1]) + { + weight[1]=1; + if (f_pos[1]==start[1]) + weight[1]*=abs(partial_start[1]); + if (f_pos[1]==stop[1]) + weight[1]*=abs(partial_stop[1]); + + for (f_pos[2]=start[2];f_pos[2]<=stop[2];++f_pos[2]) + { + weight[2]=1; + if (f_pos[2]==start[2]) + weight[2]*=abs(partial_start[2]); + if (f_pos[2]==stop[2]) + weight[2]*=abs(partial_stop[2]); + + mass += CellMass(f_pos)*weight[0]*weight[1]*weight[2]; + volume += CellVolume(f_pos)*weight[0]*weight[1]*weight[2]; + + if (m_cell_density[f_pos[0]][f_pos[1]][f_pos[2]]==0) + bg_volume += CellVolume(f_pos)*weight[0]*weight[1]*weight[2]; + else + { + for (int n=0;n<3;++n) + { + if (start[n]==f_pos[n]) + face_intersect[2*n]=true; + if (stop[n]==f_pos[n]) + face_intersect[2*n+1]=true; + } + } + } + } + } + //check if all bounds have intersected a material boundary + for (int n=0;n<6;++n) + face_valid *= face_intersect[n]; + + bg_ratio = bg_volume/volume; + + return face_valid; +} + +float SAR_Calculation::CalcCubicalSAR(float*** SAR, unsigned int pos[3], unsigned int start[3], unsigned int stop[3], float partial_start[3], float partial_stop[3], bool assignUsed) +{ + double power_mass=0; + double mass=0; + double weight[3]; + unsigned int f_pos[3]; + for (f_pos[0]=start[0];f_pos[0]<=stop[0];++f_pos[0]) + { + weight[0]=1; + if (f_pos[0]==start[0]) + weight[0]*=abs(partial_start[0]); + if (f_pos[0]==stop[0]) + weight[0]*=abs(partial_stop[0]); + + for (f_pos[1]=start[1];f_pos[1]<=stop[1];++f_pos[1]) + { + weight[1]=1; + if (f_pos[1]==start[1]) + weight[1]*=abs(partial_start[1]); + if (f_pos[1]==stop[1]) + weight[1]*=abs(partial_stop[1]); + + for (f_pos[2]=start[2];f_pos[2]<=stop[2];++f_pos[2]) + { + weight[2]=1; + if (f_pos[2]==start[2]) + weight[2]*=abs(partial_start[2]); + if (f_pos[2]==stop[2]) + weight[2]*=abs(partial_stop[2]); + + if (m_cell_density[f_pos[0]][f_pos[1]][f_pos[2]]>=0) + { + mass += CellMass(f_pos)*weight[0]*weight[1]*weight[2]; + power_mass += CalcLocalPowerDensity(f_pos) * CellVolume(f_pos)*weight[0]*weight[1]*weight[2]; + } + } + } + } + float vx_SAR = power_mass/mass; + if (SAR==NULL) + return vx_SAR; + + SAR[pos[0]][pos[1]][pos[2]]=vx_SAR; + + if (assignUsed==false) + return vx_SAR; + + // assign SAR to all used voxel + bool is_partial[3]; + for (f_pos[0]=start[0];f_pos[0]<=stop[0];++f_pos[0]) + { + if ( ((f_pos[0]==start[0]) && (partial_start[0]!=1)) || ((f_pos[0]==stop[0]) && (partial_stop[0]!=1)) ) + is_partial[0]=true; + else + is_partial[0]=false; + + for (f_pos[1]=start[1];f_pos[1]<=stop[1];++f_pos[1]) + { + if ( ((f_pos[1]==start[1]) && (partial_start[1]!=1)) || ((f_pos[1]==stop[1]) && (partial_stop[1]!=1)) ) + is_partial[1]=true; + else + is_partial[1]=false; + + for (f_pos[2]=start[2];f_pos[2]<=stop[2];++f_pos[2]) + { + if ( ((f_pos[2]==start[2]) && (partial_start[2]!=1)) || ((f_pos[2]==stop[2]) && (partial_stop[2]!=1)) ) + is_partial[2]=true; + else + is_partial[2]=false; + + if ( (!is_partial[0] && !is_partial[1] && !is_partial[2]) || m_markPartialAsUsed) + { + if (!m_Vx_Valid[f_pos[0]][f_pos[1]][f_pos[2]] && (m_cell_density[f_pos[0]][f_pos[1]][f_pos[2]]>0)) + { + m_Vx_Used[f_pos[0]][f_pos[1]][f_pos[2]]=true; + SAR[f_pos[0]][f_pos[1]][f_pos[2]]=max(SAR[f_pos[0]][f_pos[1]][f_pos[2]], vx_SAR); + } + } + } + } + } + return vx_SAR; +} + + +float*** SAR_Calculation::CalcAveragedSAR(float*** SAR) +{ + unsigned int pos[3]; + m_Vx_Used = Create3DArray<bool>(m_numLines); + m_Vx_Valid = Create3DArray<bool>(m_numLines); + + double voxel_volume; + double total_mass; + unsigned int start[3]; + unsigned int stop[3]; + float partial_start[3]; + float partial_stop[3]; + double bg_ratio; + int EC=0; + + // debug counter + unsigned int cnt_case1=0; + unsigned int cnt_case2=0; + unsigned int cnt_NoConvergence=0; + + m_Valid=0; + m_Used=0; + m_Unused=0; + m_AirVoxel=0; + + for (pos[0]=0; pos[0]<m_numLines[0]; ++pos[0]) + { + for (pos[1]=0; pos[1]<m_numLines[1]; ++pos[1]) + { + for (pos[2]=0; pos[2]<m_numLines[2]; ++pos[2]) + { + if (m_cell_density[pos[0]][pos[1]][pos[2]]==0) + { + SAR[pos[0]][pos[1]][pos[2]] = 0; + ++m_AirVoxel; + continue; + } + + // guess an initial box size and find a fitting cube + EC = FindFittingCubicalMass(pos, pow(m_avg_mass/m_cell_density[pos[0]][pos[1]][pos[2]],1.0/3.0)/2, start, stop, + partial_start, partial_stop, total_mass, voxel_volume, bg_ratio, -1, m_IgnoreFaceValid); + + if (EC==0) + { + m_Vx_Valid[pos[0]][pos[1]][pos[2]] = true; + m_Vx_Used[pos[0]][pos[1]][pos[2]] = true; + ++m_Valid; + CalcCubicalSAR(SAR, pos, start, stop, partial_start, partial_stop, true); + } + else if (EC==1) + ++cnt_case1; + else if (EC==2) + ++cnt_case2; + else if (EC==-1) + ++cnt_NoConvergence; + else + cerr << "other EC" << EC << endl; + } + } + } + if (cnt_NoConvergence>0) + { + cerr << "SAR_Calculation::CalcAveragedSAR: Warning, for some voxel a valid averaging cube could not be found (no convergence)... " << endl; + } + if (m_DebugLevel>0) + { + cerr << "Number of invalid cubes (case 1): " << cnt_case1 << endl; + cerr << "Number of invalid cubes (case 2): " << cnt_case2 << endl; + cerr << "Number of invalid cubes (failed to converge): " << cnt_NoConvergence << endl; + } + + // count all used and unused etc. + special handling of unused voxels!! + m_Used=0; + m_Unused=0; + for (pos[0]=0;pos[0]<m_numLines[0];++pos[0]) + { + for (pos[1]=0;pos[1]<m_numLines[1];++pos[1]) + { + for (pos[2]=0;pos[2]<m_numLines[2];++pos[2]) + { + if (!m_Vx_Valid[pos[0]][pos[1]][pos[2]] && m_Vx_Used[pos[0]][pos[1]][pos[2]]) + ++m_Used; + if ((m_cell_density[pos[0]][pos[1]][pos[2]]>0) && !m_Vx_Valid[pos[0]][pos[1]][pos[2]] && !m_Vx_Used[pos[0]][pos[1]][pos[2]]) + { + ++m_Unused; + + SAR[pos[0]][pos[1]][pos[2]] = 0; + double unused_volumes[6]; + float unused_SAR[6]; + + double min_Vol=FLT_MAX; + + // special handling of unused voxels: + for (int n=0;n<6;++n) + { + EC = FindFittingCubicalMass(pos, pow(m_avg_mass/m_cell_density[pos[0]][pos[1]][pos[2]],1.0/3.0)/2, start, stop, + partial_start, partial_stop, total_mass, unused_volumes[n], bg_ratio, n, true); + if ((EC!=0) && (EC!=2)) + { + // this should not happen + cerr << "SAR_Calculation::CalcAveragedSAR: Error handling unused voxels, can't find fitting cubical averaging volume' " << endl; + unused_SAR[n]=0; + } + else + { + unused_SAR[n]=CalcCubicalSAR(NULL, pos, start, stop, partial_start, partial_stop, false); + min_Vol = min(min_Vol,unused_volumes[n]); + } + } + for (int n=0;n<6;++n) + { + if (unused_volumes[n]<=m_UnusedRelativeVolLimit*min_Vol) + SAR[pos[0]][pos[1]][pos[2]] = max(SAR[pos[0]][pos[1]][pos[2]],unused_SAR[n]); + } + } + } + } + } + + if (m_Valid+m_Used+m_Unused+m_AirVoxel!=m_numLines[0]*m_numLines[1]*m_numLines[2]) + { + cerr << "SAR_Calculation::CalcAveragedSAR: critical error, mismatch in voxel status count... EXIT" << endl; + exit(1); + } + + if (m_DebugLevel>0) + cerr << "SAR_Calculation::CalcAveragedSAR: Stats: Valid=" << m_Valid << " Used=" << m_Used << " Unused=" << m_Unused << " Air-Voxel=" << m_AirVoxel << endl; + + return SAR; +} + +double SAR_Calculation::CellVolume(unsigned int pos[3]) +{ + if (m_cell_volume) + return m_cell_volume[pos[0]][pos[1]][pos[2]]; + + double volume=1; + for (int n=0;n<3;++n) + volume*=m_cellWidth[n][pos[n]]; + return volume; +} + +double SAR_Calculation::CellMass(unsigned int pos[3]) +{ + return m_cell_density[pos[0]][pos[1]][pos[2]]*CellVolume(pos); +} + diff --git a/openEMS/tools/sar_calculation.h b/openEMS/tools/sar_calculation.h new file mode 100644 index 0000000..58d9ab8 --- /dev/null +++ b/openEMS/tools/sar_calculation.h @@ -0,0 +1,122 @@ +/* +* Copyright (C) 2012 Thorsten Liebig (Thorsten.Liebig@gmx.de) +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef SAR_CALCULATION_H +#define SAR_CALCULATION_H + +#include <complex> + +class SAR_Calculation +{ +public: + SAR_Calculation(); + + enum SARAveragingMethod { IEEE_C95_3, IEEE_62704, SIMPLE}; + + //! Reset and initialize all values (will keep all SAR settings) + void Reset(); + + //! Set the debug level + void SetDebugLevel(int level) {m_DebugLevel=level;} + + //! Set the used averaging method + void SetAveragingMethod(SARAveragingMethod method, bool silent=false); + + //! Set the used averaging method + void SetAveragingMethod(std::string method, bool silent=false); + + //! Set number of lines in all direcitions. (mandatory information) + void SetNumLines(unsigned int numLines[3]); + //! Set cell width in all direcitions. (mandatory information for averaging) + void SetCellWidth(float* cellWidth[3]); + + //! Set the averaging mash. (mandatory information for averaging) + void SetAveragingMass(float mass) {m_avg_mass=mass;} + + //! Set the cell volumes (optional for speedup) + void SetCellVolumes(float*** cell_volume) {m_cell_volume=cell_volume;} + + //! Set the cell densities (mandatory information) + void SetCellDensities(float*** cell_density) {m_cell_density=cell_density;} + + //! Set the cell conductivities (mandatory if no current density field is given) + void SetCellCondictivity(float*** cell_conductivity) {m_cell_conductivity=cell_conductivity;} + + //! Set the electric field (mandatory information) + void SetEField(std::complex<float>**** field) {m_E_field=field;} + //! Set the current density field (mandatory if no conductivity distribution is given) + void SetJField(std::complex<float>**** field) {m_J_field=field;} + + //! Calculate the SAR, requires a preallocated 3D array + float*** CalcSAR(float*** SAR); + + //! Calculate the total power dumped + double CalcSARPower(); + +protected: + unsigned int m_numLines[3]; + float* m_cellWidth[3]; + + float m_avg_mass; + float*** m_cell_volume; + float*** m_cell_density; + float*** m_cell_conductivity; + std::complex<float>**** m_E_field; + std::complex<float>**** m_J_field; + + bool*** m_Vx_Used; + bool*** m_Vx_Valid; + + unsigned int m_Valid; + unsigned int m_Used; + unsigned int m_Unused; + unsigned int m_AirVoxel; + + int m_DebugLevel; + + /*********** SAR calculation parameter and settings ***********/ + float m_massTolerance; + unsigned int m_maxMassIterations; + float m_maxBGRatio; + bool m_markPartialAsUsed; + float m_UnusedRelativeVolLimit; + bool m_IgnoreFaceValid; + + /*********** SAR calculations methods ********/ + double CalcLocalPowerDensity(unsigned int pos[3]); + + //! Calculate the local SAR + float*** CalcLocalSAR(float*** SAR); + + /****** start SAR averaging and all necessary methods ********/ + //! Calculate the averaged SAR + float*** CalcAveragedSAR(float*** SAR); + + int FindFittingCubicalMass(unsigned int pos[3], float box_size, unsigned int start[3], unsigned int stop[3], + float partial_start[3], float partial_stop[3], double &mass, double &volume, double &bg_ratio, int disabledFace=-1, bool ignoreFaceValid=false); + bool GetCubicalMass(unsigned int pos[3], double box_size, unsigned int start[3], unsigned int stop[3], + float partial_start[3], float partial_stop[3], double &mass, double &volume, double &bg_ratio, int disabledFace=-1); + + float CalcCubicalSAR(float*** SAR, unsigned int pos[3], unsigned int start[3], unsigned int stop[3], float partial_start[3], float partial_stop[3], bool assignUsed=false); + /****** end SAR averaging and all necessary methods ********/ + + bool CheckValid(); + double CellVolume(unsigned int pos[3]); + double CellMass(unsigned int pos[3]); +}; + +#endif // SAR_CALCULATION_H diff --git a/openEMS/tools/useful.cpp b/openEMS/tools/useful.cpp new file mode 100644 index 0000000..50aacfb --- /dev/null +++ b/openEMS/tools/useful.cpp @@ -0,0 +1,185 @@ +/* +* 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 "useful.h" +#include <cstdio> +#include <cstdlib> +#include <cmath> +#include <climits> +#include <stdio.h> +#include <stdlib.h> +#include <iomanip> +#include <sstream> +#include <boost/algorithm/string.hpp> +#include <iostream> + +unsigned int CalcNyquistNum(double fmax, double dT) +{ + if (fmax==0) return UINT_MAX; + if (dT==0) return 1; + double T0 = 1/fmax; + return floor(T0/2/dT); +} + +double CalcNyquistFrequency(unsigned int nyquist, double dT) +{ + if (nyquist==0) return 0; + if (dT==0) return 0; + return floor(1/(double)nyquist/2/dT); +} + +std::vector<unsigned int> AssignJobs2Threads(unsigned int jobs, unsigned int nrThreads, bool RemoveEmpty) +{ + std::vector<unsigned int> jpt; //jobs per thread + + unsigned int ui_jpt = jobs/nrThreads; + for (unsigned int n=0; n<nrThreads; ++n) + { + jpt.push_back(ui_jpt); + jobs-=ui_jpt; + } + + for (unsigned int n=0; n<nrThreads; ++n) + { + if (jobs>0) + { + ++jpt.at(n); + --jobs; + } + } + + if (jobs>0) + std::cerr << "AssignJobs2Threads: Error, " << jobs << " remain to be assigned, this should not have happend..." << std::endl; + + if (RemoveEmpty) + { + while (jpt.back()==0) + jpt.pop_back(); + } + + return jpt; +} + +std::vector<float> SplitString2Float(std::string str, std::string delimiter) +{ + std::vector<float> v_f; + std::vector<std::string> results; + boost::split(results, str, boost::is_any_of(delimiter)); + + for (size_t n=0;n<results.size();++n) + { + std::istringstream is(results.at(n)); + float num; + if (is >> num) + v_f.push_back(num); + } + return v_f; +} + +std::vector<double> SplitString2Double(std::string str, std::string delimiter) +{ + std::vector<double> v_f; + std::vector<std::string> results; + boost::split(results, str, boost::is_any_of(delimiter)); + + for (size_t n=0;n<results.size();++n) + { + std::istringstream is(results.at(n)); + double num; + if (is >> num) + v_f.push_back(num); + } + return v_f; +} + +bool CrossProd(const double *v1, const double *v2, double* out) +{ + int nP,nPP; + for (int n=0;n<3;++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + out[n] = v1[nP]*v2[nPP] - v1[nPP]*v2[nP]; + } + return ((out[0]+out[1]+out[2])>0); +} + +double ScalarProd(const double *v1, const double *v2) +{ + double out=0; + for (int n=0;n<3;++n) + out+=v1[n]*v2[n]; + return out; +} + +double Determinant(const double *mat) +{ + return mat[0]*mat[4]*mat[8]+mat[1]*mat[5]*mat[6]+mat[2]*mat[3]*mat[7]-mat[2]*mat[4]*mat[6]-mat[1]*mat[3]*mat[8]-mat[0]*mat[5]*mat[7]; +} + +double* Invert(const double* in, double* out) +{ + double det = Determinant(in); + out[0] = (in[4]*in[8]-in[5]*in[7])/det; + out[1] = (in[2]*in[7]-in[1]*in[8])/det; + out[2] = (in[1]*in[5]-in[2]*in[4])/det; + out[3] = (in[5]*in[6]-in[3]*in[8])/det; + out[4] = (in[0]*in[8]-in[2]*in[6])/det; + out[5] = (in[2]*in[3]-in[0]*in[5])/det; + out[6] = (in[3]*in[7]-in[4]*in[6])/det; + out[7] = (in[1]*in[6]-in[0]*in[7])/det; + out[8] = (in[0]*in[4]-in[1]*in[3])/det; + return out; +} + +int LinePlaneIntersection(const double *p0, const double *p1, const double *p2, const double *l_start, const double *l_stop, double* is_point, double &dist) +{ + dist = 0; + double mat[9]; + for (int n=0;n<3;++n) + { + is_point[n] = 0; + mat[3*n] = l_start[n]-l_stop[n]; + mat[3*n+1] = p1[n]-p0[n]; + mat[3*n+2] = p2[n]-p0[n]; + } + double det = Determinant(mat); + if (fabs(det)<1e-50) + return -1; + + double inv_mat[9]; + Invert(mat, inv_mat); + + double t=0,u=0,v=0; + for (int n=0;n<3;++n) + { + t+=inv_mat[n]*(l_start[n]-p0[n]); + u+=inv_mat[3+n]*(l_start[n]-p0[n]); + v+=inv_mat[6+n]*(l_start[n]-p0[n]); + } + dist = t; + + for (int n=0;n<3;++n) + is_point[n] = l_start[n]*(1-dist) + l_stop[n]*dist; + + if ((u<0) || (u>1) || (v<0) || (v>1)) + return 1; + if ((t<0) || (t>1)) + return 2; + + return 0; +} diff --git a/openEMS/tools/useful.h b/openEMS/tools/useful.h new file mode 100644 index 0000000..dec13ab --- /dev/null +++ b/openEMS/tools/useful.h @@ -0,0 +1,44 @@ +/* +* 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 USEFUL_H +#define USEFUL_H + +#include <vector> +#include <string> + +//! Calc the nyquist number of timesteps for a given frequency and timestep +unsigned int CalcNyquistNum(double fmax, double dT); + +//! Calc the highest frequency allowed for a given nyquist number of timesteps and timestep +double CalcNyquistFrequency(unsigned int nyquist, double dT); + +//! Calculate an optimal job distribution to a given number of threads. Will return a vector with the jobs for each thread. +std::vector<unsigned int> AssignJobs2Threads(unsigned int jobs, unsigned int nrThreads, bool RemoveEmpty=false); + +std::vector<float> SplitString2Float(std::string str, std::string delimiter=","); +std::vector<double> SplitString2Double(std::string str, std::string delimiter=","); + +bool CrossProd(const double* v1, const double* v2, double* out); +double ScalarProd(const double* v1, const double* v2); + +double Determinant(const double* mat); +double* Invert(const double* in, double* out); + +int LinePlaneIntersection(const double *p0, const double* p1, const double* p2, const double* l_start, const double* l_stop, double* is_point, double &dist); + +#endif // USEFUL_H diff --git a/openEMS/tools/vtk_file_writer.cpp b/openEMS/tools/vtk_file_writer.cpp new file mode 100644 index 0000000..79c40f3 --- /dev/null +++ b/openEMS/tools/vtk_file_writer.cpp @@ -0,0 +1,340 @@ +/* +* Copyright (C) 2011,2012 Thorsten Liebig (Thorsten.Liebig@gmx.de) +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +using namespace std; + +#include "vtk_file_writer.h" + +#include <vtkRectilinearGrid.h> +#include <vtkRectilinearGridWriter.h> +#include <vtkXMLRectilinearGridWriter.h> +#include <vtkStructuredGrid.h> +#include <vtkStructuredGridWriter.h> +#include <vtkXMLStructuredGridWriter.h> +#include <vtkZLibDataCompressor.h> +#include <vtkFloatArray.h> +#include <vtkDoubleArray.h> +#include <vtkFieldData.h> +#include <vtkPointData.h> + +#include <sstream> +#include <iomanip> + + +VTK_File_Writer::VTK_File_Writer(string filename, int meshType) +{ + SetFilename(filename); + m_MeshType = meshType; + m_NativeDump = false; + m_Binary = true; + m_Compress = true; + m_AppendMode = false; + m_ActiveTS = false; + + if (m_MeshType==0) //cartesian mesh + m_GridData = vtkRectilinearGrid::New(); + else if (m_MeshType==1) //cylindrical mesh + m_GridData = vtkStructuredGrid::New(); + else + { + cerr << "VTK_File_Writer::VTK_File_Writer: Error, unknown mesh type: " << m_MeshType << endl; + m_GridData=NULL; + } +} + +VTK_File_Writer::~VTK_File_Writer() +{ + if (m_GridData) + m_GridData->Delete(); + m_GridData = NULL; +} + +void VTK_File_Writer::SetMeshLines(double const* const* lines, unsigned int const* count, double scaling) +{ + if (m_MeshType==0) //cartesian mesh + { + vtkRectilinearGrid* RectGrid = dynamic_cast<vtkRectilinearGrid*>(m_GridData); + if (RectGrid==NULL) + { + cerr << "VTK_File_Writer::SetMeshLines: Error, grid invalid, this should not have happend! " << endl; + exit(1); + } + RectGrid->SetDimensions(count[0],count[1],count[2]); + vtkDoubleArray *Coords[3]; + for (int n=0;n<3;++n) + { + m_MeshLines[n].clear(); + m_MeshLines[n].reserve(count[n]); + Coords[n] = vtkDoubleArray::New(); + for (unsigned int i=0; i<count[n]; i++) + { + Coords[n]->InsertNextValue(lines[n][i]*scaling); + m_MeshLines[n].push_back(lines[n][i]*scaling); + } + } + RectGrid->SetXCoordinates(Coords[0]); + RectGrid->SetYCoordinates(Coords[1]); + RectGrid->SetZCoordinates(Coords[2]); + for (int n=0;n<3;++n) + Coords[n]->Delete(); + } + else if (m_MeshType==1) //cylindrical mesh + { + vtkStructuredGrid* StructGrid = dynamic_cast<vtkStructuredGrid*>(m_GridData); + if (StructGrid==NULL) + { + cerr << "VTK_File_Writer::SetMeshLines: Error, grid invalid, this should not have happend! " << endl; + exit(1); + } + + for (int n=0;n<3;++n) + { + m_MeshLines[n].clear(); + m_MeshLines[n].reserve(count[n]); + double scale=1; + if (n!=1) + scale*=scaling; + for (unsigned int i=0; i<count[n]; i++) + m_MeshLines[n].push_back(lines[n][i]*scale); + } + + StructGrid->SetDimensions(count[0],count[1],count[2]); + vtkPoints *points = vtkPoints::New(); + points->SetNumberOfPoints(count[0]*count[1]*count[2]); + double r[3]; + int id=0; + for (unsigned int k=0; k<count[2]; ++k) + for (unsigned int j=0; j<count[1]; ++j) + for (unsigned int i=0; i<count[0]; ++i) + { + r[0] = lines[0][i] * cos(lines[1][j]) * scaling; + r[1] = lines[0][i] * sin(lines[1][j]) * scaling; + r[2] = lines[2][k] * scaling; + points->SetPoint(id++,r); + } + StructGrid->SetPoints(points); + points->Delete(); + } + else + { + cerr << "VTK_File_Writer::SetMeshLines: Error, unknown mesh type: " << m_MeshType << endl; + } +} + +void VTK_File_Writer::AddScalarField(string fieldname, double const* const* const* field) +{ + vtkDoubleArray* array = vtkDoubleArray::New(); + array->SetNumberOfTuples(m_MeshLines[0].size()*m_MeshLines[1].size()*m_MeshLines[2].size()); + array->SetName(fieldname.c_str()); + int id=0; + for (unsigned int k=0;k<m_MeshLines[2].size();++k) + { + for (unsigned int j=0;j<m_MeshLines[1].size();++j) + { + for (unsigned int i=0;i<m_MeshLines[0].size();++i) + { + array->SetTuple1(id++,field[i][j][k]); + } + } + } + m_GridData->GetPointData()->AddArray(array); + array->Delete(); +} + +void VTK_File_Writer::AddScalarField(string fieldname, float const* const* const* field) +{ + vtkFloatArray* array = vtkFloatArray::New(); + array->SetNumberOfTuples(m_MeshLines[0].size()*m_MeshLines[1].size()*m_MeshLines[2].size()); + array->SetName(fieldname.c_str()); + int id=0; + for (unsigned int k=0;k<m_MeshLines[2].size();++k) + { + for (unsigned int j=0;j<m_MeshLines[1].size();++j) + { + for (unsigned int i=0;i<m_MeshLines[0].size();++i) + { + array->SetTuple1(id++,field[i][j][k]); + } + } + } + m_GridData->GetPointData()->AddArray(array); + array->Delete(); +} + +void VTK_File_Writer::AddVectorField(string fieldname, double const* const* const* const* field) +{ + vtkDoubleArray* array = vtkDoubleArray::New(); + array->SetNumberOfComponents(3); + array->SetNumberOfTuples(m_MeshLines[0].size()*m_MeshLines[1].size()*m_MeshLines[2].size()); + array->SetName(fieldname.c_str()); + int id=0; + double out[3]; + for (unsigned int k=0;k<m_MeshLines[2].size();++k) + { + for (unsigned int j=0;j<m_MeshLines[1].size();++j) + { + double cos_a = cos(m_MeshLines[1].at(j)); //needed only for m_MeshType==1 (cylindrical mesh) + double sin_a = sin(m_MeshLines[1].at(j)); //needed only for m_MeshType==1 (cylindrical mesh) + for (unsigned int i=0;i<m_MeshLines[0].size();++i) + { + if ((m_MeshType==0) || (m_NativeDump)) + array->SetTuple3(id++,field[0][i][j][k],field[1][i][j][k],field[2][i][j][k]); + else + { + out[0] = field[0][i][j][k] * cos_a - field[1][i][j][k] * sin_a; + out[1] = field[0][i][j][k] * sin_a + field[1][i][j][k] * cos_a; + out[2] = field[2][i][j][k]; + array->SetTuple3(id++,out[0],out[1],out[2]); + } + } + } + } + m_GridData->GetPointData()->AddArray(array); + array->Delete(); +} + +void VTK_File_Writer::AddVectorField(string fieldname, float const* const* const* const* field) +{ + vtkFloatArray* array = vtkFloatArray::New(); + array->SetNumberOfComponents(3); + array->SetNumberOfTuples(m_MeshLines[0].size()*m_MeshLines[1].size()*m_MeshLines[2].size()); + array->SetName(fieldname.c_str()); + int id=0; + float out[3]; + for (unsigned int k=0;k<m_MeshLines[2].size();++k) + { + for (unsigned int j=0;j<m_MeshLines[1].size();++j) + { + float cos_a = cos(m_MeshLines[1].at(j)); //needed only for m_MeshType==1 (cylindrical mesh) + float sin_a = sin(m_MeshLines[1].at(j)); //needed only for m_MeshType==1 (cylindrical mesh) + for (unsigned int i=0;i<m_MeshLines[0].size();++i) + { + if ((m_MeshType==0) || (m_NativeDump)) + array->SetTuple3(id++,field[0][i][j][k],field[1][i][j][k],field[2][i][j][k]); + else + { + out[0] = field[0][i][j][k] * cos_a - field[1][i][j][k] * sin_a; + out[1] = field[0][i][j][k] * sin_a + field[1][i][j][k] * cos_a; + out[2] = field[2][i][j][k]; + array->SetTuple3(id++,out[0],out[1],out[2]); + } + } + } + } + m_GridData->GetPointData()->AddArray(array); + array->Delete(); +} + + +int VTK_File_Writer::GetNumberOfFields() const +{ + return m_GridData->GetPointData()->GetNumberOfArrays(); +} + +void VTK_File_Writer::ClearAllFields() +{ + while (m_GridData->GetPointData()->GetNumberOfArrays()>0) + { + const char* name = m_GridData->GetPointData()->GetArrayName(0); + m_GridData->GetPointData()->RemoveArray(name); + } +} + +bool VTK_File_Writer::Write() +{ + return WriteXML(); +} + +string VTK_File_Writer::GetTimestepFilename(int pad_length) const +{ + if (m_ActiveTS==false) + return m_filename; + + stringstream ss; + ss << m_filename << "_" << std::setw( pad_length ) << std::setfill( '0' ) << m_timestep; + + return ss.str(); +} + + +bool VTK_File_Writer::WriteASCII() +{ + vtkDataWriter* writer = NULL; + if (m_MeshType==0) //cartesian mesh + writer = vtkRectilinearGridWriter::New(); + else if (m_MeshType==1) //cylindrical mesh + writer = vtkStructuredGridWriter::New(); + else + { + cerr << "VTK_File_Writer::WriteASCII: Error, unknown mesh type: " << m_MeshType << endl; + return false; + } + + writer->SetHeader(m_header.c_str()); +#if VTK_MAJOR_VERSION>=6 + writer->SetInputData(m_GridData); +#else + writer->SetInput(m_GridData); +#endif + + string filename = GetTimestepFilename() + ".vtk"; + writer->SetFileName(filename.c_str()); + if (m_Binary) + writer->SetFileTypeToBinary(); + else + writer->SetFileTypeToASCII(); + + writer->Write(); + writer->Delete(); + return true; +} + +bool VTK_File_Writer::WriteXML() +{ + vtkXMLStructuredDataWriter* writer = NULL; + if (m_MeshType==0) //cartesian mesh + writer = vtkXMLRectilinearGridWriter::New(); + else if (m_MeshType==1) //cylindrical mesh + writer = vtkXMLStructuredGridWriter::New(); + else + { + cerr << "VTK_File_Writer::WriteXML: Error, unknown mesh type: " << m_MeshType << endl; + return false; + } + +#if VTK_MAJOR_VERSION>=6 + writer->SetInputData(m_GridData); +#else + writer->SetInput(m_GridData); +#endif + + string filename = GetTimestepFilename() + "." + writer->GetDefaultFileExtension(); + writer->SetFileName(filename.c_str()); + if (m_Compress) + writer->SetCompressor(vtkZLibDataCompressor::New()); + else + writer->SetCompressor(NULL); + + if (m_Binary) + writer->SetDataModeToBinary(); + else + writer->SetDataModeToAscii(); + + writer->Write(); + writer->Delete(); + return true; +} diff --git a/openEMS/tools/vtk_file_writer.h b/openEMS/tools/vtk_file_writer.h new file mode 100644 index 0000000..428d859 --- /dev/null +++ b/openEMS/tools/vtk_file_writer.h @@ -0,0 +1,94 @@ +/* +* Copyright (C) 2011,2012 Thorsten Liebig (Thorsten.Liebig@gmx.de) +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef VTK_FILE_WRITER_H +#define VTK_FILE_WRITER_H + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> +#include <string> +#include <vector> +#include <complex> + +class vtkDataSet; + +class VTK_File_Writer +{ +public: + VTK_File_Writer(std::string filename, int meshType=0); + virtual ~VTK_File_Writer(); + + //! Set the filename + virtual void SetFilename(std::string filename) {m_filename=filename;} + //! Set the header information. May not be supported by all file types or setting. + virtual void SetHeader(std::string header) {m_header=header;} + + //! Tell write to append data. May fail if filename has changed or filetype doesn't support this. + virtual void SetAppendMode(bool val) {m_AppendMode=val;} + //! Set binary flag (if the file type supports it) + virtual void SetBinary(bool val) {m_Binary=val;} + //! Set compression flag (if the file type supports it) + virtual void SetCompress(bool val) {m_Compress=val;} + + void SetNativeDump(bool val) {m_NativeDump=val;} + + virtual void SetMeshLines(double const* const* lines, unsigned int const* count, double scaling=1); + + virtual void AddScalarField(std::string fieldname, double const* const* const* field); + virtual void AddScalarField(std::string fieldname, float const* const* const* field); + virtual void AddVectorField(std::string fieldname, double const* const* const* const* field); + virtual void AddVectorField(std::string fieldname, float const* const* const* const* field); + + virtual int GetNumberOfFields() const; + virtual void ClearAllFields(); + + //! Get if timestep file series is active. \sa SetTimestepActive + virtual bool GetTimestepActive() {return m_ActiveTS;} + //! Set the timestep file series flag. \sa GetTimestepActive \sa SetTimestep + virtual void SetTimestepActive(bool val) {m_ActiveTS = val;} + //! Set the current timestep, this will set the timestep flag to true. \sa SetTimestepActive + virtual void SetTimestep(unsigned int ts) {m_timestep=ts;SetTimestepActive(true);} + + virtual bool Write(); + + virtual bool WriteASCII(); + virtual bool WriteXML(); + +protected: + std::string m_filename; + std::string m_header; + + //timestep properties + bool m_ActiveTS; + unsigned int m_timestep; + + vtkDataSet* m_GridData; + + //mesh information + int m_MeshType; + std::vector<double> m_MeshLines[3]; + bool m_NativeDump; + + bool m_AppendMode; + bool m_Binary; + bool m_Compress; + + virtual std::string GetTimestepFilename(int pad_length=10) const; +}; + +#endif // VTK_FILE_Writer_H |