Xyce  6.1
N_NLS_SensitivityResiduals.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_SensitivityResiduals.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.1 $
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>
59 #include <N_ERH_ErrorMgr.h>
60 
61 #include <N_LAS_Vector.h>
63 
64 #include <N_PDS_Comm.h>
65 #include <N_PDS_MPI.h>
66 #include <N_PDS_Manager.h>
67 #include <N_PDS_Serial.h>
68 
69 #include <N_TIA_DataStore.h>
70 
71 #include <N_UTL_Algorithm.h>
72 #include <N_UTL_Diagnostic.h>
73 #include <N_UTL_Expression.h>
74 #include <N_UTL_ExtendedString.h>
75 #include <N_UTL_FeatureTest.h>
76 #include <N_UTL_OptionBlock.h>
77 
78 // ---------- Static Declarations ----------
79 
80 namespace Xyce {
81 namespace Nonlinear {
82 
83 //-----------------------------------------------------------------------------
84 // Function : loadSensitivityResiduals
85 //
86 // Purpose : This function is to be called after a calculation has
87 // converged. It computes the sensitivies of different components
88 // of the residual. Recall the DAE form of the residual:
89 //
90 // F = dq/dt + f - b
91 //
92 // This function sets up the following derivatives:
93 //
94 // df/dp, dq/dp, db/dp where p is the parameter.
95 //
96 // Which can ultimately be assembled to give dF/dp:
97 //
98 // d(dq/dp)
99 // dF/dp = ------- + df/dp - db/dp
100 // dt
101 //
102 // Special Notes :
103 // Scope : public
104 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
105 // Creation Date : 7/15/02
106 //-----------------------------------------------------------------------------
108  int difference, bool forceFD_, double sqrtEta_, std::string & netlistFilename_,
109  TimeIntg::DataStore & ds,
110  Loader::NonlinearEquationLoader & nonlinearEquationLoader_,
111  const std::vector<std::string> & paramNameVec_,
113  )
114 {
115  int iparam;
116  std::string msg;
117 
118  std::vector<Linear::Vector *> & dfdpPtrVector_ = ds.nextDfdpPtrVector;
119  std::vector<Linear::Vector *> & dqdpPtrVector_ = ds.nextDqdpPtrVector;
120  std::vector<Linear::Vector *> & dbdpPtrVector_ = ds.nextDbdpPtrVector;
121 
122  ds.paramOrigVals_.clear();
123 
124  // it is necessary to load the Jacobian here to make sure we have the most
125  // up-to-date matrix. The Jacobian is not loaded for the final
126  // evaluation of the residual in the Newton solve.
127  nonlinearEquationLoader_.loadJacobian ();
128 
129  // Loop over the vector of parameters. For each parameter, find the
130  // device entity (a model or an instance) which corresponds to it, and
131  // perform the finite difference calculation.
132  std::vector<std::string>::const_iterator firstParam = paramNameVec_.begin ();
133  std::vector<std::string>::const_iterator lastParam = paramNameVec_.end ();
134  std::vector<std::string>::const_iterator iterParam;
135 
136  int maxParamStringSize_=0;
137  if (DEBUG_NONLINEAR && isActive(Diag::SENS_SOLVER))
138  {
139  for ( iterParam=firstParam, iparam=0;
140  iterParam!=lastParam; ++iterParam, ++iparam )
141  {
142  int sz = paramNameVec_[iparam].size();
143  if (sz > maxParamStringSize_)
144  {
145  maxParamStringSize_ = sz;
146  }
147  }
148  }
149 
150  for ( iterParam=firstParam, iparam=0;
151  iterParam!=lastParam; ++iterParam, ++iparam )
152  {
153  std::string paramName(*iterParam);
154 
155  // get the original value of this parameter, to be used for scaling and/or
156  // numerical derivatives later.
157  double paramOrig = 0.0;
158  bool found = nonlinearEquationLoader_.getParamAndReduce(
159  analysisManager_.getPDSManager()->getPDSComm()->comm(),paramName, paramOrig);
160 
161  if (!found)
162  {
163  std::string msg("Sensitivity::loadSensitivityResiduals: cannot find parameter ");
164  msg += paramName;
165  N_ERH_ErrorMgr::report (N_ERH_ErrorMgr::DEV_FATAL, msg);
166  }
167  ds.paramOrigVals_.push_back(paramOrig);
168 
169  // check if derivative is available analytically. If not, take FD.
170  bool analyticAvailable = false;
171  if (!forceFD_)
172  {
173  analyticAvailable = nonlinearEquationLoader_.analyticSensitivitiesAvailable (paramName);
174  }
175  if (analyticAvailable)
176  {
177  std::vector<double> dfdpVec;
178  std::vector<double> dqdpVec;
179  std::vector<double> dbdpVec;
180 
181  std::vector<int> FindicesVec;
182  std::vector<int> QindicesVec;
183  std::vector<int> BindicesVec;
184 
185  nonlinearEquationLoader_.getAnalyticSensitivities(paramName,
186  dfdpVec,dqdpVec,dbdpVec,
187  FindicesVec, QindicesVec, BindicesVec);
188 
189  dfdpPtrVector_[iparam]->putScalar(0.0);
190  dqdpPtrVector_[iparam]->putScalar(0.0);
191  dbdpPtrVector_[iparam]->putScalar(0.0);
192 
193  int Fsize=FindicesVec.size();
194  for (int i=0;i<Fsize;++i)
195  {
196  Linear::Vector & dfdpRef = *(dfdpPtrVector_[iparam]);
197  dfdpRef[FindicesVec[i]] += dfdpVec[i];
198  }
199 
200  int Qsize=QindicesVec.size();
201  for (int i=0;i<Qsize;++i)
202  {
203  Linear::Vector & dqdpRef = *(dqdpPtrVector_[iparam]);
204  dqdpRef[QindicesVec[i]] += dqdpVec[i];
205  }
206 
207  int Bsize=BindicesVec.size();
208  for (int i=0;i<Bsize;++i)
209  {
210  Linear::Vector & dbdpRef = *(dbdpPtrVector_[iparam]);
211  dbdpRef[BindicesVec[i]] += dbdpVec[i];
212  }
213 
214  dfdpPtrVector_[iparam]->fillComplete();
215  dqdpPtrVector_[iparam]->fillComplete();
216  dbdpPtrVector_[iparam]->fillComplete();
217 
218  if (DEBUG_NONLINEAR && isActive(Diag::SENS_SOLVER))
219  {
220  Xyce::dout() << *iterParam << ": ";
221  Xyce::dout().setf(std::ios::scientific);
222  Xyce::dout() << std::endl;
223 
224  int solutionSize_ = dfdpPtrVector_[iparam]->localLength();
225 
226  for (int k1 = 0; k1 < solutionSize_; ++k1)
227  {
228  Xyce::dout()
229  <<"dfdp["<<std::setw(3)<<k1<<"]= "<<std::setw(15)<<std::scientific<<std::setprecision(8)<<(*(dfdpPtrVector_[iparam]))[k1]
230  <<" dqdp["<<std::setw(3)<<k1<<"]= "<<std::setw(15)<<std::scientific<<std::setprecision(8)<<(*(dqdpPtrVector_[iparam]))[k1]
231  <<" dbdp["<<std::setw(3)<<k1<<"]= "<<std::setw(15)<<std::scientific<<std::setprecision(8)<<(*(dbdpPtrVector_[iparam]))[k1]
232  <<std::endl;
233  }
234  }
235  }
236  else
237  {
238  if (DEBUG_NONLINEAR && isActive(Diag::SENS_SOLVER))
239  {
240  Xyce::dout() << std::endl << " Calculating numerical df/dp, dq/dp and db/dp for: ";
241  Xyce::dout() << *iterParam << std::endl;
242  }
243 
244  // save a copy of the DAE vectors
245  Linear::Vector origFVector( *(ds.daeFVectorPtr) );
246  Linear::Vector origQVector( *(ds.daeQVectorPtr) );
247  Linear::Vector origBVector( *(ds.daeBVectorPtr) );
248 
249  // now perturb the value of this parameter.
250  double dp = sqrtEta_ * (1.0 + fabs(paramOrig));
251  double paramPerturbed = paramOrig;
252 
253  if (difference==SENS_FWD)
254  {
255  paramPerturbed += dp;
256  }
257  else if (difference==SENS_REV)
258  {
259  paramPerturbed -= dp;
260  }
261  else if (difference==SENS_CNT)
262  {
263  static std::string tmp = "difference=central not supported.\n";
264  N_ERH_ErrorMgr::report( N_ERH_ErrorMgr::USR_FATAL_0, tmp);
265  }
266  else
267  {
268  static std::string tmp = "difference not recognized!\n";
269  N_ERH_ErrorMgr::report( N_ERH_ErrorMgr::USR_FATAL_0, tmp);
270  }
271 
272  if (DEBUG_NONLINEAR && isActive(Diag::SENS_SOLVER))
273  {
274  Xyce::dout() << std::setw(maxParamStringSize_)<< *iterParam
275  << " dp = " << std::setw(11)<< std::scientific<< std::setprecision(4) << dp
276  << " original value = " << std::setw(16)<< std::scientific<< std::setprecision(9) << paramOrig
277  << " modified value = " << std::setw(16)<< std::scientific<< std::setprecision(9) << paramPerturbed
278  <<std::endl;
279  }
280 
281  nonlinearEquationLoader_.setParam (paramName, paramPerturbed);
282 
283  // Now that the parameter has been perturbed,
284  // calculate the numerical derivative.
285 
286  // Load F,Q and B.
287  nonlinearEquationLoader_.loadRHS();
288 
289  // save the perturbed DAE vectors
290  Linear::Vector pertFVector( *(ds.daeFVectorPtr) );
291  Linear::Vector pertQVector( *(ds.daeQVectorPtr) );
292  Linear::Vector pertBVector( *(ds.daeBVectorPtr) );
293 
294  // calculate the df/dp vector.
295  double rdp=1/dp;
296  dfdpPtrVector_[iparam]->putScalar(0.0);
297  dfdpPtrVector_[iparam]->addVec (+1.0, pertFVector); //+Fperturb
298  dfdpPtrVector_[iparam]->addVec (-1.0, origFVector); //-Forig
299  dfdpPtrVector_[iparam]->scale(rdp);
300 
301  // calculate the dq/dp vector.
302  dqdpPtrVector_[iparam]->putScalar(0.0);
303  dqdpPtrVector_[iparam]->addVec (+1.0, pertQVector); //+Fperturb
304  dqdpPtrVector_[iparam]->addVec (-1.0, origQVector); //-Forig
305  dqdpPtrVector_[iparam]->scale(rdp);
306 
307  // calculate the db/dp vector.
308  dbdpPtrVector_[iparam]->putScalar(0.0);
309  dbdpPtrVector_[iparam]->addVec (+1.0, pertBVector); //+Fperturb
310  dbdpPtrVector_[iparam]->addVec (-1.0, origBVector); //-Forig
311  dbdpPtrVector_[iparam]->scale(rdp);
312 
313  if (DEBUG_NONLINEAR && isActive(Diag::SENS_SOLVER))
314  {
315  Xyce::dout() << *iterParam << ": ";
316  Xyce::dout().width(15); Xyce::dout().precision(7); Xyce::dout().setf(std::ios::scientific);
317  Xyce::dout() << "deviceSens_dp = " << dp << std::endl;
318 
319  //int solutionSize_ = pertFVectorPtr_->localLength();
320  int solutionSize_ = pertFVector.localLength();
321 
322  for (int k1 = 0; k1 < solutionSize_; ++k1)
323  {
324 
325  Xyce::dout()
326  <<"fpert["<<std::setw(3)<<k1<<"]= "<<std::setw(15)<<std::scientific<<std::setprecision(8)<<(pertFVector)[k1]
327  <<" forig["<<std::setw(3)<<k1<<"]= "<<std::setw(15)<<std::scientific<<std::setprecision(8)<<(origFVector)[k1]
328  <<" dfdp ["<<std::setw(3)<<k1<<"]= "<<std::setw(15)<<std::scientific<<std::setprecision(8)<<(*(dfdpPtrVector_[iparam]))[k1]
329  <<std::endl;
330  }
331 
332  Xyce::dout() << std::endl;
333  for (int k1 = 0; k1 < solutionSize_; ++k1)
334  {
335  Xyce::dout()
336  <<"qpert["<<std::setw(3)<<k1<<"]= "<<std::setw(15)<<std::scientific<<std::setprecision(8)<<(pertQVector)[k1]
337  <<" qorig["<<std::setw(3)<<k1<<"]= "<<std::setw(15)<<std::scientific<<std::setprecision(8)<<(origQVector)[k1]
338  <<" dqdp ["<<std::setw(3)<<k1<<"]= "<<std::setw(15)<<std::scientific<<std::setprecision(8)<<(*(dqdpPtrVector_[iparam]))[k1]
339  <<std::endl;
340  }
341 
342  Xyce::dout() << std::endl ;
343  for (int k1 = 0; k1 < solutionSize_; ++k1)
344  {
345  Xyce::dout()
346  <<"bpert["<<std::setw(3)<<k1<<"]= "<<std::setw(15)<<std::scientific<<std::setprecision(8)<<(pertBVector)[k1]
347  <<" borig["<<std::setw(3)<<k1<<"]= "<<std::setw(15)<<std::scientific<<std::setprecision(8)<<(origBVector)[k1]
348  <<" dbdp ["<<std::setw(3)<<k1<<"]= "<<std::setw(15)<<std::scientific<<std::setprecision(8)<<(*(dbdpPtrVector_[iparam]))[k1]
349  <<std::endl;
350 
351  }
352 
353  std::ostringstream filename;
354  filename << netlistFilename_ << "_dfdp";
355  filename << std::setw(3) << std::setfill('0') << iparam;
356  filename << ".txt";
357  dfdpPtrVector_[iparam]->writeToFile(const_cast<char *>(filename.str().c_str()));
358 
359  filename.str("");
360  filename << netlistFilename_ << "_fpert";
361  filename << std::setw(3) << std::setfill('0') << iparam;
362  filename << ".txt";
363  pertFVector.writeToFile(const_cast<char *>(filename.str().c_str()));
364 
365  filename.str("");
366  filename << netlistFilename_ << "_dqdp";
367  filename << std::setw(3) << std::setfill('0') << iparam;
368  filename << ".txt";
369  dqdpPtrVector_[iparam]->writeToFile(const_cast<char *>(filename.str().c_str()));
370 
371  filename.str("");
372  filename << netlistFilename_ << "_qpert";
373  filename << std::setw(3) << std::setfill('0') << iparam;
374  filename << ".txt";
375  pertQVector.writeToFile(const_cast<char *>(filename.str().c_str()));
376 
377  filename.str("");
378  filename << netlistFilename_ << "_dbdp";
379  filename << std::setw(3) << std::setfill('0') << iparam;
380  filename << ".txt";
381  dbdpPtrVector_[iparam]->writeToFile(const_cast<char *>(filename.str().c_str()));
382 
383  filename.str("");
384  filename << netlistFilename_ << "_bpert";
385  filename << std::setw(3) << std::setfill('0') << iparam;
386  filename << ".txt";
387  pertBVector.writeToFile(const_cast<char *>(filename.str().c_str()));
388  }
389 
390  // now reset the parameter and rhs to previous values.
391  nonlinearEquationLoader_.setParam (paramName, paramOrig);
392 
393  ds.daeFVectorPtr->update(1.0, origFVector, 0.0);
394  ds.daeQVectorPtr->update(1.0, origQVector, 0.0);
395  ds.daeBVectorPtr->update(1.0, origBVector, 0.0);
396  }
397  }
398 
399  return true;
400 }
401 
402 } // namespace Nonlinear
403 } // namespace Xyce
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_)
std::vector< Linear::Vector * > nextDqdpPtrVector
Pure virtual class to augment a linear system.
std::vector< Linear::Vector * > nextDbdpPtrVector
bool getParamAndReduce(Parallel::Machine comm, const std::string &name, double &val) const
std::vector< Linear::Vector * > nextDfdpPtrVector
Parallel::Manager * getPDSManager() const
bool setParam(std::string &name, double val, bool overrideOriginal=false)
Linear::Vector * daeQVectorPtr
Linear::Vector * daeFVectorPtr
void getAnalyticSensitivities(std::string &name, std::vector< double > &dfdpVec, std::vector< double > &dqdpVec, std::vector< double > &dbdpVec, std::vector< int > &FindicesVec, std::vector< int > &QindicesVec, std::vector< int > &BindicesVec) const
AnalysisManager & analysisManager_
Definition: N_ANP_AC.C:960
Linear::Vector * daeBVectorPtr