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