Xyce  6.1
N_NLS_Sensitivity.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_Sensitivity.C,v $
27 //
28 // Purpose : Body for the sensitivity class.
29 //
30 // Special Notes :
31 //
32 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
33 //
34 // Creation Date : 10/30/02
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.141 $
40 //
41 // Revision Date : $Date $
42 //
43 // Current Owner : $Author: erkeite $
44 //-------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 
48 
49 // ---------- Standard Includes ----------
50 
51 #include <algorithm>
52 #include <sstream>
53 #include <stdexcept>
54 
55 // ---------- Xyce Includes ----------
56 
57 #include <N_ANP_AnalysisManager.h>
58 #include <N_ERH_ErrorMgr.h>
59 #include <N_IO_CircuitBlock.h>
60 #include <N_IO_OptionBlock.h>
61 #include <N_IO_PkgOptionsMgr.h>
62 #include <N_IO_SpiceSeparatedFieldTool.h>
63 #include <N_LAS_Builder.h>
64 #include <N_LAS_Matrix.h>
65 #include <N_LAS_Problem.h>
66 #include <N_LAS_Solver.h>
67 #include <N_LAS_System.h>
68 #include <N_LAS_Vector.h>
70 #include <N_NLS_Manager.h>
71 #include <N_NLS_Sensitivity.h>
72 #include <N_PDS_Comm.h>
73 #include <N_PDS_MPI.h>
74 #include <N_PDS_Manager.h>
75 #include <N_PDS_Serial.h>
76 #include <N_TIA_DataStore.h>
77 #include <N_TOP_Topology.h>
78 #include <N_UTL_Algorithm.h>
79 #include <N_UTL_Diagnostic.h>
80 #include <N_UTL_Expression.h>
81 #include <N_UTL_ExtendedString.h>
82 #include <N_UTL_FeatureTest.h>
83 #include <N_UTL_OptionBlock.h>
84 
85 // ---------- Static Declarations ----------
86 
87 namespace Xyce {
88 namespace Nonlinear {
89 
90 //-----------------------------------------------------------------------------
91 // Function : Sensitivity::Sensitivity
92 // Purpose : constructor
93 // Special Notes :
94 // Scope : public
95 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
96 // Creation Date : 10/30/02
97 //-----------------------------------------------------------------------------
99  NonLinearSolver & nls,
100  Topo::Topology & topTmp,
101  const IO::CmdParse & cp)
102  : NonLinearSolver(cp),
103  debugLevel_(1),
104  solutionSize_(0),
105  solveDirectFlag_(false),
106  solveAdjointFlag_(true),
107  outputScaledFlag_(false),
108  outputUnscaledFlag_(true),
109  maxParamStringSize_(0),
110  stdOutputFlag_(true),
111  fileOutputFlag_(false),
112  dakotaFileOutputFlag_(false),
113  forceFD_(false),
114  numSolves_(0),
115  objFuncGiven_(false),
116  objFuncGIDsetup_(false),
117  difference(SENS_FWD),
118  sqrtEta_(1.0e-8),
119  sqrtEtaGiven_(false),
120  reuseFactors_(true),
121  lambdaVectorPtr_(0),
122  savedRHSVectorPtr_(0),
123  savedNewtonVectorPtr_(0),
124 
125  nls_(nls),
126  top_(topTmp),
127  numSensParams_(0),
128  numObjectives_(0)
129 {
130  // if the base nonlinear solver class had a copy constructor, I could use
131  // that here... maybe I'll set that up later. ERK 11/15/02.
133 
137 
143 
144  savedRHSVectorPtr_ = lasSysPtr_->builder().createVector();
145  savedNewtonVectorPtr_ = lasSysPtr_->builder().createVector();
146 
147  lambdaVectorPtr_ = lasSysPtr_->builder().createVector();
148 
149  solutionSize_ = lasSysPtr_->getSolutionSize();
150 }
151 
152 //-----------------------------------------------------------------------------
153 // Function : Sensitivity::~Sensitivity
154 // Purpose : destructor
155 // Special Notes :
156 // Scope : public
157 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
158 // Creation Date : 10/30/02
159 //-----------------------------------------------------------------------------
161 {
162  delete savedRHSVectorPtr_;
163  savedRHSVectorPtr_ = 0;
164 
165  delete savedNewtonVectorPtr_;
167 
168  delete lambdaVectorPtr_;
169  lambdaVectorPtr_ = 0;
170 
171  for (int iobj=0;iobj<objFuncDataVec_.size();++iobj)
172  {
173  delete objFuncDataVec_[iobj]->dOdXVectorPtr_;
174  objFuncDataVec_[iobj]->dOdXVectorPtr_ = 0;
175 
176  delete objFuncDataVec_[iobj]->expPtr_;
177  objFuncDataVec_[iobj]->expPtr_ = 0;
178 
179  delete objFuncDataVec_[iobj];
180  objFuncDataVec_[iobj] = 0;
181  }
182 
183  // For all the stuff that is to be deleted in the nonlinear solver
184  // base class destructor, just set those pointers to zero because
185  // they will have been deleted already.
186  //
187  // This is the consequence of having the sensitivity class derived
188  // off of the nonlinear solver base class, but having it use all
189  // the same linear solver objects, etc., as the nonlinear solver used
190  // to solve the problem.
191  NewtonVectorPtr_ = 0;
192  gradVectorPtr_ = 0;
193  solWtVectorPtr_ = 0;
195  lasSolverPtr_ = 0;
196 }
197 
198 
199 
200 //-----------------------------------------------------------------------------
201 // Function : Sensitivity::stdOutput
202 // Purpose :
203 // Special Notes :
204 // Scope : public
205 // Creator : Eric Keiter, SNL
206 // Creation Date : 2/18/2014
207 //-----------------------------------------------------------------------------
209  std::string idString,
210  std::vector<double> & paramVals,
211  std::vector<double> & sensitivities,
212  std::vector<double> & scaled_sensitivities)
213 {
214  // Send the sensitivity information to the screen:
215 #ifdef Xyce_PARALLEL_MPI
216  N_PDS_Comm *pdsCommPtr = pdsMgrPtr_->getPDSComm();
217  int myPID = pdsCommPtr->procID();
218  if (myPID==0)
219 #endif
220  {
221  for (int iobj=0;iobj<objFuncDataVec_.size();++iobj)
222  {
223  Xyce::dout() << "\n"<<idString << " Sensitivities of objective function:";
224  Xyce::dout()
225  << objFuncDataVec_[iobj]->objFuncString_ << " = "
226  << objFuncDataVec_[iobj]->objFuncEval_ << std::endl;
227 
228 
229  Xyce::dout() << std::setw(maxParamStringSize_)<<"Name";
230  Xyce::dout() << "\t"<<std::setw(13)<<"Value";
231  Xyce::dout() << "\t"<<std::setw(13)<<"Sensitivity";
232  Xyce::dout() << "\t"<<std::setw(13)<<"Normalized"<<std::endl;
233 
234  for (int iparam=0; iparam< numSensParams_; ++iparam)
235  {
236  Xyce::dout() << std::setw(maxParamStringSize_)<<paramNameVec_[iparam];
237 
238  Xyce::dout() << "\t" << std::setw(13)<< std::scientific<< std::setprecision(4)
239  << paramVals[iparam];
240 
241  int index= iobj*numSensParams_ +iparam;
242  Xyce::dout() << "\t" << std::setw(13)<< std::scientific<< std::setprecision(4)
243  << sensitivities[index];
244 
245  Xyce::dout() << "\t" << std::setw(13)<< std::scientific<< std::setprecision(4)
246  << scaled_sensitivities[index] << std::endl;
247  }
248  }
249  }
250 #ifdef Xyce_PARALLEL_MPI
251  pdsCommPtr->barrier();
252 #endif
253 }
254 
255 //-----------------------------------------------------------------------------
256 // Function : Sensitivity::fileOutput
257 // Purpose : Dump sensitivity information out to a file.
258 // Special Notes :
259 // Scope : public
260 // Creator : Eric Keiter, SNL
261 // Creation Date : 2/18/2014
262 //-----------------------------------------------------------------------------
264  std::string idString,
265  std::vector<double> & paramVals,
266  std::vector<double> & sensitivities,
267  std::vector<double> & scaled_sensitivities)
268 {
269 #ifdef Xyce_PARALLEL_MPI
270  N_PDS_Comm *pdsCommPtr = pdsMgrPtr_->getPDSComm();
271  int myPID = pdsCommPtr->procID();
272  if (myPID==0)
273 #endif
274  {
275  std::ostringstream numSolvesOStr;
276  numSolvesOStr << numSolves_;
277  std::string dodpFileName = netlistFilename_ + numSolvesOStr.str() + "_dodp" + idString +".txt";
278  FILE *fp = fopen(dodpFileName.c_str(),"w");
279  for (int iparam=0;iparam< numSensParams_; ++iparam)
280  {
281  fprintf(fp,"\t%16.8e\n", sensitivities[iparam]);
282  }
283  fclose(fp);
284  }
285 #ifdef Xyce_PARALLEL_MPI
286  pdsCommPtr->barrier();
287 #endif
288 }
289 
290 #if 0
291 //-----------------------------------------------------------------------------
292 // Function : Sensitivity::dakOutput
293 // Purpose : Dump sensitivity information out to a dakota-style file.
294 // Special Notes :
295 // Scope : public
296 // Creator : Eric Keiter, SNL
297 // Creation Date : 2/19/2014
298 //-----------------------------------------------------------------------------
299 void Sensitivity::dakOutput (
300  std::string idString,
301  std::vector<double> & paramVals,
302  std::vector<double> & sensitivities,
303  std::vector<double> & scaled_sensitivities)
304 {
305 #ifdef Xyce_PARALLEL_MPI
306  N_PDS_Comm *pdsCommPtr = pdsMgrPtr_->getPDSComm();
307  int myPID = pdsCommPtr->procID();
308  if (myPID==0)
309 #endif
310  {
311  // write a file format that can be used by dakota :
312  // Note that currently, this will simply overwrite the same
313  // file every time this function is called.
314  std::string dakotaFileName = netlistFilename_ + "_dodp" + idString + "_all.txt";
315  FILE *fp2 = fopen(dakotaFileName.c_str(),"w");
316  fprintf(fp2,"%16.8e", objFuncEval_ );
317  fprintf(fp2,"%s","\n[\n");
318  for (int iparam=0;iparam< numSensParams_; ++iparam)
319  {
320  fprintf(fp2,"\t%16.8e\n", sensitivities[iparam]);
321  }
322  fprintf(fp2,"%s","]\n");
323  fclose(fp2);
324  }
325 #ifdef Xyce_PARALLEL_MPI
326  pdsCommPtr->barrier();
327 #endif
328 }
329 #endif
330 
331 
332 //-----------------------------------------------------------------------------
333 // Function : Sensitivity::icSensitivity
334 // Purpose : This function is called when there is a NOOP or UIC. The
335 // dqdp vector needs to be set up for the history to be correct.
336 // Special Notes :
337 // Scope : public
338 // Creator : Eric Keiter, SNL
339 // Creation Date :
340 //-----------------------------------------------------------------------------
342  std::vector<double> & objectiveVec,
343  std::vector<double> & dOdpVec,
344  std::vector<double> & dOdpAdjVec,
345  std::vector<double> & scaled_dOdpVec,
346  std::vector<double> & scaled_dOdpAdjVec)
347 {
348  if (!solveDirectFlag_ && !solveAdjointFlag_) return 1;
349 
350  TimeIntg::DataStore & ds = *dsPtr_;
351 
352  ds.dOdpVec_.clear();
353  ds.dOdpAdjVec_.clear();
354 
355  ds.scaled_dOdpVec_.clear();
356  ds.scaled_dOdpAdjVec_.clear();
357 
358  // first get the derivatives of the RHS vector w.r.t. the
359  // user-specified optimization parameters.
362 
364 
365  for (int iobj=0;iobj<objFuncDataVec_.size();++iobj)
366  {
367  objectiveVec.clear();
368  objectiveVec.push_back(objFuncDataVec_[iobj]->objFuncEval_);
369  ds.objectiveVec_.clear();
370  ds.objectiveVec_.push_back(objFuncDataVec_[iobj]->objFuncEval_);
371  }
372 
373  if (solveDirectFlag_)
374  {
375  ds.dOdpVec_.resize(numSensParams_*numObjectives_ ,0.0);
376  ds.scaled_dOdpVec_.resize(numSensParams_*numObjectives_,0.0);
377 
379  {
380  dOdpVec = ds.dOdpVec_;
381  }
382 
383  if (outputScaledFlag_)
384  {
385  scaled_dOdpVec = ds.scaled_dOdpVec_;
386  }
387 
388  if (stdOutputFlag_)
389  {
390  stdOutput(std::string("Direct"), ds.paramOrigVals_, ds.dOdpVec_, ds.scaled_dOdpVec_);
391  }
392  }
393 
394  if (solveAdjointFlag_)
395  {
397  ds.scaled_dOdpAdjVec_.resize(numSensParams_*numObjectives_,0.0);
398 
400  {
401  dOdpAdjVec = ds.dOdpAdjVec_;
402  }
403 
404  if (outputScaledFlag_)
405  {
406  scaled_dOdpAdjVec = ds.scaled_dOdpAdjVec_;
407  }
408  if (stdOutputFlag_)
409  {
410  stdOutput(std::string("Adjoint"), ds.paramOrigVals_, ds.dOdpAdjVec_, ds.scaled_dOdpAdjVec_);
411  }
412  }
413 
414  return true;
415 }
416 
417 //-----------------------------------------------------------------------------
418 // Function : Sensitivity::solve
419 // Purpose :
420 // Special Notes :
421 // Scope : public
422 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
423 // Creation Date : 11/21/02
424 //-----------------------------------------------------------------------------
426  std::vector<double> & objectiveVec,
427  std::vector<double> & dOdpVec,
428  std::vector<double> & dOdpAdjVec,
429  std::vector<double> & scaled_dOdpVec,
430  std::vector<double> & scaled_dOdpAdjVec)
431 {
432  Stats::StatTop _solveStat("Sensistivity Solve");
433  Stats::TimeBlock _solveTimer(_solveStat);
434 
435  if (!solveDirectFlag_ && !solveAdjointFlag_) return 1;
436 
437  TimeIntg::DataStore & ds = *dsPtr_;
438 
439  ds.dOdpVec_.clear();
440  ds.dOdpAdjVec_.clear();
441 
442  ds.scaled_dOdpVec_.clear();
443  ds.scaled_dOdpAdjVec_.clear();
444 
445  // It may now be neccessary to re-load the jacobian and rhs vectors.
446  // It is necccessary, for example, if the two-level Newton solver is the
447  // solver being used.
449 
450  // first get the derivatives of the RHS vector w.r.t. the
451  // user-specified optimization parameters.
454 
456 
457  objectiveVec.clear();
458  ds.objectiveVec_.clear();
459  for (int iobj=0;iobj<objFuncDataVec_.size();++iobj)
460  {
461  objectiveVec.push_back(objFuncDataVec_[iobj]->objFuncEval_);
462  ds.objectiveVec_.push_back(objFuncDataVec_[iobj]->objFuncEval_);
463  }
464 
465  if (solveDirectFlag_)
466  {
467  solveDirect ();
468 
470  {
471  dOdpVec = ds.dOdpVec_;
472  }
473 
474  if (outputScaledFlag_)
475  {
476  scaled_dOdpVec = ds.scaled_dOdpVec_;
477  }
478  }
479 
480  if (solveAdjointFlag_)
481  {
482  solveAdjoint ();
484  {
485  dOdpAdjVec = ds.dOdpAdjVec_;
486  }
487 
488  if (outputScaledFlag_)
489  {
490  scaled_dOdpAdjVec = ds.scaled_dOdpAdjVec_;
491  }
492  }
493 
494  numSolves_++;
495 
496  return 1;
497 }
498 
499 //-----------------------------------------------------------------------------
500 // Function : Sensitivity::solveDirect
501 //
502 // Purpose : This function calculates the direct sensitivities for
503 // the user specified parameters.
504 //
505 // The ultimate goal of this function is to obtain dO/dp,
506 // where O is the objective function, and p is a
507 // user-defined optimization parameter.
508 //
509 // This is a bit confusing because the DAKOTA folks use
510 // a different naming convention than I have tended to
511 // use. In Dakota's documentation, dO/dp would be referred
512 // to as df/du. In Xyce, f is already considered to be the
513 // right-hand-side residual vector. For clarity, this is
514 // the key between my notation and DAKOTA's:
515 // DAK Xyce
516 // f O
517 // y x
518 // u p
519 // c f
520 //
521 // To obtain dOdp, the device manager is first called, and
522 // told to calculate dfdp, which is the derivative of the
523 // residual vector w.r.t. user-defined params. It does
524 // this by numerical differentiation. Then, after that,
525 // this function solves the equation:
526 //
527 // J dx/dp = df/dp -> dx/dp = J^-1 df/dp
528 //
529 // for each p.
530 //
531 // J is the jacobian matrix, so J=df/dx. (dc/dy)
532 //
533 // After performing these linear solves, dO/dp is to be
534 // obtained using the chain rule by:
535 //
536 // dO/dp = - dO/dx * dx/dp + dO/dp
537 //
538 // The O in the dO/dp on the left side of this equation
539 // should have a hat over it "^", to indicate that it is
540 // different than the O on the right hand side.
541 //
542 // Note, this method is best if you have lots of objective
543 // functions, and a small number of parameters. For adjoint
544 // calculations it is the other way around.
545 //
546 // 11/19/02.
547 // It is assumed (for now) that dO/dp on the right hand side
548 // is zero, i.e., there is no direct
549 // dependence on p by O. So, for example, if a user
550 // defined parameter to be used is the length of a MOSFET,
551 // the MOSFET length will NOT appear in the analytical
552 // expression for O.
553 //
554 //
555 // Special Notes :
556 // Scope : public
557 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
558 // Creation Date : 10/31/02
559 //-----------------------------------------------------------------------------
561 {
562  Stats::StatTop _solveDirectStat("Solve Direct");
563  Stats::TimeBlock _solveDirectTimer(_solveDirectStat);
564 
565  if (DEBUG_NONLINEAR && isActive(Diag::SENS_SOLVER))
566  {
567  Xyce::dout() << std::endl
568  << "In Sensitivity::solveDirect" << std::endl;
569  }
570 
571  TimeIntg::DataStore & ds = *dsPtr_;
572 
573  int iparam;
574  std::vector<Linear::Vector *> & dXdpPtrVector_ = ds.nextDXdpPtrVector;
575  std::vector<Linear::Vector *> & currdXdpPtrVector_ = ds.currDXdpPtrVector;
576  std::vector<Linear::Vector *> & sensRHSPtrVector = ds.sensRHSPtrVector;
577 
578  std::vector<Linear::Vector *> & DQdxDXdpPtrVector_ = ds.nextDQdxDXdpPtrVector;
579 
580  // first save a copy of the rhs and newton vectors, in case we want them later.
581  savedRHSVectorPtr_->update(1.0, *(rhsVectorPtr_), 0.0);
582  savedNewtonVectorPtr_->update(1.0, *(NewtonVectorPtr_), 0.0);
583 
584  // via the loader, setup all the sensitivity residuals.
586 
587  if (DEBUG_NONLINEAR && isActive(Diag::SENS_SOLVER))
588  {
589  std::string matrixFile = netlistFilename_ + "_directMatrix.txt";
590  jacobianMatrixPtr_->writeToFile(const_cast<char *>(matrixFile.c_str()));
591  }
592 
593  // Now solve the series of linear systems to get dXdp.
594  for (iparam=0; iparam< numSensParams_; ++iparam)
595  {
596  // copy the sensitivity residual into the rhs vector location,
597  // as that is the RHS vector that the linear solver expects.
598  rhsVectorPtr_->update(1.0, *(sensRHSPtrVector[iparam]), 0.0);
599 
601 
602  // copy the result of the linear solve into the dxdp data structure.
603  (dXdpPtrVector_[iparam])->update(1.0, *(NewtonVectorPtr_), 0.0);
604 
605  // do debug output.
606  if (DEBUG_NONLINEAR && isActive(Diag::SENS_SOLVER))
607  {
608  Xyce::dout() << "iparam="<<iparam << "\t" << paramNameVec_[iparam] <<std::endl;
609  for (int k = 0; k < solutionSize_; ++k)
610  {
611  Xyce::dout() << "dXdp[" << std::setw(3) << k << "] = "<< std::setw(15)<< std::scientific
612  << std::setprecision(8)<< (*(dXdpPtrVector_[iparam]))[k]
613  <<std::endl;
614  }
615 
616  std::ostringstream filename;
617  filename << netlistFilename_ << "_dxdp";
618  filename << std::setw(3) << std::setfill('0') << iparam;
619  filename << ".txt";
620  dXdpPtrVector_[iparam]->writeToFile(const_cast<char *>(filename.str().c_str()));
621  }
622 
623  // Now store the DQdx*dXdp matvec
624  Linear::Matrix & dQdx = *(ds.dQdxMatrixPtr);
625  bool Transpose = false;
626  (DQdxDXdpPtrVector_[iparam])->putScalar(0.0);
627  dQdx.matvec( Transpose , *(dXdpPtrVector_[iparam]), *(DQdxDXdpPtrVector_[iparam]) );
628 
629  }// end of param for loop
630 
631  // Now update the time derivative of the matvec (this is needed for trap).
633 
634  // Restore the RHS and Newton vectors.
635  rhsVectorPtr_->update(1.0, *(savedRHSVectorPtr_),0.0);
636  NewtonVectorPtr_->update(1.0, *(savedNewtonVectorPtr_),0.0);
637 
638  // Now get the final dOdp's (one for each objective/param combination).
639  for (int iobj=0;iobj<objFuncDataVec_.size();++iobj)
640  {
641  for (iparam=0; iparam< numSensParams_; ++iparam)
642  {
643  double tmp = objFuncDataVec_[iobj]->dOdXVectorPtr_->dotProduct( (*(dXdpPtrVector_[iparam])) );
644  tmp += objFuncDataVec_[iobj]->dOdp_;
645 
646  ds.dOdpVec_.push_back(tmp);
647 
648  // get scaled value. dO/dp*(p/100)
649  double normalize = ds.paramOrigVals_[iparam]/100.0;
650  tmp *= normalize;
651  ds.scaled_dOdpVec_.push_back(tmp);
652  }
653  }
654 
655  if (stdOutputFlag_)
656  {
657  stdOutput(std::string("Direct"), ds.paramOrigVals_, ds.dOdpVec_, ds.scaled_dOdpVec_);
658  }
659 
660  if (fileOutputFlag_)
661  {
662  fileOutput(std::string("Direct"), ds.paramOrigVals_, ds.dOdpVec_, ds.scaled_dOdpVec_);
663  }
664 
665 #if 0
667  {
668  dakOutput(std::string("Direct"), ds.paramOrigVals_, ds.dOdpVec_, ds.scaled_dOdpVec_);
669  }
670 #endif
671 
672  return 1;
673 }
674 
675 //-----------------------------------------------------------------------------
676 // Function : Sensitivity::calcObjFuncDerivs
677 //
678 // Purpose : This function assumes an objective function, O, and
679 // uses it to calculate other stuff, including dO'/du,
680 // dO/dy, dO/du.
681 //
682 // The objective function simply assumes that you are
683 // trying to match a solution variable with a
684 // user-specified number. (objective=1)
685 //
686 // Or that you are trying to match your final solution
687 // with a specified solution. (objective=2)
688 //
689 // Special Notes : This is mostly for testing purposes. Usually, the
690 // objective function would be set and managed from
691 // the DAKOTA side.
692 //
693 // Scope : public
694 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
695 // Creation Date : 11/15/02
696 //-----------------------------------------------------------------------------
698 {
699  bool bsuccess = true;
700  int i;
701 
702  for (int iobj=0;iobj<objFuncDataVec_.size();++iobj)
703  {
704  objFuncDataVec_[iobj]->dOdXVectorPtr_->putScalar(0.0);
705  }
706 
707  // first check if the user specified a function via the expressions
708  // class:
709  int found(0);
710  int found2(0);
711  bool foundLocal(false);
712  bool foundLocal2(false);
713 
714  N_PDS_Comm & comm = *(pdsMgrPtr_->getPDSComm());
715  int myPID = comm.procID();
716 
717  if (objFuncGiven_)
718  {
719  if (!objFuncGIDsetup_)
720  {
721  for (int iobj=0;iobj<objFuncDataVec_.size();++iobj)
722  {
723  // set up the gid's:
724  objFuncDataVec_[iobj]->expVarGIDs_.resize( objFuncDataVec_[iobj]->numExpVars_, -1 );
725  for (i = 0; i < objFuncDataVec_[iobj]->numExpVars_; ++i)
726  {
727  std::vector<int> svGIDList1, dummyList;
728  char type1;
729  foundLocal = top_.getNodeSVarGIDs(NodeID(objFuncDataVec_[iobj]->expVarNames_[i], Xyce::_VNODE), svGIDList1, dummyList, type1);
730  found = static_cast<int>(foundLocal);
731  Xyce::Parallel::AllReduce(comm.comm(), MPI_LOR, &found, 1);
732 
733  foundLocal2 = false;
734  if (!found)// if looking for this as a voltage node failed, try a "device" (i.e. current) node.
735  {
736  foundLocal2 = top_.getNodeSVarGIDs(NodeID(objFuncDataVec_[iobj]->expVarNames_[i], Xyce::_DNODE), svGIDList1, dummyList, type1);
737  }
738  found2 = static_cast<int>(foundLocal2);
739  Xyce::Parallel::AllReduce(comm.comm(), MPI_LOR, &found2, 1);
740 
741  if (!found && !found2)
742  {
743  static std::string tmp = "objective function variable not found!\n";
744  N_ERH_ErrorMgr::report( N_ERH_ErrorMgr::USR_FATAL, tmp);
745  }
746 
747  if (found || found2)
748  {
749  int tmpGID=-1;
750  if(svGIDList1.size()==1)
751  {
752  tmpGID = svGIDList1.front();
753  }
754  objFuncDataVec_[iobj]->expVarGIDs_[i] = tmpGID;
755  }
756  }
757  }
758  objFuncGIDsetup_ = true;
759  }
760 
761  // obtain the expression variable values. It will only grab this value if it is owned on this processor.
762  for (int iobj=0;iobj<objFuncDataVec_.size();++iobj)
763  {
764  objFuncDataVec_[iobj]->expVarVals_.resize (objFuncDataVec_[iobj]->numExpVars_, 0.0);
765  objFuncDataVec_[iobj]->expVarDerivs_.resize (objFuncDataVec_[iobj]->numExpVars_, 0.0);
766 
767  comm.barrier();
768  for (i = 0; i < objFuncDataVec_[iobj]->numExpVars_; ++i)
769  {
770  int tmpGID=objFuncDataVec_[iobj]->expVarGIDs_[i];
771  double tmpVal=0.0;
772  int root=-1;
773  if (tmpGID >= 0)
774  {
775  tmpVal = (*nextSolVectorPtrPtr_)->getElementByGlobalIndex(tmpGID, 0);
776  root = myPID;
777  }
778  Xyce::Parallel::AllReduce(comm.comm(), MPI_MAX, &root, 1);
779 
780  comm.bcast( &tmpVal, 1, root );
781 
782  objFuncDataVec_[iobj]->expVarVals_[i] = tmpVal;
783  }
784  comm.barrier();
785  }
786 
787  //get expression value and partial derivatives
788  for (int iobj=0;iobj<objFuncDataVec_.size();++iobj)
789  {
790  objFuncDataVec_[iobj]->expPtr_->evaluate(
791  objFuncDataVec_[iobj]->expVal_,
792  objFuncDataVec_[iobj]->expVarDerivs_,
793  objFuncDataVec_[iobj]->expVarVals_ );
794 
795  objFuncDataVec_[iobj]->objFuncEval_ = objFuncDataVec_[iobj]->expVal_;
796  objFuncDataVec_[iobj]->dOdXVectorPtr_->putScalar(0.0);
797  for (i=0;i<objFuncDataVec_[iobj]->numExpVars_;++i)
798  {
799  int tmpGID = objFuncDataVec_[iobj]->expVarGIDs_[i];
800  double tmpDODX = objFuncDataVec_[iobj]->expVarDerivs_[i];
801 
802  if (DEBUG_NONLINEAR && isActive(Diag::SENS_SOLVER))
803  {
804  Xyce::dout() << "i="<<i<<" gid = " << tmpGID << " dodx = "<< tmpDODX << std::endl;
805  }
806 
807  if (tmpGID >= 0)
808  {
809  objFuncDataVec_[iobj]->dOdXVectorPtr_->setElementByGlobalIndex(tmpGID, tmpDODX, 0);
810  }
811  }
812 
813  // Assuming this is zero:
814  objFuncDataVec_[iobj]->dOdp_ = 0.0;
815  }
816  }
817  else // give a warning.
818  {
819  Report::UserWarning0() << "Objective function was not specified";
820  }
821 
822 
823  for (int iobj=0;iobj<objFuncDataVec_.size();++iobj)
824  {
825  objFuncDataVec_[iobj]->dOdXVectorPtr_->fillComplete();
826 
827  if (DEBUG_NONLINEAR && isActive(Diag::SENS_SOLVER))
828  {
829  std::string filename = netlistFilename_ + "_dodx.txt";
830  objFuncDataVec_[iobj]->dOdXVectorPtr_->writeToFile(const_cast<char *>(filename.c_str()));
831  }
832  }
833 
834  return bsuccess;
835 }
836 
837 //-----------------------------------------------------------------------------
838 // Function : Sensitivity::solveAdjoint
839 // Purpose : Solves first for the vector, lambda, of adjoint variables.
840 // Afterwards, it solves for dO/dp.
841 // Special Notes :
842 // Scope : public
843 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
844 // Creation Date : 11/20/02
845 //-----------------------------------------------------------------------------
847 {
848  Stats::StatTop _solveAdjointStat("Solve Adjoint");
849  Stats::TimeBlock _solveAdjointTimer(_solveAdjointStat);
850 
851  if (DEBUG_NONLINEAR && isActive(Diag::SENS_SOLVER))
852  {
853  Xyce::dout() << std::endl;
854  Xyce::dout() << "In Sensitivity::solveAdjoint" << std::endl;
855  }
856 
857  TimeIntg::DataStore & ds = *dsPtr_;
858 
859  std::vector<Linear::Vector *> & dfdpPtrVector_ = ds.nextDfdpPtrVector;
860  std::vector<Linear::Vector *> & dbdpPtrVector_ = ds.nextDbdpPtrVector;
861  std::vector<Linear::Vector *> & sensRHSPtrVector = ds.sensRHSPtrVector;
862 
863  // first save a copy of the rhs vector, in case we want it later.
864  savedRHSVectorPtr_->update(1.0, *(rhsVectorPtr_),0.0);
865  savedNewtonVectorPtr_->update(1.0, *(NewtonVectorPtr_),0.0);
866 
867  bool useTran = jacobianMatrixPtr_->useTranspose ();
868  if (DEBUG_NONLINEAR && isActive(Diag::SENS_SOLVER))
869  {
870  std::string matrixFile = netlistFilename_ + "_adjointMatrix.txt";
871  jacobianMatrixPtr_->writeToFile(const_cast<char *>(matrixFile.c_str()));
872  }
873 
874  for (int iobj=0;iobj<objFuncDataVec_.size();++iobj)
875  {
876  // copy the current dOdx vector into the rhs vector data structure.
877  rhsVectorPtr_->update(1.0, *(objFuncDataVec_[iobj]->dOdXVectorPtr_),0.0);
878 
879  int status = lasSolverPtr_->solveTranspose(reuseFactors_);
880  if (status!=0)
881  {
882  std::string msg("Sensitivity::solveAdjoint. Solver failed\n");
883  N_ERH_ErrorMgr::report (N_ERH_ErrorMgr::DEV_FATAL, msg);
884  }
885 
886  // allocate the dxdp vector for this param, and
887  // copy the resulting deltax vector into the dxdp data structure.
888  lambdaVectorPtr_->update(1.0, *(NewtonVectorPtr_),0.0);
889 
890  if (DEBUG_NONLINEAR && isActive(Diag::SENS_SOLVER))
891  {
892  std::string filename = netlistFilename_ + "_lambda.txt";
893  lambdaVectorPtr_->writeToFile(const_cast<char *>(filename.c_str()));
894  }
895 
896  // Now that we have lambda, get the dOdp's by doing dot products of
897  // lambda * df/dp.
898 
899  // do the final dot products, one for each param.
900  for (int iparam=0; iparam< numSensParams_; ++iparam)
901  {
902  // assuming that this is steady-state, then we need to sum together dfdp and -dbdp.
903  Linear::Vector & RHSVec = *(sensRHSPtrVector[iparam]);
904  Linear::Vector & dfdpVec = *(dfdpPtrVector_[iparam]);
905  Linear::Vector & dbdpVec = *(dbdpPtrVector_[iparam]);
906  RHSVec.linearCombo(0.0,RHSVec,+1.0,dfdpVec);
907  RHSVec.linearCombo(1.0,RHSVec,-1.0,dbdpVec);
908 
909  double tmp = -1.0 * lambdaVectorPtr_->dotProduct(RHSVec);
910  ds.dOdpAdjVec_.push_back(tmp);
911 
912  // get scaled value. dO/dp*(p/100)
913  double normalize = ds.paramOrigVals_[iparam]/100.0;
914  tmp *= normalize;
915  ds.scaled_dOdpAdjVec_.push_back(tmp);
916  }
917  }
918 
919  // restore the useTranspose flag to the original setting. (false)
920  jacobianMatrixPtr_->setUseTranspose (useTran);
921 
922  // Restore the RHS and Newton vectors.
923  rhsVectorPtr_->update(1.0, *(savedRHSVectorPtr_),0.0);
924  NewtonVectorPtr_->update(1.0, *(savedNewtonVectorPtr_),0.0);
925 
926  // set the sensitivity information to the screen:
927  if (stdOutputFlag_)
928  {
929  stdOutput(std::string("Adjoint"), ds.paramOrigVals_, ds.dOdpAdjVec_, ds.scaled_dOdpAdjVec_);
930  }
931  if (fileOutputFlag_)
932  {
933  fileOutput(std::string("Adjoint"), ds.paramOrigVals_, ds.dOdpAdjVec_, ds.scaled_dOdpAdjVec_);
934  }
935 
936 #if 0
938  {
939  dakOutput(std::string("Adjoint"), ds.paramOrigVals_, ds.dOdpAdjVec_, ds.scaled_dOdpAdjVec_);
940  }
941 #endif
942 
943  return 1;
944 }
945 
946 //-----------------------------------------------------------------------------
947 // Function : Sensitivity::setOptions
948 //
949 // Purpose : This function processes the .SENS line
950 //
951 // Special Notes :
952 // Scope : public
953 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
954 // Creation Date : 11/15/02
955 //-----------------------------------------------------------------------------
956 bool Sensitivity::setOptions(const Util::OptionBlock& OB)
957 {
958  bool bsuccess = true;
959  Util::ParamList::const_iterator iter = OB.begin();
960  Util::ParamList::const_iterator end = OB.end();
961 
962  numSensParams_ = 0;
963 
964  for ( ; iter != end; ++ iter)
965  {
966  if ( std::string( iter->uTag() ,0,7) == "OBJFUNC") // this is a vector
967  {
968  objectiveFunctionData * ofDataPtr = new objectiveFunctionData();
969  ofDataPtr->objFuncString_ = iter->stringValue();
970  ofDataPtr->expPtr_ = new Util::Expression(iter->stringValue());
971  ofDataPtr->dOdXVectorPtr_ = lasSysPtr_->builder().createVector();
972  objFuncDataVec_.push_back(ofDataPtr);
973 
974  objFuncGiven_ = true;
975  }
976  else if ( std::string( iter->uTag() ,0,5) == "PARAM") // this is a vector
977  {
978  ExtendedString tag = iter->stringValue();
979  tag.toUpper();
980  // set up the initial skeleton of the maps:
981  ++numSensParams_;
982  paramNameVec_.push_back(tag);
983  int sz = tag.size();
984  if (sz > maxParamStringSize_)
985  {
986  maxParamStringSize_ = sz;
987  }
988  }
989  else
990  {
991  Xyce::Report::UserWarning() << iter->uTag()
992  << " is not a recognized sensitivity solver option.\n" << std::endl;
993  }
994  }
996 
997  // parse the expression now, so if there are any errors, they will come
998  // up early in the simulation.
999  if (objFuncGiven_)
1000  {
1001  for (int iobj=0;iobj<objFuncDataVec_.size();++iobj)
1002  {
1003  // setup the names:
1004  objFuncDataVec_[iobj]->expVarNames_.clear();
1005 
1006  std::vector<std::string> nodes;
1007  objFuncDataVec_[iobj]->expPtr_->get_names(XEXP_NODE, nodes);
1008  std::vector<std::string> instances;
1009  objFuncDataVec_[iobj]->expPtr_->get_names(XEXP_INSTANCE, instances);
1010 
1011  // Make the current (instance) strings all upper case.
1012  // The topology directory apparently requires this.
1013  std::vector<std::string>::iterator iter;
1014  for (iter=instances.begin();iter!=instances.end();++iter)
1015  {
1016  ExtendedString tmpString = *iter;
1017  tmpString.toUpper ();
1018  *iter = tmpString;
1019  }
1020 
1021  objFuncDataVec_[iobj]->expVarNames_.insert(objFuncDataVec_[iobj]->expVarNames_.end(), nodes.begin(), nodes.end());
1022  objFuncDataVec_[iobj]->expVarNames_.insert(objFuncDataVec_[iobj]->expVarNames_.end(), instances.begin(), instances.end());
1023 
1024  // Order the names in the expression so that it agrees with the order
1025  // in expVarNames.
1026  if ( !(objFuncDataVec_[iobj]->expVarNames_.empty()) )
1027  {
1028  objFuncDataVec_[iobj]->expPtr_->order_names( objFuncDataVec_[iobj]->expVarNames_ );
1029  }
1030 
1031  objFuncDataVec_[iobj]->numExpVars_ = objFuncDataVec_[iobj]->expVarNames_.size();
1032 
1033  if (objFuncDataVec_[iobj]->numExpVars_<=0)
1034  {
1035  static std::string tmp = "Objective function does not contain a resolvable solution variable.\n";
1036  N_ERH_ErrorMgr::report( N_ERH_ErrorMgr::USR_FATAL_0, tmp);
1037  }
1038  }
1039  }
1040 
1041  if (DEBUG_NONLINEAR && isActive(Diag::SENS_SOLVER))
1042  {
1043  std::vector<std::string>::iterator iter;
1044  std::vector<std::string>::iterator begin = paramNameVec_.begin();
1045  std::vector<std::string>::iterator end = paramNameVec_.end ();
1046 
1047  for (iter=begin;iter!=end;++iter)
1048  {
1049  Xyce::dout() << *iter<<std::endl;
1050  }
1051  }
1052 
1054 
1055  return bsuccess;
1056 }
1057 
1058 //-----------------------------------------------------------------------------
1059 // Function : Sensitivity::setSensitivityOptions
1060 // Purpose : This function processes the .options SENSITIVITY line
1061 // Special Notes :
1062 // Scope : public
1063 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1064 // Creation Date : 06/20/2013
1065 //-----------------------------------------------------------------------------
1066 bool Sensitivity::setSensitivityOptions(const Util::OptionBlock &OB)
1067 {
1068  bool bsuccess = true;
1069  Util::ParamList::const_iterator it = OB.begin();
1070  Util::ParamList::const_iterator end = OB.end();
1071  for ( ; it != end; ++ it)
1072  {
1073  if ((*it).uTag() == "ADJOINT")
1074  {
1076  static_cast<bool>((*it).getImmutableValue<bool>());
1077  }
1078  else if ((*it).uTag() == "DIRECT")
1079  {
1080  solveDirectFlag_ =
1081  static_cast<bool>((*it).getImmutableValue<bool>());
1082  }
1083  else if ((*it).uTag() == "OUTPUTSCALED")
1084  {
1086  static_cast<bool>((*it).getImmutableValue<bool>());
1087  }
1088  else if ((*it).uTag() == "OUTPUTUNSCALED")
1089  {
1091  static_cast<bool>((*it).getImmutableValue<bool>());
1092  }
1093  else if ((*it).uTag() == "STDOUTPUT")
1094  {
1095  stdOutputFlag_ =
1096  static_cast<bool>((*it).getImmutableValue<bool>());
1097  }
1098  else if ((*it).uTag() == "DAKOTAFILE")
1099  {
1101  static_cast<bool>((*it).getImmutableValue<bool>());
1102  }
1103  else if ((*it).uTag() == "DIAGNOSTICFILE")
1104  {
1105  fileOutputFlag_ =
1106  static_cast<bool>((*it).getImmutableValue<bool>());
1107  }
1108  else if ((*it).uTag() == "FORCEFD")
1109  {
1110  forceFD_ =
1111  static_cast<bool>((*it).getImmutableValue<bool>());
1112  }
1113  else if ((*it).uTag() == "DIFFERENCE")
1114  {
1115  ExtendedString sval=(*it).stringValue();
1116  sval.toUpper();
1117  if(sval=="FORWARD")
1118  {
1120  }
1121  else if(sval=="REVERSE")
1122  {
1124  }
1125  else if(sval=="CENTRAL")
1126  {
1128  static std::string tmp = "difference=central not supported.\n";
1129  N_ERH_ErrorMgr::report( N_ERH_ErrorMgr::USR_FATAL_0, tmp);
1130  }
1131  else
1132  {
1133  static std::string tmp = "difference not recognized!\n";
1134  N_ERH_ErrorMgr::report( N_ERH_ErrorMgr::USR_FATAL_0, tmp);
1135  }
1136  }
1137  else if ((*it).uTag() == "SQRTETA")
1138  {
1139  sqrtEta_ = (*it).getImmutableValue<double>();
1140  sqrtEtaGiven_ = true;
1141  }
1142  else if ((*it).uTag() == "REUSEFACTORS")
1143  {
1144  reuseFactors_ = (*it).getImmutableValue<double>();
1145  }
1146  else if (DEBUG_NONLINEAR && (*it).uTag() == "DEBUGLEVEL")
1147  {
1148  debugLevel_ = (*it).getImmutableValue<int>();
1149  Xyce::setSensitivityDebugLevel(debugLevel_);
1150  }
1151  else
1152  {
1153  Xyce::Report::UserWarning() << (*it).uTag()
1154  << " is not a recognized sensitivity solver option.\n" << std::endl;
1155  }
1156  }
1157 
1158  return true;
1159 }
1160 
1161 //-----------------------------------------------------------------------------
1162 // Function : Sensitivity::getMaxNormF
1163 // Purpose :
1164 // Special Notes :
1165 // Scope : public
1166 // Creator : Rich Schiek, Electrical and MEMS Modeling
1167 // Creation Date : 9/28/2009
1168 //-----------------------------------------------------------------------------
1170 {
1171  return nls_.getMaxNormF();
1172 }
1173 
1174 //-----------------------------------------------------------------------------
1175 // Function : Sensitivity::getMaxNormFindex
1176 // Purpose :
1177 // Special Notes :
1178 // Scope : public
1179 // Creator : Rich Schiek, Electrical and MEMS Modeling
1180 // Creation Date : 9/28/2009
1181 //-----------------------------------------------------------------------------
1183 {
1184  return nls_.getMaxNormFindex ();
1185 }
1186 
1187 //-----------------------------------------------------------------------------
1188 // Function : extractSENSData
1189 // Purpose :
1190 // Special Notes :
1191 // Scope : public
1192 // Creator : Eric Keiter, SNL
1193 // Creation Date : 10/11/2007
1194 //-----------------------------------------------------------------------------
1196  IO::PkgOptionsMgr & options_manager,
1197  IO::CircuitBlock & circuit_block,
1198  const std::string & netlist_filename,
1199  const IO::TokenVector & parsed_line)
1200 {
1201  Util::OptionBlock option_block("SENS", Util::OptionBlock::ALLOW_EXPRESSIONS, netlist_filename, parsed_line[0].lineNumber_);
1202 
1203  int numFields = parsed_line.size();
1204 
1205  int parameterStartPos = 1;
1206 
1207  // Create an option block to temporarily store the default options.
1208  Util::OptionBlock defaultOptions;
1209 
1210  // Get the default options from metadata.
1211  addDefaultOptionsParameters(options_manager, defaultOptions, "SENS" );
1212 
1213  // Extract the parameters from parsed_line.
1214  int parameterEndPos = numFields - 1;
1215  Util::ParamList inputParameters;
1216  Util::Param parameter("", "");
1217  int intervalParameterStart = -1;
1218  int i = parameterStartPos;
1219  std::string paramBaseName;
1220  while (i <= parameterEndPos-1)
1221  {
1222  // Check for equal sign.
1223  if ( parsed_line[i+1].string_ != "=" )
1224  {
1225  // Stop after the tagged parameters have been extracted
1226  // from a .OPTIONS RESTART or .OPTIONS OUTPUT line, they
1227  // will be handled later.
1228  intervalParameterStart = i;
1229  break;
1230  }
1231 
1232  // Extract parameter name and value from parsed_line and add to
1233  // parameter list. Check to see if the parameter is "VECTOR"
1234  // valued and treat accordingly.
1235  parameter.set( parsed_line[i].string_, "" );
1236  Util::Param *parameterPtr = Util::findParameter(defaultOptions.begin(), defaultOptions.end(), parameter.tag());
1237  if (parameterPtr == NULL)
1238  {
1239  Report::UserWarning0().at(netlist_filename, parsed_line[0].lineNumber_)
1240  << "No options parameter " << parameter.tag() << " found, parameter will be ignored.";
1241  i+= 3;
1242  }
1243  else if (parameterPtr->stringValue() != "VECTOR")
1244  {
1245  parameter.setVal( parsed_line[i+2].string_ );
1246  inputParameters.push_back( parameter );
1247  i+= 3;
1248 
1249  if (i < parameterEndPos-1 && parsed_line[i].string_ == ",")
1250  {
1251  Report::UserError0().at(netlist_filename, parsed_line[0].lineNumber_)
1252  << "Options parameter " << parameter.tag() << " is flagged as not VECTOR, but has comma in value.";
1253  }
1254  }
1255  else
1256  {
1257  // We have a vector valued parameter.
1258  // Name the jth component of the parameter of the vector by appending
1259  // "j" to the parameter name.
1260  std::ostringstream paramName;
1261  paramBaseName = ExtendedString(parsed_line[i].string_).toUpper();
1262  int j = 1;
1263 
1264  paramName << paramBaseName << j;
1265  i += 2;
1266  parameter.set(paramName.str(), parsed_line[i].string_);
1267  option_block.addParam(parameter);
1268 
1269  // This while loop is dangerous if we are near the end of the
1270  // parsed line because it still assumed that the format is
1271  // option=value,value and not option=value,value,
1272  // that is no trailing comma. It does work if
1273  // option=value,value is at the end of a line now (RLS 5/07)
1274  int testSize = parsed_line.size()-1;
1275  while ((i < testSize) && (parsed_line[i+1].string_ == ",") )
1276  {
1277  paramName.str("");
1278  ++j;
1279  paramName << paramBaseName << j;
1280  i += 2;
1281  parameter.set(paramName.str(), parsed_line[i].string_);
1282  option_block.addParam(parameter);
1283  }
1284 
1285  ++i;
1286  }
1287  }
1288 
1289  // For each input parameter, check that it is in the default
1290  // set and if so, set its value in "parameters" to the input
1291  // value, otherwise flag it as an unknown parameter.
1292  for (Util::ParamList::const_iterator it = inputParameters.begin(), end = inputParameters.end(); it != end; ++it)
1293  {
1294  Util::Param *parameterPtr = Util::findParameter(defaultOptions.begin(), defaultOptions.end(), (*it).tag());
1295  if ( parameterPtr != NULL )
1296  {
1297  parameterPtr->setVal(*it);
1298  option_block.addParam( *parameterPtr );
1299  }
1300  else
1301  {
1302  Report::UserWarning0().at(netlist_filename, parsed_line[0].lineNumber_)
1303  << "No options parameter " << (*it).tag() << " found, parameter will be ignored.";
1304  }
1305  }
1306 
1307  circuit_block.addOptions(option_block);
1308 
1309  return true; // Only get here on success.
1310 }
1311 
1312 //-----------------------------------------------------------------------------
1313 // Function : Sensitivity::populateMetadata
1314 // Purpose :
1315 // Special Notes :
1316 // Scope : public
1317 // Creator : Dave Baur
1318 // Creation Date :
1319 //-----------------------------------------------------------------------------
1321  IO::PkgOptionsMgr & options_manager)
1322 {
1323  {
1324  Util::ParamMap &parameters = options_manager.addOptionsMetadataMap("SENSITIVITY");
1325 
1326  parameters.insert(Util::ParamMap::value_type("DEBUGLEVEL", Util::Param("DEBUGLEVEL", 0)));
1327  parameters.insert(Util::ParamMap::value_type("ADJOINT", Util::Param("ADJOINT", 0)));
1328  parameters.insert(Util::ParamMap::value_type("DIRECT", Util::Param("DIRECT", 0)));
1329  parameters.insert(Util::ParamMap::value_type("OUTPUTSCALED", Util::Param("OUTPUTSCALED", 0)));
1330  parameters.insert(Util::ParamMap::value_type("OUTPUTUNSCALED", Util::Param("OUTPUTUNSCALED", 1)));
1331  parameters.insert(Util::ParamMap::value_type("STDOUTPUT", Util::Param("STDOUTPUT", 1)));
1332  parameters.insert(Util::ParamMap::value_type("DIAGNOSTICFILE", Util::Param("DIAGNOSTICFILE", 0)));
1333  parameters.insert(Util::ParamMap::value_type("DAKOTAFILE", Util::Param("DAKOTAFILE", 0)));
1334  parameters.insert(Util::ParamMap::value_type("DIFFERENCE", Util::Param("DIFFERENCE", 0)));
1335  parameters.insert(Util::ParamMap::value_type("SQRTETA", Util::Param("SQRTETA", 1.0e-8)));
1336  parameters.insert(Util::ParamMap::value_type("FORCEFD", Util::Param("FORCEFD", 0)));
1337  }
1338 
1339  {
1340  Util::ParamMap &parameters = options_manager.addOptionsMetadataMap("SENS");
1341 
1342  parameters.insert(Util::ParamMap::value_type("OBJFUNC", Util::Param("OBJFUNC", "VECTOR")));
1343  parameters.insert(Util::ParamMap::value_type("PARAM", Util::Param("PARAM", "VECTOR")));
1344  }
1345 
1346  options_manager.addCommandParser(".SENS", extractSENSData);
1347 }
1348 
1349 } // namespace Nonlinear
1350 } // namespace Xyce
static void populateMetadata(IO::PkgOptionsMgr &options_manager)
std::vector< double > paramOrigVals_
bool loadSensitivityResiduals(int difference, bool forceFD_, double sqrtEta_, std::string &netlistFilename_, TimeIntg::DataStore &ds, Loader::NonlinearEquationLoader &nonlinearEquationLoader_, const std::vector< std::string > &paramNameVec_, const Analysis::AnalysisManager &analysisManager_)
virtual int getMaxNormFindex() const =0
bool extractSENSData(IO::PkgOptionsMgr &options_manager, IO::CircuitBlock &circuit_block, const std::string &netlist_filename, const IO::TokenVector &parsed_line)
Pure virtual class to augment a linear system.
std::vector< double > dOdpVec_
std::vector< double > scaled_dOdpVec_
void allocateSensitivityArrays(Linear::Builder &builder, int numParams)
std::vector< Linear::Vector * > nextDXdpPtrVector
virtual double getMaxNormF() const =0
std::vector< double > scaled_dOdpAdjVec_
int solve(NonLinearSolver *nlsTmpPtr=NULL)
std::vector< Linear::Vector * > nextDbdpPtrVector
std::vector< Linear::Vector * > nextDfdpPtrVector
Linear::Vector * savedNewtonVectorPtr_
std::vector< double > objectiveVec_
std::vector< Linear::Vector * > currDXdpPtrVector
void stdOutput(std::string idString, std::vector< double > &paramVals, std::vector< double > &sensitivities, std::vector< double > &scaled_sensitivities)
const Analysis::AnalysisManager & getAnalysisManager() const
void fileOutput(std::string idString, std::vector< double > &paramVals, std::vector< double > &sensitivities, std::vector< double > &scaled_sensitivities)
Sensitivity(NonLinearSolver &nls_, Topo::Topology &top_, const IO::CmdParse &cp)
bool icSensitivity(std::vector< double > &objectiveVec, std::vector< double > &dOdpVec, std::vector< double > &dOdpAdjVec, std::vector< double > &scaled_dOdpVec, std::vector< double > &scaled_dOdpAdjVec)
bool setOptions(const Util::OptionBlock &OB)
bool setSensitivityOptions(const Util::OptionBlock &OB)
Loader::NonlinearEquationLoader * nonlinearEquationLoader_
std::vector< double > dOdpAdjVec_
virtual bool registerAnalysisManager(Analysis::AnalysisManager *tmp_anaIntPtr)
std::vector< Linear::Vector * > sensRHSPtrVector
std::vector< objectiveFunctionData * > objFuncDataVec_
Linear::Matrix * dQdxMatrixPtr
std::vector< Linear::Vector * > nextDQdxDXdpPtrVector
std::vector< std::string > paramNameVec_