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