Beispiel #1
0
void Operator::InitDataStorage()
{
	if (m_StoreMaterial[0])
	{
		if (g_settings.GetVerboseLevel()>0)
			cerr << "Operator::InitDataStorage(): Storing epsR material data..." << endl;
		Delete_N_3DArray(m_epsR,numLines);
		m_epsR = Create_N_3DArray<float>(numLines);
	}
	if (m_StoreMaterial[1])
	{
		if (g_settings.GetVerboseLevel()>0)
			cerr << "Operator::InitDataStorage(): Storing kappa material data..." << endl;
		Delete_N_3DArray(m_kappa,numLines);
		m_kappa = Create_N_3DArray<float>(numLines);
	}
	if (m_StoreMaterial[2])
	{
		if (g_settings.GetVerboseLevel()>0)
			cerr << "Operator::InitDataStorage(): Storing muR material data..." << endl;
		Delete_N_3DArray(m_mueR,numLines);
		m_mueR = Create_N_3DArray<float>(numLines);
	}
	if (m_StoreMaterial[3])
	{
		if (g_settings.GetVerboseLevel()>0)
			cerr << "Operator::InitDataStorage(): Storing sigma material data..." << endl;
		Delete_N_3DArray(m_sigma,numLines);
		m_sigma = Create_N_3DArray<float>(numLines);
	}
}
Beispiel #2
0
void Operator::CleanupMaterialStorage()
{
	if (!m_StoreMaterial[0] && m_epsR)
	{
		if (g_settings.GetVerboseLevel()>0)
			cerr << "Operator::CleanupMaterialStorage(): Delete epsR material data..." << endl;
		Delete_N_3DArray(m_epsR,numLines);
		m_epsR = NULL;
	}
	if (!m_StoreMaterial[1] && m_kappa)
	{
		if (g_settings.GetVerboseLevel()>0)
			cerr << "Operator::CleanupMaterialStorage(): Delete kappa material data..." << endl;
		Delete_N_3DArray(m_kappa,numLines);
		m_kappa = NULL;
	}
	if (!m_StoreMaterial[2] && m_mueR)
	{
		if (g_settings.GetVerboseLevel()>0)
			cerr << "Operator::CleanupMaterialStorage(): Delete mueR material data..." << endl;
		Delete_N_3DArray(m_mueR,numLines);
		m_mueR = NULL;
	}
	if (!m_StoreMaterial[3] && m_sigma)
	{
		if (g_settings.GetVerboseLevel()>0)
			cerr << "Operator::CleanupMaterialStorage(): Delete sigma material data..." << endl;
		Delete_N_3DArray(m_sigma,numLines);
		m_sigma = NULL;
	}
}
Beispiel #3
0
void Operator::DumpOperator2File(string filename)
{
#ifdef OUTPUT_IN_DRAWINGUNITS
	double discLines_scaling = 1;
#else
	double discLines_scaling = GetGridDelta();
#endif

	cout << "Operator: Dumping FDTD operator information to vtk file: " << filename << " ..." << flush;

	FDTD_FLOAT**** exc = Create_N_3DArray<FDTD_FLOAT>(numLines);
	if (Exc)
	{
		for (unsigned int n=0; n<Exc->Volt_Count; ++n)
			exc[Exc->Volt_dir[n]][Exc->Volt_index[0][n]][Exc->Volt_index[1][n]][Exc->Volt_index[2][n]] = Exc->Volt_amp[n];
	}

	FDTD_FLOAT**** vv_temp = Create_N_3DArray<FDTD_FLOAT>(numLines);
	FDTD_FLOAT**** vi_temp = Create_N_3DArray<FDTD_FLOAT>(numLines);
	FDTD_FLOAT**** iv_temp = Create_N_3DArray<FDTD_FLOAT>(numLines);
	FDTD_FLOAT**** ii_temp = Create_N_3DArray<FDTD_FLOAT>(numLines);

	unsigned int pos[3], n;
	for (n=0; n<3; n++)
		for (pos[0]=0; pos[0]<numLines[0]; pos[0]++)
			for (pos[1]=0; pos[1]<numLines[1]; pos[1]++)
				for (pos[2]=0; pos[2]<numLines[2]; pos[2]++)
				{
					vv_temp[n][pos[0]][pos[1]][pos[2]] = GetVV(n,pos);
					vi_temp[n][pos[0]][pos[1]][pos[2]] = GetVI(n,pos);
					iv_temp[n][pos[0]][pos[1]][pos[2]] = GetIV(n,pos);
					ii_temp[n][pos[0]][pos[1]][pos[2]] = GetII(n,pos);
				}

	VTK_File_Writer* vtk_Writer = new VTK_File_Writer(filename.c_str(), m_MeshType);
	vtk_Writer->SetMeshLines(discLines,numLines,discLines_scaling);
	vtk_Writer->SetHeader("openEMS - Operator dump");

	vtk_Writer->SetNativeDump(true);

	vtk_Writer->AddVectorField("vv",vv_temp);
	Delete_N_3DArray(vv_temp,numLines);
	vtk_Writer->AddVectorField("vi",vi_temp);
	Delete_N_3DArray(vi_temp,numLines);
	vtk_Writer->AddVectorField("iv",iv_temp);
	Delete_N_3DArray(iv_temp,numLines);
	vtk_Writer->AddVectorField("ii",ii_temp);
	Delete_N_3DArray(ii_temp,numLines);
	vtk_Writer->AddVectorField("exc",exc);
	Delete_N_3DArray(exc,numLines);

	if (vtk_Writer->Write()==false)
		cerr << "Operator::DumpOperator2File: Error: Can't write file... skipping!" << endl;

	cout << " done!" << endl;
}
Beispiel #4
0
void Operator::DumpMaterial2File(string filename)
{
#ifdef OUTPUT_IN_DRAWINGUNITS
	double discLines_scaling = 1;
#else
	double discLines_scaling = GetGridDelta();
#endif

	cout << "Operator: Dumping material information to vtk file: " << filename << " ..."  << flush;

	FDTD_FLOAT**** epsilon = Create_N_3DArray<FDTD_FLOAT>(numLines);
	FDTD_FLOAT**** mue     = Create_N_3DArray<FDTD_FLOAT>(numLines);
	FDTD_FLOAT**** kappa   = Create_N_3DArray<FDTD_FLOAT>(numLines);
	FDTD_FLOAT**** sigma   = Create_N_3DArray<FDTD_FLOAT>(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])
			{
				for (int n=0; n<3; ++n)
				{
					double inMat[4];
					Calc_EffMatPos(n, pos, inMat);
					epsilon[n][pos[0]][pos[1]][pos[2]] = inMat[0]/__EPS0__;
					mue[n][pos[0]][pos[1]][pos[2]]     = inMat[2]/__MUE0__;
					kappa[n][pos[0]][pos[1]][pos[2]]   = inMat[1];
					sigma[n][pos[0]][pos[1]][pos[2]]   = inMat[3];
				}
			}
		}
	}

	VTK_File_Writer* vtk_Writer = new VTK_File_Writer(filename.c_str(), m_MeshType);
	vtk_Writer->SetMeshLines(discLines,numLines,discLines_scaling);
	vtk_Writer->SetHeader("openEMS - material dump");

	vtk_Writer->SetNativeDump(true);

	vtk_Writer->AddVectorField("epsilon",epsilon);
	Delete_N_3DArray(epsilon,numLines);
	vtk_Writer->AddVectorField("mue",mue);
	Delete_N_3DArray(mue,numLines);
	vtk_Writer->AddVectorField("kappa",kappa);
	Delete_N_3DArray(kappa,numLines);
	vtk_Writer->AddVectorField("sigma",sigma);
	Delete_N_3DArray(sigma,numLines);

	if (vtk_Writer->Write()==false)
		cerr << "Operator::DumpMaterial2File: Error: Can't write file... skipping!" << endl;

	cout << " done!" << endl;
}
Beispiel #5
0
void Operator::InitOperator()
{
	Delete_N_3DArray(vv,numLines);
	Delete_N_3DArray(vi,numLines);
	Delete_N_3DArray(iv,numLines);
	Delete_N_3DArray(ii,numLines);
	vv = Create_N_3DArray<FDTD_FLOAT>(numLines);
	vi = Create_N_3DArray<FDTD_FLOAT>(numLines);
	iv = Create_N_3DArray<FDTD_FLOAT>(numLines);
	ii = Create_N_3DArray<FDTD_FLOAT>(numLines);
}
Beispiel #6
0
void Operator::Delete()
{
	CSX = NULL;

	Delete_N_3DArray(vv,numLines);
	Delete_N_3DArray(vi,numLines);
	Delete_N_3DArray(iv,numLines);
	Delete_N_3DArray(ii,numLines);
	vv=vi=iv=ii=0;
	delete MainOp; MainOp=0;
	for (int n=0; n<3; ++n)
	{
		delete[] EC_C[n];EC_C[n]=0;
		delete[] EC_G[n];EC_G[n]=0;
		delete[] EC_L[n];EC_L[n]=0;
		delete[] EC_R[n];EC_R[n]=0;
	}

	delete Exc;Exc=0;

	Delete_N_3DArray(m_epsR,numLines);
	m_epsR=0;
	Delete_N_3DArray(m_kappa,numLines);
	m_kappa=0;
	Delete_N_3DArray(m_mueR,numLines);
	m_mueR=0;
	Delete_N_3DArray(m_sigma,numLines);
	m_sigma=0;
}
Beispiel #7
0
ProcessFieldsFD::~ProcessFieldsFD()
{
	for (size_t n = 0; n<m_FD_Fields.size(); ++n)
	{
		Delete_N_3DArray(m_FD_Fields.at(n),numLines);
	}
	m_FD_Fields.clear();
}
Beispiel #8
0
void ProcessFieldsFD::DumpFDData()
{
	if (m_fileType==VTK_FILETYPE)
	{
		unsigned int pos[3];
		FDTD_FLOAT**** field = Create_N_3DArray<float>(numLines);
		std::complex<float>**** field_fd = NULL;
		double angle=0;
		int Nr_Ph = 21;

		for (size_t n = 0; n<m_FD_Samples.size(); ++n)
		{
			//dump multiple phase to vtk-files
			for (int p=0; p<Nr_Ph; ++p)
			{
				angle = 2.0 * M_PI * p / Nr_Ph;
				std::complex<float> exp_jwt = std::exp( (std::complex<float>)( _I * angle) );
				field_fd = m_FD_Fields.at(n);
				for (pos[0]=0; pos[0]<numLines[0]; ++pos[0])
				{
					for (pos[1]=0; pos[1]<numLines[1]; ++pos[1])
					{
						for (pos[2]=0; pos[2]<numLines[2]; ++pos[2])
						{
							field[0][pos[0]][pos[1]][pos[2]] = real(field_fd[0][pos[0]][pos[1]][pos[2]] * exp_jwt);
							field[1][pos[0]][pos[1]][pos[2]] = real(field_fd[1][pos[0]][pos[1]][pos[2]] * exp_jwt);
							field[2][pos[0]][pos[1]][pos[2]] = real(field_fd[2][pos[0]][pos[1]][pos[2]] * exp_jwt);
						}
					}
				}
				stringstream ss;
				ss << m_filename << fixed << "_f=" << m_FD_Samples.at(n) << "_p=" << std::setw( 3 ) << std::setfill( '0' ) <<(int)(angle * 180 / M_PI);

				m_Vtk_Dump_File->SetFilename(ss.str());
				m_Vtk_Dump_File->ClearAllFields();
				m_Vtk_Dump_File->AddVectorField(GetFieldNameByType(m_DumpType),field);
				if (m_Vtk_Dump_File->Write()==false)
					cerr << "ProcessFieldsFD::Process: can't dump to file... abort! " << endl;
			}

			{
				//dump magnitude to vtk-files
				for (pos[0]=0; pos[0]<numLines[0]; ++pos[0])
				{
					for (pos[1]=0; pos[1]<numLines[1]; ++pos[1])
					{
						for (pos[2]=0; pos[2]<numLines[2]; ++pos[2])
						{
							field[0][pos[0]][pos[1]][pos[2]] = abs(field_fd[0][pos[0]][pos[1]][pos[2]]);
							field[1][pos[0]][pos[1]][pos[2]] = abs(field_fd[1][pos[0]][pos[1]][pos[2]]);
							field[2][pos[0]][pos[1]][pos[2]] = abs(field_fd[2][pos[0]][pos[1]][pos[2]]);
						}
					}
				}
				stringstream ss;
				ss << m_filename << fixed << "_f=" << m_FD_Samples.at(n) << "_abs";
				m_Vtk_Dump_File->SetFilename(ss.str());
				m_Vtk_Dump_File->ClearAllFields();
				m_Vtk_Dump_File->AddVectorField(GetFieldNameByType(m_DumpType),field);
				if (m_Vtk_Dump_File->Write()==false)
					cerr << "ProcessFieldsFD::Process: can't dump to file... abort! " << endl;
			}

			{
				//dump phase to vtk-files
				for (pos[0]=0; pos[0]<numLines[0]; ++pos[0])
				{
					for (pos[1]=0; pos[1]<numLines[1]; ++pos[1])
					{
						for (pos[2]=0; pos[2]<numLines[2]; ++pos[2])
						{
							field[0][pos[0]][pos[1]][pos[2]] = arg(field_fd[0][pos[0]][pos[1]][pos[2]]);
							field[1][pos[0]][pos[1]][pos[2]] = arg(field_fd[1][pos[0]][pos[1]][pos[2]]);
							field[2][pos[0]][pos[1]][pos[2]] = arg(field_fd[2][pos[0]][pos[1]][pos[2]]);
						}
					}
				}
				stringstream ss;
				ss << m_filename << fixed << "_f=" << m_FD_Samples.at(n) << "_arg";
				m_Vtk_Dump_File->SetFilename(ss.str());
				m_Vtk_Dump_File->ClearAllFields();
				m_Vtk_Dump_File->AddVectorField(GetFieldNameByType(m_DumpType),field);
				if (m_Vtk_Dump_File->Write()==false)
					cerr << "ProcessFieldsFD::Process: can't dump to file... abort! " << endl;
			}
		}
		Delete_N_3DArray(field,numLines);
		return;
	}

	if (m_fileType==HDF5_FILETYPE)
	{
		for (size_t n = 0; n<m_FD_Samples.size(); ++n)
		{
			stringstream ss;
			ss << "f" << n;
			size_t datasize[]={numLines[0],numLines[1],numLines[2]};
			if (m_HDF5_Dump_File->WriteVectorField(ss.str(), m_FD_Fields.at(n), datasize)==false)
				cerr << "ProcessFieldsFD::Process: can't dump to file...! " << endl;

			//legacy support, use /FieldData/FD frequency-Attribute in the future
			float freq[1] = {(float)m_FD_Samples.at(n)};
			if (m_HDF5_Dump_File->WriteAtrribute("/FieldData/FD/"+ss.str()+"_real","frequency",freq,1)==false)
				cerr << "ProcessFieldsFD::Process: can't dump to file...! " << endl;
			if (m_HDF5_Dump_File->WriteAtrribute("/FieldData/FD/"+ss.str()+"_imag","frequency",freq,1)==false)
				cerr << "ProcessFieldsFD::Process: can't dump to file...! " << endl;
		}
		return;
	}

	cerr << "ProcessFieldsFD::Process: unknown File-Type" << endl;
}
Beispiel #9
0
//! \brief dump PEC (perfect electric conductor) information (into VTK-file)
//! visualization via paraview
//! visualize only one component (x, y or z)
void Operator::DumpPEC2File( string filename )
{
	cout << "Operator: Dumping PEC information to vtk file: " << filename << " ..." << flush;

	FDTD_FLOAT**** pec = Create_N_3DArray<FDTD_FLOAT>( numLines );
	unsigned int pos[3];

#ifdef OUTPUT_IN_DRAWINGUNITS
	double scaling = 1.0/GetGridDelta();
#else
	double scaling = 1;
#endif

	for (pos[0]=0; pos[0]<numLines[0]-1; pos[0]++)
	{
		for (pos[1]=0; pos[1]<numLines[1]-1; pos[1]++)
		{
			for (pos[2]=0; pos[2]<numLines[2]-1; pos[2]++)
			{
				if ((pos[1] != 0) && (pos[2] != 0))
				{
					// PEC surrounds the computational area; do not output this
					if ((GetVV(0,pos) == 0) && (GetVI(0,pos) == 0))
						pec[0][pos[0]][pos[1]][pos[2]] = GetEdgeLength( 0, pos ) * scaling; // PEC-x found
				}
				if ((pos[0] != 0) && (pos[2] != 0))
				{
					// PEC surrounds the computational area; do not output this
					if ((GetVV(1,pos) == 0) && (GetVI(1,pos) == 0))
						pec[1][pos[0]][pos[1]][pos[2]] = GetEdgeLength( 1, pos ) * scaling; // PEC-y found
				}
				if ((pos[0] != 0) && (pos[1] != 0))
				{
					// PEC surrounds the computational area; do not output this
					if ((GetVV(2,pos) == 0) && (GetVI(2,pos) == 0))
						pec[2][pos[0]][pos[1]][pos[2]] = GetEdgeLength( 2, pos ) * scaling; // PEC-z found
				}
			}
		}
	}

	// evaluate boundary conditions
	for (int n=0; n<3; n++)
	{
		int nP = (n+1)%3;
		int nPP = (n+2)%3;
		for (pos[nP]=0; pos[nP]<numLines[nP]; pos[nP]++)
		{
			for (pos[nPP]=0; pos[nPP]<numLines[nPP]; pos[nPP]++)
			{
				pos[n] = 0;
				if ((pos[nP] != numLines[nP]-1) && (m_BC[2*n] == 0))
					pec[nP ][pos[0]][pos[1]][pos[2]] = GetEdgeLength( nP,  pos ) * scaling;
				if ((pos[nPP] != numLines[nPP]-1) && (m_BC[2*n] == 0))
					pec[nPP][pos[0]][pos[1]][pos[2]] = GetEdgeLength( nPP, pos ) * scaling;

				pos[n] = numLines[n]-1;
				if ((pos[nP] != numLines[nP]-1) && (m_BC[2*n+1] == 0))
					pec[nP ][pos[0]][pos[1]][pos[2]] = GetEdgeLength( nP,  pos ) * scaling;
				if ((pos[nPP] != numLines[nPP]-1) && (m_BC[2*n+1] == 0))
					pec[nPP][pos[0]][pos[1]][pos[2]] = GetEdgeLength( nPP, pos ) * scaling;
			}
		}
	}

#ifdef OUTPUT_IN_DRAWINGUNITS
	scaling = 1;
#else
	scaling = GetGridDelta();
#endif

	VTK_File_Writer* vtk_Writer = new VTK_File_Writer(filename.c_str(), m_MeshType);
	vtk_Writer->SetMeshLines(discLines,numLines,scaling);
	vtk_Writer->SetHeader("openEMS - PEC dump");

	vtk_Writer->SetNativeDump(true);

	vtk_Writer->AddVectorField("PEC",pec);
	Delete_N_3DArray(pec,numLines);

	if (vtk_Writer->Write()==false)
		cerr << "Operator::DumpPEC2File: Error: Can't write file... skipping!" << endl;

	cout << " done!" << endl;
}
Beispiel #10
0
bool nf2ff_calc::AddPlane(float **lines, unsigned int* numLines, complex<float>**** E_field, complex<float>**** H_field, int MeshType)
{
	//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<float>**** Js = Create_N_3DArray<complex<float> >(numLines);
	complex<float>**** Ms = Create_N_3DArray<complex<float> >(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<numLines[nP]-1;++n)
		edge_length_P[n]=0.5*(lines[nP][n+1]-lines[nP][n-1]);
	edge_length_P[0]=0.5*(lines[nP][1]-lines[nP][0]);
	edge_length_P[numLines[nP]-1]=0.5*(lines[nP][numLines[nP]-1]-lines[nP][numLines[nP]-2]);

	float edge_length_PP[numLines[nPP]];
	for (unsigned int n=1;n<numLines[nPP]-1;++n)
		edge_length_PP[n]=0.5*(lines[nPP][n+1]-lines[nPP][n-1]);
	edge_length_PP[0]=0.5*(lines[nPP][1]-lines[nPP][0]);
	edge_length_PP[numLines[nPP]-1]=0.5*(lines[nPP][numLines[nPP]-1]-lines[nPP][numLines[nPP]-2]);

	//check for cylindrical mesh
	if (MeshType==1)
	{
		if (ny==0) //surface a-z
		{
			for (unsigned int n=0;n<numLines[nP];++n)
				edge_length_P[n]*=lines[0][0]; //angle-width * radius
		}
		else if (ny==2) //surface r-a
		{
			//calculate: area = delta_angle * delta_radius * center_radius
			for (unsigned int n=1;n<numLines[nP]-1;++n)
				edge_length_P[n]*=lines[nP][n];  //radius-width * center-radius
			edge_length_P[0]*=(lines[nP][0]+0.5*edge_length_P[0]);
			edge_length_P[numLines[nP]-1]*=(lines[nP][numLines[nP]-1]-0.5*edge_length_P[numLines[nP]-1]);
		}
	}

	complex<float> power = 0;
	float area;
	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])
			{
				area = edge_length_P[pos[nP]]*edge_length_PP[pos[nPP]];
				power = (E_field[nP][pos[0]][pos[1]][pos[2]]*conj(H_field[nPP][pos[0]][pos[1]][pos[2]]) \
						 - E_field[nPP][pos[0]][pos[1]][pos[2]]*conj(H_field[nP][pos[0]][pos[1]][pos[2]]));
				m_radPower += 0.5*area*real(power)*normDir[ny];
			}
	unsigned int numAngles[2] = {m_numTheta, m_numPhi};

	// setup multi-threading jobs
	vector<unsigned int> 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<m_numThreads; n++)
	{
		thread_data[n].ny=ny;
		thread_data[n].mesh_type = MeshType;
		thread_data[n].normDir=normDir;
		thread_data[n].numLines=numLines;
		thread_data[n].lines=lines;
		thread_data[n].edge_length_P=edge_length_P;
		thread_data[n].edge_length_PP=edge_length_PP;
		thread_data[n].E_field=E_field;
		thread_data[n].H_field=H_field;
		thread_data[n].Js=Js;
		thread_data[n].Ms=Ms;
		thread_data[n].m_Nt=Create2DArray<complex<float> >(numAngles);
		thread_data[n].m_Np=Create2DArray<complex<float> >(numAngles);
		thread_data[n].m_Lt=Create2DArray<complex<float> >(numAngles);
		thread_data[n].m_Lp=Create2DArray<complex<float> >(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 (n<m_numThreads-1)
			stop = start + jpt.at(n+1)-1;
	}
	//all threads a running and waiting for the barrier

	m_Barrier->wait(); //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<float>** Nt = Create2DArray<complex<float> >(numAngles);
	complex<float>** Np = Create2DArray<complex<float> >(numAngles);
	complex<float>** Lt = Create2DArray<complex<float> >(numAngles);
	complex<float>** Lp = Create2DArray<complex<float> >(numAngles);

	for (unsigned int n=0; n<m_numThreads; n++)
	{
		for (unsigned int tn=0;tn<m_numTheta;++tn)
			for (unsigned int pn=0;pn<m_numPhi;++pn)
			{
				Nt[tn][pn] += thread_data[n].m_Nt[tn][pn];
				Np[tn][pn] += thread_data[n].m_Np[tn][pn];
				Lt[tn][pn] += thread_data[n].m_Lt[tn][pn];
				Lp[tn][pn] += thread_data[n].m_Lp[tn][pn];
			}
		Delete2DArray(thread_data[n].m_Nt,numAngles);
		Delete2DArray(thread_data[n].m_Np,numAngles);
		Delete2DArray(thread_data[n].m_Lt,numAngles);
		Delete2DArray(thread_data[n].m_Lp,numAngles);
	}

	m_Barrier->wait(); //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<float> factor(0,k/4.0/M_PI/m_radius);
	complex<float> f_exp(0,-1*k*m_radius);
	factor *= exp(f_exp);
	complex<float> Z0 = __Z0__;
	float P_max = 0;
	for (unsigned int tn=0;tn<m_numTheta;++tn)
		for (unsigned int pn=0;pn<m_numPhi;++pn)
		{
			m_E_theta[tn][pn] -= factor*(Lp[tn][pn] + Z0*Nt[tn][pn]);
			m_E_phi[tn][pn] += factor*(Lt[tn][pn] - Z0*Np[tn][pn]);

			m_H_theta[tn][pn] += factor*(Np[tn][pn] - Lt[tn][pn]/Z0);
			m_H_phi[tn][pn] -= factor*(Nt[tn][pn] + Lp[tn][pn]/Z0);

			m_P_rad[tn][pn] = m_radius*m_radius/(2*__Z0__) * abs((m_E_theta[tn][pn]*conj(m_E_theta[tn][pn])+m_E_phi[tn][pn]*conj(m_E_phi[tn][pn])));
			if (m_P_rad[tn][pn]>P_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;
}