1 /*
2 *	Copyright (C) 2010 Thorsten Liebig (Thorsten.Liebig@gmx.de)
3 *
4 *	This program is free software: you can redistribute it and/or modify
5 *	it under the terms of the GNU General Public License as published by
6 *	the Free Software Foundation, either version 3 of the License, or
7 *	(at your option) any later version.
8 *
9 *	This program is distributed in the hope that it will be useful,
10 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 *	GNU General Public License for more details.
13 *
14 *	You should have received a copy of the GNU General Public License
15 *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include <fstream>
19 #include <algorithm>
20 #include "operator.h"
21 #include "engine.h"
22 #include "extensions/operator_extension.h"
23 #include "extensions/operator_ext_excitation.h"
24 #include "Common/processfields.h"
25 #include "tools/array_ops.h"
26 #include "tools/vtk_file_writer.h"
27 #include "fparser.hh"
28 #include "extensions/operator_ext_excitation.h"
29 
30 #include "vtkPolyData.h"
31 #include "vtkCellArray.h"
32 #include "vtkPoints.h"
33 #include "vtkXMLPolyDataWriter.h"
34 #include "CSPrimBox.h"
35 #include "CSPrimCurve.h"
36 
37 #include "CSPropMaterial.h"
38 #include "CSPropLumpedElement.h"
39 
New()40 Operator* Operator::New()
41 {
42 	cout << "Create FDTD operator" << endl;
43 	Operator* op = new Operator();
44 	op->Init();
45 	return op;
46 }
47 
Operator()48 Operator::Operator() : Operator_Base()
49 {
50 	m_Exc = 0;
51 	m_InvaildTimestep = false;
52 	m_TimeStepVar = 3;
53 }
54 
~Operator()55 Operator::~Operator()
56 {
57 	for (size_t n=0; n<m_Op_exts.size(); ++n)
58 		delete m_Op_exts.at(n);
59 	m_Op_exts.clear();
60 
61 	Delete();
62 }
63 
CreateEngine()64 Engine* Operator::CreateEngine()
65 {
66 	m_Engine = Engine::New(this);
67 	return m_Engine;
68 }
69 
Init()70 void Operator::Init()
71 {
72 	CSX = NULL;
73 	m_Engine = NULL;
74 
75 	Operator_Base::Init();
76 
77 	vv=NULL;
78 	vi=NULL;
79 	iv=NULL;
80 	ii=NULL;
81 
82 	m_epsR=NULL;
83 	m_kappa=NULL;
84 	m_mueR=NULL;
85 	m_sigma=NULL;
86 
87 	MainOp=NULL;
88 
89 	for (int n=0; n<3; ++n)
90 	{
91 		EC_C[n]=NULL;
92 		EC_G[n]=NULL;
93 		EC_L[n]=NULL;
94 		EC_R[n]=NULL;
95 	}
96 
97 	m_Exc = 0;
98 	m_TimeStepFactor = 1;
99 	SetMaterialAvgMethod(QuarterCell);
100 }
101 
Delete()102 void Operator::Delete()
103 {
104 	CSX = NULL;
105 
106 	Delete_N_3DArray(vv,numLines);
107 	Delete_N_3DArray(vi,numLines);
108 	Delete_N_3DArray(iv,numLines);
109 	Delete_N_3DArray(ii,numLines);
110 	vv=vi=iv=ii=0;
111 	delete MainOp; MainOp=0;
112 	for (int n=0; n<3; ++n)
113 	{
114 		delete[] EC_C[n];EC_C[n]=0;
115 		delete[] EC_G[n];EC_G[n]=0;
116 		delete[] EC_L[n];EC_L[n]=0;
117 		delete[] EC_R[n];EC_R[n]=0;
118 	}
119 
120 	Delete_N_3DArray(m_epsR,numLines);
121 	m_epsR=0;
122 	Delete_N_3DArray(m_kappa,numLines);
123 	m_kappa=0;
124 	Delete_N_3DArray(m_mueR,numLines);
125 	m_mueR=0;
126 	Delete_N_3DArray(m_sigma,numLines);
127 	m_sigma=0;
128 }
129 
Reset()130 void Operator::Reset()
131 {
132 	Delete();
133 	Operator_Base::Reset();
134 }
135 
GetDiscLine(int n,unsigned int pos,bool dualMesh) const136 double Operator::GetDiscLine(int n, unsigned int pos, bool dualMesh) const
137 {
138 	if ((n<0) || (n>2)) return 0.0;
139 	if (pos>=numLines[n]) return 0.0;
140 	if (dualMesh==false)
141 		return discLines[n][pos];
142 
143 	// return dual mesh node
144 	if (pos<numLines[n]-1)
145 		return 0.5*(discLines[n][pos] + discLines[n][pos+1]);
146 
147 	// dual node for the last line (outside the field domain)
148 	return discLines[n][pos] + 0.5*(discLines[n][pos] - discLines[n][pos-1]);
149 }
150 
GetDiscDelta(int n,unsigned int pos,bool dualMesh) const151 double Operator::GetDiscDelta(int n, unsigned int pos, bool dualMesh) const
152 {
153 	if ((n<0) || (n>2)) return 0.0;
154 	if (pos>=numLines[n]) return 0.0;
155 	double delta=0;
156 	if (dualMesh==false)
157 	{
158 		if (pos<numLines[n]-1)
159 			delta = GetDiscLine(n,pos+1,false) - GetDiscLine(n,pos,false);
160 		else
161 			delta = GetDiscLine(n,pos,false) - GetDiscLine(n,pos-1,false);
162 		return delta;
163 	}
164 	else
165 	{
166 		if (pos>0)
167 			delta = GetDiscLine(n,pos,true) - GetDiscLine(n,pos-1,true);
168 		else
169 			delta = GetDiscLine(n,1,false) - GetDiscLine(n,0,false);
170 		return delta;
171 	}
172 }
173 
GetYeeCoords(int ny,unsigned int pos[3],double * coords,bool dualMesh) const174 bool Operator::GetYeeCoords(int ny, unsigned int pos[3], double* coords, bool dualMesh) const
175 {
176 	for (int n=0;n<3;++n)
177 		coords[n]=GetDiscLine(n,pos[n],dualMesh);
178 	coords[ny]=GetDiscLine(ny,pos[ny],!dualMesh);
179 
180 	//check if position is inside the FDTD domain
181 	if (dualMesh==false) //main grid
182 	{
183 		if (pos[ny]>=numLines[ny]-1)
184 			return false;
185 	}
186 	else	//dual grid
187 	{
188 		int nP = (ny+1)%3;
189 		int nPP = (ny+2)%3;
190 		if ((pos[nP]>=numLines[nP]-1) || (pos[nPP]>=numLines[nPP]-1))
191 			return false;
192 	}
193 	return true;
194 }
195 
GetNodeCoords(const unsigned int pos[3],double * coords,bool dualMesh,CoordinateSystem c_system) const196 bool Operator::GetNodeCoords(const unsigned int pos[3], double* coords, bool dualMesh, CoordinateSystem c_system) const
197 {
198 	for (int n=0;n<3;++n)
199 		coords[n]=GetDiscLine(n,pos[n],dualMesh);
200 	TransformCoordSystem(coords,coords,m_MeshType,c_system);
201 	return true;
202 }
203 
GetEdgeLength(int n,const unsigned int * pos,bool dualMesh) const204 double Operator::GetEdgeLength(int n, const unsigned int* pos, bool dualMesh) const
205 {
206 	return GetDiscDelta(n,pos[n],dualMesh)*gridDelta;
207 }
208 
GetCellVolume(const unsigned int pos[3],bool dualMesh) const209 double Operator::GetCellVolume(const unsigned int pos[3], bool dualMesh) const
210 {
211 	double vol=1;
212 	for (int n=0;n<3;++n)
213 		vol*=GetEdgeLength(n,pos,dualMesh);
214 	return vol;
215 }
216 
GetNodeWidth(int ny,const int pos[3],bool dualMesh) const217 double Operator::GetNodeWidth(int ny, const int pos[3], bool dualMesh) const
218 {
219 	if ( (pos[0]<0) || (pos[1]<0) || (pos[2]<0) )
220 		return 0.0;
221 
222 	//call the unsigned int version of GetNodeWidth
223 	unsigned int uiPos[]={(unsigned int)pos[0],(unsigned int)pos[1],(unsigned int)pos[2]};
224 	return GetNodeWidth(ny, uiPos, dualMesh);
225 }
226 
GetNodeArea(int ny,const unsigned int pos[3],bool dualMesh) const227 double Operator::GetNodeArea(int ny, const unsigned int pos[3], bool dualMesh) const
228 {
229 	int nyP = (ny+1)%3;
230 	int nyPP = (ny+2)%3;
231 	return GetNodeWidth(nyP,pos,dualMesh) * GetNodeWidth(nyPP,pos,dualMesh);
232 }
233 
GetNodeArea(int ny,const int pos[3],bool dualMesh) const234 double Operator::GetNodeArea(int ny, const int pos[3], bool dualMesh) const
235 {
236 	if ( (pos[0]<0) || (pos[1]<0) || (pos[2]<0) )
237 		return 0.0;
238 
239 	//call the unsigned int version of GetNodeArea
240 	unsigned int uiPos[]={(unsigned int)pos[0],(unsigned int)pos[1],(unsigned int)pos[2]};
241 	return GetNodeArea(ny, uiPos, dualMesh);
242 }
243 
SnapToMeshLine(int ny,double coord,bool & inside,bool dualMesh,bool fullMesh) const244 unsigned int Operator::SnapToMeshLine(int ny, double coord, bool &inside, bool dualMesh, bool fullMesh) const
245 {
246 	inside = false;
247 	if ((ny<0) || (ny>2))
248 		return 0;
249 	if (coord<GetDiscLine(ny,0))
250 		return 0;
251 	unsigned int numLines = GetNumberOfLines(ny, fullMesh);
252 	if (coord>GetDiscLine(ny,numLines-1))
253 		return numLines-1;
254 	inside=true;
255 	if (dualMesh==false)
256 	{
257 		for (unsigned int n=0;n<numLines;++n)
258 		{
259 			if (coord<=GetDiscLine(ny,n,true))
260 				return n;
261 		}
262 	}
263 	else
264 	{
265 		for (unsigned int n=1;n<numLines;++n)
266 		{
267 			if (coord<=GetDiscLine(ny,n,false))
268 				return n-1;
269 		}
270 	}
271 	//should not happen
272 	return 0;
273 }
274 
SnapToMesh(const double * dcoord,unsigned int * uicoord,bool dualMesh,bool fullMesh,bool * inside) const275 bool Operator::SnapToMesh(const double* dcoord, unsigned int* uicoord, bool dualMesh, bool fullMesh, bool* inside) const
276 {
277 	bool meshInside=false;
278 	bool ok=true;
279 	for (int n=0; n<3; ++n)
280 	{
281 		uicoord[n] = SnapToMeshLine(n,dcoord[n],meshInside,dualMesh,fullMesh);
282 		ok &= meshInside;
283 		if (inside)
284 			inside[n]=meshInside;
285 	}
286 	return ok;
287 }
288 
SnapBox2Mesh(const double * start,const double * stop,unsigned int * uiStart,unsigned int * uiStop,bool dualMesh,bool fullMesh,int SnapMethod,bool * bStartIn,bool * bStopIn) const289 int Operator::SnapBox2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh, bool fullMesh, int SnapMethod, bool* bStartIn, bool* bStopIn) const
290 {
291 	double l_start[3], l_stop[3];
292 	for (int n=0;n<3;++n)
293 	{
294 		l_start[n] = fmin(start[n],stop[n]);
295 		l_stop[n] = fmax(start[n], stop[n]);
296 		double min = GetDiscLine(n,0);
297 		double max = GetDiscLine(n,GetNumberOfLines(n, fullMesh)-1);
298 		if ( ((l_start[n]<min) && (l_stop[n]<min)) || ((l_start[n]>max) && (l_stop[n]>max)) )
299 		{
300 			return -2;
301 		}
302 	}
303 
304 	SnapToMesh(l_start, uiStart, dualMesh, fullMesh, bStartIn);
305 	SnapToMesh(l_stop, uiStop, dualMesh, fullMesh, bStopIn);
306 	int iDim = 0;
307 
308 	if (SnapMethod==0)
309 	{
310 		for (int n=0;n<3;++n)
311 			if (uiStop[n]>uiStart[n])
312 				++iDim;
313 		return iDim;
314 	}
315 	else if (SnapMethod==1)
316 	{
317 		for (int n=0;n<3;++n)
318 		{
319 			if (uiStop[n]>uiStart[n])
320 			{
321 				if ((GetDiscLine( n, uiStart[n], dualMesh ) > l_start[n]) && (uiStart[n]>0))
322 					--uiStart[n];
323 				if ((GetDiscLine( n, uiStop[n], dualMesh ) < l_stop[n]) && (uiStop[n]<GetNumberOfLines(n, fullMesh)-1))
324 					++uiStop[n];
325 			}
326 			if (uiStop[n]>uiStart[n])
327 				++iDim;
328 		}
329 		return iDim;
330 	}
331 	else if (SnapMethod==2)
332 	{
333 		for (int n=0;n<3;++n)
334 		{
335 			if (uiStop[n]>uiStart[n])
336 			{
337 				if ((GetDiscLine( n, uiStart[n], dualMesh ) < l_start[n]) && (uiStart[n]<GetNumberOfLines(n, fullMesh)-1))
338 					++uiStart[n];
339 				if ((GetDiscLine( n, uiStop[n], dualMesh ) > l_stop[n]) && (uiStop[n]>0))
340 					--uiStop[n];
341 			}
342 			if (uiStop[n]>uiStart[n])
343 				++iDim;
344 		}
345 		return iDim;
346 	}
347 	else
348 		cerr << "Operator::SnapBox2Mesh: Unknown snapping method!" << endl;
349 	return -1;
350 }
351 
SnapLine2Mesh(const double * start,const double * stop,unsigned int * uiStart,unsigned int * uiStop,bool dualMesh,bool fullMesh) const352 int Operator::SnapLine2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh, bool fullMesh) const
353 {
354 	bool bStartIn[3];
355 	bool bStopIn[3];
356 	SnapToMesh(start, uiStart, dualMesh, fullMesh, bStartIn);
357 	SnapToMesh(stop, uiStop, dualMesh, fullMesh, bStopIn);
358 
359 	for (int n=0;n<3;++n)
360 	{
361 		if ((start[n]<GetDiscLine(n,0)) && (stop[n]<GetDiscLine(n,0)))
362 			return -1; //lower bound violation
363 		if ((start[n]>GetDiscLine(n,GetNumberOfLines(n,true)-1)) && (stop[n]>GetDiscLine(n,GetNumberOfLines(n,true)-1)))
364 			return -1; //upper bound violation
365 	}
366 
367 	int ret = 0;
368 	if (!(bStartIn[0] && bStartIn[1] && bStartIn[2]))
369 		ret = ret + 1;
370 	if (!(bStopIn[0] && bStopIn[1] && bStopIn[2]))
371 		ret = ret + 2;
372 	if (ret==0)
373 		return ret;
374 
375 	//fixme, do we need to do something about start or stop being outside the field domain?
376 	//maybe caclulate the intersection point and snap to that?
377 	//it seems to work like this as well...
378 
379 	return ret;
380 }
381 
382 
FindPath(double start[],double stop[])383 Grid_Path Operator::FindPath(double start[], double stop[])
384 {
385 	Grid_Path path;
386 	unsigned int uiStart[3],uiStop[3],currPos[3];
387 
388 	int ret = SnapLine2Mesh(start, stop, uiStart, uiStop, false, true);
389 	if (ret<0)
390 		return path;
391 
392 	currPos[0]=uiStart[0];
393 	currPos[1]=uiStart[1];
394 	currPos[2]=uiStart[2];
395 	double meshStart[3] = {discLines[0][uiStart[0]], discLines[1][uiStart[1]], discLines[2][uiStart[2]]};
396 	double meshStop[3] = {discLines[0][uiStop[0]], discLines[1][uiStop[1]], discLines[2][uiStop[2]]};
397 	bool UpDir = false;
398 	double foot=0,dist=0,minFoot=0,minDist=0;
399 	int minDir=0;
400 	unsigned int minPos[3];
401 	double startFoot,stopFoot,currFoot;
402 	Point_Line_Distance(meshStart,start,stop,startFoot,dist, m_MeshType);
403 	Point_Line_Distance(meshStop,start,stop,stopFoot,dist, m_MeshType);
404 	currFoot=startFoot;
405 	minFoot=startFoot;
406 	double P[3];
407 
408 	while (minFoot<stopFoot)
409 	{
410 		minDist=1e300;
411 		for (int n=0; n<3; ++n) //check all 6 surrounding points
412 		{
413 			P[0] = discLines[0][currPos[0]];
414 			P[1] = discLines[1][currPos[1]];
415 			P[2] = discLines[2][currPos[2]];
416 			if (((int)currPos[n]-1)>=0)
417 			{
418 				P[n] = discLines[n][currPos[n]-1];
419 				Point_Line_Distance(P,start,stop,foot,dist, m_MeshType);
420 				if ((foot>currFoot) && (dist<minDist))
421 				{
422 					minFoot=foot;
423 					minDist=dist;
424 					minDir = n;
425 					UpDir = false;
426 				}
427 			}
428 			if ((currPos[n]+1)<numLines[n])
429 			{
430 				P[n] = discLines[n][currPos[n]+1];
431 				Point_Line_Distance(P,start,stop,foot,dist, m_MeshType);
432 				if ((foot>currFoot) && (dist<minDist))
433 				{
434 					minFoot=foot;
435 					minDist=dist;
436 					minDir = n;
437 					UpDir = true;
438 				}
439 			}
440 		}
441 		minPos[0]=currPos[0];
442 		minPos[1]=currPos[1];
443 		minPos[2]=currPos[2];
444 		if (UpDir)
445 		{
446 			currPos[minDir]+=1;
447 		}
448 		else
449 		{
450 			currPos[minDir]+=-1;
451 			minPos[minDir]-=1;
452 		}
453 		//check validity of current postion
454 		for (int n=0;n<3;++n)
455 			if (currPos[n]>=numLines[n])
456 			{
457 				cerr << __func__ << ": Error, path went out of simulation domain, skipping path!" << endl;
458 				Grid_Path empty;
459 				return empty;
460 			}
461 		path.posPath[0].push_back(minPos[0]);
462 		path.posPath[1].push_back(minPos[1]);
463 		path.posPath[2].push_back(minPos[2]);
464 		currFoot=minFoot;
465 		path.dir.push_back(minDir);
466 	}
467 
468 	//close missing edges, if currPos is not equal to uiStopPos
469 	for (int n=0; n<3; ++n)
470 	{
471 		if (currPos[n]>uiStop[n])
472 		{
473 			--currPos[n];
474 			path.posPath[0].push_back(currPos[0]);
475 			path.posPath[1].push_back(currPos[1]);
476 			path.posPath[2].push_back(currPos[2]);
477 			path.dir.push_back(n);
478 		}
479 		else if (currPos[n]<uiStop[n])
480 		{
481 			path.posPath[0].push_back(currPos[0]);
482 			path.posPath[1].push_back(currPos[1]);
483 			path.posPath[2].push_back(currPos[2]);
484 			path.dir.push_back(n);
485 		}
486 	}
487 
488 	return path;
489 }
490 
SetMaterialAvgMethod(MatAverageMethods method)491 void Operator::SetMaterialAvgMethod(MatAverageMethods method)
492 {
493 	switch (method)
494 	{
495 	default:
496 	case QuarterCell:
497 		return SetQuarterCellMaterialAvg();
498 	case CentralCell:
499 		return SetCellConstantMaterial();
500 	}
501 }
502 
GetNumberCells() const503 double Operator::GetNumberCells() const
504 {
505 	if (numLines)
506 		return (numLines[0])*(numLines[1])*(numLines[2]); //it's more like number of nodes???
507 	return 0;
508 }
509 
ShowStat() const510 void Operator::ShowStat() const
511 {
512 	unsigned int OpSize = 12*numLines[0]*numLines[1]*numLines[2]*sizeof(FDTD_FLOAT);
513 	unsigned int FieldSize = 6*numLines[0]*numLines[1]*numLines[2]*sizeof(FDTD_FLOAT);
514 	double MBdiff = 1024*1024;
515 
516 	cout << "------- Stat: FDTD Operator -------" << endl;
517 	cout << "Dimensions\t\t: " << numLines[0] << "x" << numLines[1] << "x" << numLines[2] << " = " <<  numLines[0]*numLines[1]*numLines[2] << " Cells (" << numLines[0]*numLines[1]*numLines[2]/1e6 << " MCells)" << endl;
518 	cout << "Size of Operator\t: " << OpSize << " Byte (" << (double)OpSize/MBdiff << " MiB) " << endl;
519 	cout << "Size of Field-Data\t: " << FieldSize << " Byte (" << (double)FieldSize/MBdiff << " MiB) " << endl;
520 	cout << "-----------------------------------" << endl;
521 	cout << "Background materials (epsR/mueR/kappa/sigma): " << GetBackgroundEpsR() << "/" << GetBackgroundMueR() << "/" << GetBackgroundKappa() << "/" << GetBackgroundSigma() << endl;
522 	cout << "-----------------------------------" << endl;
523 	cout << "Number of PEC edges\t: " << m_Nr_PEC[0]+m_Nr_PEC[1]+m_Nr_PEC[2] << endl;
524 	cout << "in " << GetDirName(0) << " direction\t\t: " << m_Nr_PEC[0] << endl;
525 	cout << "in " << GetDirName(1) << " direction\t\t: " << m_Nr_PEC[1] << endl;
526 	cout << "in " << GetDirName(2) << " direction\t\t: " << m_Nr_PEC[2] << endl;
527 	cout << "-----------------------------------" << endl;
528 	cout << "Timestep (s)\t\t: " << dT ;
529 	if (opt_dT)
530 		cout <<"\t(" << opt_dT << ")";
531 	cout << endl;
532 	cout << "Timestep method name\t: " << m_Used_TS_Name << endl;
533 	cout << "Nyquist criteria (TS)\t: " << m_Exc->GetNyquistNum() << endl;
534 	cout << "Nyquist criteria (s)\t: " << m_Exc->GetNyquistNum()*dT << endl;
535 	cout << "-----------------------------------" << endl;
536 }
537 
ShowExtStat() const538 void Operator::ShowExtStat() const
539 {
540 	if (m_Op_exts.size()==0) return;
541 	cout << "-----------------------------------" << endl;
542 	for (size_t n=0; n<m_Op_exts.size(); ++n)
543 		m_Op_exts.at(n)->ShowStat(cout);
544 	cout << "-----------------------------------" << endl;
545 }
546 
DumpOperator2File(string filename)547 void Operator::DumpOperator2File(string filename)
548 {
549 #ifdef OUTPUT_IN_DRAWINGUNITS
550 	double discLines_scaling = 1;
551 #else
552 	double discLines_scaling = GetGridDelta();
553 #endif
554 
555 	cout << "Operator: Dumping FDTD operator information to vtk file: " << filename << " ..." << flush;
556 
557 	VTK_File_Writer* vtk_Writer = new VTK_File_Writer(filename.c_str(), m_MeshType);
558 	vtk_Writer->SetMeshLines(discLines,numLines,discLines_scaling);
559 	vtk_Writer->SetHeader("openEMS - Operator dump");
560 
561 	vtk_Writer->SetNativeDump(true);
562 
563 	//find excitation extension
564 	Operator_Ext_Excitation* Op_Ext_Exc=GetExcitationExtension();
565 
566 	if (Op_Ext_Exc)
567 	{
568 		FDTD_FLOAT**** exc = NULL;
569 		if (Op_Ext_Exc->Volt_Count>0)
570 		{
571 			exc = Create_N_3DArray<FDTD_FLOAT>(numLines);
572 			for (unsigned int n=0; n<  Op_Ext_Exc->Volt_Count; ++n)
573 				exc[  Op_Ext_Exc->Volt_dir[n]][  Op_Ext_Exc->Volt_index[0][n]][  Op_Ext_Exc->Volt_index[1][n]][  Op_Ext_Exc->Volt_index[2][n]] =   Op_Ext_Exc->Volt_amp[n];
574 			vtk_Writer->AddVectorField("exc_volt",exc);
575 			Delete_N_3DArray(exc,numLines);
576 		}
577 
578 		if (  Op_Ext_Exc->Curr_Count>0)
579 		{
580 			exc = Create_N_3DArray<FDTD_FLOAT>(numLines);
581 			for (unsigned int n=0; n<  Op_Ext_Exc->Curr_Count; ++n)
582 				exc[  Op_Ext_Exc->Curr_dir[n]][  Op_Ext_Exc->Curr_index[0][n]][  Op_Ext_Exc->Curr_index[1][n]][  Op_Ext_Exc->Curr_index[2][n]] =   Op_Ext_Exc->Curr_amp[n];
583 			vtk_Writer->AddVectorField("exc_curr",exc);
584 			Delete_N_3DArray(exc,numLines);
585 		}
586 	}
587 
588 	FDTD_FLOAT**** vv_temp = Create_N_3DArray<FDTD_FLOAT>(numLines);
589 	FDTD_FLOAT**** vi_temp = Create_N_3DArray<FDTD_FLOAT>(numLines);
590 	FDTD_FLOAT**** iv_temp = Create_N_3DArray<FDTD_FLOAT>(numLines);
591 	FDTD_FLOAT**** ii_temp = Create_N_3DArray<FDTD_FLOAT>(numLines);
592 
593 	unsigned int pos[3], n;
594 	for (n=0; n<3; n++)
595 		for (pos[0]=0; pos[0]<numLines[0]; pos[0]++)
596 			for (pos[1]=0; pos[1]<numLines[1]; pos[1]++)
597 				for (pos[2]=0; pos[2]<numLines[2]; pos[2]++)
598 				{
599 					vv_temp[n][pos[0]][pos[1]][pos[2]] = GetVV(n,pos);
600 					vi_temp[n][pos[0]][pos[1]][pos[2]] = GetVI(n,pos);
601 					iv_temp[n][pos[0]][pos[1]][pos[2]] = GetIV(n,pos);
602 					ii_temp[n][pos[0]][pos[1]][pos[2]] = GetII(n,pos);
603 				}
604 
605 
606 	vtk_Writer->AddVectorField("vv",vv_temp);
607 	Delete_N_3DArray(vv_temp,numLines);
608 	vtk_Writer->AddVectorField("vi",vi_temp);
609 	Delete_N_3DArray(vi_temp,numLines);
610 	vtk_Writer->AddVectorField("iv",iv_temp);
611 	Delete_N_3DArray(iv_temp,numLines);
612 	vtk_Writer->AddVectorField("ii",ii_temp);
613 	Delete_N_3DArray(ii_temp,numLines);
614 
615 	if (vtk_Writer->Write()==false)
616 		cerr << "Operator::DumpOperator2File: Error: Can't write file... skipping!" << endl;
617 
618 	delete vtk_Writer;
619 }
620 
621 //! \brief dump PEC (perfect electric conductor) information (into VTK-file)
622 //! visualization via paraview
623 //! visualize only one component (x, y or z)
DumpPEC2File(string filename,unsigned int * range)624 void Operator::DumpPEC2File(string filename , unsigned int *range)
625 {
626 	cout << "Operator: Dumping PEC information to vtk file: " << filename << " ..." << flush;
627 
628 #ifdef OUTPUT_IN_DRAWINGUNITS
629 	double scaling = 1.0;
630 #else
631 	double scaling = GetGridDelta();;
632 #endif
633 
634 	unsigned int start[3] = {0, 0, 0};
635 	unsigned int stop[3] = {numLines[0]-1,numLines[1]-1,numLines[2]-1};
636 
637 	if (range!=NULL)
638 		for (int n=0;n<3;++n)
639 		{
640 			start[n] = range[2*n];
641 			stop[n] = range[2*n+1];
642 		}
643 
644 	vtkPolyData* polydata = vtkPolyData::New();
645 	vtkCellArray *poly = vtkCellArray::New();
646 	vtkPoints *points = vtkPoints::New();
647 
648 	int* pointIdx[2];
649 	pointIdx[0] = new int[numLines[0]*numLines[1]];
650 	pointIdx[1] = new int[numLines[0]*numLines[1]];
651 	// init point idx
652 	for (unsigned int n=0;n<numLines[0]*numLines[1];++n)
653 	{
654 		pointIdx[0][n]=-1;
655 		pointIdx[1][n]=-1;
656 	}
657 
658 	int nP,nPP;
659 	double coord[3];
660 	unsigned int pos[3],rpos[3];
661 	unsigned int mesh_idx=0;
662 	for (pos[2]=start[2];pos[2]<stop[2];++pos[2])
663 	{ // each xy-plane
664 		for (unsigned int n=0;n<numLines[0]*numLines[1];++n)
665 		{
666 			pointIdx[0][n]=pointIdx[1][n];
667 			pointIdx[1][n]=-1;
668 		}
669 		for (pos[0]=start[0];pos[0]<stop[0];++pos[0])
670 			for (pos[1]=start[1];pos[1]<stop[1];++pos[1])
671 			{
672 				for (int n=0;n<3;++n)
673 				{
674 					nP = (n+1)%3;
675 					nPP = (n+2)%3;
676 					if ((GetVV(n,pos) == 0) && (GetVI(n,pos) == 0) && (pos[nP]>0) && (pos[nPP]>0))
677 					{
678 						rpos[0]=pos[0];
679 						rpos[1]=pos[1];
680 						rpos[2]=pos[2];
681 
682 						poly->InsertNextCell(2);
683 
684 						mesh_idx = rpos[0] + rpos[1]*numLines[0];
685 						if (pointIdx[0][mesh_idx]<0)
686 						{
687 							for (int m=0;m<3;++m)
688 								coord[m] = discLines[m][rpos[m]];
689 							TransformCoordSystem(coord, coord, m_MeshType, CARTESIAN);
690 							for (int m=0;m<3;++m)
691 								coord[m] *= scaling;
692 							pointIdx[0][mesh_idx] = (int)points->InsertNextPoint(coord);
693 						}
694 						poly->InsertCellPoint(pointIdx[0][mesh_idx]);
695 
696 						++rpos[n];
697 						mesh_idx = rpos[0] + rpos[1]*numLines[0];
698 						if (pointIdx[n==2][mesh_idx]<0)
699 						{
700 							for (int m=0;m<3;++m)
701 								coord[m] = discLines[m][rpos[m]];
702 							TransformCoordSystem(coord, coord, m_MeshType, CARTESIAN);
703 							for (int m=0;m<3;++m)
704 								coord[m] *= scaling;
705 							pointIdx[n==2][mesh_idx] = (int)points->InsertNextPoint(coord);
706 						}
707 						poly->InsertCellPoint(pointIdx[n==2][mesh_idx]);
708 					}
709 				}
710 			}
711 	}
712 	delete[] pointIdx[0];
713 	delete[] pointIdx[1];
714 
715 	polydata->SetPoints(points);
716 	points->Delete();
717 	polydata->SetLines(poly);
718 	poly->Delete();
719 
720 	vtkXMLPolyDataWriter* writer  = vtkXMLPolyDataWriter::New();
721 	filename += ".vtp";
722 	writer->SetFileName(filename.c_str());
723 
724 #if VTK_MAJOR_VERSION>=6
725 	writer->SetInputData(polydata);
726 #else
727 	writer->SetInput(polydata);
728 #endif
729 	writer->Write();
730 
731 	writer->Delete();
732 	polydata->Delete();
733 	cout << " done." << endl;
734 }
735 
DumpMaterial2File(string filename)736 void Operator::DumpMaterial2File(string filename)
737 {
738 #ifdef OUTPUT_IN_DRAWINGUNITS
739 	double discLines_scaling = 1;
740 #else
741 	double discLines_scaling = GetGridDelta();
742 #endif
743 
744 	cout << "Operator: Dumping material information to vtk file: " << filename << " ..."  << flush;
745 
746 	FDTD_FLOAT**** epsilon = Create_N_3DArray<FDTD_FLOAT>(numLines);
747 	FDTD_FLOAT**** mue     = Create_N_3DArray<FDTD_FLOAT>(numLines);
748 	FDTD_FLOAT**** kappa   = Create_N_3DArray<FDTD_FLOAT>(numLines);
749 	FDTD_FLOAT**** sigma   = Create_N_3DArray<FDTD_FLOAT>(numLines);
750 
751 	unsigned int pos[3];
752 	for (pos[0]=0; pos[0]<numLines[0]; ++pos[0])
753 	{
754 		for (pos[1]=0; pos[1]<numLines[1]; ++pos[1])
755 		{
756 			vector<CSPrimitives*> vPrims = this->GetPrimitivesBoundBox(pos[0], pos[1], -1, CSProperties::MATERIAL);
757 			for (pos[2]=0; pos[2]<numLines[2]; ++pos[2])
758 			{
759 				for (int n=0; n<3; ++n)
760 				{
761 					double inMat[4];
762 					Calc_EffMatPos(n, pos, inMat, vPrims);
763 					epsilon[n][pos[0]][pos[1]][pos[2]] = inMat[0]/__EPS0__;
764 					mue[n][pos[0]][pos[1]][pos[2]]     = inMat[2]/__MUE0__;
765 					kappa[n][pos[0]][pos[1]][pos[2]]   = inMat[1];
766 					sigma[n][pos[0]][pos[1]][pos[2]]   = inMat[3];
767 				}
768 			}
769 		}
770 	}
771 
772 	VTK_File_Writer* vtk_Writer = new VTK_File_Writer(filename.c_str(), m_MeshType);
773 	vtk_Writer->SetMeshLines(discLines,numLines,discLines_scaling);
774 	vtk_Writer->SetHeader("openEMS - material dump");
775 
776 	vtk_Writer->SetNativeDump(true);
777 
778 	vtk_Writer->AddVectorField("epsilon",epsilon);
779 	Delete_N_3DArray(epsilon,numLines);
780 	vtk_Writer->AddVectorField("mue",mue);
781 	Delete_N_3DArray(mue,numLines);
782 	vtk_Writer->AddVectorField("kappa",kappa);
783 	Delete_N_3DArray(kappa,numLines);
784 	vtk_Writer->AddVectorField("sigma",sigma);
785 	Delete_N_3DArray(sigma,numLines);
786 
787 	if (vtk_Writer->Write()==false)
788 		cerr << "Operator::DumpMaterial2File: Error: Can't write file... skipping!" << endl;
789 
790 	delete vtk_Writer;
791 }
792 
SetupCSXGrid(CSRectGrid * grid)793  bool Operator::SetupCSXGrid(CSRectGrid* grid)
794  {
795 	 for (int n=0; n<3; ++n)
796 	 {
797 		 discLines[n] = grid->GetLines(n,discLines[n],numLines[n],true);
798 		 if (numLines[n]<3)
799 		 {
800 			 cerr << "CartOperator::SetupCSXGrid: you need at least 3 disc-lines in every direction (3D!)!!!" << endl;
801 			 Reset();
802 			 return false;
803 		 }
804 	 }
805 	 MainOp = new AdrOp(numLines[0],numLines[1],numLines[2]);
806 	 MainOp->SetGrid(discLines[0],discLines[1],discLines[2]);
807 	 if (grid->GetDeltaUnit()<=0)
808 	 {
809 		 cerr << "CartOperator::SetupCSXGrid: grid delta unit must not be <=0 !!!" << endl;
810 		 Reset();
811 		 return false;
812 	 }
813 	 else gridDelta=grid->GetDeltaUnit();
814 	 MainOp->SetGridDelta(1);
815 	 MainOp->AddCellAdrOp();
816 
817 	 //delete the grid clone...
818 	 delete grid;
819 	 return true;
820  }
821 
SetGeometryCSX(ContinuousStructure * geo)822 bool Operator::SetGeometryCSX(ContinuousStructure* geo)
823 {
824 	if (geo==NULL) return false;
825 
826 	CSX = geo;
827 
828 	CSBackgroundMaterial* bg_mat=CSX->GetBackgroundMaterial();
829 	SetBackgroundEpsR(bg_mat->GetEpsilon());
830 	SetBackgroundMueR(bg_mat->GetMue());
831 	SetBackgroundKappa(bg_mat->GetKappa());
832 	SetBackgroundSigma(bg_mat->GetSigma());
833 	SetBackgroundDensity(0);
834 
835 	CSRectGrid* grid=CSX->GetGrid();
836 	return SetupCSXGrid(CSRectGrid::Clone(grid));
837 }
838 
InitOperator()839 void Operator::InitOperator()
840 {
841 	Delete_N_3DArray(vv,numLines);
842 	Delete_N_3DArray(vi,numLines);
843 	Delete_N_3DArray(iv,numLines);
844 	Delete_N_3DArray(ii,numLines);
845 	vv = Create_N_3DArray<FDTD_FLOAT>(numLines);
846 	vi = Create_N_3DArray<FDTD_FLOAT>(numLines);
847 	iv = Create_N_3DArray<FDTD_FLOAT>(numLines);
848 	ii = Create_N_3DArray<FDTD_FLOAT>(numLines);
849 }
850 
InitDataStorage()851 void Operator::InitDataStorage()
852 {
853 	if (m_StoreMaterial[0])
854 	{
855 		if (g_settings.GetVerboseLevel()>0)
856 			cerr << "Operator::InitDataStorage(): Storing epsR material data..." << endl;
857 		Delete_N_3DArray(m_epsR,numLines);
858 		m_epsR = Create_N_3DArray<float>(numLines);
859 	}
860 	if (m_StoreMaterial[1])
861 	{
862 		if (g_settings.GetVerboseLevel()>0)
863 			cerr << "Operator::InitDataStorage(): Storing kappa material data..." << endl;
864 		Delete_N_3DArray(m_kappa,numLines);
865 		m_kappa = Create_N_3DArray<float>(numLines);
866 	}
867 	if (m_StoreMaterial[2])
868 	{
869 		if (g_settings.GetVerboseLevel()>0)
870 			cerr << "Operator::InitDataStorage(): Storing muR material data..." << endl;
871 		Delete_N_3DArray(m_mueR,numLines);
872 		m_mueR = Create_N_3DArray<float>(numLines);
873 	}
874 	if (m_StoreMaterial[3])
875 	{
876 		if (g_settings.GetVerboseLevel()>0)
877 			cerr << "Operator::InitDataStorage(): Storing sigma material data..." << endl;
878 		Delete_N_3DArray(m_sigma,numLines);
879 		m_sigma = Create_N_3DArray<float>(numLines);
880 	}
881 }
882 
CleanupMaterialStorage()883 void Operator::CleanupMaterialStorage()
884 {
885 	if (!m_StoreMaterial[0] && m_epsR)
886 	{
887 		if (g_settings.GetVerboseLevel()>0)
888 			cerr << "Operator::CleanupMaterialStorage(): Delete epsR material data..." << endl;
889 		Delete_N_3DArray(m_epsR,numLines);
890 		m_epsR = NULL;
891 	}
892 	if (!m_StoreMaterial[1] && m_kappa)
893 	{
894 		if (g_settings.GetVerboseLevel()>0)
895 			cerr << "Operator::CleanupMaterialStorage(): Delete kappa material data..." << endl;
896 		Delete_N_3DArray(m_kappa,numLines);
897 		m_kappa = NULL;
898 	}
899 	if (!m_StoreMaterial[2] && m_mueR)
900 	{
901 		if (g_settings.GetVerboseLevel()>0)
902 			cerr << "Operator::CleanupMaterialStorage(): Delete mueR material data..." << endl;
903 		Delete_N_3DArray(m_mueR,numLines);
904 		m_mueR = NULL;
905 	}
906 	if (!m_StoreMaterial[3] && m_sigma)
907 	{
908 		if (g_settings.GetVerboseLevel()>0)
909 			cerr << "Operator::CleanupMaterialStorage(): Delete sigma material data..." << endl;
910 		Delete_N_3DArray(m_sigma,numLines);
911 		m_sigma = NULL;
912 	}
913 }
914 
GetDiscMaterial(int type,int n,const unsigned int pos[3]) const915 double Operator::GetDiscMaterial(int type, int n, const unsigned int pos[3]) const
916 {
917 	switch (type)
918 	{
919 	case 0:
920 		if (m_epsR==0)
921 			return 0;
922 		return m_epsR[n][pos[0]][pos[1]][pos[2]];
923 	case 1:
924 		if (m_kappa==0)
925 			return 0;
926 		return m_kappa[n][pos[0]][pos[1]][pos[2]];
927 	case 2:
928 		if (m_mueR==0)
929 			return 0;
930 		return m_mueR[n][pos[0]][pos[1]][pos[2]];
931 	case 3:
932 		if (m_sigma==0)
933 			return 0;
934 		return m_sigma[n][pos[0]][pos[1]][pos[2]];
935 	}
936 	return 0;
937 }
938 
SetExcitationSignal(Excitation * exc)939 void Operator::SetExcitationSignal(Excitation* exc)
940 {
941 	m_Exc=exc;
942 }
943 
Calc_ECOperatorPos(int n,unsigned int * pos)944 void Operator::Calc_ECOperatorPos(int n, unsigned int* pos)
945 {
946 	unsigned int i = MainOp->SetPos(pos[0],pos[1],pos[2]);
947 	double C = EC_C[n][i];
948 	double G = EC_G[n][i];
949 	if (C>0)
950 	{
951 		SetVV(n,pos[0],pos[1],pos[2], (1.0-dT*G/2.0/C)/(1.0+dT*G/2.0/C) );
952 		SetVI(n,pos[0],pos[1],pos[2], (dT/C)/(1.0+dT*G/2.0/C) );
953 	}
954 	else
955 	{
956 		SetVV(n,pos[0],pos[1],pos[2], 0 );
957 		SetVI(n,pos[0],pos[1],pos[2], 0 );
958 	}
959 
960 	double L = EC_L[n][i];
961 	double R = EC_R[n][i];
962 	if (L>0)
963 	{
964 		SetII(n,pos[0],pos[1],pos[2], (1.0-dT*R/2.0/L)/(1.0+dT*R/2.0/L) );
965 		SetIV(n,pos[0],pos[1],pos[2], (dT/L)/(1.0+dT*R/2.0/L) );
966 	}
967 	else
968 	{
969 		SetII(n,pos[0],pos[1],pos[2], 0 );
970 		SetIV(n,pos[0],pos[1],pos[2], 0 );
971 	}
972 }
973 
CalcECOperator(DebugFlags debugFlags)974 int Operator::CalcECOperator( DebugFlags debugFlags )
975 {
976 	Init_EC();
977 	InitDataStorage();
978 
979 	if (Calc_EC()==0)
980 		return -1;
981 
982 	m_InvaildTimestep = false;
983 	opt_dT = 0;
984 	if (dT>0)
985 	{
986 		double save_dT = dT;
987 		CalcTimestep();
988 		opt_dT = dT;
989 		if (dT<save_dT)
990 		{
991 			cerr << "Operator::CalcECOperator: Warning, forced timestep: " << save_dT << "s is larger than calculated timestep: " << dT << "s! It is not recommended using this timestep!! " << endl;
992 			m_InvaildTimestep = true;
993 		}
994 
995 		dT = save_dT;
996 	}
997 	else
998 		CalcTimestep();
999 
1000 	dT*=m_TimeStepFactor;
1001 
1002 	if (m_Exc->GetSignalPeriod()>0)
1003 	{
1004 		unsigned int TS = ceil(m_Exc->GetSignalPeriod()/dT);
1005 		double new_dT = m_Exc->GetSignalPeriod()/TS;
1006 		cout << "Operartor::CalcECOperator: Decreasing timestep by " << round((dT-new_dT)/dT*1000)/10.0 << "% to " << new_dT << " (" << dT << ") to match periodic signal" << endl;
1007 		dT = new_dT;
1008 	}
1009 
1010 	m_Exc->Reset(dT);
1011 
1012 	InitOperator();
1013 
1014 	unsigned int pos[3];
1015 
1016 	for (int n=0; n<3; ++n)
1017 	{
1018 		for (pos[0]=0; pos[0]<numLines[0]; ++pos[0])
1019 		{
1020 			for (pos[1]=0; pos[1]<numLines[1]; ++pos[1])
1021 			{
1022 				for (pos[2]=0; pos[2]<numLines[2]; ++pos[2])
1023 				{
1024 					Calc_ECOperatorPos(n,pos);
1025 				}
1026 			}
1027 		}
1028 	}
1029 
1030 	//Apply PEC to all boundary's
1031 	bool PEC[6]={1,1,1,1,1,1};
1032 	//make an exception for BC == -1
1033 	for (int n=0; n<6; ++n)
1034 		if ((m_BC[n]==-1))
1035 			PEC[n] = false;
1036 	ApplyElectricBC(PEC);
1037 
1038 	CalcPEC();
1039 
1040 	Calc_LumpedElements();
1041 
1042 	bool PMC[6];
1043 	for (int n=0; n<6; ++n)
1044 		PMC[n] = m_BC[n]==1;
1045 	ApplyMagneticBC(PMC);
1046 
1047 	//all information available for extension... create now...
1048 	for (size_t n=0; n<m_Op_exts.size(); ++n)
1049 		m_Op_exts.at(n)->BuildExtension();
1050 
1051 	//remove inactive extensions
1052 	vector<Operator_Extension*>::iterator it = m_Op_exts.begin();
1053 	while (it!=m_Op_exts.end())
1054 	{
1055 		if ( (*it)->IsActive() == false)
1056 		{
1057 			DeleteExtension((*it));
1058 			it = m_Op_exts.begin(); //restart search for inactive extension
1059 		}
1060 		else
1061 			++it;
1062 	}
1063 
1064 	if (debugFlags & debugMaterial)
1065 		DumpMaterial2File( "material_dump" );
1066 	if (debugFlags & debugOperator)
1067 		DumpOperator2File( "operator_dump" );
1068 	if (debugFlags & debugPEC)
1069 		DumpPEC2File( "PEC_dump" );
1070 
1071 	//cleanup
1072 	for (int n=0; n<3; ++n)
1073 	{
1074 		delete[] EC_C[n];
1075 		EC_C[n]=NULL;
1076 		delete[] EC_G[n];
1077 		EC_G[n]=NULL;
1078 		delete[] EC_L[n];
1079 		EC_L[n]=NULL;
1080 		delete[] EC_R[n];
1081 		EC_R[n]=NULL;
1082 	}
1083 
1084 	return 0;
1085 }
1086 
ApplyElectricBC(bool * dirs)1087 void Operator::ApplyElectricBC(bool* dirs)
1088 {
1089 	if (!dirs)
1090 		return;
1091 
1092 	unsigned int pos[3];
1093 	for (int n=0; n<3; ++n)
1094 	{
1095 		int nP = (n+1)%3;
1096 		int nPP = (n+2)%3;
1097 		for (pos[nP]=0; pos[nP]<numLines[nP]; ++pos[nP])
1098 		{
1099 			for (pos[nPP]=0; pos[nPP]<numLines[nPP]; ++pos[nPP])
1100 			{
1101 				if (dirs[2*n])
1102 				{
1103 					// set to PEC
1104 					pos[n] = 0;
1105 					SetVV(nP, pos[0],pos[1],pos[2], 0 );
1106 					SetVI(nP, pos[0],pos[1],pos[2], 0 );
1107 					SetVV(nPP,pos[0],pos[1],pos[2], 0 );
1108 					SetVI(nPP,pos[0],pos[1],pos[2], 0 );
1109 				}
1110 
1111 				if (dirs[2*n+1])
1112 				{
1113 					// set to PEC
1114 					pos[n] = numLines[n]-1;
1115 					SetVV(n,  pos[0],pos[1],pos[2], 0 ); // these are outside the FDTD-domain as defined by the main disc
1116 					SetVI(n,  pos[0],pos[1],pos[2], 0 ); // these are outside the FDTD-domain as defined by the main disc
1117 
1118 					SetVV(nP, pos[0],pos[1],pos[2], 0 );
1119 					SetVI(nP, pos[0],pos[1],pos[2], 0 );
1120 					SetVV(nPP,pos[0],pos[1],pos[2], 0 );
1121 					SetVI(nPP,pos[0],pos[1],pos[2], 0 );
1122 				}
1123 			}
1124 		}
1125 	}
1126 }
1127 
ApplyMagneticBC(bool * dirs)1128 void Operator::ApplyMagneticBC(bool* dirs)
1129 {
1130 	if (!dirs)
1131 		return;
1132 
1133 	unsigned int pos[3];
1134 	for (int n=0; n<3; ++n)
1135 	{
1136 		int nP = (n+1)%3;
1137 		int nPP = (n+2)%3;
1138 		for (pos[nP]=0; pos[nP]<numLines[nP]; ++pos[nP])
1139 		{
1140 			for (pos[nPP]=0; pos[nPP]<numLines[nPP]; ++pos[nPP])
1141 			{
1142 				if (dirs[2*n])
1143 				{
1144 					// set to PMC
1145 					pos[n] = 0;
1146 					SetII(n,  pos[0],pos[1],pos[2], 0 );
1147 					SetIV(n,  pos[0],pos[1],pos[2], 0 );
1148 					SetII(nP, pos[0],pos[1],pos[2], 0 );
1149 					SetIV(nP, pos[0],pos[1],pos[2], 0 );
1150 					SetII(nPP,pos[0],pos[1],pos[2], 0 );
1151 					SetIV(nPP,pos[0],pos[1],pos[2], 0 );
1152 				}
1153 
1154 				if (dirs[2*n+1])
1155 				{
1156 					// set to PMC
1157 					pos[n] = numLines[n]-2;
1158 					SetII(nP, pos[0],pos[1],pos[2], 0 );
1159 					SetIV(nP, pos[0],pos[1],pos[2], 0 );
1160 					SetII(nPP,pos[0],pos[1],pos[2], 0 );
1161 					SetIV(nPP,pos[0],pos[1],pos[2], 0 );
1162 				}
1163 
1164 				// the last current lines are outside the FDTD domain and cannot be iterated by the FDTD engine
1165 				pos[n] = numLines[n]-1;
1166 				SetII(n,  pos[0],pos[1],pos[2], 0 );
1167 				SetIV(n,  pos[0],pos[1],pos[2], 0 );
1168 				SetII(nP, pos[0],pos[1],pos[2], 0 );
1169 				SetIV(nP, pos[0],pos[1],pos[2], 0 );
1170 				SetII(nPP,pos[0],pos[1],pos[2], 0 );
1171 				SetIV(nPP,pos[0],pos[1],pos[2], 0 );
1172 			}
1173 		}
1174 	}
1175 }
1176 
Calc_ECPos(int ny,const unsigned int * pos,double * EC,vector<CSPrimitives * > vPrims) const1177 bool Operator::Calc_ECPos(int ny, const unsigned int* pos, double* EC, vector<CSPrimitives*> vPrims) const
1178 {
1179 	double EffMat[4];
1180 	Calc_EffMatPos(ny,pos,EffMat, vPrims);
1181 
1182 	if (m_epsR)
1183 		m_epsR[ny][pos[0]][pos[1]][pos[2]] =  EffMat[0];
1184 	if (m_kappa)
1185 		m_kappa[ny][pos[0]][pos[1]][pos[2]] =  EffMat[1];
1186 	if (m_mueR)
1187 		m_mueR[ny][pos[0]][pos[1]][pos[2]] =  EffMat[2];
1188 	if (m_sigma)
1189 		m_sigma[ny][pos[0]][pos[1]][pos[2]] =  EffMat[3];
1190 
1191 	double delta = GetEdgeLength(ny,pos);
1192 	double area  = GetEdgeArea(ny,pos);
1193 
1194 //	if (isnan(EffMat[0]))
1195 //	{
1196 //		cerr << ny << " " << pos[0] << " " << pos[1] << " " << pos[2] << " : " << EffMat[0] << endl;
1197 //	}
1198 
1199 	if (delta)
1200 	{
1201 		EC[0] = EffMat[0] * area/delta;
1202 		EC[1] = EffMat[1] * area/delta;
1203 	}
1204 	else
1205 	{
1206 		EC[0] = 0;
1207 		EC[1] = 0;
1208 	}
1209 
1210 	delta = GetEdgeLength(ny,pos,true);
1211 	area  = GetEdgeArea(ny,pos,true);
1212 
1213 	if (delta)
1214 	{
1215 		EC[2] = EffMat[2] * area/delta;
1216 		EC[3] = EffMat[3] * area/delta;
1217 	}
1218 	else
1219 	{
1220 		EC[2] = 0;
1221 		EC[3] = 0;
1222 	}
1223 
1224 	return true;
1225 }
1226 
GetRawDiscDelta(int ny,const int pos) const1227 double Operator::GetRawDiscDelta(int ny, const int pos) const
1228 {
1229 	//numLines[ny] is expected to be larger then 1 !
1230 
1231 	if (pos<0)
1232 		return (discLines[ny][0] - discLines[ny][1]);
1233 	if (pos>=(int)numLines[ny]-1)
1234 		return (discLines[ny][numLines[ny]-2] - discLines[ny][numLines[ny]-1]);
1235 
1236 	return (discLines[ny][pos+1] - discLines[ny][pos]);
1237 }
1238 
GetCellCenterMaterialAvgCoord(const int pos[],double coord[3]) const1239 bool Operator::GetCellCenterMaterialAvgCoord(const int pos[], double coord[3]) const
1240 {
1241 	unsigned int ui_pos[3];
1242 	for (int n=0;n<3;++n)
1243 	{
1244 		if ((pos[n]<0) || (pos[n]>=(int)numLines[n]))
1245 			return false;
1246 		ui_pos[n] = pos[n];
1247 	}
1248 	GetNodeCoords(ui_pos, coord, true);
1249 	return true;
1250 }
1251 
GetMaterial(int ny,const double * coords,int MatType,vector<CSPrimitives * > vPrims,bool markAsUsed) const1252 double Operator::GetMaterial(int ny, const double* coords, int MatType, vector<CSPrimitives*> vPrims, bool markAsUsed) const
1253 {
1254 	CSProperties* prop = CSX->GetPropertyByCoordPriority(coords,vPrims,markAsUsed);
1255 //	CSProperties* old_prop = CSX->GetPropertyByCoordPriority(coords,CSProperties::MATERIAL,markAsUsed);
1256 //	if (old_prop!=prop)
1257 //	{
1258 //		cerr << "ERROR: Unequal properties!" << endl;
1259 //		exit(-1);
1260 //	}
1261 
1262 	CSPropMaterial* mat = dynamic_cast<CSPropMaterial*>(prop);
1263 	if (mat)
1264 	{
1265 		switch (MatType)
1266 		{
1267 		case 0:
1268 			return mat->GetEpsilonWeighted(ny,coords);
1269 		case 1:
1270 			return mat->GetKappaWeighted(ny,coords);
1271 		case 2:
1272 			return mat->GetMueWeighted(ny,coords);
1273 		case 3:
1274 			return mat->GetSigmaWeighted(ny,coords);
1275 		case 4:
1276 			return mat->GetDensityWeighted(coords);
1277 		default:
1278 			cerr << "Operator::GetMaterial: Error: unknown material type" << endl;
1279 			return 0;
1280 		}
1281 	}
1282 
1283 	switch (MatType)
1284 	{
1285 	case 0:
1286 		return GetBackgroundEpsR();
1287 	case 1:
1288 		return GetBackgroundKappa();
1289 	case 2:
1290 		return GetBackgroundMueR();
1291 	case 3:
1292 		return GetBackgroundSigma();
1293 	case 4:
1294 		return GetBackgroundDensity();
1295 	default:
1296 		cerr << "Operator::GetMaterial: Error: unknown material type" << endl;
1297 		return 0;
1298 	}
1299 }
1300 
AverageMatCellCenter(int ny,const unsigned int * pos,double * EffMat,vector<CSPrimitives * > vPrims) const1301 bool Operator::AverageMatCellCenter(int ny, const unsigned int* pos, double* EffMat, vector<CSPrimitives *> vPrims) const
1302 {
1303 	int n=ny;
1304 	double coord[3];
1305 	int nP = (n+1)%3;
1306 	int nPP = (n+2)%3;
1307 
1308 	int loc_pos[3] = {(int)pos[0],(int)pos[1],(int)pos[2]};
1309 	double A_n;
1310 	double area = 0;
1311 	EffMat[0] = 0;
1312 	EffMat[1] = 0;
1313 	EffMat[2] = 0;
1314 	EffMat[3] = 0;
1315 
1316 	//******************************* epsilon,kappa averaging *****************************//
1317 	//shift up-right
1318 	if (GetCellCenterMaterialAvgCoord(loc_pos,coord))
1319 	{
1320 		A_n = GetNodeArea(ny,loc_pos,true);
1321 		EffMat[0] += GetMaterial(n, coord, 0, vPrims)*A_n;
1322 		EffMat[1] += GetMaterial(n, coord, 1, vPrims)*A_n;
1323 		area+=A_n;
1324 	}
1325 
1326 	//shift up-left
1327 	--loc_pos[nP];
1328 	if (GetCellCenterMaterialAvgCoord(loc_pos,coord))
1329 	{
1330 		A_n = GetNodeArea(ny,loc_pos,true);
1331 		EffMat[0] += GetMaterial(n, coord, 0, vPrims)*A_n;
1332 		EffMat[1] += GetMaterial(n, coord, 1, vPrims)*A_n;
1333 		area+=A_n;
1334 	}
1335 
1336 	//shift down-right
1337 	++loc_pos[nP];
1338 	--loc_pos[nPP];
1339 	if (GetCellCenterMaterialAvgCoord(loc_pos,coord))
1340 	{
1341 		A_n = GetNodeArea(ny,loc_pos,true);
1342 		EffMat[0] += GetMaterial(n, coord, 0, vPrims)*A_n;
1343 		EffMat[1] += GetMaterial(n, coord, 1, vPrims)*A_n;
1344 		area+=A_n;
1345 	}
1346 
1347 	//shift down-left
1348 	--loc_pos[nP];
1349 	if (GetCellCenterMaterialAvgCoord(loc_pos,coord))
1350 	{
1351 		A_n = GetNodeArea(ny,loc_pos,true);
1352 		EffMat[0] += GetMaterial(n, coord, 0, vPrims)*A_n;
1353 		EffMat[1] += GetMaterial(n, coord, 1, vPrims)*A_n;
1354 		area+=A_n;
1355 	}
1356 
1357 	EffMat[0]*=__EPS0__/area;
1358 	EffMat[1]/=area;
1359 
1360 	//******************************* mu,sigma averaging *****************************//
1361 	loc_pos[0]=pos[0];
1362 	loc_pos[1]=pos[1];
1363 	loc_pos[2]=pos[2];
1364 	double length=0;
1365 	double delta_ny,sigma;
1366 	//shift down
1367 	--loc_pos[n];
1368 	if (GetCellCenterMaterialAvgCoord(loc_pos,coord))
1369 	{
1370 		delta_ny = GetNodeWidth(n,loc_pos,true);
1371 		EffMat[2] += delta_ny / GetMaterial(n, coord, 2, vPrims);
1372 		sigma = GetMaterial(n, coord, 3, vPrims);
1373 		if (sigma)
1374 			EffMat[3] += delta_ny / sigma;
1375 		else
1376 			EffMat[3] = 0;
1377 		length+=delta_ny;
1378 	}
1379 
1380 	//shift up
1381 	++loc_pos[n];
1382 	if (GetCellCenterMaterialAvgCoord(loc_pos,coord))
1383 	{
1384 		delta_ny = GetNodeWidth(n,loc_pos,true);
1385 		EffMat[2] += delta_ny / GetMaterial(n, coord, 2, vPrims);
1386 		sigma = GetMaterial(n, coord, 3, vPrims);
1387 		if (sigma)
1388 			EffMat[3] += delta_ny / sigma;
1389 		else
1390 			EffMat[3] = 0;
1391 		length+=delta_ny;
1392 	}
1393 
1394 	EffMat[2] = length * __MUE0__ / EffMat[2];
1395 	if (EffMat[3]) EffMat[3]=length / EffMat[3];
1396 
1397 	for (int n=0; n<4; ++n)
1398 		if (std::isnan(EffMat[n]) || std::isinf(EffMat[n]))
1399 		{
1400 			cerr << "Operator::" << __func__ << ": Error, an effective material parameter is not a valid result, this should NOT have happend... exit..." << endl;
1401 			cerr << ny << "@" << n << " : " << pos[0] << "," << pos[1] << ","  << pos[2] << endl;
1402 			exit(0);
1403 		}
1404 	return true;
1405 }
1406 
AverageMatQuarterCell(int ny,const unsigned int * pos,double * EffMat,vector<CSPrimitives * > vPrims) const1407 bool Operator::AverageMatQuarterCell(int ny, const unsigned int* pos, double* EffMat, vector<CSPrimitives*> vPrims) const
1408 {
1409 	int n=ny;
1410 	double coord[3];
1411 	double shiftCoord[3];
1412 	int nP = (n+1)%3;
1413 	int nPP = (n+2)%3;
1414 	coord[0] = discLines[0][pos[0]];
1415 	coord[1] = discLines[1][pos[1]];
1416 	coord[2] = discLines[2][pos[2]];
1417 	double delta=GetRawDiscDelta(n,pos[n]);
1418 	double deltaP=GetRawDiscDelta(nP,pos[nP]);
1419 	double deltaPP=GetRawDiscDelta(nPP,pos[nPP]);
1420 	double delta_M=GetRawDiscDelta(n,pos[n]-1);
1421 	double deltaP_M=GetRawDiscDelta(nP,pos[nP]-1);
1422 	double deltaPP_M=GetRawDiscDelta(nPP,pos[nPP]-1);
1423 
1424 	int loc_pos[3] = {(int)pos[0],(int)pos[1],(int)pos[2]};
1425 	double A_n;
1426 	double area = 0;
1427 
1428 	//******************************* epsilon,kappa averaging *****************************//
1429 	//shift up-right
1430 	shiftCoord[n] = coord[n]+delta*0.5;
1431 	shiftCoord[nP] = coord[nP]+deltaP*0.25;
1432 	shiftCoord[nPP] = coord[nPP]+deltaPP*0.25;
1433 	A_n = GetNodeArea(ny,loc_pos,true);
1434 	EffMat[0] = GetMaterial(n, shiftCoord, 0, vPrims)*A_n;
1435 	EffMat[1] = GetMaterial(n, shiftCoord, 1, vPrims)*A_n;
1436 	area+=A_n;
1437 
1438 	//shift up-left
1439 	shiftCoord[n] = coord[n]+delta*0.5;
1440 	shiftCoord[nP] = coord[nP]-deltaP_M*0.25;
1441 	shiftCoord[nPP] = coord[nPP]+deltaPP*0.25;
1442 
1443 	--loc_pos[nP];
1444 	A_n = GetNodeArea(ny,loc_pos,true);
1445 	EffMat[0] += GetMaterial(n, shiftCoord, 0, vPrims)*A_n;
1446 	EffMat[1] += GetMaterial(n, shiftCoord, 1, vPrims)*A_n;
1447 	area+=A_n;
1448 
1449 	//shift down-right
1450 	shiftCoord[n] = coord[n]+delta*0.5;
1451 	shiftCoord[nP] = coord[nP]+deltaP*0.25;
1452 	shiftCoord[nPP] = coord[nPP]-deltaPP_M*0.25;
1453 	++loc_pos[nP];
1454 	--loc_pos[nPP];
1455 	A_n = GetNodeArea(ny,loc_pos,true);
1456 	EffMat[0] += GetMaterial(n, shiftCoord, 0, vPrims)*A_n;
1457 	EffMat[1] += GetMaterial(n, shiftCoord, 1, vPrims)*A_n;
1458 	area+=A_n;
1459 
1460 	//shift down-left
1461 	shiftCoord[n] = coord[n]+delta*0.5;
1462 	shiftCoord[nP] = coord[nP]-deltaP_M*0.25;
1463 	shiftCoord[nPP] = coord[nPP]-deltaPP_M*0.25;
1464 	--loc_pos[nP];
1465 	A_n = GetNodeArea(ny,loc_pos,true);
1466 	EffMat[0] += GetMaterial(n, shiftCoord, 0, vPrims)*A_n;
1467 	EffMat[1] += GetMaterial(n, shiftCoord, 1, vPrims)*A_n;
1468 	area+=A_n;
1469 
1470 	EffMat[0]*=__EPS0__/area;
1471 	EffMat[1]/=area;
1472 
1473 	//******************************* mu,sigma averaging *****************************//
1474 	loc_pos[0]=pos[0];
1475 	loc_pos[1]=pos[1];
1476 	loc_pos[2]=pos[2];
1477 	double length=0;
1478 
1479 	//shift down
1480 	shiftCoord[n] = coord[n]-delta_M*0.25;
1481 	shiftCoord[nP] = coord[nP]+deltaP*0.5;
1482 	shiftCoord[nPP] = coord[nPP]+deltaPP*0.5;
1483 	--loc_pos[n];
1484 	double delta_ny = GetNodeWidth(n,loc_pos,true);
1485 	EffMat[2] = delta_ny / GetMaterial(n, shiftCoord, 2, vPrims);
1486 	double sigma = GetMaterial(n, shiftCoord, 3, vPrims);
1487 	if (sigma)
1488 		EffMat[3] = delta_ny / sigma;
1489 	else
1490 		EffMat[3] = 0;
1491 	length=delta_ny;
1492 
1493 	//shift up
1494 	shiftCoord[n] = coord[n]+delta*0.25;
1495 	shiftCoord[nP] = coord[nP]+deltaP*0.5;
1496 	shiftCoord[nPP] = coord[nPP]+deltaPP*0.5;
1497 	++loc_pos[n];
1498 	delta_ny = GetNodeWidth(n,loc_pos,true);
1499 	EffMat[2] += delta_ny / GetMaterial(n, shiftCoord, 2, vPrims);
1500 	sigma = GetMaterial(n, shiftCoord, 3, vPrims);
1501 	if (sigma)
1502 		EffMat[3] += delta_ny / sigma;
1503 	else
1504 		EffMat[3] = 0;
1505 	length+=delta_ny;
1506 
1507 	EffMat[2] = length * __MUE0__ / EffMat[2];
1508 	if (EffMat[3]) EffMat[3]=length / EffMat[3];
1509 
1510 	for (int n=0; n<4; ++n)
1511 		if (std::isnan(EffMat[n]) || std::isinf(EffMat[n]))
1512 		{
1513 			cerr << "Operator::" << __func__ << ": Error, An effective material parameter is not a valid result, this should NOT have happend... exit..." << endl;
1514 			cerr << ny << "@" << n << " : " << pos[0] << "," << pos[1] << ","  << pos[2] << endl;
1515 			exit(0);
1516 		}
1517 
1518 	return true;
1519 }
1520 
Calc_EffMatPos(int ny,const unsigned int * pos,double * EffMat,vector<CSPrimitives * > vPrims) const1521 bool Operator::Calc_EffMatPos(int ny, const unsigned int* pos, double* EffMat, vector<CSPrimitives *> vPrims) const
1522 {
1523 	switch (m_MatAverageMethod)
1524 	{
1525 	case QuarterCell:
1526 		return AverageMatQuarterCell(ny, pos, EffMat, vPrims);
1527 	case CentralCell:
1528 		return AverageMatCellCenter(ny, pos, EffMat, vPrims);
1529 	default:
1530 		cerr << "Operator:: " << __func__ << ":  Error, unknown material averaging method... exit" << endl;
1531 		exit(1);
1532 	}
1533 	return false;
1534 }
1535 
Calc_LumpedElements()1536 bool Operator::Calc_LumpedElements()
1537 {
1538 	vector<CSProperties*> props = CSX->GetPropertyByType(CSProperties::LUMPED_ELEMENT);
1539 	for (size_t i=0;i<props.size();++i)
1540 	{
1541 		CSPropLumpedElement* PLE = dynamic_cast<CSPropLumpedElement*>(props.at(i));
1542 		if (PLE==NULL)
1543 			return false; //sanity check: this should never happen!
1544 		vector<CSPrimitives*> prims = PLE->GetAllPrimitives();
1545 		for (size_t bn=0;bn<prims.size();++bn)
1546 		{
1547 			CSPrimBox* box = dynamic_cast<CSPrimBox*>(prims.at(bn));
1548 			if (box)
1549 			{	//calculate lumped element parameter
1550 
1551 				double C = PLE->GetCapacity();
1552 				if (C<=0)
1553 					C = NAN;
1554 				double R = PLE->GetResistance();
1555 				if (R<0)
1556 					R = NAN;
1557 
1558 				if ((std::isnan(R)) && (std::isnan(C)))
1559 				{
1560 					cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element R or C not specified! skipping. "
1561 							<< " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl;
1562 					continue;
1563 				}
1564 
1565 				int ny = PLE->GetDirection();
1566 				if ((ny<0) || (ny>2))
1567 				{
1568 					cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element direction is invalid! skipping. "
1569 							<< " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl;
1570 					continue;
1571 				}
1572 				int nyP = (ny+1)%3;
1573 				int nyPP = (ny+2)%3;
1574 
1575 				unsigned int uiStart[3];
1576 				unsigned int uiStop[3];
1577 				// snap to the native coordinate system
1578 				int Snap_Dimension = Operator::SnapBox2Mesh(box->GetStartCoord()->GetCoords(m_MeshType), box->GetStopCoord()->GetCoords(m_MeshType), uiStart, uiStop, false, true);
1579 				if (Snap_Dimension<=0)
1580 				{
1581 					if (Snap_Dimension>=-1)
1582 						cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element snapping failed! Dimension is: " << Snap_Dimension << " skipping. "
1583 								<< " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl;
1584 					// Snap_Dimension == -2 means outside the simulation domain --> no special warning, but box probably marked as unused!
1585 					continue;
1586 				}
1587 
1588 				if (uiStart[ny]==uiStop[ny])
1589 				{
1590 					cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element with zero (snapped) length is invalid! skipping. "
1591 							<< " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl;
1592 					continue;
1593 				}
1594 
1595 				//calculate geometric property for this lumped element
1596 				unsigned int pos[3];
1597 				double unitGC=0;
1598 				int ipos=0;
1599 				for (pos[ny]=uiStart[ny];pos[ny]<uiStop[ny];++pos[ny])
1600 				{
1601 					double unitGC_Plane=0;
1602 					for (pos[nyP]=uiStart[nyP];pos[nyP]<=uiStop[nyP];++pos[nyP])
1603 					{
1604 						for (pos[nyPP]=uiStart[nyPP];pos[nyPP]<=uiStop[nyPP];++pos[nyPP])
1605 						{
1606 							// capacity/conductivity in parallel: add values
1607 							unitGC_Plane += GetEdgeArea(ny,pos)/GetEdgeLength(ny,pos);
1608 						}
1609 					}
1610 
1611 					//capacity/conductivity in series: add reciprocal values
1612 					unitGC += 1/unitGC_Plane;
1613 				}
1614 				unitGC = 1/unitGC;
1615 
1616 				bool caps = PLE->GetCaps();
1617 				double kappa = 0;
1618 				double epsilon = 0;
1619 				if (R>0)
1620 					kappa = 1 / R / unitGC;
1621 				if (C>0)
1622 				{
1623 					epsilon =  C / unitGC;
1624 
1625 					if (epsilon< __EPS0__)
1626 					{
1627 						cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element capacity is too small for its size! skipping. "
1628 								<< " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl;
1629 						C = 0;
1630 					}
1631 				}
1632 
1633 				for (pos[ny]=uiStart[ny];pos[ny]<uiStop[ny];++pos[ny])
1634 				{
1635 					for (pos[nyP]=uiStart[nyP];pos[nyP]<=uiStop[nyP];++pos[nyP])
1636 					{
1637 						for (pos[nyPP]=uiStart[nyPP];pos[nyPP]<=uiStop[nyPP];++pos[nyPP])
1638 						{
1639 							ipos = MainOp->SetPos(pos[0],pos[1],pos[2]);
1640 							if (C>0)
1641 								EC_C[ny][ipos] = epsilon * GetEdgeArea(ny,pos)/GetEdgeLength(ny,pos);
1642 							if (R>0)
1643 								EC_G[ny][ipos] = kappa * GetEdgeArea(ny,pos)/GetEdgeLength(ny,pos);
1644 
1645 							if (R==0) //make lumped element a PEC if resistance is zero
1646 							{
1647 								SetVV(ny,pos[0],pos[1],pos[2], 0 );
1648 								SetVI(ny,pos[0],pos[1],pos[2], 0 );
1649 							}
1650 							else //recalculate operator inside the lumped element
1651 								Calc_ECOperatorPos(ny,pos);
1652 						}
1653 					}
1654 				}
1655 
1656 				// setup metal caps
1657 				if (caps)
1658 				{
1659 					for (pos[nyP]=uiStart[nyP];pos[nyP]<=uiStop[nyP];++pos[nyP])
1660 					{
1661 						for (pos[nyPP]=uiStart[nyPP];pos[nyPP]<=uiStop[nyPP];++pos[nyPP])
1662 						{
1663 							pos[ny]=uiStart[ny];
1664 							if (pos[nyP]<uiStop[nyP])
1665 							{
1666 								SetVV(nyP,pos[0],pos[1],pos[2], 0 );
1667 								SetVI(nyP,pos[0],pos[1],pos[2], 0 );
1668 								++m_Nr_PEC[nyP];
1669 							}
1670 
1671 							if (pos[nyPP]<uiStop[nyPP])
1672 							{
1673 								SetVV(nyPP,pos[0],pos[1],pos[2], 0 );
1674 								SetVI(nyPP,pos[0],pos[1],pos[2], 0 );
1675 								++m_Nr_PEC[nyPP];
1676 							}
1677 
1678 							pos[ny]=uiStop[ny];
1679 							if (pos[nyP]<uiStop[nyP])
1680 							{
1681 								SetVV(nyP,pos[0],pos[1],pos[2], 0 );
1682 								SetVI(nyP,pos[0],pos[1],pos[2], 0 );
1683 								++m_Nr_PEC[nyP];
1684 							}
1685 
1686 							if (pos[nyPP]<uiStop[nyPP])
1687 							{
1688 								SetVV(nyPP,pos[0],pos[1],pos[2], 0 );
1689 								SetVI(nyPP,pos[0],pos[1],pos[2], 0 );
1690 								++m_Nr_PEC[nyPP];
1691 							}
1692 						}
1693 					}
1694 				}
1695 				box->SetPrimitiveUsed(true);
1696 
1697 			}
1698 			else
1699 				cerr << "Operator::Calc_LumpedElements(): Warning: Primitves other than boxes are not supported for lumped elements! skipping "
1700 						<< prims.at(bn)->GetTypeName() << " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl;
1701 		}
1702 	}
1703 	return true;
1704 }
1705 
Init_EC()1706 void Operator::Init_EC()
1707 {
1708 	for (int n=0; n<3; ++n)
1709 	{
1710 		//init x-cell-array
1711 		delete[] EC_C[n];
1712 		delete[] EC_G[n];
1713 		delete[] EC_L[n];
1714 		delete[] EC_R[n];
1715 		EC_C[n] = new FDTD_FLOAT[MainOp->GetSize()];
1716 		EC_G[n] = new FDTD_FLOAT[MainOp->GetSize()];
1717 		EC_L[n] = new FDTD_FLOAT[MainOp->GetSize()];
1718 		EC_R[n] = new FDTD_FLOAT[MainOp->GetSize()];
1719 		for (unsigned int i=0; i<MainOp->GetSize(); i++) //init all
1720 		{
1721 			EC_C[n][i]=0;
1722 			EC_G[n][i]=0;
1723 			EC_L[n][i]=0;
1724 			EC_R[n][i]=0;
1725 		}
1726 	}
1727 }
1728 
Calc_EC()1729 bool Operator::Calc_EC()
1730 {
1731 	if (CSX==NULL)
1732 	{
1733 		cerr << "CartOperator::Calc_EC: CSX not given or invalid!!!" << endl;
1734 		return false;
1735 	}
1736 
1737 	MainOp->SetPos(0,0,0);
1738 	Calc_EC_Range(0,numLines[0]-1);
1739 	return true;
1740 }
1741 
GetPrimitivesBoundBox(int posX,int posY,int posZ,CSProperties::PropertyType type) const1742 vector<CSPrimitives*> Operator::GetPrimitivesBoundBox(int posX, int posY, int posZ, CSProperties::PropertyType type) const
1743 {
1744 	double boundBox[6];
1745 	int BBpos[3] = {posX, posY, posZ};
1746 	for (int n=0;n<3;++n)
1747 	{
1748 		if (BBpos[n]<0)
1749 		{
1750 			boundBox[2*n]   = this->GetDiscLine(n,0);
1751 			boundBox[2*n+1] = this->GetDiscLine(n,numLines[n]-1);
1752 		}
1753 		else
1754 		{
1755 			boundBox[2*n]   = this->GetDiscLine(n, max(0, BBpos[n]-1));
1756 			boundBox[2*n+1] = this->GetDiscLine(n, min(int(numLines[n])-1, BBpos[n]+1));
1757 		}
1758 	}
1759 
1760 	vector<CSPrimitives*> vPrim = this->CSX->GetPrimitivesByBoundBox(boundBox, true, type);
1761 	return vPrim;
1762 }
1763 
Calc_EC_Range(unsigned int xStart,unsigned int xStop)1764 void Operator::Calc_EC_Range(unsigned int xStart, unsigned int xStop)
1765 {
1766 //	vector<CSPrimitives*> vPrims = this->CSX->GetAllPrimitives(true, CSProperties::MATERIAL);
1767 	unsigned int ipos;
1768 	unsigned int pos[3];
1769 	double inEC[4];
1770 	for (pos[0]=xStart; pos[0]<=xStop; ++pos[0])
1771 	{
1772 		for (pos[1]=0; pos[1]<numLines[1]; ++pos[1])
1773 		{
1774 			vector<CSPrimitives*> vPrims = this->GetPrimitivesBoundBox(pos[0], pos[1], -1, CSProperties::MATERIAL);
1775 			for (pos[2]=0; pos[2]<numLines[2]; ++pos[2])
1776 			{
1777 				ipos = MainOp->GetPos(pos[0],pos[1],pos[2]);
1778 				for (int n=0; n<3; ++n)
1779 				{
1780 					Calc_ECPos(n,pos,inEC,vPrims);
1781 					EC_C[n][ipos]=inEC[0];
1782 					EC_G[n][ipos]=inEC[1];
1783 					EC_L[n][ipos]=inEC[2];
1784 					EC_R[n][ipos]=inEC[3];
1785 				}
1786 			}
1787 		}
1788 	}
1789 }
1790 
SetTimestepFactor(double factor)1791 void Operator::SetTimestepFactor(double factor)
1792 {
1793 	if ((factor<=0) || (factor>1))
1794 	{
1795 		cerr << "Operator::SetTimestepFactor: Warning, invalid timestep factor, skipping!" << endl;
1796 		return;
1797 	}
1798 
1799 	cout << "Operator::SetTimestepFactor: Setting timestep factor to " << factor << endl;
1800 	m_TimeStepFactor=factor;
1801 }
1802 
CalcTimestep()1803 double Operator::CalcTimestep()
1804 {
1805 	if (m_TimeStepVar==3)
1806 		return CalcTimestep_Var3(); //the biggest one for cartesian meshes
1807 
1808 	//variant 1 is default
1809 	return CalcTimestep_Var1();
1810 }
1811 
1812 ////Berechnung nach Andreas Rennings Dissertation 2008, Seite 66, Formel 4.52
CalcTimestep_Var1()1813 double Operator::CalcTimestep_Var1()
1814 {
1815 	m_Used_TS_Name = string("Rennings_1");
1816 //	cout << "Operator::CalcTimestep(): Using timestep algorithm by Andreas Rennings, Dissertation @ University Duisburg-Essen, 2008, pp. 66, eq. 4.52" << endl;
1817 	dT=1e200;
1818 	double newT;
1819 	unsigned int pos[3];
1820 	unsigned int smallest_pos[3] = {0, 0, 0};
1821 	unsigned int smallest_n = 0;
1822 	unsigned int ipos;
1823 	unsigned int ipos_PM;
1824 	unsigned int ipos_PPM;
1825 	MainOp->SetReflection2Cell();
1826 	for (int n=0; n<3; ++n)
1827 	{
1828 		int nP = (n+1)%3;
1829 		int nPP = (n+2)%3;
1830 
1831 		for (pos[2]=0; pos[2]<numLines[2]; ++pos[2])
1832 		{
1833 			for (pos[1]=0; pos[1]<numLines[1]; ++pos[1])
1834 			{
1835 				for (pos[0]=0; pos[0]<numLines[0]; ++pos[0])
1836 				{
1837 					ipos = MainOp->SetPos(pos[0],pos[1],pos[2]);
1838 					ipos_PM = MainOp->Shift(nP,-1);
1839 					MainOp->ResetShift();
1840 					ipos_PPM= MainOp->Shift(nPP,-1);
1841 					MainOp->ResetShift();
1842 					newT = 2/sqrt( ( 4/EC_L[nP][ipos] + 4/EC_L[nP][ipos_PPM] + 4/EC_L[nPP][ipos] + 4/EC_L[nPP][ipos_PM]) / EC_C[n][ipos] );
1843 					if ((newT<dT) && (newT>0.0))
1844 					{
1845 						dT=newT;
1846 						smallest_pos[0]=pos[0];smallest_pos[1]=pos[1];smallest_pos[2]=pos[2];
1847 						smallest_n = n;
1848 					}
1849 				}
1850 			}
1851 		}
1852 	}
1853 	if (dT==0)
1854 	{
1855 		cerr << "Operator::CalcTimestep: Timestep is zero... this is not supposed to happen!!! exit!" << endl;
1856 		exit(3);
1857 	}
1858 	if (g_settings.GetVerboseLevel()>1)
1859 	{
1860 		cout << "Operator::CalcTimestep_Var1: Smallest timestep (" << dT << "s) found at position: " <<  smallest_n << " : " << smallest_pos[0] << ";" <<  smallest_pos[1] << ";" <<  smallest_pos[2] << endl;
1861 	}
1862 	return 0;
1863 }
1864 
min(double * val,unsigned int count)1865 double min(double* val, unsigned int count)
1866 {
1867 	if (count==0)
1868 		return 0.0;
1869 	double min = val[0];
1870 	for (unsigned int n=1; n<count; ++n)
1871 		if (val[n]<min)
1872 			min = val[n];
1873 	return min;
1874 }
1875 
1876 //Berechnung nach Andreas Rennings Dissertation 2008, Seite 76 ff, Formel 4.77 ff
CalcTimestep_Var3()1877 double Operator::CalcTimestep_Var3()
1878 {
1879 	dT=1e200;
1880 	m_Used_TS_Name = string("Rennings_2");
1881 //	cout << "Operator::CalcTimestep(): Using timestep algorithm by Andreas Rennings, Dissertation @ University Duisburg-Essen, 2008, pp. 76, eq. 4.77 ff." << endl;
1882 	double newT;
1883 	unsigned int pos[3];
1884 	unsigned int smallest_pos[3] = {0, 0, 0};
1885 	unsigned int smallest_n = 0;
1886 	unsigned int ipos;
1887 	double w_total=0;
1888 	double wqp=0,wt1=0,wt2=0;
1889 	double wt_4[4]={0,0,0,0};
1890 	MainOp->SetReflection2Cell();
1891 	for (int n=0; n<3; ++n)
1892 	{
1893 		int nP = (n+1)%3;
1894 		int nPP = (n+2)%3;
1895 
1896 		for (pos[2]=0; pos[2]<numLines[2]; ++pos[2])
1897 		{
1898 			for (pos[1]=0; pos[1]<numLines[1]; ++pos[1])
1899 			{
1900 				for (pos[0]=0; pos[0]<numLines[0]; ++pos[0])
1901 				{
1902 					MainOp->ResetShift();
1903 					ipos = MainOp->SetPos(pos[0],pos[1],pos[2]);
1904 					wqp  = 1/(EC_L[nPP][ipos]*EC_C[n][MainOp->GetShiftedPos(nP ,1)]) + 1/(EC_L[nPP][ipos]*EC_C[n][ipos]);
1905 					wqp += 1/(EC_L[nP ][ipos]*EC_C[n][MainOp->GetShiftedPos(nPP,1)]) + 1/(EC_L[nP ][ipos]*EC_C[n][ipos]);
1906 					ipos = MainOp->Shift(nP,-1);
1907 					wqp += 1/(EC_L[nPP][ipos]*EC_C[n][MainOp->GetShiftedPos(nP ,1)]) + 1/(EC_L[nPP][ipos]*EC_C[n][ipos]);
1908 					ipos = MainOp->Shift(nPP,-1);
1909 					wqp += 1/(EC_L[nP ][ipos]*EC_C[n][MainOp->GetShiftedPos(nPP,1)]) + 1/(EC_L[nP ][ipos]*EC_C[n][ipos]);
1910 
1911 					MainOp->ResetShift();
1912 					ipos = MainOp->SetPos(pos[0],pos[1],pos[2]);
1913 					wt_4[0] = 1/(EC_L[nPP][ipos]						  *EC_C[nP ][ipos]);
1914 					wt_4[1] = 1/(EC_L[nPP][MainOp->GetShiftedPos(nP ,-1)] *EC_C[nP ][ipos]);
1915 					wt_4[2] = 1/(EC_L[nP ][ipos]						  *EC_C[nPP][ipos]);
1916 					wt_4[3] = 1/(EC_L[nP ][MainOp->GetShiftedPos(nPP,-1)] *EC_C[nPP][ipos]);
1917 
1918 					wt1 = wt_4[0]+wt_4[1]+wt_4[2]+wt_4[3] - 2*min(wt_4,4);
1919 
1920 					MainOp->ResetShift();
1921 					ipos = MainOp->SetPos(pos[0],pos[1],pos[2]);
1922 					wt_4[0] = 1/(EC_L[nPP][ipos]						  *EC_C[nP ][MainOp->GetShiftedPos(n,1)]);
1923 					wt_4[1] = 1/(EC_L[nPP][MainOp->GetShiftedPos(nP ,-1)] *EC_C[nP ][MainOp->GetShiftedPos(n,1)]);
1924 					wt_4[2] = 1/(EC_L[nP ][ipos]						  *EC_C[nPP][MainOp->GetShiftedPos(n,1)]);
1925 					wt_4[3] = 1/(EC_L[nP ][MainOp->GetShiftedPos(nPP,-1)] *EC_C[nPP][MainOp->GetShiftedPos(n,1)]);
1926 
1927 					wt2 = wt_4[0]+wt_4[1]+wt_4[2]+wt_4[3] - 2*min(wt_4,4);
1928 
1929 					w_total = wqp + wt1 + wt2;
1930 					newT = 2/sqrt( w_total );
1931 					if ((newT<dT) && (newT>0.0))
1932 					{
1933 						dT=newT;
1934 						smallest_pos[0]=pos[0];smallest_pos[1]=pos[1];smallest_pos[2]=pos[2];
1935 						smallest_n = n;
1936 					}
1937 				}
1938 			}
1939 		}
1940 	}
1941 	if (dT==0)
1942 	{
1943 		cerr << "Operator::CalcTimestep: Timestep is zero... this is not supposed to happen!!! exit!" << endl;
1944 		exit(3);
1945 	}
1946 	if (g_settings.GetVerboseLevel()>1)
1947 	{
1948 		cout << "Operator::CalcTimestep_Var3: Smallest timestep (" << dT << "s) found at position: " <<  smallest_n << " : " << smallest_pos[0] << ";" <<  smallest_pos[1] << ";" <<  smallest_pos[2] << endl;
1949 	}
1950 	return 0;
1951 }
1952 
CalcPEC()1953 bool Operator::CalcPEC()
1954 {
1955 	m_Nr_PEC[0]=0;
1956 	m_Nr_PEC[1]=0;
1957 	m_Nr_PEC[2]=0;
1958 
1959 	CalcPEC_Range(0,numLines[0]-1,m_Nr_PEC);
1960 
1961 	CalcPEC_Curves();
1962 
1963 	return true;
1964 }
1965 
CalcPEC_Range(unsigned int startX,unsigned int stopX,unsigned int * counter)1966 void Operator::CalcPEC_Range(unsigned int startX, unsigned int stopX, unsigned int* counter)
1967 {
1968 	double coord[3];
1969 	unsigned int pos[3];
1970 	for (pos[0]=startX; pos[0]<=stopX; ++pos[0])
1971 	{
1972 		for (pos[1]=0; pos[1]<numLines[1]; ++pos[1])
1973 		{
1974 			vector<CSPrimitives*> vPrims = this->GetPrimitivesBoundBox(pos[0], pos[1], -1, (CSProperties::PropertyType)(CSProperties::MATERIAL | CSProperties::METAL));
1975 			for (pos[2]=0; pos[2]<numLines[2]; ++pos[2])
1976 			{
1977 				for (int n=0; n<3; ++n)
1978 				{
1979 					GetYeeCoords(n,pos,coord,false);
1980 					CSProperties* prop = CSX->GetPropertyByCoordPriority(coord, vPrims, true);
1981 //					CSProperties* old_prop = CSX->GetPropertyByCoordPriority(coord, (CSProperties::PropertyType)(CSProperties::MATERIAL | CSProperties::METAL), true);
1982 //					if (old_prop!=prop)
1983 //					{
1984 //						cerr << "CalcPEC_Range: " << old_prop << " vs " << prop << endl;
1985 //						exit(-1);
1986 //					}
1987 					if (prop)
1988 					{
1989 						if (prop->GetType()==CSProperties::METAL) //set to PEC
1990 						{
1991 							SetVV(n,pos[0],pos[1],pos[2], 0 );
1992 							SetVI(n,pos[0],pos[1],pos[2], 0 );
1993 							++counter[n];
1994 						}
1995 					}
1996 				}
1997 			}
1998 		}
1999 	}
2000 }
2001 
CalcPEC_Curves()2002 void Operator::CalcPEC_Curves()
2003 {
2004 	//special treatment for primitives of type curve (treated as wires)
2005 	double p1[3];
2006 	double p2[3];
2007 	Grid_Path path;
2008 	vector<CSProperties*> vec_prop = CSX->GetPropertyByType(CSProperties::METAL);
2009 	for (size_t p=0; p<vec_prop.size(); ++p)
2010 	{
2011 		CSProperties* prop = vec_prop.at(p);
2012 		for (size_t n=0; n<prop->GetQtyPrimitives(); ++n)
2013 		{
2014 			CSPrimitives* prim = prop->GetPrimitive(n);
2015 			CSPrimCurve* curv = prim->ToCurve();
2016 			if (curv)
2017 			{
2018 				for (size_t i=1; i<curv->GetNumberOfPoints(); ++i)
2019 				{
2020 					curv->GetPoint(i-1,p1,m_MeshType);
2021 					curv->GetPoint(i,p2,m_MeshType);
2022 					path = FindPath(p1,p2);
2023 					if (path.dir.size()>0)
2024 						prim->SetPrimitiveUsed(true);
2025 					for (size_t t=0; t<path.dir.size(); ++t)
2026 					{
2027 						SetVV(path.dir.at(t),path.posPath[0].at(t),path.posPath[1].at(t),path.posPath[2].at(t), 0 );
2028 						SetVI(path.dir.at(t),path.posPath[0].at(t),path.posPath[1].at(t),path.posPath[2].at(t), 0 );
2029 						++m_Nr_PEC[path.dir.at(t)];
2030 					}
2031 				}
2032 			}
2033 		}
2034 	}
2035 }
2036 
GetExcitationExtension() const2037 Operator_Ext_Excitation* Operator::GetExcitationExtension() const
2038 {
2039 	//search for excitation extension
2040 	Operator_Ext_Excitation* Op_Ext_Exc=0;
2041 	for (size_t n=0; n<m_Op_exts.size(); ++n)
2042 	{
2043 		Op_Ext_Exc = dynamic_cast<Operator_Ext_Excitation*>(m_Op_exts.at(n));
2044 		if (Op_Ext_Exc)
2045 			break;
2046 	}
2047 	return Op_Ext_Exc;
2048 }
2049 
AddExtension(Operator_Extension * op_ext)2050 void Operator::AddExtension(Operator_Extension* op_ext)
2051 {
2052 	m_Op_exts.push_back(op_ext);
2053 }
2054 
DeleteExtension(Operator_Extension * op_ext)2055 void Operator::DeleteExtension(Operator_Extension* op_ext)
2056 {
2057 	for (size_t n=0;n<m_Op_exts.size();++n)
2058 	{
2059 		if (m_Op_exts.at(n)==op_ext)
2060 		{
2061 			m_Op_exts.erase(m_Op_exts.begin()+n);
2062 			return;
2063 		}
2064 	}
2065 }
2066 
CalcNumericPhaseVelocity(unsigned int start[3],unsigned int stop[3],double propDir[3],float freq) const2067 double Operator::CalcNumericPhaseVelocity(unsigned int start[3], unsigned int stop[3], double propDir[3], float freq) const
2068 {
2069 	double average_mesh_disc[3];
2070 	double c0 = __C0__/sqrt(GetBackgroundEpsR()*GetBackgroundMueR());
2071 
2072 	//calculate average mesh deltas
2073 	for (int n=0;n<3;++n)
2074 	{
2075 		average_mesh_disc[n] = fabs(GetDiscLine(n,start[n])-GetDiscLine(n,stop[n]))*GetGridDelta() / (fabs(stop[n]-start[n]));
2076 	}
2077 
2078 	// if propagation is in a Cartesian direction, return analytic solution
2079 	for (int n=0;n<3;++n)
2080 	{
2081 		int nP = (n+1)%3;
2082 		int nPP = (n+2)%3;
2083 		if ((fabs(propDir[n])==1) && (propDir[nP]==0) && (propDir[nPP]==0))
2084 		{
2085 			double kx = asin(average_mesh_disc[0]/c0/dT*sin(2*PI*freq*dT/2))*2/average_mesh_disc[0];
2086 			return 2*PI*freq/kx;
2087 		}
2088 	}
2089 
2090 	// else, do an newton iterative estimation
2091 	double k0=2*PI*freq/c0;
2092 	double k=k0;
2093 	double RHS = pow(sin(2*PI*freq*dT/2)/c0/dT,2);
2094 	double fk=1,fdk=0;
2095 	double old_phv=0;
2096 	double phv=c0;
2097 	double err_est = 1e-6;
2098 	int it_count=0;
2099 	while (fabs(old_phv-phv)>err_est)
2100 	{
2101 		++it_count;
2102 		old_phv=phv;
2103 		fk=0;
2104 		fdk=0;
2105 		for (int n=0;n<3;++n)
2106 		{
2107 			fk+= pow(sin(propDir[n]*k*average_mesh_disc[n]/2)/average_mesh_disc[n],2);
2108 			fdk+= propDir[n]*sin(propDir[n]*k*average_mesh_disc[n]/2)*cos(propDir[n]*k*average_mesh_disc[n]/2)/average_mesh_disc[n];
2109 		}
2110 		fk -= RHS;
2111 		k-=fk/fdk;
2112 
2113 		// do not allow a speed greater than c0 due to a numerical inaccuracy
2114 		if (k<k0)
2115 			k=k0;
2116 
2117 		phv=2*PI*freq/k;
2118 
2119 		//abort if iteration count is getting to high!
2120 		if (it_count>99)
2121 		{
2122 			cerr << "Operator::CalcNumericPhaseVelocity: Error, newton iteration estimation can't find a solution!!" << endl;
2123 			break;
2124 		}
2125 	}
2126 
2127 	if (g_settings.GetVerboseLevel()>1)
2128 		cerr << "Operator::CalcNumericPhaseVelocity: Newton iteration estimated solution: " << phv/__C0__ << "*c0 in " <<  it_count << " iterations." << endl;
2129 
2130 	return phv;
2131 }
2132