/*
* 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 .
*/
#include
#include
#include "tools/global.h"
#include "processfields.h"
#include "FDTD/engine_interface_fdtd.h"
ProcessFields::ProcessFields(Engine_Interface_Base* eng_if) : Processing(eng_if)
{
m_DumpType = E_FIELD_DUMP;
// vtk-file is default
m_fileType = VTK_FILETYPE;
subSample[0]=1;
subSample[1]=1;
subSample[2]=1;
optResolution[0]=0;
optResolution[1]=0;
optResolution[2]=0;
m_SampleType = NONE;
SetPrecision(6);
m_dualTime = false;
for (int n=0; n<3; ++n)
{
numLines[n]=0;
posLines[n]=NULL;
discLines[n]=NULL;
}
}
ProcessFields::~ProcessFields()
{
for (int n=0; n<3; ++n)
{
delete[] posLines[n];
posLines[n]=NULL;
delete[] discLines[n];
discLines[n]=NULL;
}
}
string ProcessFields::GetFieldNameByType(DumpType type)
{
switch (type)
{
case E_FIELD_DUMP:
return "E-Field";
case H_FIELD_DUMP:
return "H-Field";
}
return "unknown field";
}
void ProcessFields::InitProcess()
{
CalcMeshPos();
}
void ProcessFields::SetDumpMode(Engine_Interface_Base::InterpolationType mode)
{
m_Eng_Interface->SetInterpolationType(mode);
if (mode==Engine_Interface_Base::CELL_INTERPOLATE)
m_dualMesh=true;
else
m_dualMesh=false;
}
void ProcessFields::DefineStartStopCoord(double* dstart, double* dstop)
{
Processing::DefineStartStopCoord(dstart,dstop);
// normalize order of start and stop
for (int n=0; n<3; ++n)
{
if (start[n]>stop[n])
{
unsigned int help = start[n];
start[n]=stop[n];
stop[n]=help;
}
}
}
double ProcessFields::CalcTotalEnergy() const
{
double energy=0.0;
Engine_Interface_FDTD* EI_FDTD = dynamic_cast(m_Eng_Interface);
if (EI_FDTD)
{
const Engine* Eng = EI_FDTD->GetFDTDEngine();
unsigned int pos[3];
for (pos[0]=0; pos[0]GetNumberOfLines(0); ++pos[0])
{
for (pos[1]=0; pos[1]GetNumberOfLines(1); ++pos[1])
{
for (pos[2]=0; pos[2]GetNumberOfLines(2); ++pos[2])
{
energy+=fabs(Eng->GetVolt(0,pos[0],pos[1],pos[2]) * Eng->GetCurr(1,pos[0],pos[1],pos[2]));
energy+=fabs(Eng->GetVolt(0,pos[0],pos[1],pos[2]) * Eng->GetCurr(2,pos[0],pos[1],pos[2]));
energy+=fabs(Eng->GetVolt(1,pos[0],pos[1],pos[2]) * Eng->GetCurr(0,pos[0],pos[1],pos[2]));
energy+=fabs(Eng->GetVolt(1,pos[0],pos[1],pos[2]) * Eng->GetCurr(2,pos[0],pos[1],pos[2]));
energy+=fabs(Eng->GetVolt(2,pos[0],pos[1],pos[2]) * Eng->GetCurr(0,pos[0],pos[1],pos[2]));
energy+=fabs(Eng->GetVolt(2,pos[0],pos[1],pos[2]) * Eng->GetCurr(1,pos[0],pos[1],pos[2]));
}
}
}
}
return energy*0.5;
}
void ProcessFields::SetSubSampling(unsigned int subSampleRate, int dir)
{
if (dir>2) return;
if (dir<0)
{
subSample[0]=subSampleRate;
subSample[1]=subSampleRate;
subSample[2]=subSampleRate;
}
else subSample[dir]=subSampleRate;
m_SampleType = SUBSAMPLE;
}
void ProcessFields::SetOptResolution(double optRes, int dir)
{
if (dir>2) return;
if (dir<0)
{
optResolution[0]=optRes;
optResolution[1]=optRes;
optResolution[2]=optRes;
}
else optResolution[dir]=optRes;
m_SampleType = OPT_RESOLUTION;
}
void ProcessFields::CalcMeshPos()
{
if ((m_SampleType==SUBSAMPLE) || (m_SampleType==NONE))
{
vector tmp_pos;
for (int n=0; n<3; ++n)
{
// construct new discLines
tmp_pos.clear();
for (unsigned int i=start[n]; i<=stop[n]; i+=subSample[n])
tmp_pos.push_back(i);
numLines[n] = tmp_pos.size();
delete[] discLines[n];
discLines[n] = new double[numLines[n]];
delete[] posLines[n];
posLines[n] = new unsigned int[numLines[n]];
for (unsigned int i=0; iGetDiscLine(n,tmp_pos.at(i),m_dualMesh);
}
}
}
if ((m_SampleType==OPT_RESOLUTION))
{
vector tmp_pos;
double oldPos=0;
for (int n=0; n<3; ++n)
{
// construct new discLines
tmp_pos.clear();
tmp_pos.push_back(start[n]);
oldPos=Op->GetDiscLine(n,start[n],m_dualMesh);
for (unsigned int i=start[n]+1; i<=stop[n]-1; ++i)
{
if ( (Op->GetDiscLine(n,i+1,m_dualMesh)-oldPos) >= optResolution[n])
{
tmp_pos.push_back(i);
oldPos=Op->GetDiscLine(n,i,m_dualMesh);
}
}
if (start[n]!=stop[n])
tmp_pos.push_back(stop[n]);
numLines[n] = tmp_pos.size();
delete[] discLines[n];
discLines[n] = new double[numLines[n]];
delete[] posLines[n];
posLines[n] = new unsigned int[numLines[n]];
for (unsigned int i=0; iGetDiscLine(n,tmp_pos.at(i),m_dualMesh);
}
}
}
}
void ProcessFields::WriteVTKHeader(ofstream &file, double const* const* discLines, unsigned int const* numLines, unsigned int precision, string header_info, MeshType meshT, double discLines_scaling)
{
if (meshT==CARTESIAN_MESH)
WriteVTKCartesianGridHeader(file, discLines, numLines, precision, header_info, discLines_scaling);
else if (meshT==CYLINDRICAL_MESH)
WriteVTKCylindricalGridHeader(file, discLines, numLines, precision, header_info, discLines_scaling);
else
cerr << "ProcessFields::WriteVTKHeader: Warning: unknown mesh type, skipping header -> file will be invalid..." << endl;
}
void ProcessFields::WriteVTKCartesianGridHeader(ofstream &file, double const* const* discLines, unsigned int const* numLines, unsigned int precision, string header_info, double discLines_scaling)
{
file << "# vtk DataFile Version 2.0" << endl;
file << "Rectilinear Grid openEMS_ProcessFields";
if (!header_info.empty())
file << " " << header_info;
file << endl;
file << "ASCII" << endl;
file << "DATASET RECTILINEAR_GRID " << endl;
file << "DIMENSIONS " << numLines[0] << " " << numLines[1] << " " << numLines[2] << endl;
file << "X_COORDINATES " << numLines[0] << " " << __VTK_DATA_TYPE__ << endl;
for (unsigned int i=0; icreateDataSet( names[n].c_str(), datatype, dataspace );
//convert to float...
float* array = new float[numLines[n]];
for (unsigned int i=0; i const* const* const* const* array, unsigned int const* numLines, float weight, float frequency)
{
const H5std_string FILE_NAME(filename);
const H5std_string DATASET_NAME_RE( name + "_real");
const H5std_string DATASET_NAME_IM( name + "_imag");
H5::H5File file( FILE_NAME, H5F_ACC_RDWR );
H5::Group group( file.openGroup( groupName ));
hsize_t t_dimsf[] = {1};
H5::DataSpace t_dataspace( 1, t_dimsf );
hsize_t dimsf[4]; // dataset dimensions
dimsf[0] = 3;
dimsf[1] = numLines[2];
dimsf[2] = numLines[1];
dimsf[3] = numLines[0];
H5::DataSpace dataspace( 4, dimsf );
H5::FloatType datatype( H5::PredType::NATIVE_FLOAT );
//create and write real part
H5::DataSet dataset = group.createDataSet( DATASET_NAME_RE, datatype, dataspace );
H5::Attribute attr = dataset.createAttribute("frequency",H5::PredType::NATIVE_FLOAT,t_dataspace);
attr.write( H5::PredType::NATIVE_FLOAT , &frequency);
// I have not the slightest idea why this array-copy action is necessary... but it's the only way hdf5 does what it is supposed to do anyway!!
// at least it is save in case FDTD_FLOAT was defined as double...
// why does hdf5 write the dimensions backwards??? or matlab???
float hdf5array[3][numLines[2]][numLines[1]][numLines[0]];
for (int n=0; n<3; ++n)
{
for (unsigned int i=0; i(numLines);
if (m_DumpType==E_FIELD_DUMP)
{
for (unsigned int i=0; iGetEField(pos,out);
field[0][i][j][k] = out[0];
field[1][i][j][k] = out[1];
field[2][i][j][k] = out[2];
}
}
}
return field;
}
if (m_DumpType==H_FIELD_DUMP)
{
for (unsigned int i=0; iGetHField(pos,out);
field[0][i][j][k] = out[0];
field[1][i][j][k] = out[1];
field[2][i][j][k] = out[2];
}
}
}
return field;
}
cerr << "ProcessFields::CalcField(): Error, unknown dump type..." << endl;
return field;
}