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