Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
N_NLS_ConductanceExtractor.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_NLS_ConductanceExtractor.C,v $
27 //
28 // Purpose :
29 //
30 // Special Notes :
31 //
32 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
33 //
34 // Creation Date : 03/03/06
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.42 $
40 //
41 // Revision Date : $Date $
42 //
43 // Current Owner : $Author: dgbaur $
44 //-------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 
48 
49 // ---------- Standard Includes ----------
50 
51 #include <N_UTL_Misc.h>
52 
53 #ifdef HAVE_CSTDIO
54 #include <cstdio>
55 #else
56 #include <stdio.h>
57 #endif
58 
59 // ---------- Xyce Includes ----------
60 
62 #include <N_NLS_Manager.h>
63 
64 #include <N_LOA_Loader.h>
65 
66 #include <N_UTL_OptionBlock.h>
67 
68 #include <N_LAS_Matrix.h>
69 #include <N_LAS_Vector.h>
70 
71 #include <N_LAS_Solver.h>
72 #include <N_LAS_Problem.h>
73 
74 #include <N_LAS_System.h>
75 #include <N_LAS_Builder.h>
76 
77 #include <N_ERH_ErrorMgr.h>
78 #include <N_ANP_AnalysisManager.h>
79 
80 #include <N_TOP_Topology.h>
81 
82 #include <N_UTL_Expression.h>
83 
84 #include <N_PDS_ParMap.h>
85 #include <N_PDS_Comm.h>
86 
87 #include <N_IO_CmdParse.h>
88 #include <N_IO_PkgOptionsMgr.h>
89 
90 #include <Epetra_CrsMatrix.h>
91 
92 // ---------- Static Declarations ----------
93 
94 namespace Xyce {
95 namespace Nonlinear {
96 
97 //-----------------------------------------------------------------------------
98 // Function : ConductanceExtractor::ConductanceExtractor
99 // Purpose : constructor
100 // Special Notes :
101 // Scope : public
102 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
103 // Creation Date : 03/03/06
104 //-----------------------------------------------------------------------------
106  NonLinearSolver & nls,
107  N_TOP_Topology & topTmp,
108  N_IO_CmdParse & cp)
109  : commandLine_(cp),
110  nls_(nls),
111  top_(topTmp),
112  solutionSize_(0),
113  debugLevel_(0),
114  lasSysPtr_(0),
115  anaIntPtr_(0),
116  loaderPtr_(0),
117  rhsVectorPtr_(0),
118  dfdvVectorPtr_(0),
119  NewtonVectorPtr_(0),
120  dxdvVectorPtr_(0),
121  matrixDiagonalPtr_(0),
122  lasSolverPtr_(0),
123  jacobianMatrixPtr_(0),
124  nextSolVectorPtrPtr_(0),
125  currSolVectorPtrPtr_(0),
126  savedRHSVectorPtr_(0),
127  savedNewtonVectorPtr_(0),
128  gradVectorPtr_(0),
129  columnVectorPtr_(0),
130  columnMapPtr_(0),
131  gidsSetUpFlag_(false)
132 {
137  dfdvVectorPtr_ = nls_.rhsVectorPtr_; // using the same vector for dfdv.
138 
140  dxdvVectorPtr_ = nls_.NewtonVectorPtr_; // using same vector for dxdv.
145 
146  // creations
147  savedRHSVectorPtr_ = lasSysPtr_->builder().createVector();
148  savedNewtonVectorPtr_ = lasSysPtr_->builder().createVector();
149  matrixDiagonalPtr_ = lasSysPtr_->builder().createVector();
150  solutionSize_ = lasSysPtr_->getSolutionSize();
151 
152 #ifdef Xyce_PARALLEL_MPI
153  // construct column vector used for parallel construction of RHS's
154  const Epetra_Map & col_map = jacobianMatrixPtr_->epetraObj().ColMap();
155  columnMapPtr_ = new N_PDS_ParMap( &(const_cast<Epetra_Map&>(col_map)),
156  savedRHSVectorPtr_->pmap()->pdsComm() );
157  columnVectorPtr_ = new N_LAS_Vector( *(savedRHSVectorPtr_->pmap()), *columnMapPtr_ );
158 #endif
159 }
160 
161 //-----------------------------------------------------------------------------
162 // Function : ConductanceExtractor::~ConductanceExtractor
163 // Purpose : destructor
164 // Special Notes :
165 // Scope : public
166 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
167 // Creation Date : 03/03/06
168 //-----------------------------------------------------------------------------
170 {
171  if (savedRHSVectorPtr_)
172  {
173  delete savedRHSVectorPtr_;
174  savedRHSVectorPtr_ = 0;
175  }
176 
178  {
179  delete savedNewtonVectorPtr_;
181  }
182 
183  if (matrixDiagonalPtr_)
184  {
185  delete matrixDiagonalPtr_;
186  matrixDiagonalPtr_ = 0;
187  }
188 
189  int vecSize = dIdxPtrVector_.size();
190  for (int ivec=0; ivec<vecSize ;++ivec)
191  {
192  if (dIdxPtrVector_[ivec])
193  {
194  delete dIdxPtrVector_[ivec];
195  dIdxPtrVector_[ivec] = 0;
196  }
197  }
198 
199  if( columnVectorPtr_ )
200  {
201  delete columnVectorPtr_;
202  delete columnMapPtr_;
203  columnVectorPtr_ = 0;
204  columnMapPtr_ = 0;
205  }
206 
207  // For all the stuff that is to be deleted in the nonlinear solver
208  // base class destructor, just set those pointers to zero because
209  // they are deleted elsewhere.
210  lasSysPtr_ = 0;
211  anaIntPtr_ = 0;
212  loaderPtr_ = 0;
213  rhsVectorPtr_ = 0;
214  dfdvVectorPtr_ = 0;
215  NewtonVectorPtr_ = 0;
216  dxdvVectorPtr_ = 0;
217  lasSolverPtr_ = 0;
218  jacobianMatrixPtr_ = 0;
221  solutionSize_ = 0;
222  gradVectorPtr_ = 0;
223  lasSolverPtr_ = 0;
224 }
225 
226 //-----------------------------------------------------------------------------
227 // Function : ConductanceExtractor::registerPkgOptionsMgr
228 // Purpose :
229 // Special Notes :
230 // Scope : public
231 // Creator : Rich Schiek, 1437
232 // Creation Date : 10/21/08
233 //-----------------------------------------------------------------------------
234 bool ConductanceExtractor::registerPkgOptionsMgr( N_IO_PkgOptionsMgr *pkgOptPtr )
235 {
236  pkgOptMgrPtr_ = pkgOptPtr;
237  std::string netListFile = "";
238  if (commandLine_.getArgumentValue("netlist") != "")
239  {
240  netListFile = commandLine_.getArgumentValue("netlist");
241  }
242  pkgOptMgrPtr_->submitRegistration(
243  "CONDUCTANCE", netListFile, new ConductanceExtractor_OptionsReg( this ) );
244 
245  return true;
246 }
247 
248 //-----------------------------------------------------------------------------
249 // Function : ConductanceExtractor::setOptions
250 // Purpose :
251 // Special Notes :
252 // Scope : public
253 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
254 // Creation Date : 03/03/06
255 //-----------------------------------------------------------------------------
256 bool ConductanceExtractor::setOptions(const N_UTL_OptionBlock& OB)
257 {
258  bool bsuccess = true;
259 
260  for (std::list<N_UTL_Param>::const_iterator it_tpL = OB.getParams().begin();
261  it_tpL != OB.getParams().end(); ++ it_tpL)
262  {
263  // no-op for now.
264  if (it_tpL->uTag() == "DEBUGLEVEL")
265  {
266  debugLevel_ = it_tpL->getImmutableValue<int>();
267  }
268  }
269 
270  return bsuccess;
271 }
272 
273 //-----------------------------------------------------------------------------
274 // Function : ConductanceExtractor::setupIDs_
275 //
276 // Purpose : This function sets up the various GIDs and matrix rows,
277 // that are needed in the extract function.
278 //
279 // Special Notes : There are 2 types of IDs needed, which are both associated
280 // with independent voltage sources. One type is the GID of
281 // the current variable, which is needed for a "get" operation.
282 // The other is the LID of the matrix row for the voltage drop
283 // equation. In serial, this is the same as the current GID,
284 // but in parallel they will generally be different. For the
285 // matrix row, the LID is used for a "put" operation, so it
286 // makes more sense for it to be an LID.
287 //
288 // Scope : private
289 // Creator : Eric Keiter, SNL
290 // Creation Date : 03/03/06
291 //-----------------------------------------------------------------------------
293  (const std::map<std::string,double> & inputMap)
294 {
295  bool bsuccess = true;
296 
297  // Setup vectors for each terminal current
298  int idSize = inputMap.size();
299  currentGIDs_.resize(idSize);
300  currentLIDs_.resize(idSize);
301  vsrcPosGIDs_.resize(idSize);
302  vsrcPosLIDs_.resize(idSize);
303  for (int i=0; i<idSize ;++i)
304  {
305  dIdxPtrVector_.push_back(lasSysPtr_->builder().createVector());
306  currentGIDs_[i] = -1;
307  currentLIDs_[i] = -1;
308  vsrcPosGIDs_[i] = -1;
309  vsrcPosLIDs_[i] = -1;
310  }
311 
312  // Loop over the map, which should contain, in the first
313  // arguments, the names of the voltage sources we need.
314  std::map<std::string,double>::const_iterator iterM = inputMap.begin();
315  std::map<std::string,double>::const_iterator endM = inputMap.end ();
316  int i=0;
317  for (; iterM != endM; ++i, ++iterM)
318  {
319  // Note: When passing the sourceName to topology, it must
320  // be all CAPS, or topology won't find it.
321  ExtendedString src = iterM->first;
322  src.toUpper();
323  std::string sourceName = src;
324  char type;
325  int index;
326 
327  // This is to get the IDs for the currents through the
328  // voltage sources specified in the map.
329  std::list<int> GIDList, extGIDList;
330  top_.getNodeSVarGIDs(NodeID(sourceName, Xyce::_DNODE), GIDList, extGIDList, type);
331 
332  std::list<int>::iterator iterI;
333  if (!(GIDList.empty ()))
334  {
335  iterI = GIDList.begin();
336  currentGIDs_[i] = *iterI;
337  currentLIDs_[i] = dIdxPtrVector_[0]->pmap()->globalToLocalIndex(currentGIDs_[i]);
338 
339  iterI = extGIDList.begin();
340  vsrcPosGIDs_[i] = *iterI;
341  vsrcPosLIDs_[i] = dIdxPtrVector_[0]->pmap()->globalToLocalIndex(vsrcPosGIDs_[i]);
342 
343  if( vsrcPosLIDs_[i] == -1 )
344  {
345  std::string msg = "ConductanceExtractor::setupIDs_";
346  msg += " The " + sourceName + " source has the positive node"
347  " owned by another processor. The 2-level solve can't handle that.";
348  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL, msg);
349  }
350 
351  // check that vneg is connected to gnd
352  ++iterI;
353  int vnegGID = *iterI;
354  if (vnegGID != -1)
355  {
356  std::string msg = "ConductanceExtractor::setupIDs_";
357  msg += " The " + sourceName + " source has the negative node"
358  " connected to something other than ground! The 2-level solve can't handle that.";
359  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL, msg);
360  }
361  }
362 
363  }
364 
365 #ifdef Xyce_DEBUG_CONDUCTANCE
366  if (debugLevel_ > 0)
367  {
368  cout << "current GIDs: " << std::endl;
369  for( int i1=0; i1 < idSize; ++i1 )
370  {
371  cout << " currentGIDs_["<<i1<<"] = " << currentGIDs_[i1] << ", currentLIDs_["<<i1<<"] = " << currentLIDs_[i1] << std::endl;
372  }
373 
374  cout << "Vsrc pos equation rows: " << std::endl;
375  for( int i1=0; i1 < idSize; ++i1 )
376  {
377  cout << " vsrcPosGIDs_["<<i1<<"] = " << vsrcPosGIDs_[i1] << ", vsrcPosLIDs_["<<i1<<"] = " << vsrcPosLIDs_[i1] << std::endl;
378  }
379  }
380 #endif
381 
382  gidsSetUpFlag_ = true;
383 
384  return true;
385 }
386 
387 //-----------------------------------------------------------------------------
388 // Function : ConductanceExtractor::setup_dIdX_Vectors_
389 // Purpose :
390 // Special Notes :
391 // Scope : public
392 // Creator : Eric Keiter, SNL
393 // Creation Date : 03/05/06
394 //-----------------------------------------------------------------------------
396 {
397  bool bsuccess = true;
398 
399  // Set up dIdx's. These correspond to rows in the Jacobian.
400  // There will be one for each Vsrc current. In general, we are assuming
401  // that each "connecting" voltage source is connected to ground at the
402  // negative node, and to the rest of the circuit at the positive node,
403  // so the node of interest (and thus KCL of interest) is the
404  // positive node. dIdx is a vector containing all the derivatives
405  // from the corresponding KCL row, minus the derivative with respect to
406  // I. (I is a solution variable, but needs to be excluded from dIdx,
407  // or the various dot products will cancel some terms that they
408  // should not).
409  int idSize = currentGIDs_.size();
410 
411  N_LAS_Vector * currentVec;
412 
413  // int iC_row=0;
414  for( int iC_row=0; iC_row < idSize; ++iC_row )
415  {
416 #ifdef Xyce_PARALLEL_MPI
417  currentVec = columnVectorPtr_;
418 #else
419  currentVec = dIdxPtrVector_[iC_row];
420 #endif
421 
422  currentVec->putScalar(0.0);
423 
424  if( currentGIDs_[iC_row] != -1 )
425  {
426  int iRow = vsrcPosGIDs_[iC_row];
427  int rowLength = jacobianMatrixPtr_->getRowLength(iRow);
428  int numEntries = rowLength;
429  std::vector<double> coeffs(rowLength, 0.0);
430  std::vector<int> colIndices(rowLength, -1);
431 
432  jacobianMatrixPtr_->getRowCopy
433  (iRow, rowLength, numEntries, &coeffs[0], &colIndices[0]);
434 
435  for (int ic=0;ic<rowLength;++ic)
436  {
437  // need to exclude entries that are with respect to
438  // the the variable, 'I'.
439  int gid = colIndices[ic];
440  if (gid == currentGIDs_[iC_row]) coeffs[ic] = 0.0;
441  }
442 
443  for (int icol=0;icol<rowLength;++icol)
444  {
445  double val = coeffs[icol];
446  int gid = colIndices[icol];
447  if (gid != -1)
448  currentVec->setElementByGlobalIndex(gid, val, 0);
449  }
450  }
451  currentVec->fillComplete();
452 
453 #ifdef Xyce_PARALLEL_MPI
454  *(dIdxPtrVector_[iC_row]) = *columnVectorPtr_;
455 #endif
456 
457 #ifdef Xyce_DEBUG_CONDUCTANCE
458  if (debugLevel_ > 0)
459  {
460  cout << "\ndIdx[" << iC_row << "]:" << std::endl;
461  dIdxPtrVector_[iC_row]->printPetraObject();
462  }
463 #endif
464  }
465 
466  return bsuccess;
467 }
468 
469 //-----------------------------------------------------------------------------
470 // Function : ConductanceExtractor::extract
471 // Purpose :
472 // Special Notes :
473 // Scope : public
474 // Creator : Eric Keiter, SNL
475 // Creation Date : 03/03/06
476 //-----------------------------------------------------------------------------
478  const std::map<std::string,double> & inputMap,
479  std::vector<double> & outputVector,
480  std::vector< std::vector<double> > & jacobian )
481 
482 {
483  bool bsuccess = true;
484 
485 #ifdef Xyce_DEBUG_CONDUCTANCE
486  if (debugLevel_ > 0)
487  {
488  cout << subsection_divider << std::endl;
489  cout << "ConductanceExtractor::extract" << std::endl;
490  cout << subsection_divider << std::endl;
491  }
492 #endif
493 
494  if (inputMap.empty() ||
495  outputVector.empty() ||
496  jacobian.empty() )
497  {
498  return false;
499  }
500 
501  // Need the "next" vector.
502  N_LAS_Vector * solnVecPtr = *(nextSolVectorPtrPtr_);
503  //N_LAS_Vector * solnVecPtr = *(currSolVectorPtrPtr_);
504 
505  if (!gidsSetUpFlag_)
506  {
507  setupIDs_(inputMap);
508  }
509 
510  // Now that the solve is complete, obtain the currents and conductances
511  // that are needed for the upper level nonlinear solve.
512 
513  // The currents are owned by the individual sources in the device package:
514  // Note: this may need some parallel refactoring.
515 
516  // First obtain the currents.
517  int idSize = currentGIDs_.size();
518  for (int i=0;i<currentGIDs_.size();++i)
519  {
520  int index1 = currentGIDs_[i];
521  if( index1 > -1 )
522  outputVector[i] = solnVecPtr->getElementByGlobalIndex(index1);
523  else
524  outputVector[i] = 0.0;
525  }
526 
527 #ifdef Xyce_PARALLEL_MPI
528  //sumAll to get all currents locally
529  N_PDS_Comm * comm = dfdvVectorPtr_->pmap()->pdsComm();
530  std::vector<double> tmpVector(idSize,0.0);
531  for( int i = 0; i < idSize; ++i )
532  {
533  tmpVector[i] = outputVector[i];
534  outputVector[i] = 0.0;
535  }
536 
537  comm->sumAll( &(tmpVector[0]), &(outputVector[0]), idSize );
538 #endif
539 
540 #ifdef Xyce_DEBUG_CONDUCTANCE
541  if (debugLevel_ > 0)
542  {
543  int itmp;
544  for (itmp=0;itmp < outputVector.size();++itmp)
545  {
546  cout << "currentVector["<< itmp <<"] = " << outputVector[itmp]<<std::endl;
547  }
548  }
549 #endif
550 
551  // This function needs to solve one or more linear systems. The linear
552  // systems, (for a direct sensitivity) is:
553  // J * dx/dv = df/dv
554  //
555  // where "v" is an applied voltage, not part of the system of unknowns,
556  // which is represented by "x".
557  //
558  // J is the traditional Jacobian matrix, df/dx.
559  //
560  // For the direct approach, a different dx/dv is needed for each v, so
561  // a different linear system, with a different df/dv will be solved for
562  // each applied voltage, v.
563  //
564  // For an adjoint approach, it could be possible to do a single linear
565  // solve, and get the sensitivities to all the v's all at once.
566  //
567  // Note: In general, this extraction is done in the context of a
568  // multi-level Newton solve, in which the extracted conductances are
569  // used one "level" up in the simulation. The inputs are all voltages,
570  // which are applied via voltage sources. This means that the equation
571  // used to complete the system is of the form:
572  //
573  // f = V(n) - Vexternal = 0
574  //
575  // where V(n) is one of the solution variables in x, and Vexternal
576  // is the voltage applied from above, represented in the above
577  // equations as "v".
578  //
579  // Given that this single, simple equation is the entire coupling,
580  // the df/dv derivative, for any Vexternal, is -1.0.
581 
582  // Save the old rhs and newton vectors. (This might not be neccessary).
583  // first save a copy of the rhs vector, in case we want it later.
584  savedRHSVectorPtr_->putScalar(0.0);
585  savedRHSVectorPtr_->addVec(1.0, *(rhsVectorPtr_));
586 
587  savedNewtonVectorPtr_->putScalar(0.0);
588  savedNewtonVectorPtr_->addVec(1.0, *(NewtonVectorPtr_));
589 
590  // Before we try to do any linear solves, check that the Jacobian
591  // actually has been loaded. Sometimes, early in the run, the inner
592  // solve will not load the Jacobian, b/c the norm of f is zero, or very
593  // small. Typically this will happen if the inner problem is linear,
594  // and is entirely driven by the upper level circuit via the connected
595  // Vsrc devices.
596 
597  jacobianMatrixPtr_->getDiagonal ( *matrixDiagonalPtr_ );
598  double diagInfNorm = 0.0;
599  matrixDiagonalPtr_->infNorm(&diagInfNorm);
600 
601  // if the infinite norm of the diagonal is zero, then the matrix
602  // probably hasn't been set up yet. If that is the case, we should
603  // call loadJacobian now. It should be safe to call this, given
604  // that the RHS vector was loaded, no matter what, as part of the
605  // nonlinear solve.
606  if (diagInfNorm < 1.0e-30)
607  {
608 #ifdef Xyce_DEBUG_CONDUCTANCE
609  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::USR_WARNING_0,
610  "\n\tJacobian for inner problem not loaded. Forcing a load.\n");
611 #endif
612  nls_.jacobian_();
613  }
614 
615  // Get dIdx vectors, one for each I-row.
616  bool b1 = setup_dIdX_Vectors_(); bsuccess = bsuccess && b1;
617 
618  // This loop is over the different applied V's.
619  // This loop is also over columns of the small (output) Jacobian.
620  std::map<std::string,double>::const_iterator iterM = inputMap.begin();
621  std::map<std::string,double>::const_iterator endM = inputMap.end ();
622  int iV_col=0;
623  for (;iV_col<idSize;++iV_col,++iterM)
624  {
625  // set up dfdv:
626  dfdvVectorPtr_->putScalar(0.0);
627  int irow = currentLIDs_[iV_col];
628  // note: dfdv = -1.0, but -dfdv needs to go in here.
629  if( irow != -1 )
630  (*dfdvVectorPtr_)[irow] = 1.0; // = -dfdv.
631 
632  lasSolverPtr_->solve();
633 
634  int iC_row=0;
635  for (;iC_row<idSize;++iC_row)
636  {
637  // Get the dot product of dIdx and dxdv, to get dIdv.
638  double dIdv = dIdxPtrVector_[iC_row]->dotProduct(*(dxdvVectorPtr_));
639 
640 #ifdef Xyce_DEBUG_CONDUCTANCE
641  if (debugLevel_ > 0)
642  {
643  std::string vsrcName = iterM->first;
644  printPetraObjects_ (vsrcName);
645  cout << "dIdv = " << dIdv << std::endl;
646  }
647 #endif
648  // put dIdV's into the small matrix:
649  jacobian[iC_row][iV_col] = dIdv;
650  }
651 
652  } // cols of output Jacobian (iV_col)
653 
654  // Restore the RHS and Newton vectors. (again, this may not be necessary).
655  rhsVectorPtr_->putScalar(0.0);
656  rhsVectorPtr_->addVec(1.0, *(savedRHSVectorPtr_));
657 
658  NewtonVectorPtr_->putScalar(0.0);
659  NewtonVectorPtr_->addVec(1.0, *(savedNewtonVectorPtr_));
660 
661 #ifdef Xyce_VERBOSE_CONDUCTANCE
662  printJacobian_ (inputMap,jacobian);
663 #endif
664 
665  return bsuccess;
666 }
667 
668 //-----------------------------------------------------------------------------
669 // Function : ConductanceExtractor::setupISO_IDs_
670 //
671 // Purpose : This function sets up the various GIDs and matrix rows,
672 // that are needed in the extract function.
673 //
674 // Special Notes : This one is specific to iso devices, but uses the
675 // same STL objects as the original setup_IDs_ function.
676 //
677 // Scope : private
678 // Creator : Eric Keiter, SNL
679 // Creation Date : 03/03/06
680 //-----------------------------------------------------------------------------
681 bool ConductanceExtractor::setupISO2_IDs_(const std::string & isoName)
682 {
683  bool bsuccess = true;
684 
685  // Setup vectors for each terminal current
686  int idSize = 2; // for now assuming size 2 for iso2 devices.
687  currentGIDs_.resize(idSize);
688  currentLIDs_.resize(idSize);
689  vsrcPosGIDs_.resize(idSize);
690  vsrcPosLIDs_.resize(idSize);
691  for (int i=0; i<idSize ;++i)
692  {
693  dIdxPtrVector_.push_back(lasSysPtr_->builder().createVector());
694  currentGIDs_[i] = -1;
695  currentLIDs_[i] = -1;
696  vsrcPosGIDs_[i] = -1;
697  vsrcPosLIDs_[i] = -1;
698  }
699 
700  // Note: When passing the name to topology, it must
701  // be all CAPS, or topology won't find it.
702  ExtendedString src = isoName;
703  src.toUpper();
704  std::string sourceName = src;
705  char type;
706  int index;
707 
708  // This is to get the IDs for the currents through the
709  // voltage sources specified in the map.
710  std::list<int> GIDList, extGIDList;
711  top_.getNodeSVarGIDs(NodeID(sourceName, Xyce::_DNODE), GIDList, extGIDList, type);
712 
713  if (!(GIDList.empty ()))
714  {
715  std::list<int>::iterator gidIter = GIDList.begin();
716  std::list<int>::iterator gidExtIter = extGIDList.begin();
717 
718  int i=0;
719  for (i=0;i<idSize;++i,++gidIter,++gidExtIter)
720  {
721  currentGIDs_[i] = *(gidIter);
722  currentLIDs_[i] = dIdxPtrVector_[i]->pmap()->globalToLocalIndex(currentGIDs_[i]);
723  //cout << "currentGIDs_["<<i<<"]="<< currentGIDs_[i]<<std::endl;
724  }
725 
726  // reset i, but keep iterating gidExtIter.
727  for (i=0;i<idSize;++i,++gidExtIter)
728  {
729  vsrcPosGIDs_[i] = *(gidExtIter);
730  vsrcPosLIDs_[i] = dIdxPtrVector_[i]->pmap()->globalToLocalIndex(vsrcPosGIDs_[i]);
731 
732  //cout << "vsrcPosGIDs_["<<i<<"]="<< vsrcPosGIDs_[i]<<std::endl;
733 
734  if( vsrcPosLIDs_[i] == -1 )
735  {
736  std::string msg = "ConductanceExtractor::setupISO_IDs_";
737  msg += " The " + sourceName + " source has the positive node"
738  " owned by another processor. The 2-level solve can't handle that.";
739  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL, msg);
740  }
741  }
742 
743  }
744 
745  // No need to check if the ISO devices are connected to gnd, as
746  // they are built that way internally.
747 
748 #ifdef Xyce_DEBUG_CONDUCTANCE
749  if (debugLevel_ > 0)
750  {
751  cout << "current GIDs: " << std::endl;
752  for( int i1=0; i1 < idSize; ++i1 )
753  {
754  cout << " currentGIDs_["<<i1<<"] = " << currentGIDs_[i1] << std::endl;
755  }
756 
757  cout << "Vsrc pos equation rows: " << std::endl;
758  for( int i1=0; i1 < idSize; ++i1 )
759  {
760  cout << " vsrcPosGIDs_["<<i1<<"] = " << vsrcPosGIDs_[i1] << std::endl;
761  }
762  }
763 #endif
764 
765  gidsSetUpFlag_ = true;
766 
767  return true;
768 }
769 
770 
771 //-----------------------------------------------------------------------------
772 // Function : ConductanceExtractor::extract
773 //
774 // Purpose : Slightly different version of the extract function,
775 // intended for ISO-2 devices, rather than Vsrc's.
776 //
777 // Special Notes : Unlike the other version of this function, this function
778 // does not need to pull out Vsrc currents. It only needs
779 // to worry about conductances. Also, this means that the
780 // function doesn't have to use the solution vector at all.
781 //
782 // Scope : public
783 // Creator : Eric Keiter, SNL
784 // Creation Date : 03/03/06
785 //-----------------------------------------------------------------------------
787 ( const std::string & isoName, std::vector< std::vector<double> > & jacobian )
788 {
789  bool bsuccess = true;
790 
791  int idSize = jacobian.size();
792 
793 #ifdef Xyce_DEBUG_CONDUCTANCE
794  if (debugLevel_ > 0)
795  {
796  cout << subsection_divider << std::endl;
797  cout << "ConductanceExtractor::extract - iso2" << std::endl;
798  cout << subsection_divider << std::endl;
799  }
800 #endif
801 
802  if (!gidsSetUpFlag_)
803  {
804  setupISO2_IDs_(isoName);
805  }
806 
807  // Set asside the original Newton Vectors:
808  savedRHSVectorPtr_->putScalar(0.0);
809  savedRHSVectorPtr_->addVec(1.0, *(rhsVectorPtr_));
810 
811  savedNewtonVectorPtr_->putScalar(0.0);
812  savedNewtonVectorPtr_->addVec(1.0, *(NewtonVectorPtr_));
813 
814  // Get dIdx vectors, one for each I-row.
815  bool b1 = setup_dIdX_Vectors_(); bsuccess = bsuccess && b1;
816 
817  // This loop is over the different applied V's.
818  // This loop is also over columns of the small (output) Jacobian.
819  int iV_col=0;
820  for (;iV_col<idSize;++iV_col)
821  {
822  // set up dfdv:
823  dfdvVectorPtr_->putScalar(0.0);
824  int irow = currentLIDs_[iV_col];
825  // note: dfdv = -1.0, but -dfdv needs to go in here.
826  if( irow != -1 )
827  (*dfdvVectorPtr_)[irow] = 1.0; // = -dfdv.
828 
829  lasSolverPtr_->solve();
830 
831  int iC_row=0;
832  for (;iC_row<idSize;++iC_row)
833  {
834  // Get the dot product of dIdx and dxdv, to get dIdv.
835  double dIdv = dIdxPtrVector_[iC_row]->dotProduct(*(dxdvVectorPtr_));
836 
837 #ifdef Xyce_DEBUG_CONDUCTANCE
838  if (debugLevel_ > 0)
839  {
840  std::string tmpName = "unknown";
841  printPetraObjects_ (tmpName);
842  cout << "dIdv = " << dIdv << std::endl;
843  }
844 #endif
845  // put dIdV's into the small matrix:
846  jacobian[iC_row][iV_col] = dIdv;
847  }
848 
849  } // cols of output Jacobian (iV_col)
850 
851  // Restore the RHS and Newton vectors. (again, this may not be necessary).
852  rhsVectorPtr_->putScalar(0.0);
853  rhsVectorPtr_->addVec(1.0, *(savedRHSVectorPtr_));
854 
855  NewtonVectorPtr_->putScalar(0.0);
856  NewtonVectorPtr_->addVec(1.0, *(savedNewtonVectorPtr_));
857 
858 #ifdef Xyce_VERBOSE_CONDUCTANCE
859  varMap_["Var 0"] = 0.0;
860  varMap_["Var 1"] = 0.0;
861  printJacobian_ (varMap_,jacobian);
862 #endif
863 
864  return bsuccess;
865 }
866 
867 //-----------------------------------------------------------------------------
868 // Function : ConductanceExtractor::printJacobian_
869 // Purpose : Prints the small STL jacobian to the screen.
870 // Special Notes :
871 // Scope : public
872 // Creator : Eric Keiter, SNL
873 // Creation Date : 03/08/06
874 //-----------------------------------------------------------------------------
876  (const std::map<std::string,double> & inputMap,
877  std::vector< std::vector<double> > & jacobian)
878 {
879  Xyce::dout().width(15); Xyce::dout().precision(7); Xyce::dout().setf(std::ios::scientific);
880  Xyce::dout() << "Output Jacobian/Conductance array: \n";
881  Xyce::dout() <<" ";
882 
883  int iE1, iE2;
884  int numElectrodes = jacobian.size();
885  std::map<std::string,double>::const_iterator iterM = inputMap.begin();
886  std::map<std::string,double>::const_iterator endM = inputMap.end ();
887  for (iE1 = 0; iE1 < numElectrodes; ++iE1,++iterM)
888  {
889  Xyce::dout() << "\t"<<iterM->first;
890  }
891  Xyce::dout() << std::endl;
892  iterM = inputMap.begin();
893  for (iE1 = 0; iE1 < numElectrodes; ++iE1,++iterM)
894  {
895  Xyce::dout() << "\t"<<iterM->first;
896  for (iE2 = 0; iE2 < numElectrodes; ++iE2)
897  {
898  Xyce::dout() << "\t" <<jacobian[iE1][iE2];
899  }
900  Xyce::dout() << std::endl;
901  }
902  Xyce::dout() << std::endl;
903 
904  return;
905 }
906 
907 //-----------------------------------------------------------------------------
908 // Function : ConductanceExtractor::printPetraObjects_
909 // Purpose :
910 // Special Notes :
911 // Scope : public
912 // Creator : Eric Keiter, SNL
913 // Creation Date : 03/08/06
914 //-----------------------------------------------------------------------------
915 void ConductanceExtractor::printPetraObjects_ (const std::string & varName)
916 {
917  Xyce::dout().width(15); Xyce::dout().precision(7); Xyce::dout().setf(std::ios::scientific);
918  std::string srcName = varName;
919  Xyce::dout() << "Info for input voltage: " << srcName << std::endl;
920  Xyce::dout() << "Jacobian:" << std::endl;
921  jacobianMatrixPtr_->printPetraObject(Xyce::dout());
922 
923  // now print out the dxdv vector:
924  Xyce::dout() << "dxdv:" << std::endl;
925  dxdvVectorPtr_->printPetraObject(Xyce::dout());
926 
927  Xyce::dout() << "dfdv:" << std::endl;
928  dfdvVectorPtr_->printPetraObject(Xyce::dout());
929 
930  return;
931 }
932 
933 } // namespace Nonlinear
934 } // namespace Xyce