Xyce  6.1
N_DEV_PDE_2DMesh.C
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 // Copyright Notice
3 //
4 // Copyright 2002 Sandia Corporation. Under the terms
5 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
6 // Government retains certain rights in this software.
7 //
8 // Xyce(TM) Parallel Electrical Simulator
9 // Copyright (C) 2002-2015 Sandia Corporation
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 //-----------------------------------------------------------------------------
24 
25 //-------------------------------------------------------------------------
26 // Filename : $RCSfile: N_DEV_PDE_2DMesh.C,v $
27 //
28 // Purpose : Contains the 2D mesh information.
29 //
30 // Special Notes :
31 //
32 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
33 //
34 // Creation Date : 04/21/02
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.47.2.1 $
40 //
41 // Revision Date : $Date: 2015/04/02 18:20:12 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 
48 // ---------- Standard Includes ----------
49 #include <algorithm>
50 #include <iostream>
51 #include <map>
52 #include <string>
53 #include <cstring>
54 #include <cstdio>
55 
56 #include <N_DEV_DeviceOptions.h>
57 #include <N_DEV_PDE_2DMesh.h>
58 #include <N_ERH_ErrorMgr.h>
59 #include <N_UTL_Diagnostic.h>
60 #include <N_UTL_ExtendedString.h>
61 #include <N_UTL_FeatureTest.h>
62 #include <N_UTL_Math.h>
63 
64 namespace {
65 typedef unsigned int UINT;
66 }
67 
68 namespace Xyce {
69 namespace Device {
70 
71 //-----------------------------------------------------------------------------
72 // Function : PDE_2DMesh::PDE_2DMesh
73 // Purpose : constructor
74 // Special Notes :
75 // Scope : public
76 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
77 // Creation Date : 04/21/02
78 //-----------------------------------------------------------------------------
79 PDE_2DMesh::PDE_2DMesh (const DeviceOptions & do1, int sgplotLevel1):
80  xMax (0.0),
81  yMax (0.0),
82  xMin (0.0),
83  yMin (0.0),
84  dx (0.0),
85  dy (0.0),
86  xRatio (1.0),
87  yRatio (1.0),
88  x0 (1.0),
89  meshScaledFlag (false),
90  vol (0.0),
91  invVol (0.0),
92  surfArea (0.0),
93  circum (0.0),
94  invCircum (0.0),
95  depth (1.0),
96  numAdj (0),
97  numNodes (0),
98  numEdges (0),
99  numCells (0),
100  numLabels (0),
101  numRegLabels (1), // default is 1 - has to be at least one region.
102  maxNodeNN (0),
103  numBndryNodes(0),
104  iRecentCellLookup(0),
105  cylGeom (false),
106  dopingSet (false),
107  meshFileName ("internal"),
108  externalMeshFlag (false),
109  ixMax(0),
110  iyMax(0),
111  nodeIndices(NULL),
112  edgeIndices(NULL),
113  cellIndices(NULL),
114  devOptions_(&do1),
115  aiBegin(NULL),
116  aiEnd(NULL),
117  adjInfoAllocFlag(false),
118  sgplotLevel(sgplotLevel1),
119  useDefaultLabels(true)
120 {
121 
122 
123 }
124 
125 //-----------------------------------------------------------------------------
126 // Function : PDE_2DMesh::PDE_2DMesh
127 // Purpose : copy constructor
128 // Special Notes :
129 // Scope : public
130 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
131 // Creation Date : 11/26/02
132 //-----------------------------------------------------------------------------
134  meshFileName (right.meshFileName),
135  externalMeshFlag (right.externalMeshFlag),
136  xMax (right.xMax),
137  yMax (right.yMax),
138  xMin (right.xMin),
139  yMin (right.yMin),
140  dx (right.dx),
141  dy (right.dy),
142  xRatio (right.xRatio),
143  yRatio (right.yRatio),
144  x0 (right.x0),
145  meshScaledFlag (right.meshScaledFlag),
146  vol (right.vol),
147  invVol (right.invVol),
148  surfArea (right.surfArea),
149  circum (right.circum),
150  invCircum (right.invCircum),
151  depth (right.depth),
152  numNodes (right.numNodes),
153  numEdges (right.numEdges),
154  numCells (right.numCells),
155  numLabels (right.numLabels),
156  numRegLabels (right.numRegLabels),
157  numBndryNodes (right.numBndryNodes),
158  maxNodeNN (right.maxNodeNN),
159  iRecentCellLookup(right.iRecentCellLookup),
160  cylGeom (right.cylGeom),
161  dopingSet (right.dopingSet),
162  mNodeVector (right.mNodeVector),
163  mEdgeVector (right.mEdgeVector),
164  mCellVector (right.mCellVector),
165  mLabelVector (right.mLabelVector),
166  dopingVector (right.dopingVector),
167  xVector (right.xVector),
168  yVector (right.yVector),
169  visitCellFlagVec (right.visitCellFlagVec),
170  mLabelMap (right.mLabelMap),
171  ixMax (right.ixMax),
172  iyMax (right.iyMax),
173  devOptions_ (right.devOptions_),
174  afVisitedVec (right.afVisitedVec),
175  adjInfoAllocFlag (right.adjInfoAllocFlag),
176  sgplotLevel (right.sgplotLevel),
177  aiBegin(NULL),
178  aiEnd(NULL)
179 {
180  int i,j;
181 
182  // if we're copying over a mesh that was generated via the "internal"
183  // capability, we need to copy over these 3 structures:
184  if (!externalMeshFlag)
185  {
186  if (right.nodeIndices != NULL)
187  {
188  nodeIndices = new int*[ixMax+10];
189  for (i=0;i<ixMax+10;++i)
190  {
191  nodeIndices[i] = new int[iyMax+10];
192 
193  for (j=0;j<iyMax+10;++j)
194  {
195  nodeIndices[i][j] = right.nodeIndices[i][j];
196  }
197  }
198  }
199 
200  if (right.edgeIndices != NULL)
201  {
202  edgeIndices = new int*[numNodes+10];
203  for (i=0;i<numNodes+10;++i)
204  {
205  edgeIndices[i] = new int[numNodes+10];
206 
207  for (j=0;j<numNodes+10;++j)
208  {
209  edgeIndices[i][j] = right.edgeIndices[i][j];
210  }
211  }
212  }
213 
214  if (right.cellIndices != NULL)
215  {
216  cellIndices = new int *[ixMax+10];
217  for (i=0;i<ixMax+10;++i)
218  {
219  cellIndices[i] = new int[iyMax+10];
220  for (j=0;j<iyMax+10;++j)
221  cellIndices[i][j] = right.cellIndices[i][j];
222  }
223  }
224  } // end of externalMeshFlag if statement.
225 
226  // these arrays aren't worth copying,
227  // but if they were allocated in the original class,
228  // they need allocating here too.
229  if (adjInfoAllocFlag)
230  {
231  aiBegin = new int [numRegLabels];
232  aiEnd = new int [numRegLabels];
233  }
234 
235 }
236 
237 //-----------------------------------------------------------------------------
238 // Function : PDE_2DMesh::operator=
239 //
240 // Purpose : assignment operator
241 //
242 // Special Notes : This is probably more thorough than it absolutely needs
243 // to be.
244 // Scope :
245 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
246 // Creation Date : 11/30/02
247 //-----------------------------------------------------------------------------
249 {
250  meshFileName = rhsMesh.meshFileName;
252  xMax = rhsMesh.xMax;
253  yMax = rhsMesh.yMax;
254  xMin = rhsMesh.xMin;
255  yMin = rhsMesh.yMin;
256  dx = rhsMesh.dx;
257  dy = rhsMesh.dy;
258  xRatio = rhsMesh.xRatio;
259  yRatio = rhsMesh.yRatio;
260  x0 = rhsMesh.x0;
261  meshScaledFlag = rhsMesh.meshScaledFlag;
262  vol = rhsMesh.vol;
263  invVol = rhsMesh.invVol;
264  surfArea = rhsMesh.surfArea;
265  circum = rhsMesh.circum;
266  invCircum = rhsMesh.invCircum;
267  depth = rhsMesh.depth;
268  numNodes = rhsMesh.numNodes;
269  numEdges = rhsMesh.numEdges;
270  numCells = rhsMesh.numCells;
271  numLabels = rhsMesh.numLabels;
272  numRegLabels = rhsMesh.numRegLabels;
273  numBndryNodes = rhsMesh.numBndryNodes;
274  maxNodeNN = rhsMesh.maxNodeNN;
276  cylGeom = rhsMesh.cylGeom;
277  dopingSet = rhsMesh.dopingSet;
278  mNodeVector = rhsMesh.mNodeVector;
279  mEdgeVector = rhsMesh.mEdgeVector;
280  mCellVector = rhsMesh.mCellVector;
281  mLabelVector = rhsMesh.mLabelVector;
282  dopingVector = rhsMesh.dopingVector;
283  xVector = rhsMesh.xVector;
284  yVector = rhsMesh.yVector;
286  mLabelMap = rhsMesh.mLabelMap;
287  ixMax = rhsMesh.ixMax;
288  iyMax = rhsMesh.iyMax;
289  devOptions_ = rhsMesh.devOptions_;
290  afVisitedVec = rhsMesh.afVisitedVec;
292 
293  int i,j;
294 
295  // if we're copying over a mesh that was generated via the "internal"
296  // capability, we need to copy over these 3 structures:
297  if (!externalMeshFlag)
298  {
299  if (rhsMesh.nodeIndices != NULL)
300  {
301  nodeIndices = new int*[ixMax+10];
302  for (i=0;i<ixMax+10;++i)
303  {
304  nodeIndices[i] = new int[iyMax+10];
305 
306  for (j=0;j<iyMax+10;++j)
307  {
308  nodeIndices[i][j] = rhsMesh.nodeIndices[i][j];
309  }
310  }
311  }
312 
313  if (rhsMesh.edgeIndices != NULL)
314  {
315  edgeIndices = new int*[numNodes+10];
316  for (i=0;i<numNodes+10;++i)
317  {
318  edgeIndices[i] = new int[numNodes+10];
319 
320  for (j=0;j<numNodes+10;++j)
321  {
322  edgeIndices[i][j] = rhsMesh.edgeIndices[i][j];
323  }
324  }
325  }
326 
327  if (rhsMesh.cellIndices != NULL)
328  {
329  cellIndices = new int *[ixMax+10];
330  for (i=0;i<ixMax+10;++i)
331  {
332  cellIndices[i] = new int[iyMax+10];
333  for (j=0;j<iyMax+10;++j)
334  cellIndices[i][j] = rhsMesh.cellIndices[i][j];
335  }
336  }
337  } // end of externalMeshFlag if statement.
338 
339  // these arrays aren't worth copying,
340  // but if they were allocated in the original class,
341  // they need allocating here too.
342  if (adjInfoAllocFlag)
343  {
344  aiBegin = new int [numRegLabels];
345  aiEnd = new int [numRegLabels];
346  }
347 
348  return *this;
349 }
350 
351 //-----------------------------------------------------------------------------
352 // Function : PDE_2DMesh::~PDE_2DMesh
353 // Purpose : destructor
354 // Special Notes :
355 // Scope : public
356 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
357 // Creation Date : 04/21/02
358 //-----------------------------------------------------------------------------
360 {
361  if (!externalMeshFlag)
362  {
363  int i;
364  if( nodeIndices!=NULL)
365  {
366  for (i=0;i<ixMax+10;++i)
367  {
368  delete [] nodeIndices[i];
369  }
370  delete [] nodeIndices;
371  }
372 
373  if( edgeIndices!=NULL)
374  {
375  for (i=0;i<numNodes+10;++i)
376  {
377  delete [] edgeIndices[i];
378  }
379  delete [] edgeIndices;
380  }
381 
382  if( cellIndices!=NULL)
383  {
384  for (i=0;i<ixMax+10;++i)
385  {
386  delete [] cellIndices[i];
387  }
388  delete [] cellIndices;
389  }
390  }// end of externalMeshFlag
391 
392 
393  if (aiBegin != NULL) delete [] aiBegin;
394  if (aiEnd != NULL) delete [] aiEnd;
395 }
396 
397 //-----------------------------------------------------------------------------
398 // Function : PDE_2DMesh::initializeMesh
399 // Purpose : This function initializes the mesh, as well as many of
400 // the geometry-related variables.
401 //
402 // Special Notes : If a mesh file is specified , this function will attempt
403 // to read it in. If none is specified, it will set up
404 // a very simple default cartesian mesh.
405 //
406 // In any case, it is expected that the file, or the
407 // default mesh setup, will contain a list of nodes,
408 // edges and cells. The rest will be calculated later.
409 //
410 // Scope : public
411 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
412 // Creation Date : 04/21/02
413 //-----------------------------------------------------------------------------
414 bool PDE_2DMesh::initializeMesh (const std::string & meshFileName_tmp)
415 {
416  bool bsuccess = true;
417  bool tmpBool = true;
418 
419  if (true) // if mesh file is specified: (for now no real test here...)
420  {
421  externalMeshFlag = true;
422  meshFileName = meshFileName_tmp;
423  bsuccess = readSGFMeshFile (meshFileName_tmp);
424  }
425 
426  // set up extra data structures:
427 
428  // set up cell Node lists:
429  tmpBool = cellNodes();
430  bsuccess = bsuccess && tmpBool;
431 
432  // set up the label node information.
433 
434  // set up node nearest neighbor lists:
435 
436  // calculate geometry information:
437  tmpBool = setupGeometry ();
438  bsuccess = bsuccess && tmpBool;
439 
440  visitCellFlagVec.resize(numCells,0);
441 
442  if (DEBUG_DEVICE && isActive(Diag::DEVICE_DUMP_VECTORS))
443  dumpMesh();
444 
445  return bsuccess;
446 }
447 
448 
449 //-----------------------------------------------------------------------------
450 // Function : PDE_2DMesh::readSGFMeshFile
451 // Purpose : This function reads in a *.msh file generated by the
452 // SGF meshing program, and places the information contained
453 // in the *msh file into Xyce data structures.
454 //
455 // Special Notes :
456 //
457 // Scope : public
458 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
459 // Creation Date : 04/21/02
460 //-----------------------------------------------------------------------------
461 bool PDE_2DMesh::readSGFMeshFile (const std::string & meshFileName_tmp)
462 {
463  MESHHEAD meshhead;
464 
465  // open the mesh file
466  FILE *nFile = fopen(meshFileName_tmp.c_str(), "r");
467 
468  if (nFile == NULL)
469  {
470  std::string msg("PDE_2DMesh::readSGFMeshFile - ");
471  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg + meshFileName_tmp +
472  " file not found.");
473  }
474 
475  // read the header
476  fread(&meshhead, sizeof(MESHHEAD),1,nFile);
477 
478  // advance past the constants
479  long lOffset = meshhead.cConstant * sizeof(XLATCONST) + sizeof(UINT);
480  fseek(nFile, lOffset, SEEK_CUR);
481 
482  // read the label lists
483  UINT cLabel;
484  fread(&cLabel, sizeof(UINT),1,nFile);
485 
486  UINT i,j;
487 
488  numLabels = cLabel;
489  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
490  Xyce::dout() << "About to read label lists: cLabel = " << cLabel << std::endl;
491 
492  for(i = 0; i < cLabel; ++i)
493  {
494  XLATLABEL xlatlabel;
495  mLabel xLabel;
496 
497  fread(&xlatlabel, sizeof(XLATLABEL),1,nFile);
498  xLabel.name = std::string(xlatlabel.szName);
499  xLabel.iIndex = xlatlabel.iIndex;
500  xLabel.uType = xlatlabel.uType;
501  xLabel.cNode = xlatlabel.cNode;
502 
503  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
504  {
505  Xyce::dout() << "i = " << i ;
506  Xyce::dout() << " iIndex = " << xLabel.iIndex;
507  Xyce::dout() << " uType = " << xLabel.uType;
508  Xyce::dout() << " cNode = " << xLabel.cNode;
509  Xyce::dout() << " label name = " << xLabel.name << std::endl;
510  }
511 
512  xLabel.mNodeVector.reserve(xlatlabel.cNode+1);
513 
514  for (j=0;j<xlatlabel.cNode; ++j)
515  {
516  UINT au;
517  fread(&au, sizeof(UINT),1,nFile);
518  xLabel.mNodeVector.push_back(au);
519  }
520 
521  xLabel.mNodeVector[xlatlabel.cNode] = -1;
522 
523  ExtendedString tmpName = xLabel.name;
524  tmpName.toUpper();
525  mLabelMap[tmpName] = xLabel;
526  mLabelVector.push_back(xLabel);
527  }
528 
529  // Initialize the mesh arrays
530  // (the first two mesh arrays are the x and y values, indexed by node)
531  // The other stuff, if it exists, is probably stuff that was
532  // defined to help refine the mesh, such as the doping concentration.
533  //
534  // Since the information contained in the x and y arrays are also
535  // contained inside the node array, I'm going to skip that part.
536  // The other arrays, however, might be useful, so I'm going to read
537  // those in.
538  //
539  UINT cArray;
540  fread(&cArray, sizeof(UINT),1,nFile);
541  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
542  Xyce::dout() << "About to read in the arrays. cArray = " << cArray << std::endl;
543 
544  // the first two arrays are x and y...
545  double xtmp;
546  for(i = 0; i < 2; ++i)
547  {
548  char szArrayName[LEN_IDENT+1];
549  fread(szArrayName, LEN_IDENT+1,1,nFile);
550  ExtendedString tmpName(szArrayName);
551  tmpName.toUpper ();
552  if (DEBUG_DEVICE)
553  {
554  Xyce::dout() << "i=" <<i<< " name = " << tmpName << std::endl;
555  }
556 
557  if (tmpName == "X")
558  {
559  xVector.reserve(meshhead.cNode);
560  for (j=0;j<meshhead.cNode; ++j)
561  {
562  fread(&xtmp, sizeof(double),1,nFile);
563  xVector.push_back(xtmp);
564  }
565  }
566  else if (tmpName == "Y")
567  {
568  yVector.reserve(meshhead.cNode);
569  for (j=0;j<meshhead.cNode; ++j)
570  {
571  fread(&xtmp, sizeof(double),1,nFile);
572  yVector.push_back(xtmp);
573  }
574  }
575  }
576 
577  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
578  {
579  Xyce::dout() << "Done reading x and y arrays.";
580  Xyce::dout() << " Reading the others, if they exist." << std::endl;
581  }
582 
583  // Now read and store the other arrays, if any:
584  if (meshhead.cArray > 2)
585  {
586  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
587  Xyce::dout() << "reading extra arrays..." << std::endl;
588  for(i = 2; i < meshhead.cArray; ++i)
589  {
590  char szArrayName[LEN_IDENT+1];
591  fread(szArrayName, LEN_IDENT+1,1,nFile);
592  ExtendedString tmpName(szArrayName);
593  tmpName.toUpper ();
594  if (tmpName == "C")
595  {
596  dopingVector.reserve(meshhead.cNode);
597  for (j=0;j<meshhead.cNode; ++j)
598  {
599  fread(&xtmp, sizeof(double),1,nFile);
600  dopingVector.push_back(xtmp);
601  }
602  dopingSet = true;
603  }
604  else
605  {
606  for (j=0;j<meshhead.cNode; ++j)
607  fread(&xtmp, sizeof(double),1,nFile);
608  }
609  }
610  }
611 
612  // Read the node array
613  UINT cNodes;
614  fread(&cNodes, sizeof(UINT),1,nFile);
615  mNode xNode;
616  numNodes = cNodes;
617 
618  numBndryNodes = meshhead.cBndryNode;
619  numRegLabels = meshhead.cRegLabel;
620 
621  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
622  Xyce::dout() << "About to read the nodes. cNodes = " << cNodes << std::endl;
623 
624  for (i=0;i<cNodes;++i)
625  {
626  NODE sgfNode;
627  fread(&sgfNode, sizeof(NODE),1,nFile);
628 
629  // copy this node information into the Xyce data structure, mNode:
630  xNode.x = sgfNode.x;
631  xNode.y = sgfNode.y;
632  mNodeVector.push_back(xNode);
633  }
634 
635  // read the edge array
636  UINT cEdge;
637  fread(&cEdge, sizeof(UINT),1,nFile);
638  mEdge xEdge;
639  numEdges = cEdge;
640 
641  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
642  Xyce::dout() << "About to read the edges. cEdge = " << cEdge << std::endl;
643 
644  for (i=0; i< cEdge; ++i)
645  {
646  EDGE sgfEdge;
647  fread(&sgfEdge, sizeof(EDGE),1,nFile);
648 
649  int inode1 = sgfEdge.inodeA;
650  int inode2 = sgfEdge.inodeB;
651 
652  if (inode1 > inode2)
653  {
654  sgfEdge.inodeA = inode2;
655  sgfEdge.inodeB = inode1;
656  }
657 
658  // copy this edge information into the Xyce data structure, mEdge:
659  xEdge.uLabel = sgfEdge.uLabel;
660  xEdge.inodeA = sgfEdge.inodeA;
661  xEdge.inodeB = sgfEdge.inodeB;
662  xEdge.iedge = i;
663 
664  mEdgeVector.push_back(xEdge);
665  }
666 
667  // Read the triangle array
668  UINT cTriangle;
669  fread(&cTriangle, sizeof(UINT),1,nFile);
670  mCell xCell;
671  numCells = cTriangle;
672 
673  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
674  Xyce::dout() << "About to read the cells. numCells = " << numCells << std::endl;
675  for (i=0;i<cTriangle;++i)
676  {
677  TRI Tri;
678  fread(&Tri, sizeof(TRI),1,nFile);
679 
680  // copy this tri information into the Xyce data structure, mCell:
681  xCell.uLabel = Tri.uLabel;
682 
683  xCell.iedgeAB = Tri.iedgeAB;
684  xCell.iedgeBC = Tri.iedgeBC;
685  xCell.iedgeCD = Tri.iedgeAC;
686  xCell.iedgeDA = Tri.iedgeAD;
687 
688  xCell.icellAB = Tri.itriAB;
689  xCell.icellBC = Tri.itriBC;
690  xCell.icellCD = Tri.itriAC;
691  xCell.icellDA = Tri.itriAD;
692 
693  mCellVector.push_back(xCell);
694  }
695 
696  // read the adjacency information
697  UINT cAdj;
698  fread(&cAdj, sizeof(UINT),1,nFile);
699  numAdj = cAdj;
700 
701  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
702  Xyce::dout() << "About to read the adjacency info. cAdj = " << cAdj << std::endl;
703  // Set up scaling factors for geometry.
704  double rDistScale = 1.0;
705  double X0_1 = rDistScale;
706  double X0_2 = rDistScale * X0_1;
707  double X0_3 = rDistScale * X0_2;
708 
709  double ScaleILEN, ScaleAREA, ScaleELEN = X0_1;
710 
711  cylGeom = meshhead.fCylGeom;
712  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
713  {
714  if (meshhead.fCylGeom) Xyce::dout() << "Cylindrical Geometry\n\n";
715  else Xyce::dout() << "Cartesian Geometry\n\n";
716  }
717 
718  if (meshhead.fCylGeom)
719  {
720  ScaleILEN = X0_2;
721  ScaleAREA = X0_3;
722  }
723  else
724  {
725  ScaleILEN = X0_1;
726  ScaleAREA = X0_2;
727  }
728 
729  // Note: cAdj (numAdj) may be larger than numNodes.
730  // The reason for this is that nodes along boundaries between
731  // regions have more than one adjacency info structure.
732  // ( Fix this later....)
733  //
734  // The formula used by simgen to get cAdj is:
735  // cAdj = cNode + cBndryNode * cRegLabel;
736  //
737  // cNode = number of nodes
738  // cBndryNode = number of nodes along boundaries between regions.
739  // cRegLabel = number of region labels, such as SI and SIO2.
740  //
741  for(i = 0; i < cAdj; ++i)
742  {
743  int inode;
744  fread(&inode, sizeof(int),1,nFile);
745 
746  NODEINFO nodeInfo;
747  fread( &nodeInfo, sizeof(NODEINFO) - sizeof(EDGEINFO *),1,nFile);
748  nodeInfo.Area /= ScaleAREA;
749  UINT cNeighbor = nodeInfo.cNeighbor;
750 
751  mNodeVector[inode].area = nodeInfo.Area;
752  mNodeVector[inode].cnode = cNeighbor;
753  mNodeVector[inode].inode = inode;
754  mNodeVector[inode].numCells = nodeInfo.cTriangle;
755 
756  EDGEINFO EdgeInfo;
757  for (j=0;j<cNeighbor;++j)
758  {
759  fread( &EdgeInfo, sizeof(EDGEINFO),1,nFile);
760  mNodeVector[inode].edgeInfoVector.push_back(EdgeInfo);
761  }
762 
763  for(j = 0; j < cNeighbor; ++j)
764  {
765  // Since I set rDistScale to 1.0, these scalings are kind of
766  // irrelevant. The distances scaling can technically be set from
767  // the mesh file, which is why I left these lines in here.
768  mNodeVector[inode].edgeInfoVector[j].ilen /= ScaleILEN;
769  mNodeVector[inode].edgeInfoVector[j].elen /= ScaleELEN;
770  mNodeVector[inode].edgeInfoVector[j].Area1 /= ScaleAREA;
771  mNodeVector[inode].edgeInfoVector[j].Area2 /= ScaleAREA;
772 
773  int iedge = mNodeVector[inode].edgeInfoVector[j].iedge;
774  mEdgeVector[iedge].elen = mNodeVector[inode].edgeInfoVector[j].elen;
775  mEdgeVector[iedge].ilen = mNodeVector[inode].edgeInfoVector[j].ilen;
776  mEdgeVector[iedge].Area1 = mNodeVector[inode].edgeInfoVector[j].Area1;
777  mEdgeVector[iedge].Area2 = mNodeVector[inode].edgeInfoVector[j].Area2;
778  }
779  }
780 
781  // close the file
782  fclose(nFile);
783 
784  return true;
785 }
786 
787 //-----------------------------------------------------------------------------
788 // Function : PDE_2DMesh::writeSGFMeshFile
789 // Purpose : This function writes a *.msh file , which is the format of
790 // the SGF meshing program. You would call this function if
791 // the mesh used was generated internally, but you wanted to
792 // use sgplot to view your results.
793 //
794 // Special Notes :
795 //
796 // Scope : public
797 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
798 // Creation Date : 10/04/02
799 //-----------------------------------------------------------------------------
800 bool PDE_2DMesh::writeSGFMeshFile (const std::string & meshFileName_tmp)
801 {
802  MESHHEAD meshhead;
803  int i,j;
804 
805  // open the mesh file
806  FILE *nFile = fopen(meshFileName_tmp.c_str(), "w");
807 
808  strcpy(meshhead.szLogo, "SGFramework Mesh File Version 1.0\n\x1a");
809  strcpy(meshhead.szSign, "@~!__MESH__!~@");
810 
811  meshhead.cConstant = 0; // no constants.
812  meshhead.cLabel = mLabelVector.size();
813  meshhead.cArray = 2; // arrays: x and y (maybe C also?)
814  meshhead.cRegLabel = numRegLabels; // usually just 1 of these...
815  meshhead.cBndryNode = numBndryNodes;
816  // fix this later!? The sgplot program doesn't care about the boundary
817  // node issue it does the same plotting whether it is a boundary node
818  // or not. Other SGF related programs do care, however, and for those
819  // programs, the boundary nodes need to be listed first.
820 
821  meshhead.cNode = numNodes;
822  meshhead.cEdge = numEdges;
823  meshhead.cTriangle = numCells;
824  meshhead.fCylGeom = cylGeom;
825  fwrite( &meshhead, sizeof(MESHHEAD), 1, nFile);
826 
827  // write the constants (should be zero of these...)
828  // sgplot will advance past them anyway, if they were there.
829  fwrite( &meshhead.cConstant, sizeof(UINT), 1, nFile);
830 
831  // write the labels:
832  fwrite( &meshhead.cLabel, sizeof(UINT), 1, nFile);
833  for (i=0;i<meshhead.cLabel;++i)
834  {
835  // output label itself
836  XLATLABEL xlabel;
837  strcpy(xlabel.szName, mLabelVector[i].name.c_str());
838  xlabel.iIndex = mLabelVector[i].iIndex;
839  xlabel.uType = mLabelVector[i].uType;
840  xlabel.cNode = mLabelVector[i].cNode;
841  fwrite(&xlabel,sizeof(XLATLABEL) ,1,nFile);
842 
843  // output node list for this label
844  // these are skipped by sgplot.
845  for (j=0;j<xlabel.cNode;++j)
846  {
847  UINT istuf = mLabelVector[i].mNodeVector[j];
848  fwrite(&istuf, sizeof(UINT), 1, nFile);
849  }
850  }
851 
852  // write the 1D arrays:
853  // write the x and y coordinate arrays
854  // cArray, for some reason, is actually the true number of arrays -2.
855  // sgplot, etc., assumes there will always be x and y arrays, so the
856  // the variable cArray is only for "extra" arrays. Seems needlessly
857  // confusing to me...
858  UINT cArray = 0;
859  fwrite( &cArray, sizeof(UINT),1,nFile);
860  char szCoord1[LEN_IDENT+1];
861  strcpy(szCoord1, "X");
862  fwrite( szCoord1, (LEN_IDENT+1), 1, nFile);
863 
864  for(i = 0; i < numNodes; ++i)
865  {
866  fwrite( &(xVector[i]), sizeof(double), 1, nFile);
867  }
868 
869  char szCoord2[LEN_IDENT+1];
870  strcpy(szCoord2, "Y");
871  fwrite( szCoord2, (LEN_IDENT+1), 1, nFile);
872  for(i = 0; i < numNodes; ++i)
873  {
874  fwrite( &(yVector[i]), sizeof(double), 1, nFile);
875  }
876 
877  // write the nodes:
878  // As the nodes are mostly redundant with the x and y arrays, which
879  // were just output, sgplot will skip over the nodes.
880  fwrite( &meshhead.cNode, sizeof(UINT), 1, nFile);
881  for (i=0;i<meshhead.cNode;++i)
882  {
883  NODE n1;
884  n1.x = xVector[i]; n1.y = yVector[i];
885  fwrite(&n1, sizeof(NODE), 1, nFile);
886  }
887 
888  // write the edges:
889  fwrite( &meshhead.cEdge, sizeof(UINT), 1, nFile);
890  for (i=0;i<meshhead.cEdge;++i)
891  {
892  EDGE e1;
893  e1.uLabel = mEdgeVector[i].uLabel;
894  e1.inodeA = mEdgeVector[i].inodeA;
895  e1.inodeB = mEdgeVector[i].inodeB;
896  fwrite( &e1, sizeof(EDGE), 1, nFile);
897  }
898 
899  // write the triangles (cells):
900  fwrite(&meshhead.cTriangle, sizeof(UINT),1,nFile);
901 
902  // valgrind reports an error in this loop for some reason. I can't
903  // figure out why.
904  for(i = 0; i < meshhead.cTriangle; ++i)
905  {
906  TRI t1;
907 
908  int tmp = mCellVector[i].uLabel;
909 
910  if (tmp < 0) t1.uLabel = -1u;
911  else t1.uLabel = static_cast<unsigned int>(tmp);
912 
913  t1.iedgeAB = mCellVector[i].iedgeAB;
914  t1.iedgeBC = mCellVector[i].iedgeBC;
915  t1.iedgeAC = mCellVector[i].iedgeCD;
916  t1.iedgeAD = mCellVector[i].iedgeDA;
917 
918  t1.itriAB = mCellVector[i].icellAB;
919  t1.itriBC = mCellVector[i].icellBC;
920  t1.itriAC = mCellVector[i].icellCD;
921  t1.itriAD = mCellVector[i].icellDA;
922 
923  fwrite(&t1, sizeof(TRI), 1, nFile);
924  }
925 
926  // write the node adjacency table:
927  // This part isn't read in by sgplot, so it probably isn't neccessary.
928  // But, what the heck, maybe it will be useful at some point.
929  fwrite(&numNodes, sizeof(UINT), 1, nFile);
930  for (i=0;i<numNodes;++i)
931  {
932  UINT inode = i;
933  fwrite(&inode, sizeof(UINT),1,nFile);
934  NODEINFO nodeinfo;
935  // fill in nodeinfo w/information from mNode class.
936  nodeinfo.Area = mNodeVector[i].area;
937  nodeinfo.cNeighbor = mNodeVector[i].cnode;
938  nodeinfo.cTriangle = mNodeVector[i].numCells;
939 
940  fwrite(&nodeinfo,sizeof(NODEINFO)-sizeof(EDGEINFO *),1,nFile);
941 
942  for (j=0;j<mNodeVector[i].cnode;++j)
943  {
944  EDGEINFO edgeinfo = mNodeVector[i].edgeInfoVector[j];
945  fwrite(&edgeinfo,sizeof(EDGEINFO),1,nFile);
946  }
947  }
948 
949  // close the file
950  fclose(nFile);
951 
952  return true;
953 }
954 
955 //-----------------------------------------------------------------------------
956 // Function : PDE_2DMesh::initializeInternalMesh
957 //
958 // Purpose : This function initializes a simple cartesian mesh,
959 // as well as many of the geometry-related variables.
960 //
961 // Special Notes : This function is called if the user has specified
962 // that the mesh file name is "internal". In other words,
963 // there is no external mesh file.
964 //
965 // Scope : public
966 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
967 // Creation Date : 04/21/02
968 //-----------------------------------------------------------------------------
970  (int nx,
971  int ny,
972  double xlength,
973  double ylength,
974  int numElectrodes,
975  std::string & outputMeshFileName,
976  std::map<std::string,PDE_2DElectrode*> & elMap,
977  bool cylFlag)
978 {
979  bool bsuccess = true;
980  bool tmpBool = true;
981 
982  cylGeom = cylFlag;
983 
984  externalMeshFlag = false;
985 
986  meshFileName = outputMeshFileName; // this variable is used for output.
987 
988  bsuccess = setupInternalMesh (nx,ny,xlength,ylength);
989 
990  // If the user has not specified electrodes, then assume a default set,
991  // and call setupDefaultLabels. Need to do a little error checking
992  // first.
993  if ( !(elMap.empty()) )
994  {
995  tmpBool = errorCheckElectrodes (numElectrodes, elMap);
996  bsuccess = bsuccess && tmpBool;
997  }
998 
999  if ( useDefaultLabels )
1000  {
1001  tmpBool = setupDefaultLabels(numElectrodes);
1002  bsuccess = bsuccess && tmpBool;
1003  }
1004  else
1005  {
1006  tmpBool = setupInternalLabels(numElectrodes, elMap);
1007  bsuccess = bsuccess && tmpBool;
1008  }
1009 
1010  // set up extra data structures:
1011 
1012  // set up cell Node lists:
1013  tmpBool = cellNodes();
1014  bsuccess = bsuccess && tmpBool;
1015 
1016  // set up node nearest neighbor lists:
1017 
1018  // calculate geometry information:
1019  tmpBool = setupGeometry ();
1020  bsuccess = bsuccess && tmpBool;
1021 
1022  visitCellFlagVec.resize(numCells,0);
1023 
1024  if (DEBUG_DEVICE && isActive(Diag::DEVICE_DUMP_VECTORS))
1025  {
1026  dumpMesh ();
1027  }
1028 
1029  if (sgplotLevel > 0)
1030  {
1031  tmpBool = writeSGFMeshFile (outputMeshFileName);
1032  bsuccess = bsuccess && tmpBool;
1033  }
1034 
1035  return bsuccess;
1036 }
1037 
1038 //-----------------------------------------------------------------------------
1039 // Function : PDE_2DMesh::resizeMesh
1040 // Purpose : This function resizes the mesh to a new length and
1041 // width.
1042 //
1043 // Special Notes : This function has a similar function to that of
1044 // scaleMesh. However, unlike scaleMesh, the x-scaling and
1045 // y-scaling can be different. Unfortunately, that makes
1046 // the work of this function more complicated. Instead of
1047 // simply scaling areas, it is neccessary to recompute
1048 // them.
1049 //
1050 // Scope : public
1051 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1052 // Creation Date : 11/25/02
1053 //-----------------------------------------------------------------------------
1054 bool PDE_2DMesh::resizeMesh(double xlength, double ylength)
1055 {
1056 
1057  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1058  {
1059  Xyce::dout() << "In PDE_2DMesh:resizeMesh." << std::endl;
1060  }
1061 
1062  double old_xlength = xMax-xMin;
1063  double old_ylength = yMax-yMin;
1064 
1065  xRatio = xlength/(old_xlength);
1066  yRatio = ylength/(old_ylength);
1067 
1068  // xMin and yMin will stay in the same place, while xMax and yMax move.
1069  xMax = xMin + xlength;
1070  yMax = yMin + ylength;
1071 
1072  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1073  {
1074  Xyce::dout() << " xMax = " << xMax << std::endl;
1075  Xyce::dout() << " yMax = " << yMax << std::endl;
1076  }
1077 
1078  // Adjust the x and y arrays:
1079  int i;
1080  for (i=0;i<numNodes;++i)
1081  {
1082  xVector[i] -= xMin;
1083  xVector[i] *= xRatio;
1084  xVector[i] += xMin;
1085 
1086  yVector[i] -= yMin;
1087  yVector[i] *= yRatio;
1088  yVector[i] += yMin;
1089 
1090  mNodeVector[i].x = xVector[i];
1091  mNodeVector[i].y = yVector[i];
1092 
1093  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1094  {
1095  Xyce::dout() << "\txVec["<<i<<"] = " << xVector[i];
1096  Xyce::dout() << "\tyVec["<<i<<"] = " << yVector[i] << std::endl;
1097  }
1098  }
1099 
1100  // resize everything else:
1101  calcAdjacencyInfo ();
1102 
1103  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1104  {
1105  Xyce::dout() << "Done with PDE_2DMesh:resizeMesh." << std::endl;
1106  }
1107 
1108  return true;
1109 }
1110 
1111 //-----------------------------------------------------------------------------
1112 // Function : PDE_2DMesh::setupInternalMesh
1113 // Purpose : This function sets up a simple default mesh. It is only
1114 // called in the event that the user has not specified a file.
1115 //
1116 // Special Notes : The default mesh is a nx x ny cartesian mesh.
1117 //
1118 // First, the code sets up a simple grid of nodes, edges
1119 // and cells.
1120 //
1121 // After getting the grid in place, it then calculates the
1122 // geometrical information, such as edge lengths,
1123 // integration box areas, etc. For a cartesian grid like
1124 // this, this sort of information is pretty obvious.
1125 //
1126 // Scope : private
1127 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1128 // Creation Date : 04/21/02
1129 //-----------------------------------------------------------------------------
1131  int nx, int ny, double xlength, double ylength)
1132 {
1133  int i,j;
1134  ixMax = nx;
1135  iyMax = ny;
1136 
1137  numNodes = ixMax*iyMax;
1138 
1139  numRegLabels = 1;
1140 
1141  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1142  Xyce::dout() << "In setupInternalMesh"<<std::endl;
1143 
1144  xMax = xlength; xMin = 0.0;
1145  yMax = ylength; yMin = 0.0;
1146 
1147  dx = xMax/(static_cast<double>(ixMax-1));
1148  dy = yMax/(static_cast<double>(iyMax-1));
1149 
1150  // the "+10" is just for safety purposes.
1151  nodeIndices = new int*[ixMax+10];
1152  for (i=0;i<ixMax+10;++i)
1153  {
1154  nodeIndices[i] = new int[iyMax+10];
1155 
1156  for (j=0;j<iyMax+10;++j)
1157  {
1158  nodeIndices[i][j] = -1;
1159  }
1160  }
1161 
1162  // set up the node vector
1163  int nodeIndex = 0;
1164  numBndryNodes = 0; // if only 1 region, this should stay zero.
1165 
1166  for (i=0;i<ixMax;++i)
1167  {
1168  for (j=0;j<iyMax;++j)
1169  {
1170  mNode n1;
1171  n1.x = dx*(static_cast<double>(i));
1172  n1.y = dy*(static_cast<double>(j));
1173 
1174  nodeIndices[i][j] = nodeIndex;
1175 
1176  ++nodeIndex;
1177  if (i==0 || j==0 || i==ixMax-1 || j==iyMax-1)
1178  {
1180  }
1181  else
1182  {
1184  }
1185 
1186  mNodeVector.push_back(n1);
1187  }
1188  }
1189  numNodes = nodeIndex;
1190  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1191  {
1192  Xyce::dout() << "\nDone with Node vector" << std::endl;
1193  }
1194 
1195  edgeIndices = new int*[numNodes+10];
1196  for (i=0;i<numNodes+10;++i)
1197  {
1198  edgeIndices[i] = new int[numNodes+10];
1199 
1200  for (j=0;j<numNodes+10;++j)
1201  {
1202  edgeIndices[i][j] = -1;
1203  }
1204  }
1205 
1206  // set up the edge vector
1207  int edgeIndex = 0;
1208 
1209  for (i=0;i<ixMax;++i)
1210  {
1211  for (j=0;j<iyMax;++j)
1212  {
1213  // edges parallel to the y-axis.
1214  if (j>0)
1215  {
1216  mEdge edge1;
1217  edge1.uLabel = -1;
1218 
1219  // note: inodeA should always be smaller than inodeB!
1220  edge1.inodeA = nodeIndices[i][j ];
1221  edge1.inodeB = nodeIndices[i][j-1];
1222 
1223  if (edge1.inodeA > edge1.inodeB)
1224  {
1225  edge1.inodeB = nodeIndices[i][j ];
1226  edge1.inodeA = nodeIndices[i][j-1];
1227  }
1228 
1229  if (mNodeVector[edge1.inodeA].edgeStatus ==
1230  mNodeVector[edge1.inodeB].edgeStatus)
1231  {
1232  edge1.edgeStatus = mNodeVector[edge1.inodeA].edgeStatus;
1233  }
1234 
1235  if (edge1.inodeA == -1 || edge1.inodeB == -1)
1236  {
1237  if (DEBUG_DEVICE)
1238  {
1239  Xyce::dout() << " edge1.inodeA = " << edge1.inodeA;
1240  Xyce::dout() << " edge1.inodeB = " << edge1.inodeB <<std::endl;
1241  }
1242  Report::DevelFatal() << "Failed on edge1";
1243  }
1244 
1245  edgeIndices[edge1.inodeA][edge1.inodeB] = edgeIndex;
1246  edgeIndices[edge1.inodeB][edge1.inodeA] = edgeIndex;
1247 
1248  mEdgeVector.push_back(edge1);
1249  ++edgeIndex;
1250  }
1251 
1252  // edges parallel to the x-axis.
1253  if (i>0)
1254  {
1255  mEdge edge2;
1256  edge2.uLabel = -1;
1257 
1258  // note: inodeA should always be smaller than inodeB!
1259  edge2.inodeA = nodeIndices[i ][j];
1260  edge2.inodeB = nodeIndices[i-1][j];
1261 
1262  if (edge2.inodeA > edge2.inodeB)
1263  {
1264  edge2.inodeB = nodeIndices[i ][j];
1265  edge2.inodeA = nodeIndices[i-1][j];
1266  }
1267 
1268  if (mNodeVector[edge2.inodeA].edgeStatus ==
1269  mNodeVector[edge2.inodeB].edgeStatus)
1270  {
1271  edge2.edgeStatus = mNodeVector[edge2.inodeA].edgeStatus;
1272  }
1273 
1274  if (edge2.inodeA == -1 || edge2.inodeB == -1)
1275  {
1276  if (DEBUG_DEVICE)
1277  {
1278  Xyce::dout() << " edge2.inodeA = " << edge2.inodeA;
1279  Xyce::dout() << " edge2.inodeB = " << edge2.inodeB <<std::endl;
1280  }
1281  Report::DevelFatal() << "Failed on edge2";
1282  }
1283 
1284  edgeIndices[edge2.inodeA][edge2.inodeB] = edgeIndex;
1285  edgeIndices[edge2.inodeB][edge2.inodeA] = edgeIndex;
1286 
1287  mEdgeVector.push_back(edge2);
1288  ++edgeIndex;
1289  }
1290  }
1291  }
1292 
1293  numEdges = edgeIndex;
1294  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1295  {
1296  Xyce::dout() << "Done with Edge vector" << std::endl;
1297  }
1298 
1299  // set up the cell vector:
1300  int cellIndex = 0;
1301  cellIndices = new int *[ixMax+10];
1302  for (i=0;i<ixMax+10;++i)
1303  {
1304  cellIndices[i] = new int[iyMax+10];
1305  for (j=0;j<iyMax+10;++j)
1306  cellIndices[i][j] = -1;
1307  }
1308 
1309  for (i=1; i<ixMax; ++i)
1310  {
1311  for (j=1;j<iyMax;++j)
1312  {
1313  // All these cells are cartesean rectangles:
1314  //
1315  // A B
1316  // (i-1, j-1) --------- (i , j-1)
1317  // | |
1318  // | |
1319  // | |
1320  // | |
1321  // | |
1322  // (i-1, j ) --------- (i , j )
1323  // D C
1324  //
1325  int inodeA, inodeB, inodeC, inodeD;
1326 
1327  inodeA = nodeIndices[i-1][j-1];
1328  inodeB = nodeIndices[i ][j-1];
1329  inodeC = nodeIndices[i ][j ];
1330  inodeD = nodeIndices[i-1][j ];
1331 
1332  mCell c1;
1333  c1.iedgeAB = edgeIndices[inodeA][inodeB];
1334  c1.iedgeBC = edgeIndices[inodeB][inodeC];
1335  c1.iedgeCD = edgeIndices[inodeC][inodeD];
1336  c1.iedgeDA = edgeIndices[inodeD][inodeA];
1337 
1338  c1.inodeA = inodeA;
1339  c1.inodeB = inodeB;
1340  c1.inodeC = inodeC;
1341  c1.inodeD = inodeD;
1342 
1343  // Assumes always has SI label. See setupInternalLabels.
1344  c1.uLabel = 0;
1345 
1346  mCellVector.push_back(c1);
1347  cellIndices[i][j] = cellIndex;
1348 
1349  ++cellIndex;
1350  }
1351  }
1352  numCells = cellIndex;
1353  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1354  {
1355  Xyce::dout() << "Done with Cell vector" << std::endl;
1356  }
1357 
1358  // set up the neighbor cells. If we go off the mesh, the
1359  // value in the indices array is -1 anyway, so there will
1360  // be no problem.
1361  for (i=1; i<ixMax; ++i)
1362  {
1363  for (j=1;j<iyMax;++j)
1364  {
1365  int cellIndexTmp = cellIndices[i][j];
1366  mCellVector[cellIndexTmp].icellAB = cellIndices[i ][j-1];
1367  mCellVector[cellIndexTmp].icellBC = cellIndices[i+1][j ];
1368  mCellVector[cellIndexTmp].icellCD = cellIndices[i ][j+1];
1369  mCellVector[cellIndexTmp].icellDA = cellIndices[i-1][j ];
1370  }
1371  }
1372  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1373  {
1374  Xyce::dout() << "Done with Cell neighbors." << std::endl;
1375  }
1376 
1377  // if neccessary re-order nodes, edges, etc. SGF always orders
1378  // nodes in the following manner:
1379  // 1) all region boundary nodes
1380  // 2) all exterior boundary nodes, which are not region boundary nodes.
1381  // 3) all interior nodes.
1382  // NOT DONE YET...
1383 
1384  // copy over the x and y info into the xVector and yVector data
1385  // structures.
1386  xVector.reserve(numNodes);
1387  yVector.reserve(numNodes);
1388  for (i=0;i<numNodes;++i)
1389  {
1390  xVector.push_back(mNodeVector[i].x);
1391  yVector.push_back(mNodeVector[i].y);
1392  }
1393 
1394  // now that the grid relationships are established, now get the
1395  // edge lengths, areas, etc.
1396  calcAdjacencyInfo ();
1397 
1398  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1399  {
1400  Xyce::dout() << "Done with setupInternalMesh\n";
1401  }
1402 
1403  return true;
1404 }
1405 
1406 //-----------------------------------------------------------------------------
1407 // Function : PDE_2DMesh::setupInternalAdjacencyInfo
1408 //
1409 // Purpose : This function is being phased out. Eventually,
1410 // calcAdjacencyInfo will be the one to call, once it has
1411 // been adequately refactored.
1412 //
1413 // This function calculates adjacency information, but can
1414 // only do it right if the mesh is cartesian.
1415 //
1416 // Special Notes :
1417 // Scope : private
1418 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1419 // Creation Date : 11/30/02
1420 //-----------------------------------------------------------------------------
1422 {
1423  int i,j;
1424 
1425  if (DEBUG_DEVICE)
1426  {
1427  Xyce::dout() << "In PDE_2DMesh::setupInternalAdjacencyInfo." << std::endl;
1428  }
1429 
1430  // first do some of the edge information.
1431  for (i=0;i<numEdges;++i)
1432  {
1433  mEdge & edgeTmp = mEdgeVector[i];
1434  int inodeA = edgeTmp.inodeA;
1435  int inodeB = edgeTmp.inodeB;
1436 
1437  double DELx = fabs(xVector[inodeA]-xVector[inodeB]);
1438  double DELy = fabs(yVector[inodeA]-yVector[inodeB]);
1439 
1440  // assuming cartesian, as before.
1441  if (DELy > DELx) // y-axis parallel
1442  {
1443  edgeTmp.elen = dy;
1444  edgeTmp.ilen = dx;
1445  }
1446  else // x-axis parallel
1447  {
1448  edgeTmp.elen = dx;
1449  edgeTmp.ilen = dy;
1450  }
1451 
1452  if (edgeTmp.edgeStatus==EDGESTATUS_EXTERIOR)
1453  {
1454  edgeTmp.ilen *= 0.5;
1455  }
1456 
1457  edgeTmp.Area1 = (edgeTmp.elen * edgeTmp.ilen) * 0.25;
1458  edgeTmp.Area2 = 0.0; // need to fix Area2 later!
1459  }
1460 
1461  // Now do the "edgeinfo" information, which is owned by each node.
1462  // Get nearest neighbor node information, edgeinfo array stuff, etc.:
1463  // Set the area of the integration box as well.
1464  if (DEBUG_DEVICE)
1465  {
1466  Xyce::dout() << "About to do the edgeinfo:" << std::endl;
1467  }
1468 
1469  for (i=0;i<ixMax;++i)
1470  {
1471  for (j=0;j<iyMax;++j)
1472  {
1473  int node = nodeIndices[i][j];
1474  mNodeVector[node].area = dx*dy;
1475 
1476  mNodeVector[node].fBndry = false;
1477 
1478  if (i==0 || i==ixMax-1)
1479  {
1480  mNodeVector[node].area *= 0.5;
1481  }
1482 
1483  if (j==0 || j==iyMax-1)
1484  {
1485  mNodeVector[node].area *= 0.5;
1486  }
1487 
1488  int nnTmp;
1489  int edgeTmp;
1490  int cnodeTmp = 0;
1491  EDGEINFO eiTmp;
1492 
1493  if (i<ixMax-1)
1494  {
1495  nnTmp = nodeIndices[i+1][j];
1496  edgeTmp = edgeIndices[node][nnTmp];
1497  eiTmp.inode = nnTmp;
1498  eiTmp.iedge = edgeTmp;
1499  eiTmp.elen = mEdgeVector[edgeTmp].elen;
1500  eiTmp.ilen = mEdgeVector[edgeTmp].ilen;
1501  mNodeVector[node].edgeInfoVector.push_back(eiTmp);
1502  ++cnodeTmp;
1503  }
1504 
1505  if (j<iyMax-1)
1506  {
1507  nnTmp = nodeIndices[i][j+1];
1508  edgeTmp = edgeIndices[node][nnTmp];
1509  eiTmp.inode = nnTmp;
1510  eiTmp.iedge = edgeTmp;
1511  eiTmp.elen = mEdgeVector[edgeTmp].elen;
1512  eiTmp.ilen = mEdgeVector[edgeTmp].ilen;
1513  mNodeVector[node].edgeInfoVector.push_back(eiTmp);
1514  ++cnodeTmp;
1515  }
1516 
1517  if (i>0)
1518  {
1519  nnTmp = nodeIndices[i-1][j];
1520  edgeTmp = edgeIndices[node][nnTmp];
1521  eiTmp.inode = nnTmp;
1522  eiTmp.iedge = edgeTmp;
1523  eiTmp.elen = mEdgeVector[edgeTmp].elen;
1524  eiTmp.ilen = mEdgeVector[edgeTmp].ilen;
1525  mNodeVector[node].edgeInfoVector.push_back(eiTmp);
1526  ++cnodeTmp;
1527  }
1528 
1529  if (j>0)
1530  {
1531  nnTmp = nodeIndices[i][j-1];
1532  edgeTmp = edgeIndices[node][nnTmp];
1533  eiTmp.inode = nnTmp;
1534  eiTmp.iedge = edgeTmp;
1535  eiTmp.elen = mEdgeVector[edgeTmp].elen;
1536  eiTmp.ilen = mEdgeVector[edgeTmp].ilen;
1537  mNodeVector[node].edgeInfoVector.push_back(eiTmp);
1538  ++cnodeTmp;
1539  }
1540  mNodeVector[node].cnode = cnodeTmp;
1541 
1542  } // j
1543  } // i
1544  if (DEBUG_DEVICE)
1545  {
1546  Xyce::dout() << "Done doing the edgeinfo:" << std::endl;
1547  }
1548 
1549  return true;
1550 }
1551 
1552 //-----------------------------------------------------------------------------
1553 // Function : PDE_2DMesh::errorCheckElectrodes
1554 //
1555 // Purpose : This function checks that the user specification of
1556 // electrodes is consistent.
1557 //
1558 // Special Notes :
1559 //
1560 // Scope : private
1561 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1562 // Creation Date : 08/18/03
1563 //-----------------------------------------------------------------------------
1565  (int numElectrodes, std::map<std::string,PDE_2DElectrode*> & elMap)
1566 {
1567  bool bsuccess = true;
1568 
1569  // check that numElectrodes = elMap size.
1570  if (numElectrodes != elMap.size())
1571  {
1572  bsuccess = false;
1573  std::string msg("Number of electrodes and number of nodes are not equal.\n");
1574  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
1575  }
1576 
1577 
1578  // Check if the "start", "end" and "side" parameters
1579  // have been set or not. Either they all should be set, for every
1580  // electrode, or none of them. If all set, then use the
1581  // setupInternalLabels function (later), if none set, then use the
1582  // setupDefaultLabels function.
1583 
1584  bool allSet = true;
1585  bool allNotSet = true;
1586  useDefaultLabels = false;
1587 
1588  std::map<std::string, PDE_2DElectrode*>::iterator mapIter;
1589  std::map<std::string, PDE_2DElectrode*>::iterator mapStart = elMap.begin();
1590  std::map<std::string, PDE_2DElectrode*>::iterator mapEnd = elMap.end();
1591 
1592  for ( mapIter = mapStart; mapIter != mapEnd; ++mapIter )
1593  {
1594  PDE_2DElectrode & el = *(mapIter->second);
1595 
1596  allSet = allSet && (el.given("START") && el.given("END") && el.given("SIDE"));
1597  allNotSet = allNotSet &&
1598  (!(el.given("START")) && !(el.given("END")) && !(el.given("SIDE")));
1599  }
1600 
1601  if (!allSet && !allNotSet)
1602  {
1603  bsuccess = false;
1604  std::string msg("Some electrodes have start, end and side specified,\nsome don't. ");
1605  msg += "Either specify start, end and side for\nall electrodes, or none.\n";
1606  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
1607  }
1608 
1609  // if "allNotSet", then set the flag which will force the code to call
1610  // setupDefaultLabels.
1611  if (allNotSet)
1612  {
1613  useDefaultLabels = true;
1614  }
1615 
1616  return bsuccess;
1617 }
1618 
1619 //-----------------------------------------------------------------------------
1620 // Function : PDE_2DMesh::setupDefaultLabels
1621 //
1622 // Purpose : This function sets up the label vector, and assumes a
1623 // hardwired set of labels that are uniquely determined by
1624 // the number of electrodes.
1625 //
1626 // If you have 2 electrodes, this is a SI diode with an
1627 // ANODE and CATHODE and NOFLUX edge boundaries.
1628 //
1629 // If you have 3 electrodes, this is a silicon (SI) BJT,
1630 // with an EMITTER, COLLECTOR, BASE, and NOFLUX. (not
1631 // set up yet).
1632 //
1633 // If you specify 4 electrodes, then this is a MOSFET, and
1634 // the labels are: SI, SOURCE, GATE, DRAIN, SUB, NOFLUX
1635 //
1636 // Special Notes :
1637 // Scope : private
1638 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1639 // Creation Date : 04/23/02
1640 //-----------------------------------------------------------------------------
1641 bool PDE_2DMesh::setupDefaultLabels(int numberElectrodes)
1642 {
1643  // set up the silicon region label. This will always be here.
1644  int i,j;
1645  mLabel xLabel;
1646  ExtendedString tmpName = "SI";
1647  int nodeTmp = 0;
1648 
1649  xLabel.name = "SI";
1650  xLabel.iIndex = 0;
1651  xLabel.uType = TYPE_REGION;
1652 
1653  // This assumes every node in the mesh is SI, except for the edges.
1654  xLabel.mNodeVector.reserve(ixMax*iyMax); // just to be safe, reserve extra
1655 
1656  // fill in all the nodes:
1657  nodeTmp = 0;
1658  for (i=1;i<ixMax-1;++i)
1659  {
1660  for (j=1;j<iyMax-1;++j)
1661  {
1662  xLabel.mNodeVector.push_back(nodeIndices[i][j]);
1663  ++nodeTmp;
1664  }
1665  }
1666  xLabel.cNode = xLabel.mNodeVector.size ();
1667 
1668  tmpName = xLabel.name;
1669  tmpName.toUpper();
1670  mLabelMap[tmpName] = xLabel;
1671 
1672  mLabelVector.push_back(xLabel);
1673 
1674 
1675 
1676  // Now do the edge labels:
1677  if (numberElectrodes==2)
1678  {
1679  numLabels = 4; // SI, ANODE, CATHODE, NOFLUX.
1680 
1681  // do the Anode:
1682  xLabel.mNodeVector.clear();
1683  xLabel.name = "ANODE";
1684  xLabel.iIndex = 1;
1685  xLabel.uType = TYPE_EDGE;
1686  xLabel.cNode = ixMax;
1687  xLabel.mNodeVector.reserve(xLabel.cNode+1);
1688 
1689  // fill in all the nodes:
1690  nodeTmp = 0;
1691  j=0;
1692  for (i=0;i<ixMax;++i)
1693  {
1694  int inode = nodeIndices[i][j];
1695  xLabel.mNodeVector.push_back(inode);
1696  ++nodeTmp;
1697  }
1698 
1699  tmpName = xLabel.name;
1700  tmpName.toUpper();
1701  mLabelMap[tmpName] = xLabel;
1702 
1703 #if 0
1704  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1705  {
1706  Xyce::dout() << "Right before pushing back the ANODE label." << std::endl;
1707  for (i=0;i<xLabel.mNodeVector.size();++i)
1708  {
1709  cout << "Node: " << i << " = " << xLabel.mNodeVector[i];
1710  cout << std::endl;
1711  }
1712  }
1713 #endif
1714  mLabelVector.push_back(xLabel);
1715 
1716  // do the Cathode:
1717  xLabel.mNodeVector.clear();
1718  xLabel.name = "CATHODE";
1719  xLabel.iIndex = 2;
1720  xLabel.uType = TYPE_EDGE;
1721  xLabel.cNode = ixMax;
1722  xLabel.mNodeVector.reserve(xLabel.cNode+1);
1723 
1724  // fill in all the nodes:
1725  nodeTmp = 0;
1726  j=iyMax-1;
1727  for (i=0;i<ixMax;++i)
1728  {
1729  int inode = nodeIndices[i][j];
1730  xLabel.mNodeVector.push_back(inode);
1731  ++nodeTmp;
1732  }
1733 
1734  tmpName = xLabel.name;
1735  tmpName.toUpper();
1736  mLabelMap[tmpName] = xLabel;
1737 
1738 #if 0
1739  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1740  {
1741  Xyce::dout() << "Right before pushing back the CATHODE label." << std::endl;
1742  for (i=0;i<xLabel.mNodeVector.size();++i)
1743  {
1744  cout << "Node: " << i << " = " << xLabel.mNodeVector[i];
1745  cout << std::endl;
1746  }
1747  }
1748 #endif
1749 
1750  mLabelVector.push_back(xLabel);
1751 
1752  // set up NOFLUX:
1753  xLabel.mNodeVector.clear();
1754  xLabel.name = "NOFLUX";
1755  xLabel.iIndex = 3;
1756  xLabel.uType = TYPE_EDGE;
1757  xLabel.cNode = 2*iyMax-2;
1758  xLabel.mNodeVector.reserve(xLabel.cNode+1);
1759 
1760  // fill in all the nodes:
1761  nodeTmp = 0;
1762  i=0;
1763  for (j=1;j<iyMax-1;++j)
1764  {
1765  int inode = nodeIndices[i][j];
1766  xLabel.mNodeVector.push_back(inode);
1767  ++nodeTmp;
1768  }
1769  i=ixMax-1;
1770  for (j=1;j<iyMax-1;++j)
1771  {
1772  int inode = nodeIndices[i][j];
1773  xLabel.mNodeVector.push_back(inode);
1774  ++nodeTmp;
1775  }
1776 
1777  tmpName = xLabel.name;
1778  tmpName.toUpper();
1779  mLabelMap[tmpName] = xLabel;
1780 
1781 #if 0
1782  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
1783  {
1784  Xyce::dout() << "Right before pushing back the NOFLUX label." << std::endl;
1785  for (i=0;i<xLabel.mNodeVector.size();++i)
1786  {
1787  Xyce::dout() << "Node: " << i << " = " << xLabel.mNodeVector[i];
1788  Xyce::dout() << std::endl;
1789  }
1790  }
1791 #endif
1792  mLabelVector.push_back(xLabel);
1793 
1794  // Also assign labels to the edges in mEdgeVector.
1795  // Note: labels were already assigned to the cells in mCellVector, up
1796  // in setupInternalMesh.
1797  // Also, nodes don't get labels.
1798 
1799  j=0;
1800  for (i=1;i<ixMax;++i)
1801  {
1802  int n1 = nodeIndices[i ][j];
1803  int n2 = nodeIndices[i-1][j];
1804 
1805  int e1 = edgeIndices[n1][n2];
1806 
1807  mEdgeVector[e1].uLabel = 1; // ANODE index
1808  }
1809 
1810  j=iyMax-1;
1811  for (i=1;i<ixMax;++i)
1812  {
1813  int n1 = nodeIndices[i ][j];
1814  int n2 = nodeIndices[i-1][j];
1815 
1816  int e1 = edgeIndices[n1][n2];
1817 
1818  mEdgeVector[e1].uLabel = 2; // CATHODE index
1819  }
1820 
1821  i=0;
1822  for (j=1;j<iyMax;++j)
1823  {
1824  int n1 = nodeIndices[i][j];
1825  int n2 = nodeIndices[i][j-1];
1826 
1827  int e1 = edgeIndices[n1][n2];
1828 
1829  mEdgeVector[e1].uLabel = 3; // NOFLUX index
1830  }
1831 
1832  i=ixMax-1;
1833  for (j=1;j<iyMax;++j)
1834  {
1835  int n1 = nodeIndices[i][j];
1836  int n2 = nodeIndices[i][j-1];
1837 
1838  int e1 = edgeIndices[n1][n2];
1839 
1840  mEdgeVector[e1].uLabel = 3; // NOFLUX index
1841  }
1842  } // end of numberElectrodes==2
1843  else if (numberElectrodes==3)
1844  {
1845  // Assuming a BJT mesh:
1846  // Ratios: AB = 1/10
1847  // BC = 2/10
1848  // CD = 1/10
1849  // DE = 3/10
1850  // EF = 1/10
1851  // FG = 2/10
1852  //
1853  // So, hopefully, the number of mesh cells is
1854  // easily divisible by 10. The default mesh spacing will work.
1855  //
1856  // emitter noflux base noflux collector noflux
1857  // A-----B--------C-----D-------------E-----F---------G
1858  // | | / | | | | | |
1859  // n |-----|- | | / | | |
1860  // o | | | | / | | |
1861  // f |-----|--------|-----|- | | | noflux
1862  // l | | | | | | |
1863  // u | | | | | | |
1864  // x | | | | | | |
1865  // H-----I--------J-----K-------------L-----M---------N
1866  // noflux
1867  //
1868 
1869  int iA = 0;
1870  int iB = static_cast<int> (0.101 * static_cast<double>(ixMax-1));
1871  int iC = static_cast<int> (0.301 * static_cast<double>(ixMax-1));
1872  int iD = static_cast<int> (0.401 * static_cast<double>(ixMax-1));
1873  int iE = static_cast<int> (0.701 * static_cast<double>(ixMax-1));
1874  int iF = static_cast<int> (0.801 * static_cast<double>(ixMax-1));
1875  int iG = ixMax-1;
1876 
1877  numLabels = 5; // SI, EMITTER, BASE, COLLECTOR, NOFLUX
1878 
1879  // do the emitter . This goes from A to B, inclusive of both A and B.
1880  xLabel.mNodeVector.clear();
1881  xLabel.name = "EMITTER";
1882  xLabel.iIndex = 1;
1883  xLabel.uType = TYPE_EDGE;
1884  xLabel.cNode = iB-iA+1;
1885  xLabel.mNodeVector.reserve(xLabel.cNode+1);
1886 
1887  // fill in all the nodes:
1888  nodeTmp = 0;
1889  j=iyMax-1;
1890  for (i=iA;i<iB+1;++i)
1891  {
1892  int inode = nodeIndices[i][j];
1893  xLabel.mNodeVector.push_back(inode);
1894  ++nodeTmp;
1895  }
1896 
1897  tmpName = xLabel.name;
1898  tmpName.toUpper();
1899  mLabelMap[tmpName] = xLabel;
1900 
1901  mLabelVector.push_back(xLabel);
1902 
1903  // do the base. This goes from C to D, inclusive of both C and D.
1904  xLabel.mNodeVector.clear();
1905  xLabel.name = "BASE";
1906  xLabel.iIndex = 2;
1907  xLabel.uType = TYPE_EDGE;
1908  xLabel.cNode = iD-iC+1;
1909  xLabel.mNodeVector.reserve(xLabel.cNode+1);
1910 
1911  // fill in all the nodes:
1912  nodeTmp = 0;
1913  j=iyMax-1;
1914  for (i=iC;i<iD+1;++i)
1915  {
1916  int inode = nodeIndices[i][j];
1917  xLabel.mNodeVector.push_back(inode);
1918  ++nodeTmp;
1919  }
1920 
1921  tmpName = xLabel.name;
1922  tmpName.toUpper();
1923  mLabelMap[tmpName] = xLabel;
1924 
1925  mLabelVector.push_back(xLabel);
1926 
1927  // do the collector This goes from E to F, inclusive of both E and F.
1928  xLabel.mNodeVector.clear();
1929  xLabel.name = "COLLECTOR";
1930  xLabel.iIndex = 3;
1931  xLabel.uType = TYPE_EDGE;
1932  xLabel.cNode = iF-iE+1;
1933  xLabel.mNodeVector.reserve(xLabel.cNode+1);
1934 
1935  // fill in all the nodes:
1936  nodeTmp = 0;
1937  j=iyMax-1;
1938  for (i=iE;i<iF+1;++i)
1939  {
1940  int inode = nodeIndices[i][j];
1941  xLabel.mNodeVector.push_back(inode);
1942  ++nodeTmp;
1943  }
1944 
1945  tmpName = xLabel.name;
1946  tmpName.toUpper();
1947  mLabelMap[tmpName] = xLabel;
1948 
1949  mLabelVector.push_back(xLabel);
1950 
1951  // Now do noflux. This includes a bunch of stuff:
1952  // B to C not including b or c
1953  // D to E not including d or e
1954  // F to G not including f or g
1955  // G to N including both
1956  // N to H including both
1957  // H to A including H, not including A.
1958 
1959  xLabel.mNodeVector.clear();
1960  xLabel.name = "NOFLUX";
1961  xLabel.iIndex = 4;
1962  xLabel.uType = TYPE_EDGE;
1963  //xLabel.cNode = (iC-iB-1)+(iE-iD-1)+(iG-iF-1)+(iyMax)+(iyMax)+(ixMax-1);
1964  xLabel.mNodeVector.reserve(2*ixMax + 2*iyMax); // extra to be safe.
1965 
1966  // fill in all the nodes:
1967  nodeTmp = 0;
1968  j=iyMax-1;
1969  for (i=iB+1;i<iC;++i)
1970  {
1971  int inode = nodeIndices[i][j];
1972  xLabel.mNodeVector.push_back(inode);
1973  ++nodeTmp;
1974  }
1975 
1976  for (i=iD+1;i<iE;++i)
1977  {
1978  int inode = nodeIndices[i][j];
1979  xLabel.mNodeVector.push_back(inode);
1980  ++nodeTmp;
1981  }
1982 
1983  for (i=iF+1;i<iG;++i)
1984  {
1985  int inode = nodeIndices[i][j];
1986  xLabel.mNodeVector.push_back(inode);
1987  ++nodeTmp;
1988  }
1989 
1990  i=ixMax-1;
1991  for (j=0;j<iyMax-1;++j)
1992  {
1993  int inode = nodeIndices[i][j];
1994  xLabel.mNodeVector.push_back(inode);
1995  ++nodeTmp;
1996  }
1997 
1998  i=0;
1999  for (j=0;j<iyMax-2;++j)
2000  {
2001  int inode = nodeIndices[i][j];
2002  xLabel.mNodeVector.push_back(inode);
2003  ++nodeTmp;
2004  }
2005 
2006  j=0;
2007  for (i=0;i<ixMax-1;++i)
2008  {
2009  int inode = nodeIndices[i][j];
2010  xLabel.mNodeVector.push_back(inode);
2011  ++nodeTmp;
2012  }
2013 
2014  xLabel.cNode = xLabel.mNodeVector.size ();
2015 
2016  tmpName = xLabel.name;
2017  tmpName.toUpper();
2018  mLabelMap[tmpName] = xLabel;
2019 
2020  mLabelVector.push_back(xLabel);
2021 
2022 
2023  // Now assign labels to the edges in mEdgeVector.
2024  // Note: labels were already assigned to the cells in mCellVector, up
2025  // in setupInternalMesh.
2026  // Also, nodes don't get labels.
2027 
2028  j=iyMax-1;
2029  for (i=iA+1;i<iB+1;++i)
2030  {
2031  int n1 = nodeIndices[i-1][j];
2032  int n2 = nodeIndices[i ][j];
2033 
2034  int e1 = edgeIndices[n1][n2];
2035 
2036  mEdgeVector[e1].uLabel = 1; // EMITTER index
2037  }
2038 
2039  j=iyMax-1;
2040  for (i=iC+1;i<iD+1;++i)
2041  {
2042  int n1 = nodeIndices[i-1][j];
2043  int n2 = nodeIndices[i ][j];
2044 
2045  int e1 = edgeIndices[n1][n2];
2046 
2047  mEdgeVector[e1].uLabel = 2; // BASE index
2048  }
2049 
2050  j=iyMax-1;
2051  for (i=iE+1;i<iF+1;++i)
2052  {
2053  int n1 = nodeIndices[i-1][j];
2054  int n2 = nodeIndices[i ][j];
2055 
2056  int e1 = edgeIndices[n1][n2];
2057 
2058  mEdgeVector[e1].uLabel = 3; // COLLECTOR index
2059  }
2060 
2061 
2062  j=iyMax-1;
2063  for (i=iB+1;i<iC+1;++i)
2064  {
2065  int n1 = nodeIndices[i-1][j];
2066  int n2 = nodeIndices[i ][j];
2067 
2068  int e1 = edgeIndices[n1][n2];
2069 
2070  mEdgeVector[e1].uLabel = 4; // NOFLUX index
2071  }
2072 
2073  j=iyMax-1;
2074  for (i=iD+1;i<iE+1;++i)
2075  {
2076  int n1 = nodeIndices[i-1][j];
2077  int n2 = nodeIndices[i ][j];
2078 
2079  int e1 = edgeIndices[n1][n2];
2080 
2081  mEdgeVector[e1].uLabel = 4; // NOFLUX index
2082  }
2083 
2084  j=iyMax-1;
2085  for (i=iF+1;i<iG+1;++i)
2086  {
2087  int n1 = nodeIndices[i-1][j];
2088  int n2 = nodeIndices[i ][j];
2089 
2090  int e1 = edgeIndices[n1][n2];
2091 
2092  mEdgeVector[e1].uLabel = 4; // NOFLUX index
2093  }
2094 
2095  j=0;
2096  for (i=1;i<ixMax;++i)
2097  {
2098  int n1 = nodeIndices[i-1][j];
2099  int n2 = nodeIndices[i ][j];
2100 
2101  int e1 = edgeIndices[n1][n2];
2102 
2103  mEdgeVector[e1].uLabel = 4; // NOFLUX index
2104  }
2105 
2106  i=0;
2107  for (j=1;j<iyMax;++j)
2108  {
2109  int n1 = nodeIndices[i][j-1];
2110  int n2 = nodeIndices[i][j ];
2111 
2112  int e1 = edgeIndices[n1][n2];
2113 
2114  mEdgeVector[e1].uLabel = 4; // NOFLUX index
2115  }
2116 
2117  i=ixMax-1;
2118  for (j=1;j<iyMax;++j)
2119  {
2120  int n1 = nodeIndices[i][j-1];
2121  int n2 = nodeIndices[i][j ];
2122 
2123  int e1 = edgeIndices[n1][n2];
2124 
2125  mEdgeVector[e1].uLabel = 4; // NOFLUX index
2126  }
2127 
2128  }
2129  else if (numberElectrodes==4)
2130  {
2131  // Assuming a MOSFET mesh:
2132  //
2133  // Ratios: AB = 2/10
2134  // BC = 1/10
2135  // CD = 4/10
2136  // DE = 1/10
2137  // EF = 2/10
2138  //
2139  // So, hopefully, the number of mesh cells is
2140  // easily divisible by 10. The default mesh spacing will work.
2141  //
2142  // Note: For now, this "mosfet" doesn't include an oxide.
2143  // Later, it probably will include one. ERK
2144  // 11/12/02.
2145  //
2146  // Source Gate Drain
2147  //
2148  // |--5--| |------------3------------| |--5--|
2149  //
2150  // - A-----B---C-------------------------D---E-----F -
2151  // 6 | | | | |
2152  // - | I-------------------------J | |
2153  // n | | |Noflux
2154  // o | | 2
2155  // f | | |
2156  // l | | |
2157  // u | | |
2158  // x H---------------------------------------------G -
2159  //
2160  // |----------------------1----------------------|
2161  // Bulk
2162  //
2163  int iA = 0;
2164  int iB = static_cast<int> (0.101 * static_cast<double>(ixMax-1));
2165  int iC = static_cast<int> (0.151 * static_cast<double>(ixMax-1));
2166  int iD = static_cast<int> (0.851 * static_cast<double>(ixMax-1));
2167  int iE = static_cast<int> (0.901 * static_cast<double>(ixMax-1));
2168  int iF = ixMax-1;
2169 
2170  numLabels = 6; // SI, SOURCE, GATE, DRAIN, SUB, NOFLUX
2171 
2172  if (DEBUG_DEVICE)
2173  {
2174  Xyce::dout() << "iA = "<< iA << std::endl;
2175  Xyce::dout() << "iB = "<< iB << std::endl;
2176  Xyce::dout() << "iC = "<< iC << std::endl;
2177  Xyce::dout() << "iD = "<< iD << std::endl;
2178  Xyce::dout() << "iE = "<< iE << std::endl;
2179  Xyce::dout() << "iF = "<< iF << std::endl;
2180  }
2181 
2182  // do the source. This goes from A to B, inclusive of both A and B.
2183  xLabel.mNodeVector.clear();
2184  xLabel.name = "SOURCE";
2185  xLabel.iIndex = 1;
2186  xLabel.uType = TYPE_EDGE;
2187  xLabel.cNode = iB-iA+1;
2188  xLabel.mNodeVector.reserve(xLabel.cNode+1);
2189 
2190  // fill in all the nodes:
2191  nodeTmp = 0;
2192  j=iyMax-1;
2193  for (i=iA;i<iB+1;++i)
2194  {
2195  int inode = nodeIndices[i][j];
2196  xLabel.mNodeVector.push_back(inode);
2197  ++nodeTmp;
2198  }
2199 
2200  tmpName = xLabel.name;
2201  tmpName.toUpper();
2202  mLabelMap[tmpName] = xLabel;
2203 
2204  mLabelVector.push_back(xLabel);
2205 
2206  // do the gate. This goes from C to D, inclusive of both C and D.
2207  xLabel.mNodeVector.clear();
2208  xLabel.name = "GATE";
2209  xLabel.iIndex = 2;
2210  xLabel.uType = TYPE_EDGE;
2211  xLabel.cNode = iD-iC+1;
2212  xLabel.mNodeVector.reserve(xLabel.cNode+1);
2213 
2214  // fill in all the nodes:
2215  nodeTmp = 0;
2216  j=iyMax-1;
2217  for (i=iC;i<iD+1;++i)
2218  {
2219  int inode = nodeIndices[i][j];
2220  xLabel.mNodeVector.push_back(inode);
2221  ++nodeTmp;
2222  }
2223 
2224  tmpName = xLabel.name;
2225  tmpName.toUpper();
2226  mLabelMap[tmpName] = xLabel;
2227 
2228  mLabelVector.push_back(xLabel);
2229 
2230  // do the drain. This goes from E to F, inclusive of both E and F.
2231  xLabel.mNodeVector.clear();
2232  xLabel.name = "DRAIN";
2233  xLabel.iIndex = 3;
2234  xLabel.uType = TYPE_EDGE;
2235  xLabel.cNode = iF-iE+1;
2236  xLabel.mNodeVector.reserve(xLabel.cNode+1);
2237 
2238  // fill in all the nodes:
2239  nodeTmp = 0;
2240  j=iyMax-1;
2241  for (i=iE;i<iF+1;++i)
2242  {
2243  int inode = nodeIndices[i][j];
2244  xLabel.mNodeVector.push_back(inode);
2245  ++nodeTmp;
2246  }
2247 
2248  tmpName = xLabel.name;
2249  tmpName.toUpper();
2250  mLabelMap[tmpName] = xLabel;
2251 
2252  mLabelVector.push_back(xLabel);
2253 
2254  // do the bulk. This goes from G to H, inclusive of both G and H.
2255  // (note that this is the same x indices as A to F).
2256  xLabel.mNodeVector.clear();
2257  xLabel.name = "SUB";
2258  xLabel.iIndex = 4;
2259  xLabel.uType = TYPE_EDGE;
2260  xLabel.cNode = iF-iA+1;
2261  xLabel.mNodeVector.reserve(xLabel.cNode+1);
2262 
2263  // fill in all the nodes:
2264  nodeTmp = 0;
2265  j=0;
2266  for (i=iA;i<iF+1;++i)
2267  {
2268  int inode = nodeIndices[i][j];
2269  xLabel.mNodeVector.push_back(inode);
2270  ++nodeTmp;
2271  }
2272 
2273  tmpName = xLabel.name;
2274  tmpName.toUpper();
2275  mLabelMap[tmpName] = xLabel;
2276 
2277  mLabelVector.push_back(xLabel);
2278 
2279  // do the noflux. Everything that has not been labeled yet,
2280  // gets this one. BC, DE, FG, HA, not including
2281  // the endpoints.
2282 
2283  xLabel.mNodeVector.clear();
2284  xLabel.name = "NOFLUX";
2285  xLabel.iIndex = 5;
2286  xLabel.uType = TYPE_EDGE;
2287  xLabel.cNode = (iC-iB-1)+(iE-iD-1)+(iyMax-1)+(iyMax-1);
2288  xLabel.mNodeVector.reserve(xLabel.cNode+1);
2289 
2290  // fill in all the nodes:
2291  nodeTmp = 0;
2292  j=iyMax-1;
2293  for (i=iB+1;i<iC;++i)
2294  {
2295  int inode = nodeIndices[i][j];
2296  xLabel.mNodeVector.push_back(inode);
2297  ++nodeTmp;
2298  }
2299 
2300  for (i=iD+1;i<iE;++i)
2301  {
2302  int inode = nodeIndices[i][j];
2303  xLabel.mNodeVector.push_back(inode);
2304  ++nodeTmp;
2305  }
2306 
2307  i=ixMax-1;
2308  for (j=1;j<iyMax-1;++j)
2309  {
2310  int inode = nodeIndices[i][j];
2311  xLabel.mNodeVector.push_back(inode);
2312  ++nodeTmp;
2313  }
2314 
2315  i=0;
2316  for (j=1;j<iyMax-1;++j)
2317  {
2318  int inode = nodeIndices[i][j];
2319  xLabel.mNodeVector.push_back(inode);
2320  ++nodeTmp;
2321  }
2322 
2323  tmpName = xLabel.name;
2324  tmpName.toUpper();
2325  mLabelMap[tmpName] = xLabel;
2326 
2327  mLabelVector.push_back(xLabel);
2328 
2329  // Now assign labels to the edges in mEdgeVector.
2330  // Note: labels were already assigned to the cells in mCellVector, up
2331  // in setupInternalMesh.
2332  // Also, nodes don't get labels.
2333 
2334  j=iyMax-1;
2335  for (i=iA+1;i<iB+1;++i)
2336  {
2337  int n1 = nodeIndices[i-1][j];
2338  int n2 = nodeIndices[i ][j];
2339 
2340  int e1 = edgeIndices[n1][n2];
2341 
2342  mEdgeVector[e1].uLabel = 1; // SOURCE index
2343  }
2344 
2345  j=iyMax-1;
2346  for (i=iC+1;i<iD+1;++i)
2347  {
2348  int n1 = nodeIndices[i-1][j];
2349  int n2 = nodeIndices[i ][j];
2350 
2351  int e1 = edgeIndices[n1][n2];
2352 
2353  mEdgeVector[e1].uLabel = 2; // GATE index
2354  }
2355 
2356  j=iyMax-1;
2357  for (i=iE+1;i<iF+1;++i)
2358  {
2359  int n1 = nodeIndices[i-1][j];
2360  int n2 = nodeIndices[i ][j];
2361 
2362  int e1 = edgeIndices[n1][n2];
2363 
2364  mEdgeVector[e1].uLabel = 3; // DRAIN index
2365  }
2366 
2367  j=0;
2368  for (i=iA+1;i<iF+1;++i)
2369  {
2370  int n1 = nodeIndices[i-1][j];
2371  int n2 = nodeIndices[i ][j];
2372 
2373  int e1 = edgeIndices[n1][n2];
2374 
2375  mEdgeVector[e1].uLabel = 4; // SUB index
2376  }
2377 
2378  j=iyMax-1;
2379  for (i=iB+1;i<iC+1;++i)
2380  {
2381  int n1 = nodeIndices[i-1][j];
2382  int n2 = nodeIndices[i ][j];
2383 
2384  int e1 = edgeIndices[n1][n2];
2385 
2386  mEdgeVector[e1].uLabel = 5; // NOFLUX index
2387  }
2388 
2389  j=iyMax-1;
2390  for (i=iD+1;i<iE+1;++i)
2391  {
2392  int n1 = nodeIndices[i-1][j];
2393  int n2 = nodeIndices[i ][j];
2394 
2395  int e1 = edgeIndices[n1][n2];
2396 
2397  mEdgeVector[e1].uLabel = 5; // NOFLUX index
2398  }
2399 
2400  i=0;
2401  for (j=1;j<iyMax;++j)
2402  {
2403  int n1 = nodeIndices[i][j-1];
2404  int n2 = nodeIndices[i][j ];
2405 
2406  int e1 = edgeIndices[n1][n2];
2407 
2408  mEdgeVector[e1].uLabel = 5; // NOFLUX index
2409  }
2410 
2411  i=ixMax-1;
2412  for (j=1;j<iyMax;++j)
2413  {
2414  int n1 = nodeIndices[i][j-1];
2415  int n2 = nodeIndices[i][j ];
2416 
2417  int e1 = edgeIndices[n1][n2];
2418 
2419  mEdgeVector[e1].uLabel = 5; // NOFLUX index
2420  }
2421  }
2422  else
2423  {
2424  if (DEBUG_DEVICE)
2425  {
2426  Xyce::dout() << "Sorry, the internal mesh generator can't";
2427  Xyce::dout() << " handle anything greater than 4 electrodes." << std::endl;
2428  }
2429  }
2430 
2431  return true;
2432 
2433 }
2434 
2435 //-----------------------------------------------------------------------------
2436 // Function : PDE_2DMesh::setupInternalLabels
2437 //
2438 // Purpose : This function sets up labels, based on user-specified
2439 // information. Unlike the labels that are set up by the
2440 // function setupDefaultLabels, these label sets are not
2441 // internally hardwired.
2442 //
2443 // Special Notes :
2444 // Scope : private
2445 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2446 // Creation Date : 04/23/02
2447 //-----------------------------------------------------------------------------
2448 bool PDE_2DMesh::setupInternalLabels(int numberElectrodes,
2449  std::map<std::string,PDE_2DElectrode*> & elMap)
2450 {
2451 
2452  // Region labels of nodes-------------------------------------------------
2453  // set up the silicon region label. This will always be here.
2454  int i,j;
2455  mLabel xLabel;
2456  ExtendedString tmpName = "SI";
2457  int nodeTmp = 0;
2458 
2459  xLabel.name = "SI";
2460  xLabel.iIndex = 0;
2461  xLabel.uType = TYPE_REGION;
2462 
2463  // This assumes every node in the mesh is SI, except for the edges.
2464  xLabel.mNodeVector.reserve(ixMax*iyMax); // just to be safe, reserve extra
2465 
2466  // fill in all the nodes:
2467  nodeTmp = 0;
2468  for (i=1;i<ixMax-1;++i)
2469  {
2470  for (j=1;j<iyMax-1;++j)
2471  {
2472  xLabel.mNodeVector.push_back(nodeIndices[i][j]);
2473  ++nodeTmp;
2474  }
2475  }
2476  xLabel.cNode = xLabel.mNodeVector.size ();
2477 
2478  tmpName = xLabel.name;
2479  tmpName.toUpper();
2480  mLabelMap[tmpName] = xLabel;
2481 
2482  mLabelVector.push_back(xLabel);
2483 
2484  // Edge labels of nodes----------------------------------------------------
2485  // Now do the edge labels, using the electrode Map.
2486  std::vector<int> done;
2487  done.resize(numNodes, 0);
2488 
2489  std::map<std::string, PDE_2DElectrode*>::iterator mapIter;
2490  std::map<std::string, PDE_2DElectrode*>::iterator mapStart =
2491  elMap.begin();
2492  std::map<std::string, PDE_2DElectrode*>::iterator mapEnd =
2493  elMap.end();
2494 
2495  numLabels = 1; // SI so far...
2496  int labelIndex = 0;
2497  ++labelIndex;
2498 
2499  for ( mapIter = mapStart; mapIter != mapEnd; ++mapIter )
2500  {
2501  PDE_2DElectrode & el = *(mapIter->second);
2502 
2503  // determine if this is an x-side or a y-side, then do
2504  // appropriate stuff:
2505  if (el.side == "top" || el.side == "bottom")
2506  {
2507  double start,end;
2508  if (el.start <= el.end)
2509  {
2510  start = el.start;
2511  end = el.end;
2512  }
2513  else
2514  {
2515  start = el.end;
2516  end = el.start;
2517  }
2518 
2519  // Note: This assumes that the lower-left-hand corner of the mesh is
2520  // at the (0.0, 0.0) origin!
2521  if (start < xMin) start = xMin;
2522  if (end < xMin) end = xMin;
2523 
2524  if (start > xMax) start = xMax;
2525  if (end > xMax) end = xMax;
2526 
2527  // Now make start and end relative quantities, rather than
2528  // absolute:
2529  start = (start-xMin)/(xMax-xMin);
2530  end = (end -xMin)/(xMax-xMin);
2531 
2532  el.iA = static_cast<int> (start * static_cast<double>(ixMax-1));
2533  el.iB = static_cast<int> (end * static_cast<double>(ixMax-1));
2534 
2535  if (el.iA < 0) el.iA = 0;
2536  if (el.iA > ixMax-1) el.iA = ixMax-1;
2537  if (el.iB < 0) el.iB = 0;
2538  if (el.iB > ixMax-1) el.iB = ixMax-1;
2539 
2540  ++numLabels;
2541 
2542  ExtendedString tmpName = el.name;
2543  tmpName.toUpper ();
2544 
2545  // do the nodes. This goes from A to B, inclusive of both A and B.
2546  xLabel.mNodeVector.clear();
2547  xLabel.name = tmpName;
2548  xLabel.iIndex = labelIndex; ++labelIndex;
2549  xLabel.uType = TYPE_EDGE;
2550  xLabel.cNode = el.iB-el.iA+1;
2551  xLabel.mNodeVector.reserve(xLabel.cNode+1);
2552 
2553  el.uLabel = xLabel.iIndex;
2554 
2555  // fill in all the nodes:
2556  nodeTmp = 0;
2557  if (el.side == "top")
2558  {
2559  j=iyMax-1;
2560  }
2561  else if (el.side == "bottom")
2562  {
2563  j=0;
2564  }
2565 
2566  for (i=el.iA;i<el.iB+1;++i)
2567  {
2568  int inode = nodeIndices[i][j];
2569  xLabel.mNodeVector.push_back(inode);
2570  done[inode] = 1;
2571  ++nodeTmp;
2572  }
2573 
2574  tmpName = xLabel.name;
2575  tmpName.toUpper();
2576  mLabelMap[tmpName] = xLabel;
2577 
2578  mLabelVector.push_back(xLabel);
2579  }
2580  else if (el.side == "right" || el.side == "left")
2581  {
2582  double start,end;
2583  if (el.start <= el.end)
2584  {
2585  start = el.start;
2586  end = el.end;
2587  }
2588  else
2589  {
2590  start = el.end;
2591  end = el.start;
2592  }
2593 
2594  // Note: This assumes that the lower-left-hand corner of the mesh is
2595  // at the (0.0, 0.0) origin!
2596  if (start < yMin) start = yMin;
2597  if (end < yMin) end = yMin;
2598 
2599  if (start > yMax) start = yMax;
2600  if (end > yMax) end = yMax;
2601 
2602  // Now make start and end relative quantities, rather than
2603  // absolute:
2604  start = (start-yMin)/(yMax-yMin);
2605  end = (end -yMin)/(yMax-yMin);
2606 
2607  el.iA = static_cast<int> (start * static_cast<double>(iyMax-1));
2608  el.iB = static_cast<int> (end * static_cast<double>(iyMax-1));
2609 
2610  if (el.iA < 0) el.iA = 0;
2611  if (el.iA > iyMax-1) el.iA = iyMax-1;
2612  if (el.iB < 0) el.iB = 0;
2613  if (el.iB > iyMax-1) el.iB = iyMax-1;
2614 
2615  ++numLabels;
2616 
2617  ExtendedString tmpName = el.name;
2618  tmpName.toUpper ();
2619 
2620  // do the nodes. This goes from A to B, inclusive of both A and B.
2621  xLabel.mNodeVector.clear();
2622  xLabel.name = tmpName;
2623  xLabel.iIndex = labelIndex; ++labelIndex;
2624  xLabel.uType = TYPE_EDGE;
2625  xLabel.cNode = el.iB-el.iA+1;
2626  xLabel.mNodeVector.reserve(xLabel.cNode+1);
2627 
2628  el.uLabel = xLabel.iIndex;
2629 
2630  // fill in all the nodes:
2631  nodeTmp = 0;
2632  if (el.side == "right")
2633  {
2634  i=ixMax-1;
2635  }
2636  else if (el.side == "left")
2637  {
2638  i=0;
2639  }
2640 
2641  for (j=el.iA;j<el.iB+1;++j)
2642  {
2643  int inode = nodeIndices[i][j];
2644  xLabel.mNodeVector.push_back(inode);
2645  done[inode] = 1;
2646  ++nodeTmp;
2647  }
2648 
2649  tmpName = xLabel.name;
2650  tmpName.toUpper();
2651  mLabelMap[tmpName] = xLabel;
2652 
2653  mLabelVector.push_back(xLabel);
2654  }
2655  else
2656  {
2657  std::string msg("electrode side specification not recognized.\n");
2658  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
2659  }
2660  } // end of map loop:
2661 
2662  // now do the NOFLUX label. This will include all external edges/nodes
2663  // which have not already been assigned a label.
2664  ++numLabels;
2665 
2666  xLabel.mNodeVector.clear();
2667  xLabel.name = "NOFLUX";
2668  xLabel.iIndex = labelIndex; ++labelIndex;
2669  xLabel.uType = TYPE_EDGE;
2670  xLabel.mNodeVector.reserve(2*ixMax + 2*iyMax); // extra to be safe.
2671 
2672  int NOFLUXIndex = xLabel.iIndex;
2673 
2674  nodeTmp = 0;
2675  i=0;
2676  for (j=0;j<iyMax;++j)
2677  {
2678  int inode = nodeIndices[i][j];
2679  if (done[inode]!=1)
2680  {
2681  xLabel.mNodeVector.push_back(inode);
2682  ++nodeTmp;
2683  done[inode] = 1;
2684  }
2685  }
2686 
2687  i=ixMax-1;
2688  for (j=0;j<iyMax;++j)
2689  {
2690  int inode = nodeIndices[i][j];
2691  if (done[inode]!=1)
2692  {
2693  xLabel.mNodeVector.push_back(inode);
2694  ++nodeTmp;
2695  done[inode] = 1;
2696  }
2697  }
2698 
2699  j=0;
2700  for (i=0;i<ixMax;++i)
2701  {
2702  int inode = nodeIndices[i][j];
2703  if (done[inode]!=1)
2704  {
2705  xLabel.mNodeVector.push_back(inode);
2706  ++nodeTmp;
2707  done[inode] = 1;
2708  }
2709  }
2710 
2711  j=iyMax-1;
2712  for (i=0;i<ixMax;++i)
2713  {
2714  int inode = nodeIndices[i][j];
2715  if (done[inode]!=1)
2716  {
2717  xLabel.mNodeVector.push_back(inode);
2718  ++nodeTmp;
2719  done[inode] = 1;
2720  }
2721  }
2722 
2723  xLabel.cNode = xLabel.mNodeVector.size ();
2724 
2725  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
2726  {
2727  Xyce::dout() << "NOFLUX nodes:" << std::endl;
2728  for (int nodeIndex=0;nodeIndex<xLabel.mNodeVector.size();++nodeIndex)
2729  {
2730  int iNode = xLabel.mNodeVector[nodeIndex];
2731  Xyce::dout() << "node="<<iNode<<" x=" << xVector[iNode];
2732  Xyce::dout() << " y="<<yVector[iNode] <<std::endl;
2733  }
2734  }
2735 
2736  tmpName = xLabel.name;
2737  tmpName.toUpper();
2738  mLabelMap[tmpName] = xLabel;
2739 
2740  mLabelVector.push_back(xLabel);
2741 
2742  // Labels of edges------------------------------------------------------
2743  // Note: labels were already assigned to the cells in mCellVector, up
2744  // in setupInternalMesh.
2745  // Also, nodes don't get labels.
2746  std::vector<int> edgeDone;
2747  edgeDone.resize(numEdges, 0);
2748 
2749  for ( mapIter = mapStart; mapIter != mapEnd; ++mapIter )
2750  {
2751  PDE_2DElectrode & el = *(mapIter->second);
2752 
2753  if (el.side=="top")
2754  {
2755  j=iyMax-1;
2756  for (i=el.iA+1;i<el.iB+1;++i)
2757  {
2758  int n1 = nodeIndices[i-1][j];
2759  int n2 = nodeIndices[i ][j];
2760 
2761  int e1 = edgeIndices[n1][n2];
2762 
2763  mEdgeVector[e1].uLabel = el.uLabel;
2764  edgeDone[e1] = 1;
2765  }
2766  }
2767  else if (el.side=="bottom")
2768  {
2769  j=0;
2770  for (i=el.iA+1;i<el.iB+1;++i)
2771  {
2772  int n1 = nodeIndices[i-1][j];
2773  int n2 = nodeIndices[i ][j];
2774 
2775  int e1 = edgeIndices[n1][n2];
2776 
2777  mEdgeVector[e1].uLabel = el.uLabel;
2778  edgeDone[e1] = 1;
2779  }
2780  }
2781  else if (el.side=="left")
2782  {
2783  i=0;
2784  for (j=el.iA+1;j<el.iB+1;++j)
2785  {
2786  int n1 = nodeIndices[i][j-1];
2787  int n2 = nodeIndices[i][j ];
2788 
2789  int e1 = edgeIndices[n1][n2];
2790 
2791  mEdgeVector[e1].uLabel = el.uLabel;
2792  edgeDone[e1] = 1;
2793  }
2794  }
2795  else if (el.side=="right")
2796  {
2797  i=ixMax-1;
2798  for (j=el.iA+1;j<el.iB+1;++j)
2799  {
2800  int n1 = nodeIndices[i][j-1];
2801  int n2 = nodeIndices[i][j ];
2802 
2803  int e1 = edgeIndices[n1][n2];
2804 
2805  mEdgeVector[e1].uLabel = el.uLabel;
2806  edgeDone[e1] = 1;
2807  }
2808  }
2809  else
2810  {
2811  std::string msg("electrode side specification not recognized.\n");
2812  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
2813  }
2814  }
2815 
2816  // Now do the NOFLUX edges:
2817  i=0;
2818  for (j=1;j<iyMax;++j)
2819  {
2820  int n1 = nodeIndices[i ][j ];
2821  int n2 = nodeIndices[i ][j-1];
2822  int e1 = edgeIndices[n1][n2 ];
2823 
2824  if (edgeDone[e1]!=1)
2825  {
2826  mEdgeVector[e1].uLabel = NOFLUXIndex;
2827  edgeDone[e1] = 1;
2828  }
2829  }
2830 
2831  i=ixMax-1;
2832  for (j=1;j<iyMax;++j)
2833  {
2834  int n1 = nodeIndices[i ][j ];
2835  int n2 = nodeIndices[i ][j-1];
2836  int e1 = edgeIndices[n1][n2 ];
2837 
2838  if (edgeDone[e1]!=1)
2839  {
2840  mEdgeVector[e1].uLabel = NOFLUXIndex;
2841  edgeDone[e1] = 1;
2842  }
2843  }
2844 
2845  j=0;
2846  for (i=1;i<ixMax;++i)
2847  {
2848  int n1 = nodeIndices[i ][j ];
2849  int n2 = nodeIndices[i-1][j ];
2850  int e1 = edgeIndices[n1 ][n2];
2851 
2852  if (edgeDone[e1]!=1)
2853  {
2854  mEdgeVector[e1].uLabel = NOFLUXIndex;
2855  edgeDone[e1] = 1;
2856  }
2857  }
2858 
2859  j=iyMax-1;
2860  for (i=1;i<ixMax;++i)
2861  {
2862  int n1 = nodeIndices[i ][j ];
2863  int n2 = nodeIndices[i-1][j ];
2864  int e1 = edgeIndices[n1 ][n2];
2865 
2866  if (edgeDone[e1]!=1)
2867  {
2868  mEdgeVector[e1].uLabel = NOFLUXIndex;
2869  edgeDone[e1] = 1;
2870  }
2871  }
2872 
2873  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
2874  {
2875  Xyce::dout() << "EDGEs:"<<std::endl;
2876  j=0;
2877  for (i=1;i<ixMax;++i)
2878  {
2879  int n1 = nodeIndices[i ][j ];
2880  int n2 = nodeIndices[i-1][j ];
2881  int e1 = edgeIndices[n1 ][n2];
2882 
2883  Xyce::dout() << "edge: " << e1;
2884  Xyce::dout() << " x(A)="<<xVector[mEdgeVector[e1].inodeA];
2885  Xyce::dout() << " y(A)="<<yVector[mEdgeVector[e1].inodeA];
2886  Xyce::dout() << " x(B)="<<xVector[mEdgeVector[e1].inodeB];
2887  Xyce::dout() << " y(B)="<<yVector[mEdgeVector[e1].inodeB];
2888  Xyce::dout() << " label = " << mEdgeVector[e1].uLabel;
2889  Xyce::dout() << std::endl;
2890  }
2891  Xyce::dout() << std::endl;
2892 
2893  j=iyMax-1;
2894  for (i=1;i<ixMax;++i)
2895  {
2896  int n1 = nodeIndices[i ][j ];
2897  int n2 = nodeIndices[i-1][j ];
2898  int e1 = edgeIndices[n1 ][n2];
2899 
2900  Xyce::dout() << "edge: " << e1;
2901  Xyce::dout() << " x(A)="<<xVector[mEdgeVector[e1].inodeA];
2902  Xyce::dout() << " y(A)="<<yVector[mEdgeVector[e1].inodeA];
2903  Xyce::dout() << " x(B)="<<xVector[mEdgeVector[e1].inodeB];
2904  Xyce::dout() << " y(B)="<<yVector[mEdgeVector[e1].inodeB];
2905  Xyce::dout() << " label = " << mEdgeVector[e1].uLabel;
2906  Xyce::dout() << std::endl;
2907  }
2908  Xyce::dout() << std::endl;
2909 
2910  i=0;
2911  for (j=1;j<iyMax;++j)
2912  {
2913  int n1 = nodeIndices[i ][j ];
2914  int n2 = nodeIndices[i ][j-1];
2915  int e1 = edgeIndices[n1 ][n2 ];
2916 
2917  Xyce::dout() << "edge: " << e1;
2918  Xyce::dout() << " x(A)="<<xVector[mEdgeVector[e1].inodeA];
2919  Xyce::dout() << " y(A)="<<yVector[mEdgeVector[e1].inodeA];
2920  Xyce::dout() << " x(B)="<<xVector[mEdgeVector[e1].inodeB];
2921  Xyce::dout() << " y(B)="<<yVector[mEdgeVector[e1].inodeB];
2922  Xyce::dout() << " label = " << mEdgeVector[e1].uLabel;
2923  Xyce::dout() << std::endl;
2924  }
2925  Xyce::dout() << std::endl;
2926 
2927  i=ixMax-1;
2928  for (j=1;j<iyMax;++j)
2929  {
2930  int n1 = nodeIndices[i ][j ];
2931  int n2 = nodeIndices[i ][j-1];
2932  int e1 = edgeIndices[n1 ][n2 ];
2933 
2934  Xyce::dout() << "edge: " << e1;
2935  Xyce::dout() << " x(A)="<<xVector[mEdgeVector[e1].inodeA];
2936  Xyce::dout() << " y(A)="<<yVector[mEdgeVector[e1].inodeA];
2937  Xyce::dout() << " x(B)="<<xVector[mEdgeVector[e1].inodeB];
2938  Xyce::dout() << " y(B)="<<yVector[mEdgeVector[e1].inodeB];
2939  Xyce::dout() << " label = " << mEdgeVector[e1].uLabel;
2940  Xyce::dout() << std::endl;
2941  }
2942  Xyce::dout() << std::endl;
2943  }
2944 
2945  return true;
2946 }
2947 
2948 //-----------------------------------------------------------------------------
2949 // Function : PDE_2DMesh::setupGeometry
2950 // Purpose : This function sets up a lot of basic GLOBAL mesh geometry
2951 // information. For example it calculates total volume of
2952 // the mesh, but not volumes around individual nodes.
2953 //
2954 // Special Notes :
2955 // Scope : private
2956 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2957 // Creation Date : 04/23/02
2958 //-----------------------------------------------------------------------------
2960 {
2961 
2962  // Information from a node loop:
2963  // Obtain:
2964  // - the maximum number of nearest neighbors for a single node.
2965  // - the total area(volume) of the mesh. (note: this is a 2D mesh, so "volume"
2966  // is clear-cut if dealing with cylindrical coord., but less so for cartesian.)
2967  // - the total surface area (surface length?) of the mesh. (not done yet)
2968  //
2969  std::vector<mNode>::iterator first = mNodeVector.begin ();
2970  std::vector<mNode>::iterator last = mNodeVector.end ();
2971  std::vector<mNode>::iterator iter;
2972 
2973  maxNodeNN = -999;
2974  vol = 0.0;
2975 
2976  for (iter=first;iter!=last;++iter)
2977  {
2978  if (maxNodeNN < iter->cnode) maxNodeNN = iter->cnode;
2979  vol += iter->area;
2980 
2981  }
2982  if (!cylGeom) vol *= depth;
2983 
2984 
2985  // loop over each region (lists of nodes associated with labels which have
2986  // been designated as "region" labels ) and obtain:
2987  // - the total area(volume) of each region.
2988  // - the surface length(area) of each region. (not done yet)
2989 
2990  std::map<std::string, mLabel>::iterator firstL = mLabelMap.begin ();
2991  std::map<std::string, mLabel>::iterator lastL = mLabelMap.end ();
2992  std::map<std::string, mLabel>::iterator iterL;
2993 
2994  for (iterL=firstL; iterL!=lastL; ++iterL)
2995  {
2996  if (iterL->second.uType == TYPE_EDGE) continue;
2997 
2998  std::vector<int>::iterator firstN = iterL->second.mNodeVector.begin ();
2999  std::vector<int>::iterator lastN = iterL->second.mNodeVector.end ();
3000  std::vector<int>::iterator iterN;
3001 
3002  iterL->second.vol = 0.0;
3003 
3004  for (iterN=firstN; iterN!=lastN; ++iterN)
3005  {
3006  iterL->second.vol += mNodeVector[*iterN].area;
3007  }
3008  if (!cylGeom) iterL->second.vol *= depth;
3009  }
3010 
3011  // calculate xMax and yMax (could also be called rMax and zMax)
3012 
3013  for (iter=first;iter!=last;++iter)
3014  {
3015  if (xMax < iter->x) xMax = iter->x;
3016  if (yMax < iter->y) yMax = iter->y;
3017  if (xMin > iter->x) xMin = iter->x;
3018  if (yMin > iter->y) yMin = iter->y;
3019  }
3020 
3021  return true;
3022 }
3023 
3024 //-----------------------------------------------------------------------------
3025 // Function : PDE_2DMesh::dumpMesh
3026 // Purpose : This function dumps the current mesh stored in memory to
3027 // a text file.
3028 // Special Notes :
3029 // Scope : public
3030 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3031 // Creation Date : 04/21/02
3032 //-----------------------------------------------------------------------------
3034 {
3035  // open output file
3036  std::string dbFileName = meshFileName.substr(0, meshFileName.size() - 4) + "mesh_debug.txt";
3037  FILE *file = fopen(dbFileName.c_str(), "wt");
3038 
3039  fprintf(file, "CELLS\n");
3040  fprintf(file, " | | EDGES CELLS \n");
3041  fprintf(file, " i | u | AB BC AC/CD AD AB BC AC/CD AD \n");
3042  fprintf(file, "----- | --- | ----- ----- ----- ----- ----- ----- ----- -----\n");
3043 
3044  for(int i = 0; i < numCells; ++i)
3045  {
3046  mCell c1 = mCellVector[i];
3047 
3048  fprintf(file, "%5u | ", i);
3049  if (c1.uLabel != -1 ) fprintf(file, "%3u | ", c1.uLabel);
3050  else fprintf(file, " | ");
3051 
3052  if (c1.iedgeAB != -1 ) fprintf(file, "%5u ", c1.iedgeAB);
3053  else fprintf(file, " ");
3054 
3055  if (c1.iedgeBC != -1 ) fprintf(file, "%5u ", c1.iedgeBC);
3056  else fprintf(file, " ");
3057 
3058  if (c1.iedgeCD != -1 ) fprintf(file, "%5u ", c1.iedgeCD);
3059  else fprintf(file, " ");
3060 
3061  if (c1.iedgeDA != -1 ) fprintf(file, "%5u ", c1.iedgeDA);
3062  else fprintf(file, " n/a ");
3063 
3064  fprintf(file, " ");
3065  if (c1.icellAB != -1 ) fprintf(file, "%5u ", c1.icellAB);
3066  else fprintf(file, " ");
3067 
3068  if (c1.icellBC != -1 ) fprintf(file, "%5u ", c1.icellBC);
3069  else fprintf(file, " ");
3070 
3071  if (c1.icellCD != -1 ) fprintf(file, "%5u ", c1.icellCD);
3072  else fprintf(file, " ");
3073 
3074  if (c1.icellDA != -1 ) fprintf(file, "%5u" , c1.icellDA);
3075  else fprintf(file, " n/a");
3076 
3077  fprintf(file, "\n");
3078  }
3079  fprintf(file, "----- | --- | ----- ----- ----- ----- ----- ----- ----- -----\n");
3080 
3081  fprintf(file, "\nEDGES\n");
3082  fprintf(file, " | | NODES | | | | |\n");
3083  fprintf(file, " i | u | A B | ilen | elen | Area1 | Area2 |\n");
3084  fprintf(file, "----- | --- | ----- ----- | ------------ | ------------ | ------------ | ------------ |\n");
3085 
3086  for(int i = 0; i < numEdges; ++i)
3087  {
3088  mEdge e1 = mEdgeVector[i];
3089  fprintf(file, "%5u | ", i);
3090  if (e1.uLabel != -1 ) fprintf(file, "%3u | ", e1.uLabel);
3091  else fprintf(file, " | ");
3092  fprintf(file, "%5u %5u | %12.4e | %12.4e | %12.4e | %12.4e |\n",
3093  e1.inodeA, e1.inodeB, e1.ilen, e1.elen, e1.Area1, e1.Area2);
3094  }
3095 
3096  fprintf(file, "\nNODES\n");
3097  fprintf(file, " | | |\n");
3098  fprintf(file, " i | x y | Area |\n");
3099  fprintf(file, "----- | ------------ ------------ | ------------ |\n");
3100 
3101  for(int i = 0; i < numNodes; ++i)
3102  {
3103  mNode n1 = mNodeVector[i];
3104  fprintf(file, "%5u | ", i);
3105  fprintf(file, "%12.4e %12.4e | %12.4e |\n", n1.x, n1.y, n1.area);
3106  }
3107 
3108  fprintf(file, "\nNodeEdgeInfo\n");
3109  for(int i = 0; i < numNodes; ++i)
3110  {
3111  fprintf(file, "------\n");
3112  fprintf(file, " node index = %d\n", i);
3113  for (int j=0;j<mNodeVector[i].cnode;++j)
3114  {
3115  fprintf(file," local edge index = %d\n", j);
3116 
3117  fprintf(file," global edge index = %d\n",
3118  mNodeVector[i].edgeInfoVector[j].iedge);
3119 
3120  fprintf(file," neighbor node = %d\n",
3121  mNodeVector[i].edgeInfoVector[j].inode);
3122 
3123  fprintf(file," elen = %12.4e\n",
3124  mNodeVector[i].edgeInfoVector[j].elen );
3125 
3126  fprintf(file," ilen = %12.4e\n",
3127  mNodeVector[i].edgeInfoVector[j].ilen );
3128  }
3129  fprintf(file, "------\n");
3130  }
3131 
3132  fclose(file);
3133 
3134 }
3135 
3136 //-----------------------------------------------------------------------------
3137 // Function : PDE_2DMesh::printLabels
3138 // Purpose : Prints the list of mesh labels (both cell and edge) to
3139 // stdout.
3140 // Special Notes :
3141 // Scope : public
3142 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3143 // Creation Date : 04/21/02
3144 //-----------------------------------------------------------------------------
3146 {
3147  int i;
3148 
3149  std::map<std::string,mLabel>::iterator first = mLabelMap.begin ();
3150  std::map<std::string,mLabel>::iterator last = mLabelMap.end ();
3151  std::map<std::string,mLabel>::iterator iter = mLabelMap.end ();
3152 
3153  Xyce::dout() << std::endl;
3154  Xyce::dout() << "Mesh Labels:" <<std::endl;
3155  Xyce::dout() << " Index # nodes Type Label";
3156  Xyce::dout() << std::endl;
3157  for (i=0, iter=first; iter!=last; ++iter, ++i)
3158  {
3159  Xyce::dout().width(8);
3160  Xyce::dout() << iter->second.iIndex;
3161  Xyce::dout().width(10);
3162  Xyce::dout() << iter->second.cNode;
3163 
3164  if (iter->second.uType == TYPE_EDGE) Xyce::dout() << " Edge ";
3165  else Xyce::dout() << " Region ";
3166 
3167  Xyce::dout() << " ";
3168  Xyce::dout().width(15);
3169  Xyce::dout() << iter->second.name << std::endl;
3170  }
3171  Xyce::dout() << std::endl;
3172 
3173 }
3174 
3175 //-----------------------------------------------------------------------------
3176 // Function : PDE_2DMesh::outputMeshInfo
3177 // Purpose :
3178 // Special Notes :
3179 // Scope : public
3180 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3181 // Creation Date : 04/21/02
3182 //-----------------------------------------------------------------------------
3184 {
3185 
3186 }
3187 
3188 //-----------------------------------------------------------------------------
3189 // Function : PDE_2DMesh::computeIntPB
3190 // Purpose : This function computes the intersection of the
3191 // perpendicular bisection of the triangle given by nodes
3192 // A, B and C.
3193 // Special Notes :
3194 // Scope : private
3195 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3196 // Creation Date : 04/22/02
3197 //-----------------------------------------------------------------------------
3199  (double &x, double &y,int inodeA,int inodeB,int inodeC)
3200 {
3201 
3202  mNode nA = mNodeVector[inodeA];
3203  mNode nB = mNodeVector[inodeB];
3204  mNode nC = mNodeVector[inodeC];
3205 
3206  double x1 = nA.x; double y1 = nA.y;
3207  double x2 = nB.x; double y2 = nB.y;
3208  double x3 = nC.x; double y3 = nC.y;
3209 
3210  double dx12 = x1 - x2;
3211  double dx23 = x2 - x3;
3212  double dx13 = x1 - x3;
3213 
3214  double m12 = (dx12) ? (y1 - y2) / dx12 : 0.0;
3215  double m23 = (dx23) ? (y2 - y3) / dx23 : 0.0;
3216  double m13 = (dx13) ? (y1 - y3) / dx13 : 0.0;
3217  double x12 = (x1 + x2) / 2.0; double y12 = (y1 + y2) / 2.0;
3218  double x23 = (x2 + x3) / 2.0; double y23 = (y2 + y3) / 2.0;
3219  double x13 = (x1 + x3) / 2.0; double y13 = (y1 + y3) / 2.0;
3220 
3221  UINT iSmallest;
3222  if (fabs(dx12) < fabs(dx23))
3223  {
3224  iSmallest = (fabs(dx12) < fabs(dx13)) ? TAG12 : TAG13;
3225  }
3226  else
3227  {
3228  iSmallest = (fabs(dx23) < fabs(dx13)) ? TAG23 : TAG13;
3229  }
3230 
3231  switch (iSmallest)
3232  {
3233  case TAG12:
3234  x = (m13 * m23 * (y13 - y23) + m23 * x13 - m13 * x23) / (m23 - m13);
3235  break;
3236 
3237  case TAG23:
3238  x = (m13 * m12 * (y13 - y12) + m12 * x13 - m13 * x12) / (m12 - m13);
3239  break;
3240 
3241  case TAG13:
3242  x = (m12 * m23 * (y12 - y23) + m23 * x12 - m12 * x23) / (m23 - m12);
3243  break;
3244  }
3245 
3246  UINT iLargest;
3247  if (fabs(m12) > fabs(m23))
3248  {
3249  iLargest = (fabs(m12) > fabs(m13)) ? TAG12 : TAG13;
3250  }
3251  else
3252  {
3253  iLargest = (fabs(m23) > fabs(m13)) ? TAG23 : TAG13;
3254  }
3255 
3256  switch (iLargest)
3257  {
3258  case TAG12:
3259  y = (x12 - x) / m12 + y12;
3260  break;
3261 
3262  case TAG23:
3263  y = (x23 - x) / m23 + y23;
3264  break;
3265 
3266  case TAG13:
3267  y = (x13 - x) / m13 + y13;
3268  break;
3269  }
3270 
3271  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
3272  {
3273  Xyce::dout() << "In computeIntPB:\n";
3274  Xyce::dout() << " inodeA = " << inodeA;
3275  Xyce::dout() << " inodeB = " << inodeB;
3276  Xyce::dout() << " inodeC = " << inodeC << std::endl;
3277  Xyce::dout() << " x1 = " << x1;
3278  Xyce::dout() << " y1 = " << y1 <<std::endl;
3279 
3280  Xyce::dout() << " x2 = " << x2;
3281  Xyce::dout() << " y2 = " << y2 <<std::endl;
3282 
3283  Xyce::dout() << " x3 = " << x3;
3284  Xyce::dout() << " y3 = " << y3 <<std::endl;
3285 
3286  Xyce::dout() << " iSmallest = " << iSmallest << std::endl;
3287  Xyce::dout() << " iLargest = " << iLargest << std::endl;
3288 
3289  Xyce::dout() << " m12 = " << m12 << std::endl;
3290  Xyce::dout() << " m23 = " << m23 << std::endl;
3291  Xyce::dout() << " m13 = " << m13 << std::endl;
3292 
3293  Xyce::dout() << " x = " << x << std::endl;
3294  Xyce::dout() << " y = " << y << std::endl;
3295  }
3296 
3297  return true;
3298 }
3299 
3300 //-----------------------------------------------------------------------------
3301 // Function: : PDE_2DMesh::lengthAdjust
3302 // Purpose: : This function returns a length between two points
3303 // defined by (x1,y1) and (x2,y2).
3304 //
3305 // The length is adjusted cylinderical geometries.
3306 // (otherwise the length would just be sqrt(dx*dx + dy*dy)).
3307 //
3308 // The integration segment
3309 // becomes an integration surface by rotating the
3310 // integration segment around the y axis.
3311 //
3312 // Special Notes :
3313 // Scope : public
3314 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3315 // Creation Date : 04/22/02
3316 //-----------------------------------------------------------------------------
3318  (double x1, double y1, double x2, double y2)
3319 {
3320  double dx1 = x2 - x1;
3321  double dy1 = y2 - y1;
3322  double h = sqrt(dx1 * dx1 + dy1 * dy1);
3323  double pi = M_PI;
3324  double A = pi * (x1 + x2) * h;
3325  return A;
3326 }
3327 
3328 
3329 //-----------------------------------------------------------------------------
3330 // Function: : PDE_2DMesh::areaAdjust
3331 //
3332 //
3333 // Purpose: : This function calculates an area which has been adjusted
3334 // for cylinderical geometries. The surfaces become
3335 // regions by rotating the surfaces around the y axis.
3336 //
3337 //
3338 // Special Notes :
3339 // Scope : private
3340 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3341 // Creation Date : 04/22/02
3342 //-----------------------------------------------------------------------------
3344  (double x1, double y1, double x2, double y2, double x3, double y3)
3345 {
3346  // sort the coordinates so that x1 <= x2 <= x3
3347  double xT, yT;
3348  if (x1 > x2) { xT = x1; yT = y1; x1 = x2; y1 = y2; x2 = xT; y2 = yT; }
3349  if (x2 > x3) { xT = x2; yT = y2; x2 = x3; y2 = y3; x3 = xT; y3 = yT; }
3350  if (x1 > x2) { xT = x1; yT = y1; x1 = x2; y1 = y2; x2 = xT; y2 = yT; }
3351 
3352  // calculate the slope of m13 which is never undefined since x1 != x3
3353  double m13 = (y1 - y3) / (x1 - x3);
3354 
3355  // calculate the square and cube of x2
3356  double x2_2 = x2 * x2;
3357  double x2_3 = x2 * x2_2;
3358 
3359  // calculate the volume from integrating from x1 to x2
3360  double V12 = 0.0;
3361  if (fabs(x1-x2) > 1.0e-14) // @@@ need to make this relative
3362  {
3363  double m12 = (y1 - y2) / (x1 - x2);
3364  double x1_2 = x1 * x1;
3365  double x1_3 = x1 * x1_2;
3366  V12 = (m12 - m13) * ((x2_3 - x1_3) / 3.0 - x1 * (x2_2 - x1_2) / 2.0);
3367  }
3368 
3369  // calculate the volume from integrating from x2 to x3
3370  double V23 = 0.0;
3371  if (fabs(x2-x3) > 1.0e-14) // @@@ need to make this relative
3372  {
3373  double m23 = (y2 - y3) / (x2 - x3);
3374  double x3_2 = x3 * x3;
3375  double x3_3 = x3 * x3_2;
3376  V23 = (m23 - m13) * ((x3_3 - x2_3) / 3.0 - x3 * (x3_2 - x2_2) / 2.0);
3377  }
3378 
3379  // calculate the total volume
3380  double pi = M_PI;
3381  double V = 2.0 * pi * (fabs(V12) + fabs(V23));
3382  return V;
3383 }
3384 
3385 //-----------------------------------------------------------------------------
3386 // Function : PDE_2DMesh::computeAngle
3387 // Description : This function computes the angle between the three nodes.
3388 // The angle is assumed to be less than PI radians.
3389 // Special Notes :
3390 // Scope : private
3391 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3392 // Creation Date : 04/22/02
3393 //-----------------------------------------------------------------------------
3394 double PDE_2DMesh::computeAngle (int inode1,int inode2,int inode3)
3395 {
3396  mNode n1 = mNodeVector[inode1];
3397  mNode n2 = mNodeVector[inode2];
3398  mNode n3 = mNodeVector[inode3];
3399 
3400  double xl = n1.x - n2.x;
3401  double xr = n3.x - n2.x;
3402  double yl = n1.y - n2.y;
3403  double yr = n3.y - n2.y;
3404 
3405  double r = (xl*xr+yl*yr)/(sqrt(sq(xl)+sq(yl))*sqrt(sq(xr)+sq(yr)));
3406  if (r > 1.0) r = 1.0;
3407  else if (r < -1.0) r = -1.0;
3408 
3409  double angle = acos(r);
3410  //double pi = M_PI;
3411  // if (xl*yr-xr*yl > 0) angle = 2*pi - angle;
3412  return angle;
3413 }
3414 
3415 //-----------------------------------------------------------------------------
3416 // Function : PDE_2DMesh::cellNodes
3417 // Description : This function determines the nodes of all the cells:
3418 // Special Notes :
3419 // Scope : private
3420 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3421 // Creation Date : 04/22/02
3422 //-----------------------------------------------------------------------------
3424 {
3425 
3426  // set up cell Node lists:
3427  std::vector<mCell>::iterator first = mCellVector.begin();
3428  std::vector<mCell>::iterator last = mCellVector.end ();
3429  std::vector<mCell>::iterator iter;
3430 
3431  int i;
3432  for (i=0,iter=first; iter!=last ; ++i, ++iter)
3433  {
3434  mCell & cellObj = *iter;
3435 
3436  int iedgeDA = cellObj.iedgeDA;
3437 
3438  mEdge edgeAB = mEdgeVector[cellObj.iedgeAB];
3439  mEdge edgeBC = mEdgeVector[cellObj.iedgeBC];
3440  mEdge edgeCD = mEdgeVector[cellObj.iedgeCD];
3441 
3442  // temporary vector of node indices:
3443  int inode[9];
3444 
3445  inode[0] = edgeAB.inodeA;
3446  inode[1] = edgeAB.inodeB;
3447  inode[2] = edgeBC.inodeA;
3448  inode[3] = edgeBC.inodeB;
3449  inode[4] = edgeCD.inodeA;
3450  inode[5] = edgeCD.inodeB;
3451 
3452  // triangular element
3453  if (iedgeDA == -1)
3454  {
3455  if (inode[0] == inode[2])
3456  {
3457  cellObj.mNodeVector[VERTEX_A] = inode[1];
3458  cellObj.mNodeVector[VERTEX_B] = inode[0];
3459  cellObj.mNodeVector[VERTEX_C] = inode[3];
3460  cellObj.inodeA = inode[1];
3461  cellObj.inodeB = inode[0];
3462  cellObj.inodeC = inode[3];
3463  }
3464  else if (inode[0] == inode[3])
3465  {
3466  cellObj.mNodeVector[VERTEX_A] = inode[1];
3467  cellObj.mNodeVector[VERTEX_B] = inode[0];
3468  cellObj.mNodeVector[VERTEX_C] = inode[2];
3469  cellObj.inodeA = inode[1];
3470  cellObj.inodeB = inode[0];
3471  cellObj.inodeC = inode[2];
3472  }
3473  else if (inode[1] == inode[2])
3474  {
3475  cellObj.mNodeVector[VERTEX_A] = inode[0];
3476  cellObj.mNodeVector[VERTEX_B] = inode[1];
3477  cellObj.mNodeVector[VERTEX_C] = inode[3];
3478  cellObj.inodeA = inode[0];
3479  cellObj.inodeB = inode[1];
3480  cellObj.inodeC = inode[3];
3481  }
3482  else
3483  {
3484  cellObj.mNodeVector[VERTEX_A] = inode[0];
3485  cellObj.mNodeVector[VERTEX_B] = inode[1];
3486  cellObj.mNodeVector[VERTEX_C] = inode[2];
3487  cellObj.inodeA = inode[0];
3488  cellObj.inodeB = inode[1];
3489  cellObj.inodeC = inode[2];
3490  }
3491  cellObj.mNodeVector[VERTEX_D] = -1;
3492  cellObj.inodeD = -1;
3493  }
3494  // rectangular element
3495  else
3496  {
3497  mEdge edgeDA = mEdgeVector[cellObj.iedgeDA];
3498 
3499  inode[6] = edgeDA.inodeA;
3500  inode[7] = edgeDA.inodeB;
3501 
3502  if ((inode[0] == inode[2]) || (inode[0] == inode[3]))
3503  {
3504  cellObj.mNodeVector[VERTEX_A] = inode[1];
3505  cellObj.mNodeVector[VERTEX_B] = inode[0];
3506  cellObj.inodeA = inode[1];
3507  cellObj.inodeB = inode[0];
3508  }
3509  else
3510  {
3511  cellObj.mNodeVector[VERTEX_A] = inode[0];
3512  cellObj.mNodeVector[VERTEX_B] = inode[1];
3513  cellObj.inodeA = inode[0];
3514  cellObj.inodeB = inode[1];
3515  }
3516  if ((inode[4] == inode[2]) || (inode[4] == inode[3]))
3517  {
3518  cellObj.mNodeVector[VERTEX_C] = inode[4];
3519  cellObj.mNodeVector[VERTEX_D] = inode[5];
3520  cellObj.inodeC = inode[4];
3521  cellObj.inodeD = inode[5];
3522  }
3523  else
3524  {
3525  cellObj.mNodeVector[VERTEX_C] = inode[5];
3526  cellObj.mNodeVector[VERTEX_D] = inode[4];
3527  cellObj.inodeC = inode[5];
3528  cellObj.inodeD = inode[4];
3529  }
3530  }
3531  } // end of cell loop.
3532 
3533  return true;
3534 }
3535 
3536 //-----------------------------------------------------------------------------
3537 // Function : PDE_2DMesh::fCCWorder
3538 // Description : This function determines if a rotation from segment 12 to
3539 // segment 13 is in the counter-clockwise direction.
3540 // Special Notes :
3541 // Scope : private
3542 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3543 // Creation Date : 04/22/02
3544 //-----------------------------------------------------------------------------
3545 bool PDE_2DMesh::fCCWorder (int inode1, int inode2, int inode3)
3546 {
3547  mNode node1 = mNodeVector[inode1];
3548  mNode node2 = mNodeVector[inode2];
3549  mNode node3 = mNodeVector[inode3];
3550 
3551  double x1 = node1.x;
3552  double y1 = node1.y;
3553  double x2 = node2.x;
3554  double y2 = node2.y;
3555  double x3 = node3.x;
3556  double y3 = node3.y;
3557 
3558  double x12 = x2 - x1;
3559  double y12 = y2 - y1;
3560  double x13 = x3 - x1;
3561  double y13 = y3 - y1;
3562 
3563  double d12 = sqrt(x12*x12 + y12*y12);
3564  double d13 = sqrt(x13*x13 + y13*y13);
3565 
3566  double arg12 = x12/d12;
3567  double arg13 = x13/d13;
3568 
3569  if (arg12 < -1.0) arg12 = 1.0; else if (arg12 > 1.0) arg12 = 1.0;
3570  if (arg13 < -1.0) arg13 = 1.0; else if (arg13 > 1.0) arg13 = 1.0;
3571 
3572  double a12 = acos(arg12);
3573  double a13 = acos(arg13);
3574 
3575  double pi = M_PI;
3576 
3577  if (y12 < 0) a12 = 2*pi - a12;
3578  if (y13 < 0) a13 = 2*pi - a13;
3579 
3580  return (a13 > a12) ? true : false;
3581 }
3582 
3583 //-----------------------------------------------------------------------------
3584 // Function : PDE_2DMesh::elementNodes
3585 // Purpose : This function determines the three nodes of a triangle
3586 // or the four nodes of a rectangle, whatever the
3587 // Special Notes :
3588 // Scope : public
3589 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3590 // Creation Date : 11/26/02
3591 //-----------------------------------------------------------------------------
3592 void PDE_2DMesh::elementNodes (int itri, int *ainode)
3593 {
3594  int iedgeAB = mCellVector[itri].iedgeAB;
3595  int inode1 = mEdgeVector[iedgeAB].inodeA;
3596  int inode2 = mEdgeVector[iedgeAB].inodeB;
3597 
3598  int iedgeBC = mCellVector[itri].iedgeBC;
3599  int inode3 = mEdgeVector[iedgeBC].inodeA;
3600  int inode4 = mEdgeVector[iedgeBC].inodeB;
3601 
3602  int iedgeDA = mCellVector[itri].iedgeDA;
3603  if (iedgeDA == -1) // triangular element
3604  {
3605  if (inode1 == inode3)
3606  {
3607  ainode[VERTEX_A] = inode2;
3608  ainode[VERTEX_B] = inode1;
3609  ainode[VERTEX_C] = inode4;
3610  }
3611  else if (inode1 == inode4)
3612  {
3613  ainode[VERTEX_A] = inode2;
3614  ainode[VERTEX_B] = inode1;
3615  ainode[VERTEX_C] = inode3;
3616  }
3617  else if (inode2 == inode3)
3618  {
3619  ainode[VERTEX_A] = inode1;
3620  ainode[VERTEX_B] = inode2;
3621  ainode[VERTEX_C] = inode4;
3622  }
3623  else
3624  {
3625  ainode[VERTEX_A] = inode1;
3626  ainode[VERTEX_B] = inode2;
3627  ainode[VERTEX_C] = inode3;
3628  }
3629  ainode[VERTEX_D] = -1;
3630  }
3631  else // rectangular element
3632  {
3633  int iedgeCD = mCellVector[itri].iedgeCD;
3634  int inode5 = mEdgeVector[iedgeCD].inodeA;
3635  int inode6 = mEdgeVector[iedgeCD].inodeB;
3636 
3637  if ((inode1 == inode3) || (inode1 == inode4))
3638  {
3639  ainode[VERTEX_A] = inode2;
3640  ainode[VERTEX_B] = inode1;
3641  }
3642  else
3643  {
3644  ainode[VERTEX_A] = inode1;
3645  ainode[VERTEX_B] = inode2;
3646  }
3647 
3648  if ((inode5 == inode3) || (inode5 == inode4))
3649  {
3650  ainode[VERTEX_C] = inode5;
3651  ainode[VERTEX_D] = inode6;
3652  }
3653  else
3654  {
3655  ainode[VERTEX_C] = inode6;
3656  ainode[VERTEX_D] = inode5;
3657  }
3658  }
3659 }
3660 
3661 //-----------------------------------------------------------------------------
3662 // Function : PDE_2DMesh::getElementInfo
3663 //
3664 // Purpose : This function initialize the ainode, aiedge, aitri and
3665 // auLabel arrays with the elements node indices,
3666 // edge indices, adjacent triangle indices and label indices.
3667 // Special Notes :
3668 // Scope : public
3669 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3670 // Creation Date : 11/26/02
3671 //-----------------------------------------------------------------------------
3673  (int itri, int *ainode, int *aiedge, int *aitri, int *auLabel)
3674 {
3675  elementNodes(itri,ainode);
3676 
3677  int iedgeAB, iedgeBC, iedgeCD, iedgeDA;
3678 
3679  iedgeAB = aiedge[0] = mCellVector[itri].iedgeAB;
3680  iedgeBC = aiedge[1] = mCellVector[itri].iedgeBC;
3681  iedgeCD = aiedge[2] = mCellVector[itri].iedgeCD;
3682  iedgeDA = aiedge[3] = mCellVector[itri].iedgeDA;
3683 
3684  aitri[0] = mCellVector[itri].icellAB;
3685  aitri[1] = mCellVector[itri].icellBC;
3686  aitri[2] = mCellVector[itri].icellCD;
3687  aitri[3] = mCellVector[itri].icellDA;
3688 
3689  auLabel[0] = mEdgeVector[iedgeAB].uLabel;
3690  auLabel[1] = mEdgeVector[iedgeBC].uLabel;
3691  auLabel[2] = mEdgeVector[iedgeCD].uLabel;
3692  auLabel[3] = (iedgeDA != -1) ? mEdgeVector[iedgeDA].uLabel : -1;
3693 }
3694 
3695 //-----------------------------------------------------------------------------
3696 // Function : PDE_2DMesh::initNodeAdjStructure
3697 // Purpose : This function initializes the static adjacency structure
3698 // with the neighbors of the specified node.
3699 // Special Notes :
3700 // Scope : public
3701 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3702 // Creation Date : 11/26/02
3703 //-----------------------------------------------------------------------------
3705  (NADJ &nadj, int itri, int iVertex, int uIntLabel, bool fCW)
3706 {
3707  int inode;
3708  int ainode[4];
3709  int aiedge[4];
3710  int aitri[4];
3711  int auLabel[4];
3712 
3713  // vertices to edge map
3714  int aauVertices2Edge[4][4] =
3715  { // VERTEX_A VERTEX_B VERTEX_C VERTEX_D
3716  { /* VERTEX_A */ -1 , EDGE_AB , EDGE_AC , EDGE_AD },
3717  { /* VERTEX_B */ EDGE_AB , -1 , EDGE_BC , -1 },
3718  { /* VERTEX_C */ EDGE_AC , EDGE_BC , -1 , EDGE_CD },
3719  { /* VERTEX_D */ EDGE_AD , -1 , EDGE_CD , -1 }
3720  };
3721 
3722  // initialize variables
3723  getElementInfo(itri, ainode, aiedge, aitri, auLabel);
3724  int cVertices = (ainode[VERTEX_D] != -1) ? 4 : 3;
3725  int cnode = 0;
3726  nadj.cnode = 0;
3727  nadj.inode = ainode[iVertex];
3728  nadj.fBndry = true;
3729  nadj.fGotAll = false;
3730 
3731 
3732  // determine the direction to rotate
3733  int fCCW = fCCWorder(ainode[VERTEX_A], ainode[VERTEX_B], ainode[VERTEX_C]);
3734  int nNextVertex = (fCCW == fCW) ? 1 : -1;
3735  int i = (iVertex + nNextVertex + cVertices) % cVertices;
3736  int i1 = aauVertices2Edge[iVertex][i];
3737  nadj.ainode[0] = inode = ainode[i];
3738  nadj.aiedge[0] = aiedge[i1];
3739  nadj.aielem[0] = itri;
3740  bool fBndry = (auLabel[i1] != uIntLabel);
3741 
3742  // loop around and find the nodes
3743  for(;;)
3744  { for(i = 0; i < cVertices; ++i)
3745  { if (ainode[i] == nadj.inode) iVertex = i;
3746  if (ainode[i] == inode) i1 = i;
3747  }
3748  UINT iA = (iVertex + 1) % cVertices;
3749  UINT iB = (iVertex + cVertices - 1) % cVertices;
3750  UINT iV = (i1 == iA) ? iB : iA;
3751  UINT iE = aauVertices2Edge[iVertex][iV];
3752 
3753  nadj.auLabel[cnode] = mCellVector[itri].uLabel;
3754  ++cnode;
3755  nadj.ainode[cnode] = inode = ainode[iV];
3756  nadj.aiedge[cnode] = aiedge[iE];
3757  nadj.aielem[cnode] = aitri[iE];
3758  fBndry = fBndry || (auLabel[iE] != uIntLabel);
3759  itri = aitri[iE];
3760 
3761  if (nadj.ainode[cnode] == nadj.ainode[0])
3762  { nadj.fGotAll = true;
3763  break;
3764  }
3765 
3766  if (itri == -1) break;
3767 
3768  getElementInfo(itri, ainode, aiedge, aitri, auLabel);
3769  cVertices = (ainode[VERTEX_D] != -1) ? 4 : 3;
3770  }
3771 
3772  nadj.fBndry = fBndry;
3773  nadj.cnode = (nadj.fGotAll) ? cnode : cnode + 1;
3774 }
3775 
3776 //-----------------------------------------------------------------------------
3777 // Function : PDE_2DMesh::calcAdjacencyInfo
3778 //
3779 // Purpose : This function calcultes the node adjacency information.
3780 // This includes things such as integration box areas,
3781 // edge lengths, bisector lengths, partial areas, etc.
3782 // It works for structured and non-structured meshes.
3783 // (non-structured = triangle based)
3784 //
3785 // Special Notes : This is a modified version of a similar function from
3786 // SGF's refine program. Eventually, it needs to be
3787 // refactored a bit to take better advantage of Xyce's data
3788 // structures. At the moment it relies a little too much
3789 // on SGF mesh primatives, and C-style implementation.
3790 //
3791 // Scope : public
3792 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
3793 // Creation Date : 11/26/02
3794 //-----------------------------------------------------------------------------
3796 {
3797  int i, j, k;
3798 
3799  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
3800  {
3801  Xyce::dout() << "In PDE_2DMesh::calcAdjacencyInfo" << std::endl;
3802  }
3803 
3804  // if neccessary, do some allocations:
3805  if (!adjInfoAllocFlag)
3806  {
3807  afVisitedVec.resize(numNodes,0);
3808  aiBegin = new int [numRegLabels];
3809  aiEnd = new int [numRegLabels];
3810  }
3811 
3812  // initialize the visit flag array
3813  for (i=0;i<numNodes;++i) afVisitedVec[i] = 0;
3814 
3815 #if 0
3816  // allocate start and ending region indices
3817  int cRegion = 1; // just SI. for now... This will need updating later.
3818 #endif
3819 
3820  // loop through each element
3821  for(i = 0; i < numCells; ++i)
3822  {
3823  // get the 3 or 4 nodes of this cell:
3824  int ainode[4];
3825  elementNodes(i, ainode);
3826  int *pinode = ainode;
3827 
3828  // loop over the 3 or 4 nodes of the current cell.
3829  for(j = 0; j < 4; ++j, ++pinode)
3830  {
3831  // only process this node if it has not been visited yet.
3832  if ( (afVisitedVec[*pinode]==0) && (*pinode != -1) )
3833  {
3834  afVisitedVec[*pinode] = 1;
3835 
3836  // store the adjacent nodes in the nadj structure
3837  NADJ nadj;
3838  initNodeAdjStructure(nadj, i, j, -1, false);
3839 
3840  // hit an edge w/o an adjacent triangle ... need to find the nodes
3841  // we may have missed
3842  if (!nadj.fGotAll)
3843  {
3844  NADJ nadjT;
3845  initNodeAdjStructure(nadjT, i, j, -1, true);
3846  int c = nadjT.cnode - 2;
3847  for(k = nadj.cnode - 1; k != -1; --k)
3848  {
3849  nadj.ainode [k + c] = nadj.ainode[k];
3850  nadj.aiedge [k + c] = nadj.aiedge[k];
3851  nadj.auLabel[k + c] = nadj.auLabel[k];
3852  }
3853  for(k = 0; k < c; ++k)
3854  {
3855  nadj.ainode [k] = nadjT.ainode[nadjT.cnode - k - 1];
3856  nadj.aiedge [k] = nadjT.aiedge[nadjT.cnode - k - 1];
3857  nadj.auLabel[k] = nadjT.auLabel[nadjT.cnode - k - 2];
3858  }
3859  nadj.cnode += c;
3860  }
3861 
3862  // compute the corners of the integration box
3863  int c = nadj.cnode;
3864  double x[32];
3865  double y[32];
3866 
3867  double xA = mNodeVector[nadj.inode].x;
3868  double yA = mNodeVector[nadj.inode].y;
3869  if (!nadj.fGotAll)
3870  {
3871  x[0] = (xA + mNodeVector[nadj.ainode[0]].x) / 2.0;
3872  y[0] = (yA + mNodeVector[nadj.ainode[0]].y) / 2.0;
3873  }
3874  else
3875  {
3876  computeIntPB(x[0],y[0],nadj.inode,nadj.ainode[0],nadj.ainode[c-1]);
3877  }
3878 
3879  for(k = 0; k < c-1; ++k)
3880  {
3881  computeIntPB
3882  (x[k+1],y[k+1],nadj.inode,nadj.ainode[k],nadj.ainode[k+1]);
3883  }
3884 
3885  if (!nadj.fGotAll)
3886  {
3887  x[c] = (xA + mNodeVector[nadj.ainode[c-1]].x) / 2.0;
3888  y[c] = (yA + mNodeVector[nadj.ainode[c-1]].y) / 2.0;
3889  }
3890  else
3891  { x[c] = x[0];
3892  y[c] = y[0];
3893  }
3894 
3895  // compute the node and edge information
3896  NODEINFO nodeinfo;
3897  EDGEINFO aedgeinfo[32];
3898  UINT cTriangle = (nadj.fGotAll) ? c : c-1;
3899  nodeinfo.cNeighbor = c;
3900  nodeinfo.cTriangle = cTriangle;
3901  nodeinfo.Area = 0.0;
3902  for(k = 0; k < c; ++k)
3903  {
3904  double xB = mNodeVector[nadj.ainode[k]].x;
3905  double yB = mNodeVector[nadj.ainode[k]].y;
3906  double elen = sqrt(sq(xA-xB)+sq(yA-yB));
3907  double ilen, area;
3908  if (cylGeom)
3909  {
3910  ilen = lengthAdjust(x[k],y[k],x[k+1],y[k+1]);
3911  area = areaAdjust(xA,yA,x[k],y[k],x[k+1],y[k+1]);
3912  }
3913  else
3914  {
3915  ilen = sqrt(sq(x[k]-x[k+1])+sq(y[k]-y[k+1]));
3916  area = ilen * elen * 0.25;
3917  }
3918  aedgeinfo[k].iedge = nadj.aiedge[k];
3919  aedgeinfo[k].inode = nadj.ainode[k];
3920  aedgeinfo[k].ielem = nadj.aielem[k];
3921  aedgeinfo[k].ilen = ilen;
3922  aedgeinfo[k].elen = elen;
3923  aedgeinfo[k].Area1 = area;
3924  aedgeinfo[k].Area2 = 0.0;
3925  nodeinfo.Area += area;
3926  }
3927 
3928  for(k = 0; k < cTriangle; ++k)
3929  {
3930  double xB = mNodeVector[nadj.ainode[k]].x;
3931  double yB = mNodeVector[nadj.ainode[k]].y;
3932  double xC = mNodeVector[nadj.ainode[k+1]].x;
3933  double yC = mNodeVector[nadj.ainode[k+1]].y;
3934  double xo = x[k+1];
3935  double yo = y[k+1];
3936  double xAB = (xA+xB)/2.0;
3937  double yAB = (yA+yB)/2.0;
3938  double xAC = (xA+xC)/2.0;
3939  double yAC = (yA+yC)/2.0;
3940  double area;
3941  if (cylGeom)
3942  {
3943  area = areaAdjust(xA,yA,xo,yo,xAB,yAB)+
3944  areaAdjust(xA,yA,xo,yo,xAC,yAC);
3945  }
3946  else
3947  {
3948  area = 0.5*
3949  (sqrt(sq(xAB-xA)+sq(yAB-yA))*sqrt(sq(xAB-xo)+sq(yAB-yo))+
3950  sqrt(sq(xAC-xA)+sq(yAC-yA))*sqrt(sq(xAC-xo)+sq(yAC-yo)));
3951  }
3952  aedgeinfo[k].Area2 = area;
3953  }
3954 
3955 #if 0
3956  // write the node and edge information to disk
3957  write(nFile, &nadj.inode, sizeof(INODE));
3958  write(nFile, &nodeinfo, sizeof(NODEINFO) - sizeof(EDGEINFO *));
3959  write(nFile, aedgeinfo, c * sizeof(EDGEINFO));
3960 #else
3961  // fill in mNode class w/information from nodeinfo.
3962  mNodeVector[*pinode].area = nodeinfo.Area;
3963  mNodeVector[*pinode].cnode = nodeinfo.cNeighbor;
3964  mNodeVector[*pinode].numCells = nodeinfo.cTriangle;
3965 
3966  // fill in the edgeInfo...
3967  mNodeVector[*pinode].edgeInfoVector.resize
3968  (mNodeVector[*pinode].cnode);
3969  for (k=0;k<mNodeVector[*pinode].cnode;++k)
3970  {
3971  mNodeVector[*pinode].edgeInfoVector[k] = aedgeinfo[k];
3972 
3973  mEdge & edgeTmp =
3974  mEdgeVector[mNodeVector[*pinode].edgeInfoVector[k].iedge];
3975 
3976  edgeTmp.elen = mNodeVector[*pinode].edgeInfoVector[k].elen;
3977  edgeTmp.ilen = mNodeVector[*pinode].edgeInfoVector[k].ilen;
3978  edgeTmp.Area1 = mNodeVector[*pinode].edgeInfoVector[k].Area1;
3979  edgeTmp.Area2 = mNodeVector[*pinode].edgeInfoVector[k].Area2;
3980  }
3981 #endif
3982  // Is this node a boundary node?
3983  // may need to change this if statement later. It dependes upon the
3984  // node list being ordered a certain way. Either have to use a boundary
3985  // stencil instead, or make certain to re-order all the nodes.
3986 
3987  // For a boundary node, we do extra stuff - a different
3988  // set of edgeInfo's have to be generated for each region. So
3989  // if this node is on the boundary between SI and SIO2, then
3990  // there needs to be an edgeinfo for SI and SIO2, in addition
3991  // to the default (which covers both).
3992  // For now, multiple regions are not supported, so this stuff
3993  // is commented out. FIX LATER.
3994 #if 0
3995  int l;
3996  if (nadj.inode < numBndryNodes)
3997  {
3998  // compute the start and end of the regions
3999  int *piBegin = aiBegin;
4000  int *piEnd = aiEnd;
4001  for(k = 0; k < cRegion; ++k, ++piBegin, ++piEnd)
4002  {
4003  *piBegin = *piEnd = -1;
4004  }
4005 
4006  int c = nadj.cnode;
4007  if (!nadj.fGotAll) --c;
4008  int *puLabel = nadj.auLabel;
4009  for(k = 0; k < c; ++k, ++puLabel)
4010  {
4011  int uLabel = *puLabel;
4012  if (aiBegin[uLabel] == -1)
4013  {
4014  aiBegin[uLabel] = k;
4015  aiEnd[uLabel] = k + 1;
4016  }
4017  else if (aiEnd[uLabel] == k) ++aiEnd[uLabel];
4018  }
4019  int uLabel = nadj.auLabel[0];
4020  puLabel = nadj.auLabel + c - 1;
4021  for(k = c; *puLabel == uLabel; --k, --puLabel);
4022  aiBegin[uLabel] = k % c;
4023 
4024  // write the node and edge information to disk
4025  piBegin = aiBegin;
4026  piEnd = aiEnd;
4027  for(k = 0; k < cRegion; ++k, ++piBegin, ++piEnd)
4028  {
4029  int iBegin = *piBegin;
4030  int iEnd = *piEnd;
4031  int cEdge = 0;
4032  if (iBegin != -1)
4033  {
4034  cEdge = (iEnd > iBegin) ? iEnd - iBegin : (c + iEnd) - iBegin;
4035  ++cEdge;
4036  }
4037  iEnd %= nadj.cnode;
4038  int cTEdge = (cEdge) ? cEdge - 1 : 0;
4039  nodeinfo.cNeighbor = cEdge;
4040  nodeinfo.cTriangle = cTEdge;
4041  nodeinfo.Area = 0.0;
4042  for(l = 0; l < cEdge; ++l)
4043  {
4044  int m = (iBegin + l) % nadj.cnode;
4045  double xB = mNodeVector[nadj.ainode[m]].x;
4046  double yB = mNodeVector[nadj.ainode[m]].y;
4047  double xmdpt = (xA + xB) / 2.0;
4048  double ymdpt = (yA + yB) / 2.0;
4049  double elen = sqrt(sq(xA-xB)+sq(yA-yB));
4050  double ilen, area, x1, y1, x2, y2;
4051  if (m == iBegin)
4052  { x1 = xmdpt; x2 = x[m+1];
4053  y1 = ymdpt; y2 = y[m+1];
4054  }
4055  else if (m == iEnd)
4056  { x1 = x[m]; x2 = xmdpt;
4057  y1 = y[m]; y2 = ymdpt;
4058  }
4059  else
4060  { x1 = x[m]; x2 = x[m+1];
4061  y1 = y[m]; y2 = y[m+1];
4062  }
4063  if (cylGeom)
4064  { ilen = lengthAdjust(x1,y1,x2,y2);
4065  area = areaAdjust(xA,yA,x1,y1,x2,y2);
4066  }
4067  else
4068  { ilen = sqrt(sq(x1-x2)+sq(y1-y2));
4069  area = ilen * elen / 4.0;
4070  }
4071  aedgeinfo[l].iedge = nadj.aiedge[m];
4072  aedgeinfo[l].inode = nadj.ainode[m];
4073  aedgeinfo[l].ielem = nadj.aielem[m];
4074  aedgeinfo[l].ilen = ilen;
4075  aedgeinfo[l].elen = elen;
4076  aedgeinfo[l].Area1 = area;
4077  aedgeinfo[l].Area2 = 0.0;
4078  nodeinfo.Area += area;
4079  }
4080 
4081  for(l = 0; l < cTEdge; ++l)
4082  { int m = (iBegin + l) % nadj.cnode;
4083  int n = (m + 1) % nadj.cnode;
4084  //PNODE pnodeB = danode.GetPointer(nadj.ainode[m]);
4085  double xB = mNodeVector[nadj.ainode[m]].x;
4086  double yB = mNodeVector[nadj.ainode[m]].y;
4087  //PNODE pnodeC = danode.GetPointer(nadj.ainode[n]);
4088  double xC = mNodeVector[nadj.ainode[n]].x;
4089  double yC = mNodeVector[nadj.ainode[n]].y;
4090  double xo = x[m+1];
4091  double yo = y[m+1];
4092  double xAB = (xA+xB)/2.0;
4093  double yAB = (yA+yB)/2.0;
4094  double xAC = (xA+xC)/2.0;
4095  double yAC = (yA+yC)/2.0;
4096  double area;
4097  if (cylGeom)
4098  { area = areaAdjust(xA,yA,xo,yo,xAB,yAB)+
4099  areaAdjust(xA,yA,xo,yo,xAC,yAC);
4100  }
4101  else
4102  { area = 0.5*
4103  (sqrt(sq(xAB-xA)+sq(yAB-yA))*sqrt(sq(xAB-xo)+sq(yAB-yo))+
4104  sqrt(sq(xAC-xA)+sq(yAC-yA))*sqrt(sq(xAC-xo)+sq(yAC-yo)));
4105  }
4106  aedgeinfo[l].Area2 = area;
4107  }
4108 
4109  // write the node and edge information to disk
4110  int inode = numNodes + nadj.inode * cRegion + k;
4111 #if 0
4112  write(nFile, &inode, sizeof(INODE));
4113  write(nFile, &nodeinfo, sizeof(NODEINFO) - sizeof(EDGEINFO *));
4114  write(nFile, aedgeinfo, cEdge * sizeof(EDGEINFO));
4115 #else
4116  // fill in mNode class w/information from nodeinfo.
4117  // Check: is the mNodeVector big enough. FIX THIS!
4118  mNodeVector[inode].area = nodeinfo.Area;
4119  mNodeVector[inode].cnode = nodeinfo.cNeighbor;
4120  mNodeVector[inode].numCells = nodeinfo.cTriangle;
4121 
4122  // fill in the edgeInfo...
4123  mNodeVector[inode].edgeInfoVector.resize
4124  (mNodeVector[inode].cnode);
4125  for (k=0;k<mNodeVector[inode].cnode;++k)
4126  {
4127  mNodeVector[inode].edgeInfoVector[k] = aedgeinfo[k];
4128  mEdge & edgeTmp =
4129  mEdgeVector[mNodeVector[*pinode].edgeInfoVector[k].iedge];
4130 
4131  edgeTmp.elen = mNodeVector[*pinode].edgeInfoVector[k].elen;
4132  edgeTmp.ilen = mNodeVector[*pinode].edgeInfoVector[k].ilen;
4133  edgeTmp.Area1 = mNodeVector[*pinode].edgeInfoVector[k].Area1;
4134  edgeTmp.Area2 = mNodeVector[*pinode].edgeInfoVector[k].Area2;
4135  }
4136 #endif
4137  } // loop over regions.
4138  } // boundary node if statement.
4139 #endif
4140  } // if !visited if statement.
4141  } // loop over nodes of cell.
4142  } // loop over cells.
4143 
4144  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
4145  {
4146  Xyce::dout() << "Done with PDE_2DMesh::calcAdjacencyInfo" << std::endl;
4147  }
4148 
4149 }
4150 
4151 //-----------------------------------------------------------------------------
4152 // Function : PDE_2DMesh::labelNameExist
4153 // Description : This function returns a "true" if the label name specified
4154 // in the function argument exists in the mesh data structures.
4155 // Special Notes :
4156 // Scope : public
4157 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
4158 // Creation Date : 04/22/02
4159 //-----------------------------------------------------------------------------
4160 bool PDE_2DMesh::labelNameExist (std::string & labelName)
4161 {
4162  bool bsuccess = false;
4163 
4164  ExtendedString tmpName = labelName;
4165  tmpName.toUpper ();
4166 
4167  if ( mLabelMap.find(tmpName) != mLabelMap.end() ) bsuccess = true;
4168 
4169  return bsuccess;
4170 }
4171 
4172 //-----------------------------------------------------------------------------
4173 // Function : PDE_2DMesh::labelEdgeType
4174 // Description : This function returns a "true" if the label name specified
4175 // corresponds to an edge label (rather than a region label)
4176 // Special Notes :
4177 // Scope : public
4178 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
4179 // Creation Date : 04/22/02
4180 //-----------------------------------------------------------------------------
4181 bool PDE_2DMesh::labelEdgeType (std::string & labelName)
4182 {
4183  ExtendedString tmpName = labelName;
4184  tmpName.toUpper ();
4185 
4186  if ( mLabelMap.find(tmpName) != mLabelMap.end() )
4187  {
4188  if (mLabelMap[tmpName].uType == TYPE_EDGE) return true;
4189  }
4190 
4191  return false;
4192 
4193 }
4194 
4195 //-----------------------------------------------------------------------------
4196 // Function : PDE_2DMesh::getDopingVector
4197 // Description :
4198 // Special Notes :
4199 // Scope : public
4200 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
4201 // Creation Date : 04/22/02
4202 //-----------------------------------------------------------------------------
4203 bool PDE_2DMesh::getDopingVector (std::vector<double> & cvec_tmp)
4204 {
4205  cvec_tmp.resize(dopingVector.size(), 0.0);
4206  copy(dopingVector.begin(),dopingVector.end(),cvec_tmp.begin());
4207  return true;
4208 }
4209 
4210 //-----------------------------------------------------------------------------
4211 // Function : PDE_2DMesh::getXVector
4212 // Description :
4213 // Special Notes :
4214 // Scope : public
4215 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
4216 // Creation Date : 04/22/02
4217 //-----------------------------------------------------------------------------
4218 bool PDE_2DMesh::getXVector (std::vector<double> & xvec_tmp)
4219 {
4220  xvec_tmp.resize(xVector.size(), 0.0);
4221  copy(xVector.begin(),xVector.end(),xvec_tmp.begin());
4222  return true;
4223 }
4224 
4225 //-----------------------------------------------------------------------------
4226 // Function : PDE_2DMesh::getYVector
4227 // Description :
4228 // Special Notes :
4229 // Scope : public
4230 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
4231 // Creation Date : 04/22/02
4232 //-----------------------------------------------------------------------------
4233 bool PDE_2DMesh::getYVector (std::vector<double> & yvec_tmp)
4234 {
4235  yvec_tmp.resize(yVector.size(), 0.0);
4236  copy(yVector.begin(),yVector.end(),yvec_tmp.begin());
4237  return true;
4238 }
4239 
4240 //-----------------------------------------------------------------------------
4241 // Function : PDE_2DMesh::getLabel
4242 // Description : returns a pointer to the label with the specified name.
4243 // Special Notes :
4244 // Scope : public
4245 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
4246 // Creation Date : 04/27/02
4247 //-----------------------------------------------------------------------------
4248 mLabel * PDE_2DMesh::getLabel (std::string & labelName)
4249 {
4250 
4251  ExtendedString tmpName = labelName;
4252  tmpName.toUpper ();
4253 
4254  int index = 0;
4255  if ( mLabelMap.find(tmpName) != mLabelMap.end() )
4256  {
4257  index = mLabelMap[tmpName].iIndex;
4258  }
4259 
4260  return &(mLabelVector[index]);
4261 }
4262 
4263 //-----------------------------------------------------------------------------
4264 // Function : PDE_2DMesh::scaleMesh
4265 //
4266 // Description : This function scales mesh quantities such as area, ilen and
4267 // elen based on the passed-in scalar. The function accounts
4268 // for the geomtry (cylindrical or cartesian)
4269 //
4270 // Special Notes :
4271 // Scope : public
4272 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
4273 // Creation Date : 04/29/02
4274 //-----------------------------------------------------------------------------
4275 bool PDE_2DMesh::scaleMesh (double xScale)
4276 {
4277  if (meshScaledFlag == true)
4278  {
4279  meshScaledFlag = false;
4280  }
4281  else
4282  {
4283  meshScaledFlag = true;
4284  }
4285  // save the scale constant.
4286  x0 = xScale;
4287 
4288  double X0_1 = xScale;
4289  double X0_2 = xScale * X0_1;
4290  double X0_3 = xScale * X0_2;
4291 
4292  double scaleILEN, scaleArea;
4293  double scaleELEN = X0_1;
4294 
4295  if (cylGeom) { scaleILEN = X0_2; scaleArea = X0_3; }
4296  else { scaleILEN = X0_1; scaleArea = X0_2; }
4297 
4298  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
4299  {
4300  Xyce::dout() << section_divider << std::endl;
4301  Xyce::dout() << " In PDE_2DMesh::scaleMesh"<<std::endl;
4302  Xyce::dout() << " scaleELEN = " << scaleELEN <<std::endl;
4303  Xyce::dout() << " scaleILEN = " << scaleILEN <<std::endl;
4304  Xyce::dout() << " scaleArea = " << scaleArea <<std::endl;
4305  Xyce::dout() << section_divider << std::endl;
4306  }
4307 
4308  // Make everything reciprocals, so can use * instead of /.
4309  scaleELEN = 1.0/scaleELEN;
4310  scaleILEN = 1.0/scaleILEN;
4311  scaleArea = 1.0/scaleArea;
4312 
4313  int i;
4314  for (i=0;i<numNodes;++i)
4315  {
4316  mNodeVector[i].area *= scaleArea;
4317 
4318  std::vector<EDGEINFO>::iterator firstEI = mNodeVector[i].edgeInfoVector.begin ();
4319  std::vector<EDGEINFO>::iterator lastEI = mNodeVector[i].edgeInfoVector.end ();
4320  std::vector<EDGEINFO>::iterator iterEI;
4321  for (iterEI=firstEI;iterEI!=lastEI;++iterEI)
4322  {
4323  iterEI->ilen *= scaleILEN;
4324  iterEI->elen *= scaleELEN;
4325  iterEI->Area1 *= scaleArea;
4326  iterEI->Area2 *= scaleArea;
4327  }
4328  }
4329 
4330  for (i=0;i<numEdges;++i)
4331  {
4332  mEdgeVector[i].ilen *= scaleILEN;
4333  mEdgeVector[i].elen *= scaleELEN;
4334  mEdgeVector[i].Area1 *= scaleArea;
4335  mEdgeVector[i].Area2 *= scaleArea;
4336  }
4337 
4338  for (i=0;i<numLabels;++i)
4339  {
4340  mLabelVector[i].vol *= scaleArea;
4341  mLabelVector[i].surfArea *= scaleILEN;
4342  }
4343 
4344  std::map<std::string, mLabel>::iterator firstL = mLabelMap.begin ();
4345  std::map<std::string, mLabel>::iterator lastL = mLabelMap.end ();
4346  std::map<std::string, mLabel>::iterator iterL;
4347 
4348  for (iterL=firstL; iterL!=lastL; ++iterL)
4349  {
4350  iterL->second.vol *= scaleArea;
4351  iterL->second.surfArea *= scaleILEN;
4352  }
4353 
4354  xMax *= scaleELEN;
4355  xMin *= scaleELEN;
4356  yMax *= scaleELEN;
4357  yMin *= scaleELEN;
4358 
4359  for (i=0;i<numNodes;++i)
4360  {
4361  xVector[i] *= scaleELEN;
4362  yVector[i] *= scaleELEN;
4363  mNodeVector[i].x *= scaleELEN;
4364  mNodeVector[i].y *= scaleELEN;
4365  }
4366 
4367  return true;
4368 }
4369 
4370 //-----------------------------------------------------------------------------
4371 // Function : PDE_2DMesh::interp
4372 // Author : Eric Keiter
4373 // Scope : public
4374 // Description : This file returns an interpolated value for a function,
4375 // F, given the spatial location(r,z).
4376 //
4377 //-----------------------------------------------------------------------------
4378 double PDE_2DMesh::interp(double *F, double r, double z)
4379 {
4380  int iNodeA,iNodeB,iNodeC,iNodeD;
4381 
4382  mInterpAreaHelp intAHelp;
4383 
4384  double func;
4385 
4386  int iCell;
4387 
4388  int istatus = 0;
4389  int inode;
4390  findCell(r, z, istatus, inode, iCell, iRecentCellLookup);
4391  iRecentCellLookup = iCell;
4392 
4393  if (istatus == 2) return F[inode];
4394  if (istatus == -1) return 0.0;
4395 
4396  iNodeA = mCellVector[iCell].inodeA;
4397  iNodeB = mCellVector[iCell].inodeB;
4398  iNodeC = mCellVector[iCell].inodeC;
4399  iNodeD = mCellVector[iCell].inodeD;
4400 
4401  if(iNodeD == -1)
4402  {
4403  intAHelp.x0 = xVector[iNodeA];
4404  intAHelp.x1 = xVector[iNodeB];
4405  intAHelp.x2 = xVector[iNodeC];
4406  intAHelp.y0 = yVector[iNodeA];
4407  intAHelp.y1 = yVector[iNodeB];
4408  intAHelp.y2 = yVector[iNodeC];
4409  intAHelp.f0 = F[iNodeA];
4410  intAHelp.f1 = F[iNodeB];
4411  intAHelp.f2 = F[iNodeC];
4412  }
4413  else // need to figure out which half of rectangle.
4414  { // Either: ABC or ADC.
4415  intAHelp.x0 = xVector[iNodeA];
4416  intAHelp.x2 = xVector[iNodeC];
4417  intAHelp.y0 = yVector[iNodeA];
4418  intAHelp.y2 = yVector[iNodeC];
4419  intAHelp.f0 = F[iNodeA];
4420  intAHelp.f2 = F[iNodeC];
4421 
4422  double r1 = xVector[iNodeB];
4423  double r2 = xVector[iNodeD];
4424  double z1 = yVector[iNodeB];
4425  double z2 = yVector[iNodeD];
4426  double f1 = F[iNodeB];
4427  double f2 = F[iNodeD];
4428 
4429  if( pow((r1-r),2.0)+pow((z1-z),2.0) <
4430  pow((r2-r),2.0)+pow((z2-z),2.0)
4431  )
4432  {
4433  intAHelp.x1 = r1;
4434  intAHelp.y1 = z1;
4435  intAHelp.f1 = f1;
4436  }
4437  else
4438  {
4439  intAHelp.x1 = r2;
4440  intAHelp.y1 = z2;
4441  intAHelp.f1 = f2;
4442  }
4443  }
4444 
4445  // call the FindCoef function
4446  func = intAHelp.interpReg(r,z);
4447 
4448  return(func);
4449 }
4450 
4451 //-----------------------------------------------------------------------------
4452 // Function: PDE_2DMesh::interpVector
4453 // Author: Eric Keiter
4454 // Scope: public
4455 // Description: This file returns an interpolated value for a function,
4456 // F, given the spatial location(r,z).
4457 //
4458 // Note that the passed double precision array, F, is expected
4459 // to be a vector array, which corresponds to mesh edges. The
4460 // number of elements in it should equal the size of mEdgeVector.
4461 //
4462 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
4463 // Creation Date : 09/24/02
4464 //-----------------------------------------------------------------------------
4466  double *F,
4467  double r,
4468  double z,
4469  double & xvec,
4470  double & yvec)
4471 {
4472 
4473  mInterpAreaHelp intAHelp;
4474  int iEdgeAB, iEdgeBC, iEdgeCD, iEdgeDA;
4475 
4476  double ABx, ABy, ABangle, ABFx, ABFy;
4477  double BCx, BCy, BCangle, BCFx, BCFy;
4478  double CDx, CDy, CDangle, CDFx, CDFy;
4479  double DAx, DAy, DAangle, DAFx, DAFy;
4480  double xA, xB, yA, yB;
4481  int inodeA, inodeB;
4482 
4483  double alpha = 0.0;
4484  int inodeC, inodeD;
4485 
4486  // Find the cell.
4487  int iCell;
4488  int istatus = 0;
4489  int inode;
4490  findCell(r, z, istatus, inode, iCell,iRecentCellLookup);
4491  iRecentCellLookup = iCell;
4492 
4493  xvec = 0.0;
4494  yvec = 0.0;
4495 
4496  if (istatus==-1)
4497  {
4498  xvec = 0.0;
4499  yvec = 0.0;
4500  return true;
4501  }
4502 
4503  // Is this cell a rectangle or a triangle?
4504  bool triFlag = (mCellVector[iCell].inodeD == -1);
4505 
4506  int iA = mCellVector[iCell].inodeA;
4507  int iB = mCellVector[iCell].inodeB;
4508  int iC = mCellVector[iCell].inodeC;
4509  int iD = mCellVector[iCell].inodeD;
4510 
4511  // Look at each edge of the cell. Find the angle of each edge
4512  // with the x-axis.
4513  iEdgeAB = mCellVector[iCell].iedgeAB;
4514  iEdgeBC = mCellVector[iCell].iedgeBC;
4515  iEdgeCD = mCellVector[iCell].iedgeCD;
4516  if (triFlag) iEdgeDA = -1;
4517  else iEdgeDA = mCellVector[iCell].iedgeDA;
4518 
4519  //get the midpoints, angles of the edges:
4520  // AB
4521  inodeA = mEdgeVector[iEdgeAB].inodeA; xA=mNodeVector[inodeA].x; yA=mNodeVector[inodeA].y;
4522  inodeB = mEdgeVector[iEdgeAB].inodeB; xB=mNodeVector[inodeB].x; yB=mNodeVector[inodeB].y;
4523  ABx = 0.5*(xA+xB);
4524  ABy = 0.5*(yA+yB);
4525  ABangle = compAngle(xB,yB, xA,yA, (xA+0.1), yA);
4526  mEdgeVector[iEdgeAB].midpoint_x = ABx;
4527  mEdgeVector[iEdgeAB].midpoint_y = ABy;
4528  mEdgeVector[iEdgeAB].angle = ABangle;
4529  ABFx = F[iEdgeAB] * cos(ABangle);
4530  ABFy = F[iEdgeAB] * sin(ABangle);
4531 
4532  // BC
4533  inodeA = mEdgeVector[iEdgeBC].inodeA; xA=mNodeVector[inodeA].x; yA=mNodeVector[inodeA].y;
4534  inodeB = mEdgeVector[iEdgeBC].inodeB; xB=mNodeVector[inodeB].x; yB=mNodeVector[inodeB].y;
4535  BCx = 0.5*(xA+xB);
4536  BCy = 0.5*(yA+yB);
4537  BCangle = compAngle(xB,yB, xA,yA, (xA+0.1), yA);
4538  mEdgeVector[iEdgeBC].midpoint_x = BCx;
4539  mEdgeVector[iEdgeBC].midpoint_y = BCy;
4540  mEdgeVector[iEdgeBC].angle = BCangle;
4541  BCFx = F[iEdgeBC] * cos(BCangle);
4542  BCFy = F[iEdgeBC] * sin(BCangle);
4543 
4544  // CD
4545  inodeA = mEdgeVector[iEdgeCD].inodeA; xA=mNodeVector[inodeA].x; yA=mNodeVector[inodeA].y;
4546  inodeB = mEdgeVector[iEdgeCD].inodeB; xB=mNodeVector[inodeB].x; yB=mNodeVector[inodeB].y;
4547  CDx = 0.5*(xA+xB);
4548  CDy = 0.5*(yA+yB);
4549  CDangle = compAngle(xB,yB, xA,yA, (xA+0.1), yA);
4550  mEdgeVector[iEdgeCD].midpoint_x = CDx;
4551  mEdgeVector[iEdgeCD].midpoint_y = CDy;
4552  mEdgeVector[iEdgeCD].angle = CDangle;
4553  CDFx = F[iEdgeCD] * cos(CDangle);
4554  CDFy = F[iEdgeCD] * sin(CDangle);
4555 
4556  // DA
4557  if (!triFlag)
4558  {
4559  inodeA = mEdgeVector[iEdgeDA].inodeA; xA=mNodeVector[inodeA].x; yA=mNodeVector[inodeA].y;
4560  inodeB = mEdgeVector[iEdgeDA].inodeB; xB=mNodeVector[inodeB].x; yB=mNodeVector[inodeB].y;
4561  DAx = 0.5*(xA+xB);
4562  DAy = 0.5*(yA+yB);
4563  DAangle = compAngle(xB,yB, xA,yA, (xA+0.1), yA);
4564  mEdgeVector[iEdgeDA].midpoint_x = DAx;
4565  mEdgeVector[iEdgeDA].midpoint_y = DAy;
4566  mEdgeVector[iEdgeDA].angle = DAangle;
4567  DAFx = F[iEdgeDA] * cos(DAangle);
4568  DAFy = F[iEdgeDA] * sin(DAangle);
4569  }
4570  else
4571  {
4572  DAx = 0.0;
4573  DAy = 0.0;
4574  DAangle = 0.0;
4575  DAFx = 0.0;
4576  DAFy = 0.0;
4577  }
4578 
4579  bool madeIt = false;
4580 
4581  if (triFlag)
4582  {
4583  // If this is a triangular cell, do a "interp" interpolation to
4584  // get Fx and Fy at (r,z).
4585  intAHelp.x0 = ABx;
4586  intAHelp.x1 = BCx;
4587  intAHelp.x2 = CDx;
4588  intAHelp.y0 = ABy;
4589  intAHelp.y1 = BCy;
4590  intAHelp.y2 = CDy;
4591  intAHelp.f0 = ABFx;
4592  intAHelp.f1 = BCFx;
4593  intAHelp.f2 = CDFx;
4594 
4595  xvec = intAHelp.interpReg(r,z);
4596 
4597  intAHelp.f0 = ABFy;
4598  intAHelp.f1 = BCFy;
4599  intAHelp.f2 = CDFy;
4600 
4601  yvec = intAHelp.interpReg(r,z);
4602 
4603  madeIt = true;
4604  }
4605  else // rectangle: Note this assumes that if not a triangle,
4606  // the only other option is rectangle.
4607  {
4608  double alpha;
4609  int iA = mCellVector[iCell].inodeA;
4610  int iB = mCellVector[iCell].inodeB;
4611  int iC = mCellVector[iCell].inodeC;
4612  int iD = mCellVector[iCell].inodeD;
4613 
4614  if ((mNodeVector[iA].y == mNodeVector[iB].y)) // if AB and CD are parallel to x-axis.
4615  {
4616  alpha = ((ABy < CDy)?1.0:0.0) * (z-ABy)/(CDy-ABy) +
4617  ((ABy >= CDy)?1.0:0.0) * (ABy-z)/(ABy-CDy);
4618  xvec = (1.0-alpha)*ABFx + alpha*CDFx;
4619 
4620  alpha = ((BCx < DAx)?1.0:0.0) * (r-BCx)/(DAx-BCx) +
4621  ((BCx >= DAx)?1.0:0.0) * (BCx-r)/(BCx-DAx);
4622  yvec = (1.0-alpha)*BCFy + alpha*DAFy;
4623 
4624  madeIt = true;
4625  }
4626  else if ((mNodeVector[iA].x == mNodeVector[iB].x)) // if AB and CD are parallel to y-axis.
4627  {
4628  alpha = ((BCy < DAy)?1.0:0.0) * (z-BCy)/(DAy-BCy) +
4629  ((BCy >= DAy)?1.0:0.0) * (BCy-z)/(BCy-DAy);
4630  xvec = (1.0-alpha)*BCFx + alpha*DAFx;
4631 
4632  alpha = ((ABx < CDx)?1.0:0.0) * (r-ABx)/(CDx-ABx) +
4633  ((ABx >= CDx)?1.0:0.0) * (ABx-r)/(ABx-CDx);
4634  yvec = (1.0-alpha)*ABFy + alpha*CDFy;
4635 
4636  madeIt = true;
4637  }
4638  else
4639  {
4640  madeIt = false;
4641  }
4642  }
4643 
4644  if (DEBUG_DEVICE)
4645  {
4646  // debug output:
4647  double rtest = ((2.1e-3)/209.0) * 22.0;
4648  double rtol = fabs(rtest/1000.0);
4649  double ztest = -9.0e-5;
4650  double ztol = fabs(ztest/1000.0);
4651 
4652  if (!madeIt ||
4653  (xvec != 0.0 && !(xvec > 0.0) && !(xvec < 0.0)) ||
4654  (yvec != 0.0 && !(yvec > 0.0) && !(yvec < 0.0))
4655  || (r >= (rtest-rtol) && r <= (rtest+rtol) &&
4656  z >= (ztest-ztol) && z <= (ztest+ztol))
4657  )
4658  {
4659  Xyce::dout() << Xyce::section_divider << std::endl;
4660  Xyce::dout() << "Vector Interpolation failed!" << std::endl;
4661  Xyce::dout() << std::endl;
4662  Xyce::dout() << " iCell = " << iCell << std::endl;
4663  Xyce::dout() << " alpha = " << alpha << std::endl;
4664  Xyce::dout() << " number of cells on mesh: " << numCells << std::endl;
4665  Xyce::dout() << " r = " << r << std::endl;
4666  Xyce::dout() << " z = " << z << std::endl;
4667  Xyce::dout() << std::endl;
4668  Xyce::dout() << " xvec = " << xvec << std::endl;
4669  Xyce::dout() << " yvec = " << yvec << std::endl;
4670 
4671  Xyce::dout() << " inodeA = " << iA << std::endl;
4672  Xyce::dout() << " inodeB = " << iB << std::endl;
4673  Xyce::dout() << " inodeC = " << iC << std::endl;
4674  Xyce::dout() << " inodeD = " << iD << std::endl;
4675 
4676  Xyce::dout() << " nodeA (x,y) = ("<<mNodeVector[iA].x<<", "<<mNodeVector[iA].y<<")"<<std::endl;
4677  Xyce::dout() << " nodeB (x,y) = ("<<mNodeVector[iB].x<<", "<<mNodeVector[iB].y<<")"<<std::endl;
4678  Xyce::dout() << " nodeC (x,y) = ("<<mNodeVector[iC].x<<", "<<mNodeVector[iC].y<<")"<<std::endl;
4679  if (iD != -1)
4680  Xyce::dout() << " nodeD (x,y) = ("<<mNodeVector[iD].x<<", "<<mNodeVector[iD].y<<")"<<std::endl;
4681 
4682  double pi = M_PI;
4683  Xyce::dout() << " ABangle = " << ABangle << " = " <<(ABangle/pi)<< " * PI" << std::endl;
4684  Xyce::dout() << " BCangle = " << BCangle << " = " <<(BCangle/pi)<< " * PI" << std::endl;
4685  Xyce::dout() << " CDangle = " << CDangle << " = " <<(CDangle/pi)<< " * PI" << std::endl;
4686  if (iD != -1)
4687  Xyce::dout() << " DAangle = " << DAangle << " = " <<(DAangle/pi)<< " * PI" << std::endl;
4688 
4689  Xyce::dout() << " ABFx = " << ABFx << std::endl;
4690  Xyce::dout() << " ABFy = " << ABFy << std::endl;
4691  Xyce::dout() << " BCFx = " << BCFx << std::endl;
4692  Xyce::dout() << " BCFy = " << BCFy << std::endl;
4693  Xyce::dout() << " CDFx = " << CDFx << std::endl;
4694  Xyce::dout() << " CDFy = " << CDFy << std::endl;
4695  Xyce::dout() << " DAFx = " << DAFx << std::endl;
4696  Xyce::dout() << " DAFy = " << DAFy << std::endl;
4697 
4698  Xyce::dout() << " F[iEdgeAB] = " << F[iEdgeAB] <<std::endl;
4699  Xyce::dout() << " F[iEdgeBC] = " << F[iEdgeBC] <<std::endl;
4700  Xyce::dout() << " F[iEdgeCD] = " << F[iEdgeCD] <<std::endl;
4701  if (iEdgeDA != -1)
4702  Xyce::dout() << " F[iEdgeDA] = " << F[iEdgeDA] <<std::endl;
4703  Xyce::dout() << Xyce::section_divider << std::endl;
4704  Report::DevelFatal() << "Vector Interpolation failed";
4705  }
4706 
4707  }
4708 
4709  return true;
4710 }
4711 
4712 //-----------------------------------------------------------------------------
4713 // Function : PDE_2DMesh::findCell
4714 // Author : Eric Keiter
4715 // Scope : public
4716 //
4717 // Description : This function performs a search over the mesh to find the
4718 // mesh cell which contains the point (r,z). The test at each
4719 // cell requires that (r,z) be compared to the 3 or 4
4720 // lines(edges) which comprise the edges of the cell.
4721 // If it is found to be on the correct side of all 3 or
4722 // 4 edges, it is declared to be the correct cell and
4723 // the function exits.
4724 //
4725 // The original version of this function looped over the
4726 // array of mesh cells, and stopped when it had found the
4727 // correct one. This was really slow. This version
4728 // marches accross the mesh in a linked-list fashion,
4729 // going from cell to neighbor cell. It chooses the
4730 // next cell in the search based on which of the
4731 // neighbors is closest to (r,z).
4732 //
4733 // This function is usually called as part of an
4734 // interpolation, which is usually performed for the
4735 // purpose of plotting results.
4736 //
4737 // As such, the result of the previous "findCell" search
4738 // is often a very good starting cell for the current
4739 // search. The argument "iStartCell" should be the
4740 // callers best guess for which cell is likely to be the
4741 // correct cell. Usually, if one uses the class
4742 // variable "iRecentCellLookup" as the iStartCell argument,
4743 // the search will be very quick - at most it will look at
4744 // 2 or 3 cells.
4745 //
4746 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
4747 // Creation Date : 09/27/02
4748 //-----------------------------------------------------------------------------
4750  double r,
4751  double z,
4752  int & istatus,
4753  int & inode,
4754  int & iCell,
4755  int iStartCell)
4756 {
4757  int iEdgeAB,iEdgeBC,iEdgeCD,iEdgeDA;
4758  int iNodeA,iNodeB,iNodeC,iNodeD;
4759  bool doneFlag = false;
4760 
4761  mInterpEdgeHelp intEHelp;
4762 
4763  int ixhi,ixlo,iyhi,iylo;
4764 
4765  istatus = 0;
4766 
4767  iCell = iStartCell;
4768 
4769  // note: change this to a STL function call later, to speed it up.
4770  for (int i1=0;i1<numCells; ++i1) visitCellFlagVec[i1] = 0;
4771 
4772  // find the proper triangular/rectangular region
4773  while (!doneFlag)
4774  {
4775  iEdgeAB = mCellVector[iCell].iedgeAB;
4776  iEdgeBC = mCellVector[iCell].iedgeBC;
4777  iEdgeCD = mCellVector[iCell].iedgeCD;
4778  iEdgeDA = mCellVector[iCell].iedgeDA;
4779 
4780  iNodeA = mCellVector[iCell].inodeA;
4781  iNodeB = mCellVector[iCell].inodeB;
4782  iNodeC = mCellVector[iCell].inodeC;
4783  iNodeD = mCellVector[iCell].inodeD;
4784 
4785  // if (r,z) is exactly on one of the nodes, then the search is done.
4786  if(r==xVector[iNodeA] && z==yVector[iNodeA]){inode=iNodeA; istatus=2;}
4787  if(r==xVector[iNodeB] && z==yVector[iNodeB]){inode=iNodeB; istatus=2;}
4788  if(r==xVector[iNodeC] && z==yVector[iNodeC]){inode=iNodeC; istatus=2;}
4789  if(iNodeD != -1)
4790  if(r==xVector[iNodeD] && z==yVector[iNodeD]){inode=iNodeD; istatus=2;}
4791 
4792  if (istatus == 2) return;
4793 
4794  ixhi = 0;
4795  ixlo = 0;
4796  iyhi = 0;
4797  iylo = 0;
4798 
4799  intEHelp.xA = xVector[mEdgeVector[iEdgeAB].inodeA];
4800  intEHelp.xB = xVector[mEdgeVector[iEdgeAB].inodeB];
4801  intEHelp.yA = yVector[mEdgeVector[iEdgeAB].inodeA];
4802  intEHelp.yB = yVector[mEdgeVector[iEdgeAB].inodeB];
4803  intEHelp.setupEdge(r,z);
4804 
4805  if(intEHelp.x_hiFlag) ixhi += 1;
4806  if(intEHelp.x_loFlag) ixlo += 1;
4807  if(intEHelp.y_hiFlag) iyhi += 1;
4808  if(intEHelp.y_loFlag) iylo += 1;
4809 
4810  intEHelp.xA = xVector[mEdgeVector[iEdgeBC].inodeA];
4811  intEHelp.xB = xVector[mEdgeVector[iEdgeBC].inodeB];
4812  intEHelp.yA = yVector[mEdgeVector[iEdgeBC].inodeA];
4813  intEHelp.yB = yVector[mEdgeVector[iEdgeBC].inodeB];
4814  intEHelp.setupEdge(r,z);
4815 
4816  if(intEHelp.x_hiFlag) ixhi += 1;
4817  if(intEHelp.x_loFlag) ixlo += 1;
4818  if(intEHelp.y_hiFlag) iyhi += 1;
4819  if(intEHelp.y_loFlag) iylo += 1;
4820 
4821  intEHelp.xA = xVector[mEdgeVector[iEdgeCD].inodeA];
4822  intEHelp.xB = xVector[mEdgeVector[iEdgeCD].inodeB];
4823  intEHelp.yA = yVector[mEdgeVector[iEdgeCD].inodeA];
4824  intEHelp.yB = yVector[mEdgeVector[iEdgeCD].inodeB];
4825  intEHelp.setupEdge(r,z);
4826 
4827  if(intEHelp.x_hiFlag) ixhi += 1;
4828  if(intEHelp.x_loFlag) ixlo += 1;
4829  if(intEHelp.y_hiFlag) iyhi += 1;
4830  if(intEHelp.y_loFlag) iylo += 1;
4831 
4832  if(iNodeD != -1)
4833  {
4834  intEHelp.xA = xVector[mEdgeVector[iEdgeDA].inodeA];
4835  intEHelp.xB = xVector[mEdgeVector[iEdgeDA].inodeB];
4836  intEHelp.yA = yVector[mEdgeVector[iEdgeDA].inodeA];
4837  intEHelp.yB = yVector[mEdgeVector[iEdgeDA].inodeB];
4838  intEHelp.setupEdge(r,z);
4839 
4840  if(intEHelp.x_hiFlag) ixhi += 1;
4841  if(intEHelp.x_loFlag) ixlo += 1;
4842  if(intEHelp.y_hiFlag) iyhi += 1;
4843  if(intEHelp.y_loFlag) iylo += 1;
4844  }
4845 
4846  // Have we found the cell?
4847  if((ixhi >= 1) && (ixlo >= 1) && (iyhi >= 1) && (iylo >= 1))
4848  {
4849  // yes!
4850  doneFlag = true;
4851  istatus = 0;
4852  break;
4853  }
4854  else
4855  {
4856  // no! move to a neighbor cell.
4857  doneFlag = false;
4858  istatus = -1;
4859 
4860  // of the 3 or 4 neighbor cells, which one is closest to (r,z)
4861  double minimum = +1.0e+99;
4862  int iC;
4863 
4864  // first get distance for current cell:
4865  double curr_min = findMinDist(iCell,r,z);
4866 
4867  // neighbor AB
4868  int AB_iC = mCellVector[iCell].icellAB;
4869  double ABmin;
4870  if (AB_iC != -1)
4871  {
4872  if (!(visitCellFlagVec[AB_iC]))
4873  {
4874  ABmin = findMinDist(AB_iC,r,z);
4875  if (ABmin <= minimum) { minimum = ABmin; iC = AB_iC; }
4876  }
4877  }
4878 
4879  // neighbor BC
4880  int BC_iC = mCellVector[iCell].icellBC;
4881  double BCmin;
4882  if (BC_iC != -1)
4883  {
4884  if (!(visitCellFlagVec[BC_iC]))
4885  {
4886  BCmin = findMinDist(BC_iC,r,z);
4887  if (BCmin <= minimum) { minimum = BCmin; iC = BC_iC; }
4888  }
4889  }
4890 
4891  // neighbor CD
4892  int CD_iC = mCellVector[iCell].icellCD;
4893  double CDmin;
4894  if (CD_iC != -1)
4895  {
4896  if (!(visitCellFlagVec[CD_iC]))
4897  {
4898  CDmin = findMinDist(CD_iC,r,z);
4899  if (CDmin <= minimum) { minimum = CDmin; iC = CD_iC; }
4900  }
4901  }
4902 
4903  // neighbor DA
4904  int DA_iC = mCellVector[iCell].icellDA;
4905  double DAmin = 0.0;
4906  if (DA_iC != -1)
4907  {
4908  if (!(visitCellFlagVec[DA_iC]))
4909  {
4910  DAmin = findMinDist(DA_iC,r,z);
4911  if (DAmin < minimum) { minimum = DAmin; iC = DA_iC; }
4912  }
4913  }
4914 
4915  // now reset iCell.
4916  if (iC != iCell)
4917  {
4918  visitCellFlagVec[iCell] = 1;
4919  iCell = iC;
4920  istatus=0;
4921  }
4922  else // we are stuck, and can't go anywhere.
4923  // This cell doesn't exist, so exit.
4924  {
4925  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
4926  {
4927  Xyce::dout() << std::endl;
4928  Xyce::dout() << "iCell = " << iCell << std::endl;
4929  Xyce::dout() << "r = " << r << " z = " << z << std::endl;
4930  Xyce::dout() << "curr_min = " << curr_min << std::endl;
4931  Xyce::dout() << std::endl;
4932 
4933  if (AB_iC != -1)
4934  {
4935  Xyce::dout() << "AB_iC = " << AB_iC;
4936  Xyce::dout() << " ABmin = " << ABmin;
4937  Xyce::dout() << " visit = " << visitCellFlagVec[AB_iC] << std::endl;
4938  }
4939 
4940  if (BC_iC != -1)
4941  {
4942  Xyce::dout() << "BC_iC = " << BC_iC;
4943  Xyce::dout() << " BCmin = " << BCmin;
4944  Xyce::dout() << " visit = " << visitCellFlagVec[BC_iC] << std::endl;
4945  }
4946 
4947  if (CD_iC != -1)
4948  {
4949  Xyce::dout() << "CD_iC = " << CD_iC;
4950  Xyce::dout() << " CDmin = " << CDmin;
4951  Xyce::dout() << " visit = " << visitCellFlagVec[CD_iC] << std::endl;
4952  }
4953 
4954  if (DA_iC != -1)
4955  {
4956  Xyce::dout() << "DA_iC = " << DA_iC;
4957  Xyce::dout() << " DAmin = " << DAmin;
4958  Xyce::dout() << " visit = " << visitCellFlagVec[DA_iC] << std::endl;
4959  }
4960  }
4961  doneFlag = true;
4962  istatus = -1;
4963  }
4964  }
4965  } // end of while loop
4966 
4967  return;
4968 }
4969 
4970 //-----------------------------------------------------------------------------
4971 // Function: PDE_2DMesh::findMinDist
4972 // Author: Eric Keiter
4973 // Scope: public
4974 // Description: This function fines the minimum distance between an (r,z)
4975 // location and the nodes of a specified cell. Whichever node
4976 // is closest, the distance between that node and (r,z)
4977 // is returned.
4978 //
4979 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
4980 // Creation Date : 09/24/02
4981 //-----------------------------------------------------------------------------
4982 double PDE_2DMesh::findMinDist(int iCell, double r, double z)
4983 {
4984  double minDist = +1.0e99;
4985  double x1, y1;
4986  double rdist,zdist,dist;
4987 
4988  int inodeA = mCellVector[iCell].inodeA;
4989  if (inodeA != -1)
4990  {
4991  x1 = xVector[inodeA];
4992  y1 = yVector[inodeA];
4993  rdist = r-x1; zdist = z-y1;
4994  dist = sqrt (rdist*rdist + zdist*zdist);
4995  if (dist < minDist) { minDist = dist; }
4996  }
4997 
4998  int inodeB = mCellVector[iCell].inodeB;
4999  if (inodeB != -1)
5000  {
5001  x1 = xVector[inodeB];
5002  y1 = yVector[inodeB];
5003  rdist = r-x1; zdist = z-y1;
5004  dist = sqrt (rdist*rdist + zdist*zdist);
5005  if (dist < minDist) { minDist = dist; }
5006  }
5007 
5008  int inodeC = mCellVector[iCell].inodeC;
5009  if (inodeC != -1)
5010  {
5011  x1 = xVector[inodeC];
5012  y1 = yVector[inodeC];
5013  rdist = r-x1; zdist = z-y1;
5014  dist = sqrt (rdist*rdist + zdist*zdist);
5015  if (dist < minDist) { minDist = dist; }
5016  }
5017 
5018  int inodeD = mCellVector[iCell].inodeD;
5019  if (inodeD != -1)
5020  {
5021  x1 = xVector[inodeD];
5022  y1 = yVector[inodeD];
5023  rdist = r-x1; zdist = z-y1;
5024  dist = sqrt (rdist*rdist + zdist*zdist);
5025  if (dist < minDist) { minDist = dist; }
5026  }
5027 
5028  return minDist;
5029 }
5030 
5031 //-----------------------------------------------------------------------------
5032 // Function: PDE_2DMesh::compAngle
5033 // Author: Eric Keiter
5034 // Scope: public
5035 // Description: This function computes the angle between three points given
5036 // by coordinates (x1,y1), (x2,y2) and (x3,y3). The angle
5037 // is measured from vector 12 to 32.
5038 //
5039 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
5040 // Creation Date : 09/24/02
5041 //-----------------------------------------------------------------------------
5043  double x1, double y1, // coordinate (x1,y1)
5044  double x2, double y2, // coordinate (x2,y2)
5045  double x3, double y3) // coordinate (x3,y3)
5046 {
5047  double xl,yl; // coordinates of vector 12
5048  double xr,yr; // coordinates of vector 32
5049  double r; // temporary number
5050  double angle; // angle between vectors 12 & 32
5051 
5052  xl = x1 - x2; yl = y1 - y2;
5053  xr = x3 - x2; yr = y3 - y2;
5054 
5055  r = (xl*xr+yl*yr)/(sqrt(sq(xl)+sq(yl))*sqrt(sq(xr)+sq(yr)));
5056  if (r > 1.0) r = 1.0;
5057  else if (r < -1.0) r = -1.0;
5058  angle = acos(r);
5059  if (xl*yr-xr*yl > 0) angle = 2*M_PI-angle;
5060  return(angle);
5061 }
5062 
5063 //-----------------------------------------------------------------------------
5064 // Functions associated with mesh primitive classes
5065 //-----------------------------------------------------------------------------
5066 
5067 //-----------------------------------------------------------------------------
5068 // Function : mNode::mNode
5069 // Description : constructor
5070 // Special Notes :
5071 // Scope : public
5072 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
5073 // Creation Date : 04/22/02
5074 //-----------------------------------------------------------------------------
5076  x(0.0),
5077  y(0.0),
5078  area(0.0),
5079  cnode(0),
5080  inode(-1),
5081  numCells(0),
5082  fBndry(false),
5083  fGotAll(false),
5084  edgeStatus(EDGESTATUS_INTERIOR)
5085 {
5086 
5087 #if 0
5088  aiNodeVector.reserve (32);
5089  aiEdgeVector.reserve (32);
5090  aiCellVector.reserve (32);
5091  auLabelVector.reserve (32);
5092 
5093 
5094  for (int i=0;i<32;++i)
5095  {
5096  aiNodeVector[i] = -1;
5097  aiEdgeVector[i] = -1;
5098  aiCellVector[i] = -1;
5099  auLabelVector[i] = -1;
5100  }
5101 #endif
5102 }
5103 
5104 //-----------------------------------------------------------------------------
5105 // Function : mEdge::mEdge
5106 // Description : constructor
5107 // Special Notes :
5108 // Scope : public
5109 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
5110 // Creation Date : 04/22/02
5111 //-----------------------------------------------------------------------------
5113  uLabel(-1),
5114  inodeA(-1),
5115  inodeB(-1),
5116  ilen(0.0),
5117  elen(0.0),
5118  Area1(0.0),
5119  Area2(0.0),
5120  angle(0.0),
5121  midpoint_x(0.0),
5122  midpoint_y(0.0),
5123  iedge(-1),
5124  ielem(-1),
5125  edgeStatus(EDGESTATUS_INTERIOR)
5126 {
5127 
5128 }
5129 
5130 //-----------------------------------------------------------------------------
5131 // Function : mCell::mCell
5132 // Description : constructor
5133 // Special Notes :
5134 // Scope : public
5135 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
5136 // Creation Date : 04/22/02
5137 //-----------------------------------------------------------------------------
5139  uLabel (-1),
5140  iedgeAB (-1), iedgeBC (-1), iedgeCD (-1), iedgeDA (-1),
5141  icellAB (-1), icellBC (-1), icellCD (-1), icellDA (-1)
5142 {
5143  mNodeVector.resize(4,-1);
5144 }
5145 
5146 //-----------------------------------------------------------------------------
5147 // Function : mLabel::mLabel
5148 // Description : constructor
5149 // Special Notes :
5150 // Scope : public
5151 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
5152 // Creation Date : 04/23/02
5153 //-----------------------------------------------------------------------------
5155  name("no name"),
5156  iIndex(-1),
5157  uType(-1),
5158  cNode(0),
5159  vol(0.0),
5160  surfArea(0.0)
5161 {
5162 
5163 }
5164 
5165 
5166 //-----------------------------------------------------------------------------
5167 // Function : mInterpAreaHelp::mInterpAreaHelp
5168 // Description : constructor
5169 // Special Notes :
5170 // Scope : public
5171 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
5172 // Creation Date : 09/18/02
5173 //-----------------------------------------------------------------------------
5175  x0 (0.0),
5176  y0 (0.0),
5177  x1 (0.0),
5178  y1 (0.0),
5179  x2 (0.0),
5180  y2 (0.0),
5181  v0 (0.0),
5182  v1 (0.0),
5183  v2 (0.0),
5184  f0 (0.0),
5185  f1 (0.0),
5186  f2 (0.0),
5187  vlim(0.0),
5188  aa (0.0),
5189  bb (0.0),
5190  cc (0.0),
5191  errorFlag(0),
5192  iend(0)
5193 {
5194 
5195 }
5196 
5197 //-----------------------------------------------------------------------------
5198 // Function : mInterpAreaHelp::interpReg
5199 // Description :
5200 // Special Notes :
5201 // Scope : public
5202 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
5203 // Creation Date : 09/18/02
5204 //-----------------------------------------------------------------------------
5205 double mInterpAreaHelp::interpReg (double r, double z)
5206 {
5207  findCoef();
5208  double f = aa*r + bb*z + cc;
5209  return(f);
5210 }
5211 
5212 //-----------------------------------------------------------------------------
5213 // Function : mInterpAreaHelp::findCoef
5214 // Description : This function returns the coefficients of the linear
5215 // equation f = a*x + b*y + c. The class needs to have
5216 // been passed the values of f,x and y for three different
5217 // points.
5218 // Special Notes :
5219 // Scope : public
5220 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
5221 // Creation Date : 09/18/02
5222 //-----------------------------------------------------------------------------
5224 {
5225  if( (y1-y0)*(x2-x1)- (y2-y1)*(x1-x0) != 0.0)
5226  {
5227  bb = ((f1-f0)*(x2-x1) - (f2-f1)*(x1-x0))/
5228  ((y1-y0)*(x2-x1) - (y2-y1)*(x1-x0));
5229  }
5230  else
5231  {
5232  bb = 0.0;
5233  }
5234 
5235  if(x1!=x0)
5236  {
5237  aa = (f1-f0)/(x1-x0) - bb*(y1-y0)/(x1-x0);
5238  }
5239  else
5240  {
5241  if(x2!=x1)
5242  {
5243  aa = (f2-f1)/(x2-x1) - bb*(y2-y1)/(x2-x1);
5244  }
5245  else
5246  {
5247  aa = 0.0;
5248  }
5249  }
5250 
5251  cc = f0 - aa*x0 - bb*y0;
5252 
5253  return(true);
5254 }
5255 
5256 //-----------------------------------------------------------------------------
5257 // Function : mInterpEdgeHelp::mInterpEdgeHelp
5258 // Description : constructor
5259 // Special Notes :
5260 // Scope : public
5261 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
5262 // Creation Date : 09/18/02
5263 //-----------------------------------------------------------------------------
5265  xA(0.0),
5266  yA(0.0),
5267  xB(0.0),
5268  yB(0.0),
5269  AA(0.0),
5270  BB(0.0),
5271  iflagx(false),
5272  iflagy(false),
5273  x_hiFlag(false),
5274  x_loFlag(false),
5275  y_hiFlag(false),
5276  y_loFlag(false)
5277 {
5278 
5279 }
5280 
5281 //-----------------------------------------------------------------------------
5282 // Function : mInterpEdgeHelp::setupEdge
5283 // Description :
5284 // Special Notes :
5285 // Scope : public
5286 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
5287 // Creation Date : 09/18/02
5288 //-----------------------------------------------------------------------------
5289 bool mInterpEdgeHelp::setupEdge (double r, double z)
5290 {
5291  double xtmp, ytmp;
5292 
5293  AA = 0.0;
5294  BB = 0.0;
5295 
5296  // is this a verticle line?
5297  if(xB == xA)
5298  {
5299  iflagx = false;
5300  y_hiFlag = false;
5301  y_loFlag = false;
5302 
5303  if( (yA <= z && yB >= z) || (yB <= z && yA >= z) )
5304  iflagy = true;
5305  else
5306  iflagy = false;
5307 
5308  if(iflagy)
5309  {
5310  xtmp = xA;
5311  if(xtmp ==r) {x_hiFlag = true; x_loFlag = true; }
5312  if(xtmp > r) {x_hiFlag = true; x_loFlag = false;}
5313  if(xtmp < r) {x_hiFlag = false; x_loFlag = true; }
5314  }
5315  else
5316  {
5317  x_hiFlag = false;
5318  x_loFlag = false;
5319  }
5320  return(true);
5321  }
5322 
5323  // is this a horizontal line?
5324  if( yB == yA ) AA = 0.0;
5325  else AA = (yB-yA)/ (xB-xA);
5326 
5327  BB = yA - AA * xA;
5328 
5329  if((xA <= r && xB >= r)||(xB <= r && xA >= r))
5330  iflagx = true;
5331  else
5332  iflagx = false;
5333 
5334  if((yA <= z && yB >= z)||(yB <= z && yA >= z))
5335  iflagy = true;
5336  else
5337  iflagy = false;
5338 
5339  if(iflagx)
5340  {
5341  ytmp = AA*r + BB;
5342  if(ytmp ==z) {y_hiFlag = true; y_loFlag = true;}
5343  if(ytmp > z) {y_hiFlag = true; y_loFlag = false;}
5344  if(ytmp < z) {y_hiFlag = false; y_loFlag = true;}
5345  }
5346  else
5347  {
5348  y_hiFlag = false;
5349  y_loFlag = false;
5350  }
5351 
5352  if(iflagy)
5353  {
5354  xtmp = (z-BB)/AA;
5355  if(xtmp ==r) {x_hiFlag = true; x_loFlag = true;}
5356  if(xtmp > r) {x_hiFlag = true; x_loFlag = false;}
5357  if(xtmp < r) {x_hiFlag = false; x_loFlag = true;}
5358  }
5359  else
5360  {
5361  x_hiFlag = false;
5362  x_loFlag = false;
5363  }
5364 
5365  return(true);
5366 }
5367 
5368 } // namespace Device
5369 } // namespace Xyce
#define TYPE_EDGE
#define TYPE_REGION
double computeAngle(int inode1, int inode2, int inode3)
bool initializeInternalMesh(int nx, int ny, double xlength, double ylength, int numElectrodes, std::string &outputMeshFileName, std::map< std::string, PDE_2DElectrode * > &elMap, bool cylFlag)
bool computeIntPB(double &x, double &y, int inodeA, int inodeB, int inodeC)
Pure virtual class to augment a linear system.
const DeviceOptions * devOptions_
std::vector< double > yVector
bool setupEdge(double r, double z)
bool writeSGFMeshFile(const std::string &meshFileName_tmp)
std::vector< mLabel > mLabelVector
std::vector< mEdge > mEdgeVector
std::vector< int > mNodeVector
#define TAG12
#define TAG13
bool setupDefaultLabels(int numberElectrodes)
#define EDGE_BC
bool labelEdgeType(std::string &labelName)
bool interpVector(double *F, double r, double z, double &xvec, double &yvec)
void getElementInfo(int itri, int *ainode, int *aiedge, int *aitri, int *auLabel)
bool fCCWorder(int inode1, int inode2, int inode3)
#define EDGE_AD
void elementNodes(int itri, int *ainode)
std::map< std::string, mLabel > mLabelMap
#define VERTEX_B
bool scaleMesh(double xScale)
std::vector< int > visitCellFlagVec
std::vector< double > dopingVector
std::vector< int > afVisitedVec
#define EDGE_AC
double compAngle(double x1, double y1, double x2, double y2, double x3, double y3)
#define EDGESTATUS_INTERIOR
#define VERTEX_C
double interpReg(double r, double z)
bool given(const std::string &parameter_name) const
given returns true if the value was specified in the netlist (not defaulted).
void initNodeAdjStructure(NADJ &nadj, int itri, int iVertex, int uIntLabel, bool fCW)
#define LEN_IDENT
std::vector< mCell > mCellVector
double findMinDist(int iCell, double r, double z)
double interp(double *F, double r, double z)
bool errorCheckElectrodes(int numElectrodes, std::map< std::string, PDE_2DElectrode * > &elMap)
double areaAdjust(double x1, double y1, double x2, double y2, double x3, double y3)
std::vector< mNode > mNodeVector
bool setupInternalLabels(int numberElectrodes, std::map< std::string, PDE_2DElectrode * > &elMap)
#define M_PI
PDE_2DMesh & operator=(PDE_2DMesh const &rhsMesh)
#define VERTEX_D
void findCell(double r, double z, int &isuccess, int &inode, int &iCell, int iStartCell=0)
bool setupInternalMesh(int nx, int ny, double xlength, double ylength)
bool initializeMesh(const std::string &meshFileName_tmp)
std::vector< int > mNodeVector
#define VERTEX_A
double sq(double x)
#define EDGE_CD
std::vector< double > xVector
bool resizeMesh(double xlength, double ylength)
double lengthAdjust(double x1, double y1, double x2, double y2)
#define TAG23
#define EDGE_AB
#define EDGESTATUS_EXTERIOR
bool readSGFMeshFile(const std::string &meshFileName_tmp)
bool labelNameExist(std::string &labelName)