diff --git a/nf2ff/main.cpp b/nf2ff/main.cpp new file mode 100644 index 0000000..1dc7cfe --- /dev/null +++ b/nf2ff/main.cpp @@ -0,0 +1,44 @@ +/* +* 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 . +*/ + +#include + +#include "nf2ff.h" + +using namespace std; + +int main(int argc, char *argv[]) +{ + cout << " ---------------------------------------------------------------------- " << endl; + cout << " | nf2ff, near-field to far-field transformation for openEMS " << endl; + cout << " | (C) 2012 Thorsten Liebig GPL license" << endl; + cout << " ---------------------------------------------------------------------- " << endl; + + if (argc<=1) + { + cout << " Usage: nf2ff " << endl << endl; + cout << endl; + exit(-1); + } + + if (argc>=2) + { + return !nf2ff::AnalyseXMLFile(argv[argc-1]); + } + + return 0; +} diff --git a/nf2ff/nf2ff.cpp b/nf2ff/nf2ff.cpp new file mode 100644 index 0000000..17b2f7c --- /dev/null +++ b/nf2ff/nf2ff.cpp @@ -0,0 +1,365 @@ +/* +* 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 . +*/ + +#include "nf2ff.h" +#include "nf2ff_calc.h" +#include "../tools/array_ops.h" +#include "../tools/useful.h" +#include "../tools/hdf5_file_reader.h" +#include "../tools/hdf5_file_writer.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//external libs +#include "tinyxml.h" + +nf2ff::nf2ff(vector freq, vector theta, vector phi, unsigned int numThreads) +{ + m_freq = freq; + + m_numTheta = theta.size(); + m_theta = new float[m_numTheta]; + for (size_t n=0;nSetNumThreads(numThreads); + } + + m_radius = 1; + m_Verbose = 0; +} + +nf2ff::~nf2ff() +{ + m_freq.clear(); + for (size_t fn=0;fnQueryIntAttribute("NumThreads",&ihelp) == TIXML_SUCCESS) + { + numThreads = ihelp; + cerr << "nf2ff: Set number of threads to: " << numThreads << endl; + } + int Verbose=0; + if (ti_nf2ff->QueryIntAttribute("Verbose",&Verbose) == TIXML_SUCCESS) + cerr << "nf2ff: Set verbose level to " << Verbose << endl; + else + Verbose = 0; + + const char* attr = NULL; + attr = ti_nf2ff->Attribute("freq"); + if (attr==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read frequency inforamtions ... " << endl; + return false; + } + vector freq = SplitString2Float(attr); + attr = ti_nf2ff->Attribute("Outfile"); + if (attr==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read frequency inforamtions ... " << endl; + return false; + } + string outfile = string(attr); + if (outfile.empty()) + { + cerr << "nf2ff::AnalyseXMLNode: outfile is empty, skipping nf2ff... " << endl; + return false; + } + + TiXmlElement* ti_theta = ti_nf2ff->FirstChildElement("theta"); + if (ti_theta==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read theta values ... " << endl; + return false; + } + TiXmlNode* ti_theta_node = ti_theta->FirstChild(); + if (ti_theta_node==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read theta text child ... " << endl; + return false; + } + TiXmlText* ti_theta_text = ti_theta_node->ToText(); + if (ti_theta_text==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read theta text values ... " << endl; + return false; + } + vector theta = SplitString2Float(ti_theta_text->Value()); + + TiXmlElement* ti_phi = ti_nf2ff->FirstChildElement("phi"); + if (ti_phi==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read phi values ... " << endl; + return false; + } + TiXmlNode* ti_phi_node = ti_phi->FirstChild(); + if (ti_phi_node==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read phi text child ... " << endl; + return false; + } + TiXmlText* ti_phi_text = ti_phi_node->ToText(); + if (ti_phi_text==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read phi text values ... " << endl; + return false; + } + vector phi = SplitString2Float(ti_phi_text->Value()); + + nf2ff* l_nf2ff = new nf2ff(freq,theta,phi,numThreads); + l_nf2ff->SetVerboseLevel(Verbose); + + TiXmlElement* ti_Planes = ti_nf2ff->FirstChildElement(); + string E_name; + string H_name; + while (ti_Planes!=NULL) + { + E_name = string(ti_Planes->Attribute("E_Field")); + H_name = string(ti_Planes->Attribute("H_Field")); + if ((!E_name.empty()) && (!H_name.empty())) + { + if (l_nf2ff->AnalyseFile(E_name,H_name)==false) + { + cerr << "nf2ff::AnalyseXMLNode: Error, analysing Plane ... " << endl; + return false; + } + } + else + { + cerr << "nf2ff::AnalyseXMLNode: Error, invalid plane entry ... " << endl; + return false; + } + ti_Planes = ti_Planes->NextSiblingElement("Planes"); + } + l_nf2ff->Write2HDF5(outfile); + delete l_nf2ff; + return true; +} + +bool nf2ff::AnalyseXMLFile(string filename) +{ + TiXmlDocument doc(filename.c_str()); + if (!doc.LoadFile()) + { + cerr << "nf2ff::AnalyseXMLFile: Error loading xml-file failed!!! File: " << filename << endl; + return false; + } + TiXmlElement* ti_nf2ff = doc.FirstChildElement("nf2ff"); + if (ti_nf2ff==NULL) + { + cerr << "nf2ff::AnalyseXMLFile: Can't read nf2ff ... " << endl; + return false; + } + + return AnalyseXMLNode(ti_nf2ff); +} + +bool nf2ff::AnalyseFile(string E_Field_file, string H_Field_file) +{ + HDF5_File_Reader E_file(E_Field_file); + HDF5_File_Reader H_file(H_Field_file); + + if (m_Verbose>0) + cerr << "nf2ff: Reading planes: " << E_Field_file << " & " << E_Field_file << endl; + + // read E-mesh + float* E_lines[3]={NULL,NULL,NULL}; + unsigned int E_numLines[3]; + int E_meshType; + if (E_file.ReadMesh(E_lines, E_numLines, E_meshType) == false) + { + cerr << "nf2ff::AnalyseFile: Error reading E-field mesh..." << endl; + return false; + } + + // read H-mesh + float* H_lines[3]={NULL,NULL,NULL}; + unsigned int H_numLines[3]; + int H_meshType; + if (H_file.ReadMesh(H_lines, H_numLines, H_meshType) == false) + { + cerr << "nf2ff::AnalyseFile: Error reading H-Field mesh..." << endl; + return false; + } + + // compare E/H meshs + if (E_meshType!=H_meshType) + { + cerr << "nf2ff::AnalyseFile: Error mesh types don't agree" << endl; + return false; + } + if ((E_numLines[0]!=H_numLines[0]) || (E_numLines[1]!=H_numLines[1]) || (E_numLines[2]!=H_numLines[2])) + { + cerr << "nf2ff::AnalyseFile: Error mesh dimensions don't agree" << endl; + return false; + } + for (int n=0;n<3;++n) + for (unsigned int m=0;m1) + cerr << "nf2ff: Data-Size: " << E_numLines[0] << "x" << E_numLines[1] << "x" << E_numLines[2] << endl; + if (m_Verbose>1) + cerr << "nf2ff: calculate dft..." << endl; + + unsigned int data_size[4]; + vector****> E_fd_data; + E_file.CalcFDVectorData(m_freq,E_fd_data,data_size); + + vector****> H_fd_data; + H_file.CalcFDVectorData(m_freq,H_fd_data,data_size); + + if (m_Verbose>0) + cerr << "nf2ff: Analysing far-field for " << m_nf2ff.size() << " frequencies. " << endl; + + for (size_t fn=0;fn1) + cerr << "nf2ff: f = " << m_freq.at(fn) << "Hz (" << fn+1 << "/" << m_nf2ff.size() << ") ..."; + m_nf2ff.at(fn)->AddPlane(E_lines, E_numLines, E_fd_data.at(fn), H_fd_data.at(fn)); + if (m_Verbose>1) + cerr << " done." << endl; + } + for (int n=0;n<3;++n) + { + delete[] H_lines[n]; + delete[] E_lines[n]; + } + return true; +} + +bool nf2ff::Write2HDF5(string filename) +{ + HDF5_File_Writer hdf_file(filename); + + //write mesh information + hdf_file.SetCurrentGroup("/Mesh"); + size_t meshsize[1]={m_numTheta}; + if (hdf_file.WriteData(string("theta"),m_theta,1,meshsize)==false) + return false; + meshsize[0]=m_numPhi; + if (hdf_file.WriteData(string("phi"),m_phi,1,meshsize)==false) + return false; + meshsize[0]=1; + float rad[1]={m_radius}; + if (hdf_file.WriteData(string("r"),rad,1,meshsize)==false) + return false; + + float attr_value = 2; + hdf_file.WriteAtrribute("/Mesh", "MeshType", &attr_value, 1); + + //write field data + size_t dim = 2; + size_t pos = 0; + size_t datasize[2]={m_numPhi,m_numTheta}; + size_t size = datasize[0]*datasize[1]; + float* buffer = new float[size]; + complex** field_data; + string field_names[2]={"E_theta", "E_phi"}; + for (int n=0;n<2;++n) + { + hdf_file.SetCurrentGroup("/nf2ff/" + field_names[n] + "/FD"); + for (size_t fn=0;fn. +*/ + +#ifndef NF2FF_H +#define NF2FF_H + +#include +#include +#include +#include +#include +#include "nf2ff_calc.h" + +using namespace std; + +class TiXmlElement; + +class nf2ff +{ +public: + nf2ff(vector freq, vector theta, vector phi, unsigned int numThreads=0); + ~nf2ff(); + + bool AnalyseFile(string E_Field_file, string H_Field_file); + + float GetRadPower(size_t f_idx) const {return m_nf2ff.at(f_idx)->GetRadPower();} + float GetMaxDirectivity(size_t f_idx) const {return m_nf2ff.at(f_idx)->GetMaxDirectivity();} + + complex** GetETheta(size_t f_idx) const {return m_nf2ff.at(f_idx)->GetETheta();} + complex** GetEPhi(size_t f_idx) const {return m_nf2ff.at(f_idx)->GetEPhi();} + + //! Write results to a hdf5 file + bool Write2HDF5(string filename); + + void SetVerboseLevel(int level) {m_Verbose=level;} + + static bool AnalyseXMLNode(TiXmlElement* ti_nf2ff); + static bool AnalyseXMLFile(string filename); + +protected: + vector m_freq; + unsigned int m_numTheta; + unsigned int m_numPhi; + float* m_theta; + float* m_phi; + float m_radius; + int m_Verbose; + vector m_nf2ff; +}; + +#endif // NF2FF_H diff --git a/nf2ff/nf2ff.pro b/nf2ff/nf2ff.pro new file mode 100644 index 0000000..f8b6dc7 --- /dev/null +++ b/nf2ff/nf2ff.pro @@ -0,0 +1,60 @@ +TARGET = nf2ff +CONFIG += console +CONFIG -= app_bundle qt +TEMPLATE = app +OBJECTS_DIR = obj +INCLUDEPATH += . +INCLUDEPATH += ../../tinyxml +CONFIG += debug_and_release + +win32 { + INCLUDEPATH += ../../hdf5/include ../../hdf5/include/cpp ../../boost/include/boost-1_42 + LIBS += ../../hdf5/lib/hdf5.lib + LIBS += ../../boost/lib/libboost_thread-mgw44-mt.lib + LIBS += ../../tinyxml/release/libtinyxml2.a +} +!win32 { + LIBS += -lboost_thread + LIBS += -lhdf5 + LIBS += ../../tinyxml/libtinyxml.so +} +QMAKE_LFLAGS += \'-Wl,-rpath,\$$ORIGIN/../../tinyxml\' + +TOOLSPATH = ../tools + +#### SOURCES ################################################################ +SOURCES += main.cpp \ + nf2ff.cpp \ + nf2ff_calc.cpp + +# tools + SOURCES += $$TOOLSPATH/global.cpp \ + $$TOOLSPATH/useful.cpp \ + $$TOOLSPATH/array_ops.cpp \ + $$TOOLSPATH/hdf5_file_reader.cpp \ + $$TOOLSPATH/hdf5_file_writer.cpp + +#### HEADERS ################################################################ +HEADERS += nf2ff.h \ + nf2ff_calc.h + +# tools +HEADERS += $$TOOLSPATH/constants.h \ + $$TOOLSPATH/array_ops.h \ + $$TOOLSPATH/global.h \ + $$TOOLSPATH/useful.h \ + $$TOOLSPATH/aligned_allocator.h \ + $$TOOLSPATH/hdf5_file_reader.h \ + $$TOOLSPATH/hdf5_file_writer.h + +QMAKE_CXXFLAGS_RELEASE = -O3 \ + -g \ + -march=native +QMAKE_CXXFLAGS_DEBUG = -O0 \ + -g \ + -march=native + +# add git revision +# QMAKE_CXXFLAGS += -DGIT_VERSION=\\\"`git describe --tags`\\\" + + diff --git a/nf2ff/nf2ff_calc.cpp b/nf2ff/nf2ff_calc.cpp new file mode 100644 index 0000000..3f04f11 --- /dev/null +++ b/nf2ff/nf2ff_calc.cpp @@ -0,0 +1,353 @@ +/* +* 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 . +*/ + +#include "nf2ff_calc.h" +#include "../tools/array_ops.h" +#include "../tools/useful.h" + +#include +#include +#include +#include +#include +#include +#include + +nf2ff_calc_thread::nf2ff_calc_thread(nf2ff_calc* nfc, unsigned int start, unsigned int stop, unsigned int threadID, nf2ff_data &data) +{ + m_nf_calc = nfc; + m_start = start; + m_stop = stop; + m_threadID = threadID; + m_data = data; +} + +void nf2ff_calc_thread::operator()() +{ + m_nf_calc->m_Barrier->wait(); // start + + int ny = m_data.ny; + int nP = (ny+1)%3; + int nPP = (ny+2)%3; + + unsigned int* numLines = m_data.numLines; + float* normDir = m_data.normDir; + float **lines = m_data.lines; + float* edge_length_P = m_data.edge_length_P; + float* edge_length_PP = m_data.edge_length_PP; + + unsigned int pos[3]; + unsigned int pos_t=0; + unsigned int num_t=m_stop-m_start+1; + + + complex**** Js=m_data.Js; + complex**** Ms=m_data.Ms; + complex**** E_field=m_data.E_field; + complex**** H_field=m_data.H_field; + + // calc Js and Ms (eq. 8.15a/b) + pos[ny]=0; + for (pos_t=0; pos_t** m_Nt=m_data.m_Nt; + complex** m_Np=m_data.m_Np; + complex** m_Lt=m_data.m_Lt; + complex** m_Lp=m_data.m_Lp; + + // calc local Nt,Np,Lt and Lp + float area; + float cosT_cosP,cosP_sinT; + float cosT_sinP,sinT_sinP; + float sinT,sinP; + float cosP,cosT; + float r_cos_psi; + float k = 2*M_PI*m_nf_calc->m_freq/__C0__; + complex exp_jkr; + complex _I_(0,1); + for (unsigned int tn=0;tnm_numTheta;++tn) + for (unsigned int pn=0;pnm_numPhi;++pn) + { + sinT = sin(m_nf_calc->m_theta[tn]); + sinP = sin(m_nf_calc->m_phi[pn]); + cosT = cos(m_nf_calc->m_theta[tn]); + cosP = cos(m_nf_calc->m_phi[pn]); + cosT_cosP = cosT*cosP; + cosT_sinP = cosT*sinP; + cosP_sinT = cosP*sinT; + sinT_sinP = sinP*sinT; + + for (pos_t=0; pos_tm_Barrier->wait(); //combine all thread local Nt,Np,Lt and Lp + + m_nf_calc->m_Barrier->wait(); //wait for termination +} + + +/***********************************************************************/ + + +nf2ff_calc::nf2ff_calc(float freq, vector theta, vector phi) +{ + m_freq = freq; + + m_numTheta = theta.size(); + m_theta = new float[m_numTheta]; + for (size_t n=0;n >(numLines); + m_E_phi = Create2DArray >(numLines); + m_H_theta = Create2DArray >(numLines); + m_H_phi = Create2DArray >(numLines); + m_P_rad = Create2DArray(numLines); + + m_centerCoord[0]=m_centerCoord[1]=m_centerCoord[2]=0; + + m_radPower = 0; + m_maxDir = 0; + m_radius = 1; + + m_Barrier = NULL; + m_numThreads = boost::thread::hardware_concurrency(); +} + +nf2ff_calc::~nf2ff_calc() +{ + delete[] m_phi; + m_phi = NULL; + delete[] m_theta; + m_theta = NULL; + + unsigned int numLines[2] = {m_numTheta, m_numPhi}; + Delete2DArray(m_E_theta,numLines); + m_E_theta = NULL; + Delete2DArray(m_E_phi,numLines); + m_E_phi = NULL; + Delete2DArray(m_H_theta,numLines); + m_H_theta = NULL; + Delete2DArray(m_H_phi,numLines); + m_H_phi = NULL; + Delete2DArray(m_P_rad,numLines); + m_P_rad = NULL; + + delete m_Barrier; + m_Barrier = NULL; +} + +bool nf2ff_calc::AddPlane(float **lines, unsigned int* numLines, complex**** E_field, complex**** H_field) +{ + //find normal direction + int ny = -1; + int nP,nPP; + for (int n=0;n<3;++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + if ((numLines[n]==1) && (numLines[nP]>2) && (numLines[nPP]>2)) + ny=n; + } + nP = (ny+1)%3; + nPP = (ny+2)%3; + if (ny<0) + { + cerr << "nf2ff_calc::AddPlane: Error can't determine normal direction..." << endl; + return false; + } + + complex**** Js = Create_N_3DArray >(numLines); + complex**** Ms = Create_N_3DArray >(numLines); + + float normDir[3]= {0,0,0}; + if (lines[ny][0]>=m_centerCoord[ny]) + normDir[ny]=1; + else + normDir[ny]=-1; + unsigned int pos[3]; + + float edge_length_P[numLines[nP]]; + for (unsigned int n=1;n power = 0; + float area; + for (pos[0]=0; pos[0] jpt = AssignJobs2Threads(numLines[nP], m_numThreads, true); + m_numThreads = jpt.size(); + nf2ff_data thread_data[m_numThreads]; + m_Barrier = new boost::barrier(m_numThreads+1); // numThread workers + 1 controller + unsigned int start=0; + unsigned int stop=jpt.at(0)-1; + for (unsigned int n=0; n >(numAngles); + thread_data[n].m_Np=Create2DArray >(numAngles); + thread_data[n].m_Lt=Create2DArray >(numAngles); + thread_data[n].m_Lp=Create2DArray >(numAngles); + + boost::thread *t = new boost::thread( nf2ff_calc_thread(this,start,stop,n,thread_data[n]) ); + + m_thread_group.add_thread( t ); + + start = stop+1; + if (nwait(); //start + + // threads: calc Js and Ms (eq. 8.15a/b) + // threads calc their local Nt,Np,Lt and Lp + + m_Barrier->wait(); //combine all thread local Nt,Np,Lt and Lp + + //cleanup E- & H-Fields + Delete_N_3DArray(E_field,numLines); + Delete_N_3DArray(H_field,numLines); + + complex** Nt = Create2DArray >(numAngles); + complex** Np = Create2DArray >(numAngles); + complex** Lt = Create2DArray >(numAngles); + complex** Lp = Create2DArray >(numAngles); + + for (unsigned int n=0; nwait(); //wait for termination + m_thread_group.join_all(); // wait for termination + delete m_Barrier; + m_Barrier = NULL; + + //cleanup Js & Ms + Delete_N_3DArray(Js,numLines); + Delete_N_3DArray(Ms,numLines); + + // calc equations 8.23a/b and 8.24a/b + float k = 2*M_PI*m_freq/__C0__; + complex factor(0,k/4.0/M_PI/m_radius); + complex f_exp(0,-1*k*m_radius); + factor *= exp(f_exp); + complex Z0 = __Z0__; + float P_max = 0; + for (unsigned int tn=0;tnP_max) + P_max = m_P_rad[tn][pn]; + } + + //cleanup Nx and Lx + Delete2DArray(Nt,numAngles); + Delete2DArray(Np,numAngles); + Delete2DArray(Lt,numAngles); + Delete2DArray(Lp,numAngles); + + m_maxDir = 4*M_PI*P_max / m_radPower; + + return true; +} diff --git a/nf2ff/nf2ff_calc.h b/nf2ff/nf2ff_calc.h new file mode 100644 index 0000000..fbfbb6a --- /dev/null +++ b/nf2ff/nf2ff_calc.h @@ -0,0 +1,114 @@ +/* +* 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 . +*/ + +#ifndef NF2FF_CALC_H +#define NF2FF_CALC_H + +#include +#include +#include +#include +#include +#include + +using namespace std; + +class nf2ff_calc; + +// data structure to exchange data between thread-controller and worker-threads +typedef struct +{ + //local working data IN + int ny; + float* normDir; + unsigned int* numLines; + float **lines; + float* edge_length_P; + float* edge_length_PP; + + complex**** E_field; + complex**** H_field; + complex**** Js; + complex**** Ms; + + //local working data OUT + complex** m_Nt; + complex** m_Np; + complex** m_Lt; + complex** m_Lp; + +} nf2ff_data; + +class nf2ff_calc_thread +{ +public: + nf2ff_calc_thread(nf2ff_calc* nfc, unsigned int start, unsigned int stop, unsigned int threadID, nf2ff_data &data); + void operator()(); + +protected: + unsigned int m_start, m_stop, m_threadID; + nf2ff_calc *m_nf_calc; + + nf2ff_data m_data; +}; + +class nf2ff_calc +{ + // allow full data access to nf2ff_calc_thread class + friend class nf2ff_calc_thread; +public: + nf2ff_calc(float freq, vector theta, vector phi); + ~nf2ff_calc(); + + float GetRadPower() const {return m_radPower;} + float GetMaxDirectivity() const {return m_maxDir;} + + complex** GetETheta() const {return m_E_theta;} + complex** GetEPhi() const {return m_E_phi;} + + unsigned int GetNumThreads() const {return m_numThreads;} + void SetNumThreads(unsigned int n) {m_numThreads=n;} + + bool AddPlane(float **lines, unsigned int* numLines, complex**** E_field, complex**** H_field); + +protected: + float m_freq; + float m_radius; + + float m_radPower; + float m_maxDir; + + complex** m_E_theta; + complex** m_E_phi; + complex** m_H_theta; + complex** m_H_phi; + float** m_P_rad; + + float m_centerCoord[3]; + unsigned int m_numTheta; + unsigned int m_numPhi; + float* m_theta; + float* m_phi; + + //boost multi-threading + unsigned int m_numThreads; + boost::thread_group m_thread_group; + boost::barrier *m_Barrier; +}; + + +#endif // NF2FF_CALC_H