Xyce  6.1
N_DEV_NumericalJacobian.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_DEV_NumericalJacobian.C,v $
27 //
28 // Purpose :
29 //
30 // Special Notes :
31 //
32 // Creator : Eric Keiter, SNL, Electrical and Microsystems Modeling
33 //
34 // Creation Date : 04/30/02
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.75 $
40 //
41 // Revision Date : $Date: 2015/09/30 14:47:01 $
42 //
43 // Current Owner : $Author: peshola $
44 //-------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 
48 // ---------- Standard Includes ----------
49 #include <string>
50 #include <iostream>
51 #include <cstdio>
52 #include <sstream>
53 
54 // ---------- Xyce Includes ----------
56 #include <N_DEV_MatrixLoadData.h>
57 #include <N_DEV_DeviceOptions.h>
58 #include <N_DEV_SolverState.h>
59 #include <N_DEV_ExternData.h>
60 #include <N_DEV_DeviceInstance.h>
61 #include <N_DEV_DeviceMgr.h>
62 
63 #include <N_ERH_ErrorMgr.h>
64 
65 #include <N_LAS_Vector.h>
66 #include <N_LAS_Matrix.h>
67 #include <N_UTL_FeatureTest.h>
68 #include <N_UTL_ExtendedString.h>
69 
70 // ---------- Static Initializations ----------
71 
72 
73 namespace Xyce {
74 namespace Device {
75 
76 //-----------------------------------------------------------------------------
77 // Function : NumericalJacobian::NumericalJacobian
78 // Purpose : block constructor
79 // Special Notes :
80 // Scope : public
81 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
82 // Creation Date : 4/30/02
83 //-----------------------------------------------------------------------------
85  MatrixLoadData & mlData1,
86  const SolverState &ss1,
87  const ExternData &ed1,
88  const DeviceOptions & do1)
89  : mlData(mlData1),
90  cols(mlData1.cols),
91  vals(mlData1.vals),
92  Qvals(mlData1.Qvals),
93  val_local(mlData1.val_local),
94  Qval_local(mlData1.Qval_local),
95  col_local(mlData1.col_local),
96  row_local(mlData1.row_local),
97  internalFlag(mlData1.internalFlag),
98  solState (ss1),
99  extData (ed1),
100  devOptions(do1),
101  maxCols(10) // guess
102 {}
103 
104 //-----------------------------------------------------------------------------
105 // Function : NumericalJacobian::NumericalJacobian
106 // Purpose : copy constructor
107 // Special Notes :
108 // Scope : public
109 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
110 // Creation Date : 4/30/02
111 //-----------------------------------------------------------------------------
113  : mlData(right.mlData),
114  cols(right.cols),
115  vals(right.vals),
116  Qvals(right.Qvals),
117  val_local(right.val_local),
118  Qval_local(right.Qval_local),
119  col_local(right.col_local),
120  row_local(right.row_local),
121  internalFlag(right.internalFlag),
122  solState (right.solState),
123  extData (right.extData),
124  devOptions(right.devOptions),
125  maxCols(right.maxCols)
126 {
127 
128 }
129 
130 //-----------------------------------------------------------------------------
131 // Function : NumericalJacobian::~NumericalJacobian
132 // Purpose : destructor
133 // Special Notes :
134 // Scope : public
135 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
136 // Creation Date : 3/30/00
137 //-----------------------------------------------------------------------------
139 {
140 
141 }
142 
143 //-----------------------------------------------------------------------------
144 // Function : NumericalJacobian::testDAEMatrices
145 //
146 // Purpose : Performs a numerical jacobian test on the dFdx and dQdx
147 // matrices.
148 //
149 // Special Notes : This is the main numerical jacoabian test. There is
150 // another numerical jacobian test, which pre-dates this
151 // one, but is not recommended. The older one is handled
152 // by the functions preceding this one in this file.
153 //
154 // The old one attempt to run the code using a purely
155 // numerical jacobian. It does not work with votlage limiting.
156 //
157 // The new one (controlled from this function) operates along
158 // side the analytic jacobian, but does not replace it, as
159 // the solvers will still use the analytic jacobian. This
160 // function will test, on a device-by-device basis, the device
161 // contributions to the analytic jaocian. That way,
162 // it is possible to test a single device (rather than the whole
163 // problem), and test it at a precise point during the simulation.
164 //
165 // Scope : public
166 // Creator : Eric Keiter, SNL, Electrical and Microsystems Modeling
167 // Creation Date : 12/15/06
168 //-----------------------------------------------------------------------------
169 bool NumericalJacobian::testDAEMatrices(DeviceInstance & instance, const std::vector<const std::string *> & nameVec)
170 {
171 
172  // Set up various references to indexing arrays
173  const std::vector<int> & devLIDs = instance.getDevLIDs();
174  const std::vector<int> & devStateLIDs = instance.getStaLIDVec();
175  const std::vector< std::vector<int> > & devJacLIDs = instance.getDevJacLIDs();
176  const std::vector< std::vector<int> > & jacStamp = instance.jacobianStamp();
177 
178 
179  // Set up references to temporary data structures.
180  std::vector< std::vector<double> > & numJacF = mlData.numJac;
181  std::vector< std::vector<double> > & saveJacF = mlData.saveJac;
182  std::vector< std::vector<double> > & devJacF = mlData.devJac;
183  std::vector< std::vector<double> > & diffJacF = mlData.diffJac;
184  std::vector< std::vector<double> > & relJacF = mlData.relJac;
185 
186  std::vector< std::vector<double> > & numJacQ = mlData.numJacQ;
187  std::vector< std::vector<double> > & saveJacQ = mlData.saveJacQ;
188  std::vector< std::vector<double> > & devJacQ = mlData.devJacQ;
189  std::vector< std::vector<double> > & diffJacQ = mlData.diffJacQ;
190  std::vector< std::vector<double> > & relJacQ = mlData.relJacQ;
191 
192  std::vector< std::vector<int> > & statusF = mlData.status;
193  std::vector< std::vector<int> > & statusQ = mlData.statusQ;
194  std::vector< std::vector<int> > & stencil = mlData.stencil;
195 
196  std::vector<double> & saveF = mlData.saveRHS;
197  std::vector<double> & pertF = mlData.pertRHS;
198  std::vector<double> & origF = mlData.origRHS;
199  std::vector<double> & saveQ = mlData.saveQ;
200  std::vector<double> & pertQ = mlData.pertQ;
201  std::vector<double> & origQ = mlData.origQ;
202 
203  std::vector<double> & saveSoln = mlData.saveSoln;
204  std::vector<double> & pertSoln = mlData.pertSoln;
205  std::vector<double> & saveCurrSoln = mlData.saveCurrSoln;
206 
207  std::vector<double> & saveLastState = mlData.saveLastState;
208  std::vector<double> & saveCurrState = mlData.saveCurrState;
209  std::vector<double> & saveNextState = mlData.saveNextState;
210  std::vector<double> & saveStateDerivs = mlData.saveStateDerivs;
211 
212  // set up references to epetra objects.
213  Linear::Vector & Fvec = (*extData.daeFVectorPtr);
214  Linear::Vector & Qvec = (*extData.daeQVectorPtr);
215 
216  Linear::Vector & currSol = (*extData.currSolVectorPtr);
217  Linear::Vector & nextSol = (*extData.nextSolVectorPtr);
218 
219  Linear::Vector & lastSta = (*extData.lastStaVectorPtr);
220  Linear::Vector & currSta = (*extData.currStaVectorPtr);
221  Linear::Vector & nextSta = (*extData.nextStaVectorPtr);
222  Linear::Vector & nextStaDeriv = (*extData.nextStaDerivVectorPtr);
223 
224  Linear::Matrix & dQdxMat = (*extData.dQdxMatrixPtr);
225  Linear::Matrix & dFdxMat = (*extData.dFdxMatrixPtr);
226 
227  int numRows, numCols;
228  numCols = devLIDs.size();
229  numRows = jacStamp.size();
230 
231  int testSize= (numRows>numCols)?numRows:numCols;
232  if (testSize > saveF.size())
233  {
234  mlData.resizeTestJacSolData(testSize);
235  mlData.resizeTestJacQData(testSize);
236  }
237 
238  int numState = devStateLIDs.size();
239  if (numState > saveCurrState.size())
240  {
241  mlData.resizeTestJacStateData(numState);
242  }
243 
244  int i, j, jCol;
245 
246  if(devJacLIDs.empty())
247  {
248  if (DEBUG_DEVICE)
249  {
250  Report::UserWarning() << instance.getName() << " does not have jacLIDs available";
251  }
252 
253  return true;
254  }
255 
256  if (instance.getOrigFlag() && numRows > 0 && numRows == jacStamp.size())
257  {
258 
259  // Zero out all the mlData structures
260  saveF.assign(saveF.size(),0.0);
261  pertF.assign(pertF.size(),0.0);
262  origF.assign(origF.size(),0.0);
263 
264  saveQ.assign(saveQ.size(),0.0);
265  pertQ.assign(pertQ.size(),0.0);
266  origQ.assign(origQ.size(),0.0);
267 
268  saveSoln.assign(saveSoln.size(),0.0);
269  pertSoln.assign(pertSoln.size(),0.0);
270  saveCurrSoln.assign(saveCurrSoln.size(),0.0);
271 
272  saveLastState.assign(saveLastState.size(),0.0);
273  saveCurrState.assign(saveCurrState.size(),0.0);
274  saveNextState.assign(saveNextState.size(),0.0);
275  saveStateDerivs.assign(saveStateDerivs.size(),0.0);
276  for (i=0;i<numJacF.size();++i)
277  {
278  numJacF[i].assign(numJacF[i].size(),0.0);
279  saveJacF[i].assign(saveJacF[i].size(),0.0);
280  devJacF[i].assign(devJacF[i].size(),0.0);
281  diffJacF[i].assign(diffJacF[i].size(),0.0);
282  statusF[i].assign(statusF[i].size(),-1);
283  stencil[i].assign(stencil[i].size(),0);
284 
285  numJacQ[i].assign(numJacQ[i].size(),0.0);
286  saveJacQ[i].assign(saveJacQ[i].size(),0.0);
287  devJacQ[i].assign(devJacQ[i].size(),0.0);
288  diffJacQ[i].assign(diffJacQ[i].size(),0.0);
289  statusQ[i].assign(statusQ[i].size(),-1);
290  }
291 
292  // Save Soln, RHS, and State for this device
293  bool origFlag = instance.getOrigFlag();
294  //for (i=0 ; i<numRows ; ++i)
295  int tmpSize= (numRows>numCols)?numRows:numCols;
296  double sqrtEta=devOptions.testJac_SqrtEta;
297  for (i=0 ; i<tmpSize; ++i)
298  {
299  saveF[i] = Fvec[devLIDs[i]];
300  saveQ[i] = Qvec[devLIDs[i]];
301 
302  saveSoln[i] = nextSol[devLIDs[i]];
303  saveCurrSoln[i] = currSol[devLIDs[i]];
304  pertSoln[i] = sqrtEta * (1.0 + fabs(saveSoln[i]));
305  }
306 
307  for (i=0 ; i<numState ; ++i)
308  {
309  saveLastState[i] = lastSta[devStateLIDs[i]];
310  saveCurrState[i] = currSta[devStateLIDs[i]];
311  saveNextState[i] = nextSta[devStateLIDs[i]];
312  saveStateDerivs[i] = nextStaDeriv[devStateLIDs[i]];
313  }
314 
315  // Save the original matrix for later:
316  for (i=0 ; i<numRows ; ++i)
317  {
318  jCol = devJacLIDs[i].size();
319  for (j=0 ; j<jCol ; ++j)
320  {
321  double valF = dFdxMat[devLIDs[i]][devJacLIDs[i][j]];
322  saveJacF[i][j] = valF;
323  double valQ = dQdxMat[devLIDs[i]][devJacLIDs[i][j]];
324  saveJacQ[i][j] = valQ;
325  }
326  }
327 
328  // Zeroing needs to be done after all saved values are
329  // recorded because there can be multiple references
330  // to the same element
331  for (i=0 ; i<numRows ; ++i)
332  {
333  jCol = devJacLIDs[i].size();
334  for (j=0 ; j<jCol ; ++j)
335  {
336  dFdxMat[devLIDs[i]][devJacLIDs[i][j]] = 0;
337  dQdxMat[devLIDs[i]][devJacLIDs[i][j]] = 0;
338  }
339  }
340 
341  // Now that the original load has been zeroed out, re-load the
342  // analytic contributions, to get the contributions from *just* this
343  // device.
344  instance.loadDAEdQdx ();
345  instance.loadDAEdFdx ();
346 
347  for (i=0 ; i<numRows ; ++i)
348  {
349  devJacF[i].assign(devJacF[i].size(),0.0);
350  devJacQ[i].assign(devJacQ[i].size(),0.0);
351  stencil[i].assign(stencil[i].size(),0);
352 
353  jCol = devJacLIDs[i].size();
354  for (j=0 ; j<jCol ; ++j)
355  {
356  double valF = dFdxMat[devLIDs[i]][devJacLIDs[i][j]];
357  devJacF[i][jacStamp[i][j]] = valF;
358  double valQ = dQdxMat[devLIDs[i]][devJacLIDs[i][j]];
359  devJacQ[i][jacStamp[i][j]] = valQ;
360  stencil[i][jacStamp[i][j]] = 1;
361  }
362  }
363 
364  // zero out the RHS, and re-load, so that we have only the
365  // elements from one device present.
366  for (i=0 ; i<numRows ; ++i)
367  {
368  Fvec[devLIDs[i]] = 0.0;
369  Qvec[devLIDs[i]] = 0.0;
370  }
371  // re-load for just this instance:
372  loadLocalDAEVectors (instance);
373 
374  // Save RHS for just this instance:
375  for (i=0 ; i<numRows ; ++i)
376  {
377  origF[i] = Fvec[devLIDs[i]];
378  origQ[i] = Qvec[devLIDs[i]];
379  }
380 
381  for (i=0 ; i<numRows ; ++i)
382  {
383  jCol = devJacLIDs[i].size();
384  for (j=0 ; j<jCol ; ++j)
385  {
386  statusF[i][jacStamp[i][j]] = -1;
387  statusQ[i][jacStamp[i][j]] = -1;
388  }
389  }
390 
391  // This test, of the merged numRows/numCols, should only be needed 1 time.
392  // Leaving this off by default for now. For reasons, see the header
393  // for the mergeTest function.
394  if (false)
395  {
396  mergeTest(instance);
397  }
398 
399  // These are the tolerances for determining jacobian agreement
400  // relT: similar to reltol, fractional error that is allowed
401  // absT: similar to abstol, error that is allowed for small derivatives
402  double relTol=devOptions.testJac_relTol;
403  double absTol=devOptions.testJac_absTol;
404 
405  double ndFdx, adFdx, ddFdx, relError_dFdx;
406  double ndQdx, adQdx, ddQdx, relError_dQdx;
407 
408  bool failedTest = false;
409  for (i=0 ; i<numCols ; ++i)
410  {
411  // Don't bother perturbing gnd.
412  if (*nameVec[devLIDs[i]] == "gnd") continue;
413 
414  for (j=0 ; j<numRows ; ++j)
415  {
416  nextSol[devLIDs[j]] = saveSoln[j];
417  currSol[devLIDs[j]] = saveCurrSoln[j];
418  Fvec[devLIDs[j]] = 0.0;
419  Qvec[devLIDs[j]] = 0.0;
420  }
421 
422  for (j=0 ; j<numState ; ++j)
423  {
424  lastSta[devStateLIDs[j]] = saveLastState[j];
425  currSta[devStateLIDs[j]] = saveCurrState[j];
426  nextSta[devStateLIDs[j]] = saveNextState[j];
427  nextStaDeriv[devStateLIDs[j]] = saveStateDerivs[j];
428  }
429 
430  // Perturb the solution.
431  double dX = pertSoln[i];
432  nextSol[devLIDs[i]] += dX;
433 
434  // Re-load the F,Q vectors:
435  loadLocalDAEVectors (instance);
436 
437  for (j=0 ; j<numRows ; ++j)
438  {
439  pertF[j] = Fvec[devLIDs[j]];
440  pertQ[j] = Qvec[devLIDs[j]];
441  }
442 
443 #ifdef Xyce_DEBUG_TESTJAC
444  testDebugHead (instance, nameVec, i, dX);
445 #endif
446 
447  for (j=0 ; j<numRows ; ++j)
448  {
449  // Don't bother with the gnd row.
450  if (*nameVec[devLIDs[j]] == "gnd") continue;
451 
452  // if this derivative is not loaded analytically, don't bother
453  // with it.
454  if (stencil[j][i]!=1) continue;
455 
456  double dF = (pertF[j]-origF[j]);
457  double dQ = (pertQ[j]-origQ[j]);
458  numJacF[j][i] = dF/dX;
459  numJacQ[j][i] = dQ/dX;
460 
461  ndFdx = numJacF[j][i];
462  adFdx = devJacF[j][i];
463  ddFdx = fabs(adFdx-ndFdx);
464  relError_dFdx = ddFdx/(relTol*fabs(ndFdx)+absTol);
465 
466  diffJacF[j][i] = ddFdx;
467  relJacF[j][i] = relError_dFdx;
468 
469  ndQdx = numJacQ[j][i];
470  adQdx = devJacQ[j][i];
471  ddQdx = fabs(adQdx-ndQdx);
472  relError_dQdx = ddQdx/(relTol*fabs(ndQdx)+absTol);
473 
474  diffJacQ[j][i] = ddQdx;
475  relJacQ[j][i] = relError_dQdx;
476 
477 #ifdef Xyce_DEBUG_TESTJAC
478  if (isnan(numJacF[j][i]))
479  {
480  testDebugOut (instance, nameVec, i, j);
481  }
482 #endif
483  // if the device is a Inductor, and IC= has been specified,
484  // then skip this term as it is a special case.
485  ExtendedString varNameI(*nameVec[devLIDs[i]]); varNameI.toUpper();
486  ExtendedString varNameJ(*nameVec[devLIDs[j]]); varNameJ.toUpper();
487  if ( ((solState.dcopFlag) && varNameI[0]=='L' && varNameJ[0]=='L') )
488  {
489  // For the inductor branch current, the matrix element will be
490  // there whether IC= was specified or not.
491  if (adFdx == 1 && ndFdx == 0)
492  {
493  statusF[j][i] = 3;
494  statusQ[j][i] = 3;
495  }
496  }
497  // if the device is a capacitor, and it has a branch current,
498  // that means that IC= has been used, thus it is a "special case"
499  // that should be skipped. The branch current will only be there
500  // for IC=.
501  else if((!(solState.dcopFlag) && varNameI[0]=='C') && varNameJ[0]=='C')
502  {
503  statusF[j][i] = 3;
504  statusQ[j][i] = 3;
505  }
506 
507  if ( statusF[j][i] != 3 )
508  {
509  if (relError_dFdx > 1.0) // failure
510  {
511  statusF[j][i] = -2;
512  failedTest = true;
513  }
514  else // success
515  {
516  statusF[j][i] = 1;
517  }
518 
519  if (relError_dQdx > 1.0) // failure
520  {
521  statusQ[j][i] = -2;
522  failedTest = true;
523  }
524  else // success
525  {
526  statusQ[j][i] = 1;
527  }
528  }
529  }
530 
531 #ifdef Xyce_DEBUG_TESTJAC
532  testDebugTail (instance, nameVec);
533 #endif
534  }
535 
536  // Output Jacobians Differences. If debug enabled, always output. otherwise only output for failures.
537  if (DEBUG_DEVICE)
538  printJacobian_(dout(), instance, nameVec, failedTest);
539  else if (failedTest)
540  printJacobian_(lout(), instance, nameVec, failedTest);
541 
542  // Restore jacobian, RHS for this device
543  instance.setOrigFlag(origFlag);
544  tmpSize= (numRows>numCols)?numRows:numCols;
545  for (i=0 ; i<tmpSize; ++i)
546  {
547  Fvec[devLIDs[i]] = saveF[i];
548  Qvec[devLIDs[i]] = saveQ[i];
549  nextSol[devLIDs[i]] = saveSoln[i];
550  currSol[devLIDs[i]] = saveCurrSoln[i];
551  }
552  for (i=0 ; i<numState ; ++i)
553  {
554  lastSta[devStateLIDs[i]] = saveLastState[i];
555  currSta[devStateLIDs[i]] = saveCurrState[i];
556  nextSta[devStateLIDs[i]] = saveNextState[i];
557  nextStaDeriv[devStateLIDs[i]] = saveStateDerivs[i];
558  }
559 
560 
561  for (i=0 ; i<numRows ; ++i)
562  {
563  jCol = devJacLIDs[i].size();
564  for (j=0 ; j<jCol ; ++j)
565  {
566  dFdxMat[devLIDs[i]][devJacLIDs[i][j]] = saveJacF[i][j];
567  dQdxMat[devLIDs[i]][devJacLIDs[i][j]] = saveJacQ[i][j];
568  }
569  }
570  }
571 
572  return true;
573 }
574 
575 //-----------------------------------------------------------------------------
576 // Function : NumericalJacobian::loadLocalDAEVectors
577 // Purpose :
578 // Special Notes : Note this function ignores the B-vector.
579 // Scope : public
580 // Creator : Eric Keiter, SNL, Electrical and Microsystems Modeling
581 // Creation Date : 12/15/06
582 //-----------------------------------------------------------------------------
584 {
585  Linear::Vector & currSta = (*extData.currStaVectorPtr);
586  Linear::Vector & nextSta = (*extData.nextStaVectorPtr);
587  Linear::Vector & nextStaDeriv = (*extData.nextStaDerivVectorPtr);
588  Linear::Vector & nextSol = (*extData.nextSolVectorPtr);
589 
590  const std::vector<int> & devStateLIDs = instance.getStaLIDVec();
591  int numState = devStateLIDs.size();
592 
593  instance.updateDependentParameters(nextSol); // this line necessary for expressions
594  instance.updatePrimaryState ();
595 
596  // Assume backward euler integration, so that the time integrator
597  // accessors are not needed.
598  //anaIntPtr_->updateDivDiffs(devLIDs, devStateLIDs);
599  //anaIntPtr_->updateDerivs(devLIDs, devStateLIDs);
600  for (int j=0 ; j<numState ; ++j)
601  {
602  nextStaDeriv[devStateLIDs[j]] =
603  solState.pdt_ * (nextSta[devStateLIDs[j]]-currSta[devStateLIDs[j]]);
604  }
605 
606  instance.updateSecondaryState ();
607  instance.loadDAEQVector ();
608  instance.loadDAEFVector ();
609 
610  return;
611 }
612 
613 //-----------------------------------------------------------------------------
614 // Function : NumericalJacobian::printJacobian_
615 // Purpose :
616 // Special Notes :
617 // Scope : public
618 // Creator : Eric Keiter, SNL, Electrical and Microsystems Modeling
619 // Creation Date : 12/12/06
620 //-----------------------------------------------------------------------------
622  std::ostream & os,
623  const DeviceInstance & instance,
624  const std::vector<const std::string *> & nameVec,
625  bool failed)
626 {
627  bool NAflag = false;
628  const std::vector<int> & devLIDs = instance.getDevLIDs();
629 
630  // These curly brackets are for scoping only.
631  {
632  const std::vector< std::vector<double> > & numJac = mlData.numJac;
633  const std::vector< std::vector<double> > & anaJac = mlData.devJac;
634  const std::vector< std::vector<double> > & diffJac = mlData.diffJac;
635  const std::vector< std::vector<double> > & relJac = mlData.relJac;
636  const std::vector< std::vector<int> > & stencil = mlData.stencil;
637  const std::vector< std::vector<int> > & status = mlData.status;
638 
639 
640  os << Xyce::section_divider << std::endl;
641  os << "dFdx matrix for " << instance.getName();
642 
643  if (failed)
644  {
645  os << ": JACOBIAN TEST FAILURE";
646  }
647  else
648  {
649  os << ": JACOBIAN TEST SUCCESS";
650  }
651  os << " at time = " << solState.currTime_;
652  os << " at Niter = " << solState.newtonIter;
653  os << std::endl;
654  os << " Numerical Analytic absDiff relative Error Status Names (row, col)"<<std::endl;
655 
656  int i,j;
657  int numCols = devLIDs.size();
658  int numRows = (status.size()<numCols)?status.size():numCols;
659 
660  for (i = 0; i < numRows; ++i)
661  {
662  if (*nameVec[devLIDs[i]] == "gnd") continue;
663 
664  for (j = 0; j < numCols; ++j)
665  {
666  if (*nameVec[devLIDs[j]] == "gnd") continue;
667 
668  // if this variable has not been tested for any reason, skip.
669  if (status[i][j]==-1) continue;
670 
671  // if this derivative is not loaded analytically, skip.
672  if (stencil[i][j]!=1) continue;
673 
674  // Note: JT=jacobian test is there to make this easy to grep.
675  static char tmpChar[128];
676  static char prefix[4];
677 
678  sprintf(prefix,"%s","FT:");
679 
680  if (status[i][j]==-2)
681  {
682  sprintf(tmpChar,"%s %12.4e %12.4e %12.4e %12.4e fail",prefix,
683  numJac[i][j], anaJac[i][j], diffJac[i][j], relJac[i][j]);
684  }
685  else if (status[i][j]==3)
686  {
687  NAflag = true;
688  sprintf(tmpChar,"%s %12.4e %12.4e %12.4e %12.4e NA ",prefix,
689  numJac[i][j], anaJac[i][j], diffJac[i][j], relJac[i][j]);
690  }
691  else
692  {
693  sprintf(tmpChar,"%s %12.4e %12.4e %12.4e %12.4e ",prefix,
694  numJac[i][j], anaJac[i][j], diffJac[i][j], relJac[i][j]);
695  }
696 
697  os << std::string(tmpChar);
698 
699  os << " ("<< *nameVec[devLIDs[i]]
700  << ", " << *nameVec[devLIDs[j]]
701  << ") "
702  << " row,col=[ " << i << ", " << j << "]" << std::endl;
703 
704 
705  }
706  }
707  }
708 
709  const std::vector< std::vector<double> > & numJac = mlData.numJacQ;
710  const std::vector< std::vector<double> > & anaJac = mlData.devJacQ;
711  const std::vector< std::vector<double> > & diffJac = mlData.diffJacQ;
712  const std::vector< std::vector<double> > & relJac = mlData.relJacQ;
713  const std::vector< std::vector<int> > & stencil = mlData.stencil;
714  const std::vector< std::vector<int> > & status = mlData.statusQ;
715 
716  os << "dQdx matrix for " << instance.getName();
717 
718  if (failed)
719  {
720  os << ": JACOBIAN TEST FAILURE";
721  }
722  else
723  {
724  os << ": JACOBIAN TEST SUCCESS";
725  }
726  os << " at time = " << solState.currTime_;
727  os << std::endl;
728  os << " Numerical Analytic absDiff relative Error Status Names (row, col)"<<std::endl;
729 
730  int i,j;
731  int numCols = devLIDs.size();
732  int numRows = (status.size()<numCols)?status.size():numCols;
733 
734  for (i = 0; i < numRows; ++i)
735  {
736  if (*nameVec[devLIDs[i]] == "gnd") continue;
737 
738  for (j = 0; j < numCols; ++j)
739  {
740  if (*nameVec[devLIDs[j]] == "gnd") continue;
741 
742  // if this variable has not been tested for any reason, skip.
743  if (status[i][j]==-1) continue;
744 
745  // if this derivative is not loaded analytically, skip.
746  if (stencil[i][j]!=1) continue;
747 
748  // Note: QT=jacobian test is there to make this easy to grep.
749  static char tmpChar[128];
750  if (status[i][j]==-2)
751  {
752  sprintf(tmpChar,"QT: %12.4e %12.4e %12.4e %12.4e fail",
753  numJac[i][j], anaJac[i][j], diffJac[i][j], relJac[i][j]);
754  }
755  else if (status[i][j]==3)
756  {
757  NAflag = true;
758  sprintf(tmpChar,"QT: %12.4e %12.4e %12.4e %12.4e NA ",
759  numJac[i][j], anaJac[i][j], diffJac[i][j], relJac[i][j]);
760  }
761  else
762  {
763  sprintf(tmpChar,"QT: %12.4e %12.4e %12.4e %12.4e ",
764  numJac[i][j], anaJac[i][j], diffJac[i][j], relJac[i][j]);
765  }
766 
767  os << std::string(tmpChar);
768 
769  os << " ("<< *nameVec[devLIDs[i]]
770  << ", " << *nameVec[devLIDs[j]]
771  << ") "
772  << " row,col=[ " << i << ", " << j << "]" << std::endl;
773 
774  }
775  }
776 
777  if(NAflag)
778  os << " Note: NA = untestable special case, such as IC=, etc." << std::endl;
779  os << Xyce::section_divider << std::endl;
780 
781  if (failed)
782  {
783  if (!(devOptions.testJacWarn))
784  {
785  Report::UserError() << "Numerical Jacobian test failure" << std::endl
786  << "If you want this failure to be a warning, rather than an error, "
787  << "then add .options device testjacwarn=1 to the netlist.";
788  }
789  else
790  {
791  Report::UserWarning() << "Numerical Jacobian test failure";
792  }
793  }
794 }
795 
796 //-----------------------------------------------------------------------------
797 // Function : NumericalJacobian::mergeTest
798 //
799 // Purpose : ERK: This function tests merged rows and cols, to make sure
800 // that they are actually equivalent. This is adapted from
801 // a version of this diagnostic by Dave Shirley.
802 //
803 // Another purpose of this test is to avoid testing the same
804 // element (numerical vs. analytic) more than once. I've
805 // chosen to use a different simpler approach for this, using
806 // a matrix stencil. The nice thing about stencils is that
807 // they don't require very many if-statements.
808 //
809 // With the stencil implemented, the only purpose for this test
810 // is essentially to test that the merged rows and cols are
811 // in fact correctly merged. I think that is a low-probability
812 // bug, so for now I'm not calling this test function, in
813 // the interests of speed.
814 //
815 // Finally, I'm leaving this test out, because it relies on
816 // "==" style comparisons of floating point numbers, which can
817 // be dangerous and easy to break.
818 //
819 // However, for historical reasons I'm leaving it in the code.
820 //
821 // Special Notes :
822 // Scope : public
823 // Creator : Eric Keiter, SNL, Electrical and Microsystems Modeling
824 // Creation Date : 12/14/06
825 //-----------------------------------------------------------------------------
827 {
828  int i,j,k;
829  const std::vector<int> & devLIDs = instance.getDevLIDs();
830  const std::vector< std::vector<double> > & devJac = mlData.devJac;
831  std::vector< std::vector<int> > & status = mlData.status;
832  int numRows, numCols;
833  numRows = devLIDs.size();
834  numCols = numRows;
835 
836  // insure that for any instance this is only checked once.
837  if (!(instance.getMergeRowColChecked()))
838  {
839  for (i=1 ; i<numRows ; ++i)
840  {
841  for (j=0 ; j<i ; ++j)
842  {
843  if (devLIDs[i] == devLIDs[j])
844  {
845  for (k=0 ; k<numCols ; ++k)
846  {
847  if (devJac[i][k] != devJac[j][k])
848  {
849  Report::UserWarning() << "In device " << instance.getName() << " different non-zero values in row merge";
850  }
851  status[i][k] = 2;
852  }
853  for (k=0 ; k<numRows ; ++k)
854  {
855  if (devJac[k][i] != devJac[k][j])
856  {
857  Report::UserWarning() << "In device " << instance.getName() << " different non-zero values in column merge";
858  }
859  status[k][i] = 2;
860  }
861  }
862  }
863  }
864  instance.setMergeRowColChecked(true);
865  }
866 
867 }
868 
869 //-----------------------------------------------------------------------------
870 // Function : NumericalJacobian::testDebugHead
871 // Purpose :
872 // Special Notes :
873 // Scope : public
874 // Creator : Eric Keiter, SNL, Electrical and Microsystems Modeling
875 // Creation Date : 12/14/06
876 //-----------------------------------------------------------------------------
877 void NumericalJacobian::testDebugHead( DeviceInstance & instance, const std::vector<const std::string *> & nameVec, int i, double dX)
878 {
879  const std::vector<int> & devLIDs = instance.getDevLIDs();
880 
881  Xyce::dout() << Xyce::section_divider<<std::endl;
882  Xyce::dout() << "Perturbing (LID="<<devLIDs[i]<<") " << *nameVec[devLIDs[i]] << " by " << dX << std::endl;
883 }
884 
885 //-----------------------------------------------------------------------------
886 // Function : NumericalJacobian::testDebugOut
887 // Purpose :
888 // Special Notes :
889 // Scope : public
890 // Creator : Eric Keiter, SNL, Electrical and Microsystems Modeling
891 // Creation Date : 12/14/06
892 //-----------------------------------------------------------------------------
893 void NumericalJacobian::testDebugOut( DeviceInstance & instance, const std::vector<const std::string *> & nameVec, int i, int j)
894 {
895  const std::vector<int> & devLIDs = instance.getDevLIDs();
896  const std::vector<double> & pertRHS = mlData.pertRHS;
897  const std::vector<double> & origRHS = mlData.origRHS;
898 
899  const std::vector< std::vector<double> > & numJac = mlData.numJac;
900  const std::vector< std::vector<double> > & relJac = mlData.relJac;
901 
902  Xyce::dout().width(15); Xyce::dout().precision(7); Xyce::dout().setf(std::ios::scientific);
903  Xyce::dout() << "dFdX: ";
904  Xyce::dout() << " (" << devLIDs[j] << ", " << devLIDs[i] << ") ";
905  Xyce::dout() << numJac[j][i];
906  Xyce::dout() << " Forig = " << origRHS[j];
907  Xyce::dout() << " Fperturb = " << pertRHS[j];
908  double dF = -(pertRHS[j]-origRHS[j]);
909  Xyce::dout() << " dF = " << dF;
910  Xyce::dout() << " (" << *nameVec[devLIDs[j]] << ", " << *nameVec[devLIDs[i]] << ") ";
911  Xyce::dout() << std::endl;
912  Xyce::dout() << " relative error = " << relJac[j][i] << std::endl;
913 }
914 
915 //-----------------------------------------------------------------------------
916 // Function : NumericalJacobian::testDebugTail
917 // Purpose :
918 // Special Notes :
919 // Scope : public
920 // Creator : Eric Keiter, SNL, Electrical and Microsystems Modeling
921 // Creation Date : 12/14/06
922 //-----------------------------------------------------------------------------
923 void NumericalJacobian::testDebugTail( DeviceInstance & instance, const std::vector<const std::string *> & nameVec)
924 {
925  Xyce::dout() << Xyce::section_divider<<std::endl;
926 }
927 
928 } // namespace Device
929 } // namespace Xyce
const InstanceName & getName() const
Linear::Vector * lastStaVectorPtr
double testJac_absTol
abstol for num. jacobian diagnostic.
std::vector< double > saveStateDerivs
double pdt_
Previous delta time alpha/dt (Many devices)
Linear::Vector * currSolVectorPtr
Linear::Vector * nextSolVectorPtr
const std::vector< IdVector > & getDevJacLIDs() const
Linear::Vector * daeQVectorPtr
Pure virtual class to augment a linear system.
virtual bool loadDAEFVector()=0
std::vector< double > saveLastState
std::vector< std::vector< double > > numJac
std::vector< std::vector< double > > devJac
virtual bool loadDAEQVector()=0
void testDebugOut(DeviceInstance &instance, const std::vector< const std::string * > &nameVec, int i, int j)
virtual bool loadDAEdFdx()=0
double testJac_relTol
reltol for num. jacobian diagnostic
void mergeTest(DeviceInstance &instance)
std::vector< std::vector< int > > statusQ
void setOrigFlag(bool origFlag_local)
const IdVector & getStaLIDVec() const
std::vector< std::vector< double > > diffJacQ
void printJacobian_(std::ostream &os, const DeviceInstance &instance, const std::vector< const std::string * > &nameVec, bool failed)
const IdVector & getDevLIDs() const
std::vector< std::vector< int > > status
NumericalJacobian(MatrixLoadData &mlData1, const SolverState &ss1, const ExternData &ed1, const DeviceOptions &do1)
bool testDAEMatrices(DeviceInstance &instance, const std::vector< const std::string * > &nameVec)
void testDebugHead(DeviceInstance &instance, const std::vector< const std::string * > &nameVec, int i, double dX)
void setMergeRowColChecked(bool mergeRowColChecked_local)
Linear::Vector * nextStaVectorPtr
Linear::Matrix * dFdxMatrixPtr
virtual bool loadDAEdQdx()=0
std::vector< std::vector< double > > relJacQ
void testDebugTail(DeviceInstance &instance, const std::vector< const std::string * > &nameVec)
virtual bool updatePrimaryState()=0
#define isnan(x)
std::vector< std::vector< double > > saveJac
std::vector< double > saveCurrSoln
std::vector< double > saveCurrState
std::vector< std::vector< double > > saveJacQ
bool updateDependentParameters(const Linear::Vector &vars)
void loadLocalDAEVectors(DeviceInstance &instance)
virtual const JacobianStamp & jacobianStamp() const
Linear::Vector * currStaVectorPtr
Linear::Vector * daeFVectorPtr
std::vector< std::vector< double > > devJacQ
double testJac_SqrtEta
dx = numJacSqrtEta * (1.0 + std::fabs(soln[i]));
std::vector< std::vector< int > > stencil
std::vector< std::vector< double > > relJac
double currTime_
DeviceEntity for expression time, breakpoints DeviceMgr for dependent parameters, breakpoints...
Linear::Matrix * dQdxMatrixPtr
std::vector< std::vector< double > > numJacQ
std::vector< double > saveNextState
std::vector< std::vector< double > > diffJac
Linear::Vector * nextStaDerivVectorPtr