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