Xyce  6.1
N_TIA_BackwardDifferentiation15.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_TIA_BackwardDifferentiation15.C,v $
27 //
28 // Purpose : This file contains the functions which define the
29 // backward differentiation, order 1-5, class.
30 //
31 // Special Notes :
32 //
33 // Creator : Todd Coffey
34 //
35 // Creation Date : 2/16/04
36 //
37 // Revision Information:
38 // ---------------------
39 //
40 // Revision Number: $Revision: 1.175.2.1 $
41 //
42 // Revision Date : $Date: 2015/04/02 18:20:18 $
43 //
44 // Current Owner : $Author: tvrusso $
45 //-----------------------------------------------------------------------------
46 
47 #include <Xyce_config.h>
48 
49 // ---------- Standard Includes ----------
50 #include <iostream>
51 
52 // ---------- Xyce Includes ----------
54 
55 #include <N_ANP_OutputMgrAdapter.h>
56 #include <N_ERH_ErrorMgr.h>
57 #include <N_LAS_BlockVector.h>
58 #include <N_LAS_Matrix.h>
59 #include <N_LAS_System.h>
60 #include <N_LAS_Vector.h>
61 #include <N_PDS_Comm.h>
62 #include <N_PDS_Manager.h>
64 #include <N_TIA_DataStore.h>
65 #include <N_TIA_StepErrorControl.h>
66 #include <N_TIA_TIAParams.h>
67 #include <N_UTL_MachDepParams.h>
68 #include <N_UTL_Diagnostic.h>
69 #include <N_UTL_FeatureTest.h>
70 
71 namespace Xyce {
72 namespace TimeIntg {
73 
74 const char *
75 BackwardDifferentiation15::name = "Backward Differentiation 15";
76 
77 //-----------------------------------------------------------------------------
78 // Function : BackwardDifferentiation15::factory
79 // Purpose :
80 // Special Notes :
81 // Scope : public
82 // Creator : Todd Coffey, SNL
83 // Creation Date : 2/16/04
84 //-----------------------------------------------------------------------------
85 TimeIntegrationMethod *
87  const TIAParams & tia_params,
88  StepErrorControl & step_error_control,
89  DataStore & data_store)
90 {
91  return new BackwardDifferentiation15(tia_params, step_error_control, data_store);
92 }
93 
94 //-----------------------------------------------------------------------------
95 // Function : BackwardDifferentiation15::
96 // BackwardDifferentiation15
97 // Purpose : constructor
98 // Special Notes :
99 // Scope : public
100 // Creator : Todd Coffey, SNL
101 // Creation Date : 2/16/04
102 //-----------------------------------------------------------------------------
103 
105  const TIAParams & tia_params,
106  StepErrorControl & secTmp,
107  DataStore & dsTmp)
109  leadingCoeff(1.0),
110  sec(secTmp),
111  ds(dsTmp)
112 {
113  leadingCoeff = 1;
114  sec.maxOrder_ = std::min(5, tia_params.maxOrder);
115  sec.minOrder_ = std::max(1, tia_params.minOrder);
116  if (sec.minOrder_ > sec.maxOrder_)
117  {
119  }
120  timept_ = -1.0;
121 }
122 
123 // Computes the step addjustment(BDF1-5).
124 // 2/16/04 tscoffe: I'm not exactly sure what this routine is for...
126  double stepadjust)
127 {
128  return pow(stepadjust, 1.0 / 3.0);
129 }
130 
131 //-----------------------------------------------------------------------------
132 // Function : BackwardDifferentiation15::obtainPredictor
133 // Purpose : Calculate predictor
134 // Special Notes : stored in ds.xn0Ptr,qn0Ptr,qpn0Ptr
135 // Scope : public
136 // Creator : Todd Coffey, SNL
137 // Creation Date : 2/16/04
138 //-----------------------------------------------------------------------------
140 {
141  // prepare history array for prediction
142  for (int i=sec.nscsco_;i<=sec.currentOrder_;++i)
143  {
144  (ds.xHistory[i])->scale(sec.beta_[i]);
145  (ds.qHistory[i])->scale(sec.beta_[i]);
146  (ds.sHistory[i])->scale(sec.beta_[i]);
147  (ds.stoHistory[i])->scale(sec.beta_[i]);
148  (ds.stoLeadCurrQHistory[i])->scale(sec.beta_[i]);
149  (ds.leadCurrentHistory[i])->scale(sec.beta_[i]);
150  (ds.leadCurrentQHistory[i])->scale(sec.beta_[i]);
151  (ds.leadDeltaVHistory[i])->scale(sec.beta_[i]);
152  }
153 
154  // evaluate predictor
155  *ds.xn0Ptr = *(ds.xHistory[0]);
156  *ds.qn0Ptr = *(ds.qHistory[0]);
157  *ds.sn0Ptr = *(ds.sHistory[0]);
158  *ds.ston0Ptr = *(ds.stoHistory[0]);
163 
164  ds.qpn0Ptr->putScalar(0.0);
165  ds.spn0Ptr->putScalar(0.0);
166  ds.stopn0Ptr->putScalar(0.0);
167  ds.stoQpn0Ptr->putScalar(0.0);
168  ds.leadCurrentpn0Ptr->putScalar(0.0);
169  ds.leadCurrentQpn0Ptr->putScalar(0.0);
170  ds.leadDeltaVpn0Ptr->putScalar(0.0);
171  for (int i=1;i<=sec.currentOrder_;++i)
172  {
173  ds.xn0Ptr->linearCombo(1.0,*(ds.xHistory[i]),1.0,*ds.xn0Ptr);
174  ds.qn0Ptr->linearCombo(1.0,*(ds.qHistory[i]),1.0,*ds.qn0Ptr);
175  ds.sn0Ptr->linearCombo(1.0,*(ds.sHistory[i]),1.0,*ds.sn0Ptr);
176  ds.ston0Ptr->linearCombo(1.0,*(ds.stoHistory[i]),1.0,*ds.ston0Ptr);
177  ds.stoQn0Ptr->linearCombo(1.0,*(ds.stoLeadCurrQHistory[i]),1.0,*ds.stoQn0Ptr);
178  ds.qpn0Ptr->linearCombo(sec.gamma_[i],*(ds.qHistory[i]),1.0,*ds.qpn0Ptr);
179  ds.spn0Ptr->linearCombo(sec.gamma_[i],*(ds.sHistory[i]),1.0,*ds.spn0Ptr);
180  ds.stopn0Ptr->linearCombo(sec.gamma_[i],*(ds.stoHistory[i]),1.0,*ds.stopn0Ptr);
181  ds.stoQpn0Ptr->linearCombo(sec.gamma_[i],*(ds.stoLeadCurrQHistory[i]),1.0,*ds.stoQpn0Ptr);
182  ds.leadCurrentn0Ptr->linearCombo(1.0,*(ds.leadCurrentHistory[i]),1.0,*ds.leadCurrentn0Ptr);
184  ds.leadCurrentQn0Ptr->linearCombo(1.0,*(ds.leadCurrentQHistory[i]),1.0,*ds.leadCurrentQn0Ptr);
186  ds.leadDeltaVn0Ptr->linearCombo(1.0,*(ds.leadDeltaVHistory[i]),1.0,*ds.leadDeltaVn0Ptr);
187  ds.leadDeltaVpn0Ptr->linearCombo(sec.gamma_[i],*(ds.leadDeltaVHistory[i]),1.0,*ds.leadDeltaVpn0Ptr);
188  }
189 
190  if (DEBUG_TIME && isActive(Diag::TIME_PREDICTOR))
191  {
192  Xyce::dout().width(21);
193  Xyce::dout().precision(13);
194  Xyce::dout().setf(std::ios::scientific);
195  Xyce::dout() << std::endl;
196  Xyce::dout() << Xyce::section_divider << std::endl;
197  Xyce::dout() << " BackwardDifferentiation15::obtainPredictor" << std::endl;
198  Xyce::dout() << "\n currentOrder = " << sec.currentOrder_ << std::endl;
199  Xyce::dout() << "\n sec.nscsco_: " << sec.nscsco_ << std::endl;
200  for (int i=0; i<=sec.currentOrder_ ; ++i)
201  Xyce::dout() << "\n sec.beta_[" << i << "] = " << sec.beta_[i] << "\n" << std::endl;
202  for (int i=0; i<=sec.currentOrder_ ; ++i)
203  {
204  Xyce::dout() << "\n xHistory["<< i << "]: \n" << std::endl;
205  (ds.xHistory[i])->printPetraObject(Xyce::dout());
206  Xyce::dout() << std::endl;
207  }
208  for (int i=0; i<=sec.currentOrder_ ; ++i)
209  {
210  Xyce::dout() << "\n qHistory["<< i << "]: \n" << std::endl;
211  (ds.qHistory[i])->printPetraObject(Xyce::dout());
212  Xyce::dout() << std::endl;
213  }
214  for (int i=0; i<=sec.currentOrder_ ; ++i)
215  {
216  Xyce::dout() << "\n sHistory["<< i << "]: \n" << std::endl;
217  (ds.sHistory[i])->printPetraObject(Xyce::dout());
218  Xyce::dout() << std::endl;
219  }
220  Xyce::dout() << "\n xn0: \n" << std::endl;
221  ds.xn0Ptr->printPetraObject(Xyce::dout());
222  Xyce::dout() << std::endl;
223  Xyce::dout() << "\n qn0: \n" << std::endl;
224  ds.qn0Ptr->printPetraObject(Xyce::dout());
225  Xyce::dout() << std::endl;
226  Xyce::dout() << "\n qpn0: \n" << std::endl;
227  ds.qpn0Ptr->printPetraObject(Xyce::dout());
228  Xyce::dout() << std::endl;
229  Xyce::dout() << "\n sn0: \n" << std::endl;
230  ds.sn0Ptr->printPetraObject(Xyce::dout());
231  Xyce::dout() << std::endl;
232  Xyce::dout() << "\n spn0: \n" << std::endl;
233  ds.spn0Ptr->printPetraObject(Xyce::dout());
234  Xyce::dout() << std::endl;
235  Xyce::dout() << "\n stoQn0Ptr: \n" << std::endl;
236  ds.stoQn0Ptr->printPetraObject(Xyce::dout());
237  Xyce::dout() << std::endl;
238  Xyce::dout() << "\n stoQpn0Ptr: \n" << std::endl;
239  ds.stoQpn0Ptr->printPetraObject(Xyce::dout());
240  Xyce::dout() << std::endl;
241  Xyce::dout() << Xyce::section_divider << std::endl;
242  }
243  // copy the prediction into the next solution:
244  *(ds.nextSolutionPtr) = *(ds.xn0Ptr);
245 }
246 
247 //-----------------------------------------------------------------------------
248 // Function : BackwardDifferentiation15::obtainResidual
249 // Purpose : Calculate Residual
250 // Special Notes :
251 // Scope : public
252 // Creator : Todd Coffey, SNL
253 // Creation Date : 3/8/04
254 //-----------------------------------------------------------------------------
256 {
257  // output: ds.RHSVectorPtr
258 
259  // This function returns the following residual:
260  // $qpn0 - (sec.alphas_/hn)(Q(x)-qn0)+F(x)-B(t)$
261 
262  // Note: ds.nextSolutionPtr is used to get Q,F,B in Analysis::AnalysisManager::loadRHS.
263  ds.RHSVectorPtr->linearCombo(1.0,*ds.daeQVectorPtr,-1.0,*ds.qn0Ptr);
265 
266  if (DEBUG_TIME && isActive(Diag::TIME_RESIDUAL))
267  {
268  Xyce::dout() << std::endl;
269  Xyce::dout() << Xyce::section_divider << std::endl;
270  Xyce::dout() << " BackwardDifferentiation15::obtainResidual" << std::endl;
271  Xyce::dout() << "\n t = " << sec.nextTime << "\n" << std::endl;
272  Xyce::dout() << "\n solution: \n" << std::endl;
273  ds.nextSolutionPtr->printPetraObject(Xyce::dout());
274  Xyce::dout() << "\n daeQVector: \n" << std::endl;
275  ds.daeQVectorPtr->printPetraObject(Xyce::dout());
276  Xyce::dout() << "\n qn0: \n" << std::endl;
277  ds.qn0Ptr->printPetraObject(Xyce::dout());
278  Xyce::dout() << "\n qpn0: \n" << std::endl;
279  ds.qpn0Ptr->printPetraObject(Xyce::dout());
280  Xyce::dout() << "\n sec.alphas_/hn: " << sec.alphas_/sec.currentTimeStep << "\n" << std::endl;
281  Xyce::dout() << "\n daeFVector: \n" << std::endl;
282  ds.daeFVectorPtr->printPetraObject(Xyce::dout());
283 
284  Xyce::dout() << "\n dQdt-vector: \n" << std::endl;
285  ds.RHSVectorPtr->printPetraObject(Xyce::dout());
286  Xyce::dout() << std::endl;
287  }
288 
289  ds.RHSVectorPtr->linearCombo(1.0,*ds.RHSVectorPtr,+1.0,*ds.daeFVectorPtr);
290  ds.RHSVectorPtr->linearCombo(1.0,*ds.RHSVectorPtr,-1.0,*ds.daeBVectorPtr);
291 
292  // since the nonlinear solver is expecting a -f, scale by -1.0:
293  ds.RHSVectorPtr->scale(-1.0);
294 
295  // if voltage limiting is on, add it in:
296  if (ds.limiterFlag)
297  {
299 
300  (ds.RHSVectorPtr)->daxpy(
301  *(ds.RHSVectorPtr), +1.0, *(ds.dQdxdVpVectorPtr));
302 
303  (ds.RHSVectorPtr)->daxpy(
304  *(ds.RHSVectorPtr), +1.0, *(ds.dFdxdVpVectorPtr));
305  }
306 
307  if (DEBUG_TIME && isActive(Diag::TIME_RESIDUAL))
308  {
309  Xyce::dout() << "\n Residual-vector: \n" << std::endl;
310  Xyce::dout() << "-(qpn0-(sec.alpha_s/h)*(Q-qn0)+F-B) \n" << std::endl;
311  ds.RHSVectorPtr->printPetraObject(Xyce::dout());
312  Xyce::dout() << Xyce::section_divider << std::endl;
313  Xyce::dout() << std::endl;
314  }
315 }
316 
317 //-----------------------------------------------------------------------------
318 // Function : BackwardDifferentiation15::obtainSensitivityResiduals
319 // Purpose : Calculate Residual
320 // Special Notes :
321 // Scope : public
322 // Creator : Eric Keiter, SNL
323 // Creation Date :
324 //-----------------------------------------------------------------------------
326 {}
327 
328 //-----------------------------------------------------------------------------
329 // Function : BackwardDifferentiation15::obtainJacobian
330 // Purpose : Calculate Jacobian
331 // Special Notes :
332 // Scope : public
333 // Creator : Todd Coffey, SNL
334 // Creation Date : 3/8/04
335 //-----------------------------------------------------------------------------
336 
338 {
339  if (DEBUG_TIME && isActive(Diag::TIME_JACOBIAN))
340  {
341  Xyce::dout() << std::endl;
342  Xyce::dout() << Xyce::section_divider << std::endl;
343  Xyce::dout() << " BackwardDifferentiation15::obtainJacobian" << std::endl;
344  }
345 
346  // output: ds.JMatrixPtr
347 
348  // This function returns the following matrix:
349  // $-(sec.alphas_/hn)dQdx(x)+dFdx$
350 
351  // Note: ds.nextSolutionPtr is used to get dQdx,dFdx in Analysis::AnalysisManager::loadJacobian.
352 // ds.JmatrixPtr->linearCombo(-sec.alphas_/sec.currentTimeStep,*ds.dQdxMatrixPtr,+1.0,*ds.dFdxMatrixPtr);
353 
354  Linear::Matrix & dQdx = *(ds.dQdxMatrixPtr);
355  Linear::Matrix & dFdx = *(ds.dFdxMatrixPtr);
356  Linear::Matrix & Jac = *(ds.JMatrixPtr);
357 
358  double qscalar(-sec.alphas_/sec.currentTimeStep);
359 
360  Jac.linearCombo( qscalar, dQdx, 1.0, dFdx );
361 
362  if (DEBUG_TIME && isActive(Diag::TIME_JACOBIAN))
363  {
364  Xyce::dout() << "\n dFdx:" <<std::endl;
365  dFdx.printPetraObject(Xyce::dout());
366  Xyce::dout() << "\n Total Jacobian:" <<std::endl;
367  Jac.printPetraObject(Xyce::dout());
368 // for (int i=0;i<3;++i)
369 // {
370 // printf("[ %25.20g\t%25.20g\t%25.20g ]\n",Jac[i][0],Jac[i][1],Jac[i][2]);
371 // }
372 
373  Xyce::dout() << Xyce::section_divider << std::endl;
374  Xyce::dout() << std::endl;
375  }
376 }
377 
378 //-----------------------------------------------------------------------------
379 // Function : BackwardDifferentiation15::interpolateSolution
380 // Purpose : Interpolate solution approximation at prescribed time point.
381 // Special Notes : This routine computes the solution at the output
382 // : timepoint by intepolation of the history using the order
383 // : used for the most recent completed step, orderUsed.
384 // : The output is put into ds.tmpSolVectorPtr.
385 // Scope : public
386 // Creator : Todd Coffey, SNL
387 // Creation Date : 2/16/04
388 //-----------------------------------------------------------------------------
389 
391  Linear::Vector * tmpSolVectorPtr, std::vector<Linear::Vector*> & historyVec)
392 {
393  // 03/23/04 tscoffe: Currently this code is nearly identical to the IDA code
394  // for interpolating to an output time. Either we acknowledge the copyright,
395  // the list of conditions in the license and the disclaimer or we rewrite this
396  // function. The IDA license is included after this routine.
397  double tfuzz; // fuzz factor to check for valid output time
398  double tp; // approximately t_{n-1}
399  double delt; // distance between timepoint and currentTime
400  double c = 1.0; // coefficient for interpolation
401  double gam; // coefficient for interpolation
402  int kord; // order of interpolation
403  double tn = sec.currentTime;
404  double hh = sec.currentTimeStep;
405  double hused = sec.usedStep_;
406  int kused = sec.usedOrder_;
407  // TVR: changed line below in addressing bug 1258
408  // This is what was here prior to my change:
409  // double uround = 0.0; // unit round-off (set to zero for now)
410  // The value below is a WAG
411  double uround = Util::MachineDependentParams::MachinePrecision();
412 
413  tfuzz = 100 * uround * (tn + hh);
414  tp = tn - hused - tfuzz;
415 
416  if ( (timepoint - tp)*hh < 0.0 )
417  return false;
418 
419  *tmpSolVectorPtr = *(historyVec[0]);
420  kord = kused;
421  if ( (kused == 0) || (timepoint == tn) )
422  kord = 1;
423 
424  delt = timepoint - tn;
425  gam = delt/sec.psi_[0];
426  for (int j=1 ; j <= kord ; ++j)
427  {
428  c = c*gam;
429  gam = (delt + sec.psi_[j-1])/sec.psi_[j];
430  tmpSolVectorPtr->linearCombo(1.0,*tmpSolVectorPtr,c,*(historyVec[j]));
431  }
432  return true;
433 }
434 
435 //-----------------------------------------------------------------------------
436 // Function : BackwardDifferentiation15::interpolateMPDESolution
437 // Purpose : Interpolate solution approximation at prescribed time points.
438 // Special Notes : This routine computes the solution at the output
439 // : timepoints by intepolation of the history using the order
440 // : used for the most recent completed step, orderUsed.
441 // : The output is put into provided Linear::Vector pointer.
442 // : The interpolation is as follows:
443 // : tmpSolVectorPtr->block(i) is interpolated at timepoint(i)
444 // : Therefore, if you want them all interpolated at the same time,
445 // : then use timepoint(i) = timepoint(0) forall i
446 // : or use interpolateSolution.
447 // Scope : public
448 // Creator : Todd Coffey, Eric Keiter, SNL
449 // Creation Date : 11/28/06
450 //-----------------------------------------------------------------------------
451 
452 bool BackwardDifferentiation15::interpolateMPDESolution(std::vector<double>& timepoint,
453  Linear::Vector * tmpSolVectorPtr)
454 {
455  Linear::BlockVector * blockTempSolVectorPtr =
456  dynamic_cast<Linear::BlockVector*>(tmpSolVectorPtr);
457  if (blockTempSolVectorPtr == NULL)
458  {
459  std::string msg = "BackwardDifferentiation15::interpolateMPDESolution: ";
460  msg += "Linear::Vector tmpSolVectorPtr is not of type Linear::BlockVector";
461  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
462  return(false);
463  }
464 
465  double tfuzz; // fuzz factor to check for valid output time
466  double tp; // approximately t_{n-1}
467  int numblocks = timepoint.size();
468  int blockCount = blockTempSolVectorPtr->blockCount();
469  if (numblocks > blockCount)
470  {
471  std::string msg = "BackwardDifferentiation15::interpolateMPDESolution: ";
472  msg += "Number of time points requested is greater than number of fast time points in MPDE block vector";
473  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
474  return(false);
475  }
476  double delt;
477  double c = 1.0;
478  double gam;
479  int kord; // order of interpolation
480  double tn = sec.currentTime;
481  double hh = sec.currentTimeStep;
482  double hused = sec.usedStep_;
483  int kused = sec.usedOrder_;
484  double uround = 0.0; // unit round-off (set to zero for now)
485 
486  tfuzz = 100 * uround * (tn + hh);
487  tp = tn - hused - tfuzz;
488  for (int i=0; i<numblocks ; ++i)
489  {
490  if ( (timepoint[i] - tp)*hh < 0.0 )
491  return false;
492  }
493 
494  *tmpSolVectorPtr = *(ds.xHistory[0]);
495 
496  Linear::Vector * solVectorPtr;
497  Linear::Vector * xHistoryVectorPtr;
498  // Loop over blocks first so that maximal order can be maintained
499  for (int i=0; i < numblocks ; ++i)
500  {
501  if ((kused == 0) || (timepoint[i] == tn)) { kord = 1; }
502  else { kord = kused; }
503  solVectorPtr = &(blockTempSolVectorPtr->block(i));
504  c = 1.0;
505  delt = timepoint[i] - tn;
506  gam = delt/sec.psi_[0];
507  for (int j=1 ; j <= kord ; ++j)
508  {
509  c = c*gam;
510  gam = (delt + sec.psi_[j-1])/sec.psi_[j];
511  Linear::BlockVector * blockXHistoryVectorPtr =
512  dynamic_cast<Linear::BlockVector*>(ds.xHistory[j]);
513  if (blockXHistoryVectorPtr == NULL)
514  {
515  Xyce::Report::DevelFatal0().in("BackwardDifferentiation15::interpolateMPDESolution") << "Linear::Vector ds.xHistory[j] is not of type Linear::BlockVector\n j = " << j;
516  return(false);
517  }
518  xHistoryVectorPtr = &(blockXHistoryVectorPtr->block(i));
519  solVectorPtr->linearCombo(1.0,*solVectorPtr,c,*xHistoryVectorPtr);
520  }
521  }
522  return true;
523 }
524 
525 //-----------------------------------------------------------------------------
526 // Function : BackwardDifferentiation15::printMPDEOutputSolution()
527 // Purpose : Print transient output from MPDE simulation
528 // Special Notes : This routine uses interpolateMPDESolution.
529 // Scope : public
530 // Creator : Todd Coffey, SNL, 1414
531 // Creation Date : 11/28/06
532 //-----------------------------------------------------------------------------
534  Analysis::OutputMgrAdapter & outputManagerAdapter,
535  const double time,
536  Linear::Vector * solnVecPtr,
537  const std::vector<double> & fastTimes )
538 {
539  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
540  {
541  Xyce::dout() << std::endl;
542  Xyce::dout() << Xyce::section_divider << std::endl;
543  Xyce::dout() << " BackwardDifferentiation15::printMPDEOutputSolution" << std::endl;
544  }
545 
546  double timestep = sec.lastAttemptedTimeStep;
547  double lasttime = sec.currentTime - timestep;
548  double tn = sec.currentTime;
549  // Set these values up to read output time intervals. FIXME
550  double beg_of_output_time_interval = lasttime;
551  double end_of_output_time_interval = tn;
552  double start_time = std::max(lasttime,beg_of_output_time_interval);
553  double stop_time = std::min(tn,end_of_output_time_interval);
554  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
555  {
556  Xyce::dout() << "timestep = " << timestep << std::endl;
557  Xyce::dout() << "lasttime = " << lasttime << std::endl;
558  Xyce::dout() << "tn = " << tn << std::endl;
559  Xyce::dout() << "beg_of_output_time_interval = " << beg_of_output_time_interval << std::endl;
560  Xyce::dout() << "end_of_output_time_interval = " << end_of_output_time_interval << std::endl;
561  Xyce::dout() << "start_time = " << start_time << std::endl;
562  Xyce::dout() << "stop_time = " << stop_time << std::endl;
563  }
564 
565  Linear::BlockVector * blockTmpSolVectorPtr =
566  dynamic_cast<Linear::BlockVector*>(ds.tmpSolVectorPtr);
567 
568  if (blockTmpSolVectorPtr == NULL)
569  {
570  std::string msg = "BackwardDifferentiation15::printMPDEOutputSolution: ";
571  msg += "Linear::Vector ds.tmpSolVectorPtr is not of type Linear::BlockVector";
572  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
573  return(false);
574  }
575  int blockCount = blockTmpSolVectorPtr->blockCount();
576 
577  // Create list of timepoints to interpolate (along characteristic curve)
578  double T2 = fastTimes.back();
579  //double charcross = start_time - floor(start_time/T2)*T2; // (start_time mod T2)
580  double charcross = fmod(start_time,T2); // (start_time mod T2)
581  int s_ind_0 = -1;
582  // find s_ind_0 = first fast time point >= charcross.
583  // This could probably be made faster: FIXME
584  for (int i=0 ; i<=blockCount ; ++i)
585  {
586  if (fastTimes[i] >= charcross)
587  {
588  s_ind_0 = i;
589  break;
590  }
591  }
592  if (s_ind_0 == -1)
593  {
594  std::string msg = "BackwardDifferentiation15::printMPDEOutputSolution: ";
595  msg += "Cannot find where characteristic curve crosses fast time slice at start_time";
596  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
597  return(false);
598  }
599  std::vector<double> h2(blockCount,0);
600  for (int j=0 ; j < blockCount ; ++j)
601  {
602  h2[j] = fastTimes[j+1] - fastTimes[j];
603  }
604  std::vector<double> ti;
605  //double first_interp = floor(start_time/T2)*T2 + fastTimes[s_ind_0];
606  double first_interp = start_time - charcross + fastTimes[s_ind_0];
607  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
608  {
609  Xyce::dout() << "first_interp = " << first_interp << std::endl;
610  }
611 
612  if (s_ind_0 == blockCount) { s_ind_0 = 0; };
613  // Don't interpolate the first point
614  double eps = fabs(start_time)*1.0e-6;
615  if ( fabs(first_interp-timept_) <= eps )
616  {
617  first_interp += h2[s_ind_0];
618  s_ind_0++;
619  if (s_ind_0 == blockCount) { s_ind_0 = 0; };
620  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
621  {
622  Xyce::dout() << "Moving first_interp forward to avoid duplicate outputs: " << first_interp << std::endl;
623  }
624  }
625  int sn = s_ind_0;
626  double t = first_interp;
627  while (t <= stop_time)
628  {
629  ti.push_back(t);
630  t += h2[sn];
631  sn++;
632  if (sn >= blockCount) { sn = 0; }
633  }
634  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
635  {
636  Xyce::dout() << "T2 = " << T2 << std::endl;
637  Xyce::dout() << "charcross = " << charcross << std::endl;
638  Xyce::dout() << "s_ind_0 = " << s_ind_0 << std::endl;
639  Xyce::dout() << "Expecting to interpolate the following points:" << std::endl;
640  unsigned int numinterp = ti.size();
641  for (unsigned int i=0 ; i < numinterp ; ++i)
642  {
643  Xyce::dout() << ti[i] << std::endl;
644  }
645  Xyce::dout() << "Total of " << numinterp << " points" << std::endl;
646  }
647 
648  timept_ = start_time; // used later for interpolating stop_time
649  unsigned int tinum = ti.size();
650  int total_interp = 0;
651  std::vector<double> timepoint_vec(blockCount,stop_time);
652  int num_interp_this_cycle = 0;
653  int s_ind = s_ind_0;
654  for (unsigned int i=0; i < tinum ; ++i)
655  {
656  timepoint_vec[s_ind] = ti[i];
657  num_interp_this_cycle++;
658  s_ind++;
659  if (s_ind >= blockCount) { s_ind = 0; };
660  // If we're back to s_ind_0 or out of ti points, then interpolate:
661  if ((s_ind == s_ind_0) || (i == tinum-1))
662  {
664  // Now we print these points out
665  int s = s_ind_0;
666  for (int j=0 ; j < num_interp_this_cycle ; ++j)
667  {
668  timept_ = timepoint_vec[s];
669  outputManagerAdapter.tranOutput(
670  timept_, blockTmpSolVectorPtr->block(s),
674  total_interp++;
675  s++;
676  if (s >= blockCount) { s = 0; }
677  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
678  Xyce::dout() << "Interpolated to t = " << timept_ << std::endl;
679  }
680  num_interp_this_cycle = 0;
681  }
682  }
683  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
684  Xyce::dout() << "Total of " << total_interp << " points" << std::endl;
685 
686  // Now we interpolate stop_time unless its too close to the last timept interpolated.
687  eps = fabs(stop_time)*1.0e-8;
688  // fudge factor for printing, this should come from elsewhere FIXME
689  if (fabs(timept_ - stop_time) >= eps)
690  {
691  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
692  {
693  Xyce::dout() << "Previous timept = " << timept_ << std::endl;
694  Xyce::dout() << "Expecting to interpolate the following point: " << stop_time << std::endl;
695  }
696 
697  Linear::Vector* tmpSolnVecPtr = solnVecPtr;
698  Linear::Vector* tmpVecPtr = ds.tmpXn0APtr;
699  if (stop_time < tn)
700  {
702  tmpSolnVecPtr = ds.tmpXn0BPtr;
703  }
704  Linear::BlockVector * blockTmpSolnVecPtr =
705  dynamic_cast<Linear::BlockVector*>(tmpSolnVecPtr);
706  Linear::BlockVector * blockTmpVecPtr =
707  dynamic_cast<Linear::BlockVector*>(tmpVecPtr);
708  if (blockTmpSolnVecPtr == NULL)
709  {
710  std::string msg = "BackwardDifferentiation15::printMPDEOutputSolution: ";
711  msg += "Linear::Vector tmpSolnVecPtr is not of type Linear::BlockVector";
712  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
713  return(false);
714  }
715  if (blockTmpVecPtr == NULL)
716  {
717  std::string msg = "BackwardDifferentiation15::printMPDEOutputSolution: ";
718  msg += "Linear::Vector tmpVecPtr is not of type Linear::BlockVector";
719  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
720  return(false);
721  }
722  // Interpolate where the caracteristic crosses stop_time (instead of start_time).
723  //charcross = stop_time - floor(stop_time/T2)*T2;
724  charcross = fmod(stop_time,T2);
725  int s_ind_1 = -1;
726  // Find index just before charcross:
727  if( charcross < fastTimes[0] )
728  {
729  // by periodicity, the one before in this case is the one at the end
730  s_ind_1 = blockCount-1;
731  }
732  else
733  {
734  for (int i=blockCount-1 ; i>=0 ; --i)
735  {
736  if (fastTimes[i] <= charcross)
737  {
738  s_ind_1 = i;
739  break;
740  }
741  }
742  }
743  if (s_ind_1 == -1)
744  {
745  std::string msg = "BackwardDifferentiation15::printMPDEOutputSolution: ";
746  msg += "Cannot find where characteristic curve crosses fast time slice at stop_time";
747  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
748  return(false);
749  }
750  int sm = s_ind_1;
751  int sp = s_ind_1+1;
752  double coeff_sm = fastTimes[sp]-charcross;
753  double coeff_sp = charcross-fastTimes[sm];
754  if (sp == blockCount) { sp = 0; }
755  double dt = h2[s_ind_1];
756  timept_ = stop_time;
757  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
758  {
759  Xyce::dout() << "charcross = " << charcross << std::endl;
760  Xyce::dout() << "s_ind_1 = " << s_ind_1 << std::endl;
761  Xyce::dout() << "sp = " << sp << std::endl;
762  Xyce::dout() << "sm = " << sm << std::endl;
763  Xyce::dout() << "dt = " << dt << std::endl;
764  Xyce::dout() << "timept = " << timept_ << std::endl;
765  Xyce::dout() << "coeff_sm = " << coeff_sm << std::endl;
766  Xyce::dout() << "coeff_sp = " << coeff_sp << std::endl;
767  }
768 
769  blockTmpVecPtr->block(0).linearCombo(
770  coeff_sm/dt, blockTmpSolnVecPtr->block(sm),
771  coeff_sp/dt, blockTmpSolnVecPtr->block(sp)
772  );
773  outputManagerAdapter.tranOutput(
774  timept_, blockTmpVecPtr->block(0),
778 
779  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
780  Xyce::dout() << "Interpolated to t = " << timept_ << std::endl;
781  }
782 
783  else if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT)) // no extra interpolation
784  {
785  Xyce::dout() << "No further interpolation required." << std::endl;
786  }
787 
788  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
789  Xyce::dout() << Xyce::section_divider << std::endl;
790 
791  return true;
792 }
793 
794 
795 //-----------------------------------------------------------------------------
796 // Function : BackwardDifferentiation15::printWaMPDEOutputSolution()
797 // Purpose : Print transient output from WaMPDE simulation
798 // Special Notes : This routine uses interpolateSolution.
799 // Scope : public
800 // Creator : Todd Coffey, SNL, 1414
801 // Creation Date : 12/15/06
802 //-----------------------------------------------------------------------------
804  Analysis::OutputMgrAdapter & outputManagerAdapter,
805  const double time,
806  Linear::Vector * solnVecPtr,
807  const std::vector<double> & fastTimes,
808  const int phiGID )
809 {
810  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
811  {
812  Xyce::dout() << std::endl;
813  Xyce::dout() << Xyce::section_divider << std::endl;
814  Xyce::dout() << " BackwardDifferentiation15::printWaMPDEOutputSolution" << std::endl;
815  }
816 
817  double timestep = sec.lastAttemptedTimeStep;
818  double lasttime = sec.currentTime - timestep;
819  double tn = sec.currentTime;
820  // Set these values up to read output time intervals. FIXME
821  double beg_of_output_time_interval = lasttime;
822  double end_of_output_time_interval = tn;
823  double start_time = std::max(lasttime,beg_of_output_time_interval);
824  double stop_time = std::min(tn,end_of_output_time_interval);
825 
826  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
827  {
828  Xyce::dout() << "start_time = " << start_time << std::endl;
829  Xyce::dout() << "stop_time = " << stop_time << std::endl;
830  }
831 
832  // 12/15/06 tscoffe:
833  // First break the interval up as printOutputSolution does:
834  // hh = timestep/(sec.usedOrder_) and interpolate in the intervals:
835  // [tn+(i-1)*hh,tn+i*hh], i=1..usedOrder
836  // Assume phi(t_1) is linear in these intervals and approximate with:
837  // phi(t) = (1/hh)*(phi(tn)(tn+hh-t)+phi(tn+hh)(t-tn))
838  // Then the t_1 values we want to interpolate are:
839  // n2 = number of fast time points.
840  // T2 = fast time period
841  // h2 = T2/n2 = average spacing on fast time scale
842  // t1_vals = [tn:h2:tn+hh]
843  // And the t_2 values we want to interpolate are:
844  // t2_vals = phi(t1_vals) mod T2
845  // Then take the N_LAS blocks and do 2D linear interpolation on the intervals:
846  // (t1,s1), (t1,s2), (t2,s1), (t2,s2)
847  // x(t) = x(t,s) approx =
848  // (1/(t2-t1))(1/(s2-s1))[ x(t1,s1)(t2-t)(s2-s)
849  // +x(t1,s2)(t2-t)(s-s1)
850  // +x(t2,s1)(t-t1)(s2-s)
851  // +x(t2,s2)(t-t1)(s-s1) ]
852  // where t = t1_vals and s = t2_vals
853 
854  Linear::BlockVector * blockTmpSolVectorPtr =
855  dynamic_cast<Linear::BlockVector*>(ds.tmpSolVectorPtr);
856  Linear::BlockVector * blockTmpXn0APtr =
857  dynamic_cast<Linear::BlockVector*>(ds.tmpXn0APtr);
858  Linear::BlockVector * blockTmpXn0BPtr =
859  dynamic_cast<Linear::BlockVector*>(ds.tmpXn0BPtr);
860  if (blockTmpSolVectorPtr == NULL)
861  {
862  std::string msg = "BackwardDifferentiation15::printWaMPDEOutputSolution: ";
863  msg += "Linear::Vector ds.tmpSolVectorPtr is not of type Linear::BlockVector";
864  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
865  return(false);
866  }
867  if (blockTmpXn0APtr == NULL)
868  {
869  std::string msg = "BackwardDifferentiation15::printWaMPDEOutputSolution: ";
870  msg += "Linear::Vector ds.tmpXn0APtr is not of type Linear::BlockVector";
871  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
872  return(false);
873  }
874  if (blockTmpXn0BPtr == NULL)
875  {
876  std::string msg = "BackwardDifferentiation15::printWaMPDEOutputSolution: ";
877  msg += "Linear::Vector ds.tmpXn0BPtr is not of type Linear::BlockVector";
878  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
879  return(false);
880  }
881  int phiLID = blockTmpSolVectorPtr->pmap()->globalToLocalIndex(phiGID);
882  double hh = timestep/(sec.usedOrder_);
883  double timeA = -1.0;
884  double timeB = -1.0;
885  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
886  {
887  Xyce::dout() << " sec.usedOrder_ = " << sec.usedOrder_ << std::endl;
888  Xyce::dout() << " sec.currentTime_ = " << sec.currentTime << std::endl;
889  Xyce::dout() << " lasttime = " << lasttime << std::endl;
890  }
891 
892  for (int i=0 ; i < sec.usedOrder_ ; ++i)
893  {
894  if (i == 0)
895  {
896  bool junk;
897  timeA = lasttime + hh*i;
899  if (!junk)
900  {
901  std::string msg = "interpolateSolution returned false!";
902  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0,msg);
903  }
904  }
905  else
906  {
907  // We don't need to interpolate this again.
909  timeA = timeB;
910  }
911  timeB = lasttime + hh*(i+1);
913  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
914  {
915  Xyce::dout() << "Interpolating in [ " << timeA << ", " << timeB << " ]" << std::endl;
916  Xyce::dout() << "timeA = " << timeA << std::endl;
917  Xyce::dout() << "timeB = " << timeB << std::endl;
918  }
919 
920  // Now we can interpolate [tmpXn0APtr,tmpXn0BPtr] in [timeA,timeB].
921  std::vector<double> t1vals;
922  double T2 = fastTimes.back();
923  int blockCount = blockTmpSolVectorPtr->blockCount();
924  double h2 = T2/blockCount; // Average mesh width in fast time-scale
925  double tval = timeA+h2;
926  while (tval <= timeB)
927  {
928  t1vals.push_back(tval);
929  tval += h2;
930  }
931  // fudge factor for printing, this should come from elsewhere FIXME
932  double eps = fabs(timeB)*1.0e-8;
933  if ( (t1vals.size() == 0) || (fabs(t1vals.back() - timeB) >= eps) )
934  {
935  t1vals.push_back(timeB);
936  }
937  std::vector<double> t2vals, phiAB(2);
938  std::vector<double> tmpPhiAB(2, 0.0);
939  if (phiLID >= 0)
940  {
941  tmpPhiAB[0] = (*ds.tmpXn0APtr)[phiLID]; // Get from MPDE Manager
942  tmpPhiAB[1] = (*ds.tmpXn0BPtr)[phiLID]; // Get from MPDE Manager
943  }
944  blockTmpSolVectorPtr->pmap()->pdsComm().sumAll( &tmpPhiAB[0], &phiAB[0], 2 );
945 
946  double phiA = phiAB[0], phiB = phiAB[1];
947  for (unsigned int j=0 ; j<t1vals.size() ; ++j)
948  {
949  double phi = (1/(timeB-timeA))*(phiA*(timeB-t1vals[j])+phiB*(t1vals[j]-timeA));
950  t2vals.push_back(fmod(phi,T2)); // phi(t1vals[j]) mod T2
951  }
952  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
953  {
954  Xyce::dout() << "t1vals = " << std::endl;
955  for (unsigned int j=0 ; j < t1vals.size() ; ++j)
956  {
957  Xyce::dout() << t1vals[j] << std::endl;
958  }
959  Xyce::dout() << "phi(" << timeA << ") = " << phiA << std::endl;
960  Xyce::dout() << "phi(" << timeB << ") = " << phiB << std::endl;
961  Xyce::dout() << "t2vals = " << std::endl;
962  for (unsigned int j=0 ; j< t2vals.size() ; ++j)
963  {
964  Xyce::dout() << t2vals[j] << std::endl;
965  }
966  }
967 
968  // Now we can do our block 2D interpolations
969  // loop through t1vals and move the fast time blocks as we go
970  double t1 = timeA; // slow time indices
971  double t2 = timeB;
972  double t = t1vals[0]; // current time indices
973  double s = t2vals[0];
974  int b1,b2; // fast time block indices corresponding to s1,s2
975  // Find the block surrounding s:
976  b1 = -2;
977  for (int j=0 ; j < blockCount ; ++j)
978  {
979  if ((fastTimes[j] <= s) && (s < fastTimes[j+1]))
980  {
981  b1 = j;
982  }
983  }
984  b2 = b1+1;
985  if (b2 == blockCount)
986  {
987  b2 = 0;
988  }
989  double s1 = fastTimes[b1];
990  double s2 = fastTimes[b1+1]; // Note: fastTimes[blockCount] = T2
991  if ((s < s1) || (s > s2))
992  {
993  std::string msg = "BackwardDifferentiation15::printWaMPDEOutputSolution: ";
994  msg += " Interpolator cannot find a fast time block containing the first point ";
995  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
996  }
997  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
998  {
999  Xyce::dout() << "Found s = " << s << " in block " << b1;
1000  Xyce::dout() << " with boundary = [" << s1 << "," << s2 << "]" << std::endl;
1001  }
1002 
1003  for (unsigned int j=0 ; j < t1vals.size() ; ++j)
1004  {
1005  t = t1vals[j];
1006  s = t2vals[j];
1007  if (t > t2) break; // This should never occur
1008  // If s has moved outside our block, then increment block.
1009  if ( (s < s1) || (s > s2) )
1010  {
1011  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
1012  Xyce::dout() << "Incrementing fast time block for next interpolation." << std::endl;
1013 
1014  b1++;
1015  if (b1 == blockCount)
1016  {
1017  b1 = 0;
1018  }
1019  b2 = b1+1;
1020  if (b2 == blockCount)
1021  {
1022  b2 = 0;
1023  }
1024  s1 = fastTimes[b1];
1025  s2 = fastTimes[b1+1];
1026  }
1027  // If s isn't in the next block, then search for it.
1028  if ((s < s1) || (s > s2))
1029  {
1030  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
1031  Xyce::dout() << "Searching for fast time block for next interpolation." << std::endl;
1032 
1033  b1 = -2;
1034  for (int j2=0 ; j2 < blockCount ; ++j2)
1035  {
1036  if ((fastTimes[j2] <= s) && (s < fastTimes[j2+1]))
1037  {
1038  b1 = j2;
1039  }
1040  }
1041  b2 = b1+1;
1042  if (b2 == blockCount)
1043  {
1044  b2 = 0;
1045  }
1046  s1 = fastTimes[b1];
1047  s2 = fastTimes[b1+1];
1048  }
1049  // If a block surrounding s can't be found, then quit.
1050  if ((s < s1) || (s > s2))
1051  {
1052  std::string msg = "BackwardDifferentiation15::printWaMPDEOutputSolution: ";
1053  msg += " Interpolator moved fast time block but new point is not in this block ";
1054  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
1055  }
1056  if (s > T2) break; // Just double checking...
1057  //blockTmpXn0APtr->block(b1) // x(t1,s1)
1058  //blockTmpXn0APtr->block(b2) // x(t1,s2)
1059  //blockTmpXn0BPtr->block(b1) // x(t2,s1)
1060  //blockTmpXn0BPtr->block(b2) // x(t2,s2)
1061  // (1/(t2-t1))(1/(s2-s1))[ x(t1,s1)(t2-t)(s2-s)
1062  // +x(t1,s2)(t2-t)(s-s1)
1063  // +x(t2,s1)(t-t1)(s2-s)
1064  // +x(t2,s2)(t-t1)(s-s1) ]
1065  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
1066  {
1067  Xyce::dout() << "Interpolating in the block:" << std::endl;
1068  Xyce::dout() << "(t1,t2) = (" << t1 << "," << t2 << ")" << std::endl;
1069  Xyce::dout() << "(s1,s2) = (" << s1 << "," << s2 << ")" << std::endl;
1070  }
1071 
1072  double denom = (t2-t1)*(s2-s1);
1073  double coeff0 = (t2-t)*(s2-s)/denom;
1074  double coeff1 = (t2-t)*(s-s1)/denom;
1075  double coeff2 = (t-t1)*(s2-s)/denom;
1076  double coeff3 = (t-t1)*(s-s1)/denom;
1077  (blockTmpSolVectorPtr->block(b1)).linearCombo(
1078  coeff0, blockTmpXn0APtr->block(b1),
1079  coeff1, blockTmpXn0APtr->block(b2),
1080  coeff2, blockTmpXn0BPtr->block(b1) );
1081  (blockTmpSolVectorPtr->block(b1)).update(
1082  coeff3, blockTmpXn0BPtr->block(b2), 1.0 );
1083 
1084  // erkeite 2/24/07. This is needed because currently the interpolation goes back to t=-1.0.
1085  if (t >= 0.0)
1086  {
1087  outputManagerAdapter.tranOutput(
1088  t, blockTmpSolVectorPtr->block(b1),
1092 
1093  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
1094  Xyce::dout() << "Interpolated to (t,phi(t)) = (" << t << "," << s << ")" << std::endl;
1095  }
1096  }
1097  }
1098 
1099  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
1100  Xyce::dout() << Xyce::section_divider << std::endl;
1101 
1102  return true;
1103 }
1104 
1105 //-----------------------------------------------------------------------------
1106 // Function : BackwardDifferentiation15::printOutputSolution()
1107 // Purpose : Print output that is dumbed down in order.
1108 // Special Notes : This routine picks smaller time steps to approximate first
1109 // : order integration from the perspective of the output.
1110 // Scope : public
1111 // Creator : Todd Coffey, SNL, 1414
1112 // Creation Date : 11/21/05
1113 //-----------------------------------------------------------------------------
1114 bool
1116  Analysis::OutputMgrAdapter & outputManagerAdapter,
1117  const TIAParams & tia_params,
1118  const double time,
1119  Linear::Vector * solnVecPtr,
1120  const bool doNotInterpolate,
1121  const std::vector<double> & outputInterpolationTimes,
1122  bool skipPrintLineOutput)
1123 {
1124  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
1125  {
1126  Xyce::dout() << std::endl;
1127  Xyce::dout() << Xyce::section_divider << std::endl;
1128  Xyce::dout() << " BackwardDifferentiation15::printOutputSolution" << std::endl;
1129  Xyce::dout() << "usedOrder_ = " << sec.usedOrder_ << std::endl;
1130  }
1131 
1132  double timestep = sec.lastAttemptedTimeStep;
1133  double lasttime = sec.currentTime - timestep;
1134  bool dointerp = true;
1135  double hh = timestep/(sec.usedOrder_);
1136  if (hh <= 10*sec.minTimeStep)
1137  {
1138  dointerp = false;
1139  }
1140 
1141  if (!tia_params.interpOutputFlag)
1142  {
1143  dointerp = false;
1144  }
1145 
1146  if (doNotInterpolate)
1147  {
1148  dointerp = false;
1149  }
1150 
1151  if (dointerp && !outputInterpolationTimes.empty())
1152  {
1153  for (unsigned int i=0;i<outputInterpolationTimes.size();++i)
1154  {
1155  interpolateSolution(outputInterpolationTimes[i], ds.tmpSolVectorPtr, ds.xHistory); // interpolate solution vector
1156  interpolateSolution(outputInterpolationTimes[i], ds.tmpStaVectorPtr, ds.sHistory); // interpolate state vector
1157  interpolateSolution(outputInterpolationTimes[i], ds.tmpStoVectorPtr, ds.stoHistory); // interpolate store vector
1158  interpolateSolution(outputInterpolationTimes[i], ds.tmpLeadCurrentVectorPtr, ds.leadCurrentHistory); // interpolate lead current vector
1159  interpolateSolution(outputInterpolationTimes[i], ds.tmpLeadDeltaVPtr, ds.leadDeltaVHistory); // interpolate junction voltage vector
1160  outputManagerAdapter.tranOutput(outputInterpolationTimes[i], *ds.tmpSolVectorPtr,
1164  skipPrintLineOutput);
1165  }
1166  }
1167  else if ( (sec.usedOrder_ > 2) && dointerp )
1168  {
1169  for (int i=1 ; i<sec.usedOrder_; ++i)
1170  {
1171  double timept = lasttime + hh*i;
1172  interpolateSolution(timept,ds.tmpSolVectorPtr, ds.xHistory); // interpolate solution vector
1173  interpolateSolution(timept,ds.tmpStaVectorPtr, ds.sHistory); // interpolate state vector
1174  interpolateSolution(timept,ds.tmpStoVectorPtr, ds.stoHistory); // interpolate store vector
1175  interpolateSolution(timept, ds.tmpLeadCurrentVectorPtr, ds.leadCurrentHistory); // interpolate lead current vector
1176  interpolateSolution(timept, ds.tmpLeadDeltaVPtr, ds.leadDeltaVHistory); // interpolate junction voltage vector
1177  outputManagerAdapter.tranOutput(timept, *ds.tmpSolVectorPtr,
1181  skipPrintLineOutput);
1182 
1183  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
1184  Xyce::dout() << "Interpolated to t = " << timept << std::endl;
1185  }
1186  }
1187 
1188  // Either way, do an output on the actual computed time step, but only
1189  // if we weren't given a list of specific times *or* we were told not to
1190  // interpoloate.
1191  if (outputInterpolationTimes.empty() || doNotInterpolate)
1192  outputManagerAdapter.tranOutput(time, *ds.currSolutionPtr,
1196  skipPrintLineOutput);
1197 
1198  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
1199  Xyce::dout() << Xyce::section_divider << std::endl;
1200 
1201  return true;
1202 }
1203 
1204 //-----------------------------------------------------------------------------
1205 // Function : BackwardDifferentiation15::saveOutputSolution
1206 // Purpose : This is similar to printOutputSolution, but is in support of
1207 // the .SAVE capability, rather than .PRINT.
1208 // Special Notes :
1209 // Scope : public
1210 // Creator : Eric Keiter, SNL
1211 // Creation Date : 10/21/07
1212 //-----------------------------------------------------------------------------
1213 bool
1215  Analysis::OutputMgrAdapter & outputManagerAdapter,
1216  const TIAParams & tia_params,
1217  Linear::Vector * solnVecPtr,
1218  const double saveTime,
1219  const bool doNotInterpolate)
1220 {
1221  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
1222  {
1223  Xyce::dout() << std::endl;
1224  Xyce::dout() << Xyce::section_divider << std::endl;
1225  Xyce::dout() << " BackwardDifferentiation15::saveOutputSolution" << std::endl;
1226  }
1227 
1228  double timestep = sec.lastAttemptedTimeStep;
1229  double lasttime = sec.currentTime - timestep;
1230  bool dointerp = true;
1231  double hh = timestep/(sec.usedOrder_);
1232  if (hh <= 10*sec.minTimeStep)
1233  {
1234  dointerp = false;
1235  }
1236 
1237  if (!tia_params.interpOutputFlag)
1238  {
1239  dointerp = false;
1240  }
1241 
1242  if (doNotInterpolate)
1243  {
1244  dointerp = false;
1245  }
1246 
1247  if (dointerp)
1248  {
1250  outputManagerAdapter.outputDCOP( *(ds.tmpSolVectorPtr) );
1251  }
1252  else
1253  {
1254  outputManagerAdapter.outputDCOP( *(solnVecPtr) );
1255  }
1256 
1257  if (DEBUG_TIME && isActive(Diag::TIME_OUTPUT))
1258  Xyce::dout() << Xyce::section_divider << std::endl;
1259 
1260  return true;
1261 }
1262 
1263 //-----------------------------------------------------------------------------
1264 // IDA source license:
1265 //-----------------------------------------------------------------------------
1266 // Copyright (c) 2002, The Regents of the University of California.
1267 // Produced at the Lawrence Livermore National Laboratory.
1268 // Written by Alan Hindmarsh, Allan Taylor, Radu Serban.
1269 // UCRL-CODE-2002-59
1270 // All rights reserved.
1271 //
1272 // This file is part of IDA.
1273 //
1274 // Redistribution and use in source and binary forms, with or without
1275 // modification, are permitted provided that the following conditions
1276 // are met:
1277 //
1278 // 1. Redistributions of source code must retain the above copyright
1279 // notice, this list of conditions and the disclaimer below.
1280 //
1281 // 2. Redistributions in binary form must reproduce the above copyright
1282 // notice, this list of conditions and the disclaimer (as noted below)
1283 // in the documentation and/or other materials provided with the
1284 // distribution.
1285 //
1286 // 3. Neither the name of the UC/LLNL nor the names of its contributors
1287 // may be used to endorse or promote products derived from this software
1288 // without specific prior written permission.
1289 //
1290 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1291 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1292 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
1293 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
1294 // REGENTS OF THE UNIVERSITY OF CALIFORNIA, THE U.S. DEPARTMENT OF ENERGY
1295 // OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1296 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
1297 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1298 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
1299 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1300 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
1301 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1302 //
1303 // Additional BSD Notice
1304 // ---------------------
1305 // 1. This notice is required to be provided under our contract with
1306 // the U.S. Department of Energy (DOE). This work was produced at the
1307 // University of California, Lawrence Livermore National Laboratory
1308 // under Contract No. W-7405-ENG-48 with the DOE.
1309 //
1310 // 2. Neither the United States Government nor the University of
1311 // California nor any of their employees, makes any warranty, express
1312 // or implied, or assumes any liability or responsibility for the
1313 // accuracy, completeness, or usefulness of any information, apparatus,
1314 // product, or process disclosed, or represents that its use would not
1315 // infringe privately-owned rights.
1316 //
1317 // 3. Also, reference herein to any specific commercial products,
1318 // process, or services by trade name, trademark, manufacturer or
1319 // otherwise does not necessarily constitute or imply its endorsement,
1320 // recommendation, or favoring by the United States Government or the
1321 // University of California. The views and opinions of authors expressed
1322 // herein do not necessarily state or reflect those of the United States
1323 // Government or the University of California, and shall not be used for
1324 // advertising or product endorsement purposes.
1325 //-----------------------------------------------------------------------------
1326 
1327 
1328 //-----------------------------------------------------------------------------
1329 // Function : BackwardDifferentiation15::updateHistory
1330 // Purpose : Update history array after a successful step
1331 // Special Notes :
1332 // Scope : public
1333 // Creator : Todd Coffey, SNL
1334 // Creation Date : 03/08/04
1335 //-----------------------------------------------------------------------------
1337 {
1338 
1339  if (DEBUG_TIME && isActive(Diag::TIME_HISTORY))
1340  {
1341  Xyce::dout() << std::endl;
1342  Xyce::dout() << Xyce::section_divider << std::endl;
1343  Xyce::dout() <<
1344  " BackwardDifferentiation15::updateHistory" << std::endl;
1345  Xyce::dout() << "\n Before updates \n" << std::endl;
1346  for (int i=0; i<=sec.maxOrder_ ; ++i)
1347  {
1348  Xyce::dout() << "\n xHistory["<< i << "]: \n" << std::endl;
1349  (ds.xHistory[i])->printPetraObject(Xyce::dout());
1350  Xyce::dout() << std::endl;
1351  }
1352  for (int i=0; i<=sec.maxOrder_ ; ++i)
1353  {
1354  Xyce::dout() << "\n qHistory["<< i << "]: \n" << std::endl;
1355  (ds.qHistory[i])->printPetraObject(Xyce::dout());
1356  Xyce::dout() << std::endl;
1357  }
1358  for (int i=0; i<=sec.maxOrder_ ; ++i)
1359  {
1360  Xyce::dout() << "\n sHistory["<< i << "]: \n" << std::endl;
1361  (ds.sHistory[i])->printPetraObject(Xyce::dout());
1362  Xyce::dout() << std::endl;
1363  }
1364  Xyce::dout() << Xyce::section_divider << std::endl;
1365  }
1366 
1367  // Save Newton correction for potential order increase on next step.
1368  if (sec.usedOrder_ < sec.maxOrder_)
1369  {
1372  }
1373  (ds.xHistory[sec.usedOrder_])->linearCombo(1.0,*(ds.xHistory[sec.usedOrder_]),1.0,*ds.newtonCorrectionPtr);
1374  (ds.qHistory[sec.usedOrder_])->linearCombo(1.0,*(ds.qHistory[sec.usedOrder_]),1.0,*ds.qNewtonCorrectionPtr);
1375  for (int j=sec.usedOrder_-1;j>=0;j--)
1376  {
1377  (ds.xHistory[j])->linearCombo(1.0,*(ds.xHistory[j]),1.0,*(ds.xHistory[j+1]));
1378  (ds.qHistory[j])->linearCombo(1.0,*(ds.qHistory[j]),1.0,*(ds.qHistory[j+1]));
1379  }
1380 
1381  if (sec.usedOrder_ < sec.maxOrder_)
1382  {
1384  }
1385  (ds.sHistory[sec.usedOrder_])->linearCombo(1.0,*(ds.sHistory[sec.usedOrder_]),1.0,*ds.sNewtonCorrectionPtr);
1386  for (int j=sec.usedOrder_-1;j>=0;j--)
1387  {
1388  (ds.sHistory[j])->linearCombo(1.0,*(ds.sHistory[j]),1.0,*(ds.sHistory[j+1]));
1389  }
1390 
1391  // Update Store History
1392  if (sec.usedOrder_ < sec.maxOrder_)
1393  {
1396  }
1399  for (int j=sec.usedOrder_-1;j>=0;j--)
1400  {
1401  (ds.stoHistory[j])->linearCombo(1.0,*(ds.stoHistory[j]),1.0,*(ds.stoHistory[j+1]));
1402  (ds.stoLeadCurrQHistory[j])->linearCombo(1.0,*(ds.stoLeadCurrQHistory[j]),1.0,*(ds.stoLeadCurrQHistory[j+1]));
1403  }
1404 
1405  // Update lead currenti and junction voltage History
1406  if (sec.usedOrder_ < sec.maxOrder_)
1407  {
1411  }
1415 
1416 
1417  for (int j=sec.usedOrder_-1;j>=0;j--)
1418  {
1419  (ds.leadCurrentHistory[j])->linearCombo(1.0,*(ds.leadCurrentHistory[j]),1.0,*(ds.leadCurrentHistory[j+1]));
1420  (ds.leadCurrentQHistory[j])->linearCombo(1.0,*(ds.leadCurrentQHistory[j]),1.0,*(ds.leadCurrentQHistory[j+1]));
1421  (ds.leadDeltaVHistory[j])->linearCombo(1.0,*(ds.leadDeltaVHistory[j]),1.0,*(ds.leadDeltaVHistory[j+1]));
1422  }
1423 
1424  if (DEBUG_TIME && isActive(Diag::TIME_HISTORY))
1425  {
1426  Xyce::dout() << "\n After updates \n" << std::endl;
1427  Xyce::dout() << "\n newtonCorrectionPtr: " << std::endl;
1428  ds.newtonCorrectionPtr->printPetraObject(Xyce::dout());
1429  Xyce::dout() << "\n qnewtonCorrectionPtr: " << std::endl;
1430  ds.qNewtonCorrectionPtr->printPetraObject(Xyce::dout());
1431  for (int i=0; i<=sec.maxOrder_ ; ++i)
1432  {
1433  Xyce::dout() << "\n xHistory["<< i << "]: \n" << std::endl;
1434  (ds.xHistory[i])->printPetraObject(Xyce::dout());
1435  Xyce::dout() << std::endl;
1436  }
1437  for (int i=0; i<=sec.maxOrder_ ; ++i)
1438  {
1439  Xyce::dout() << "\n qHistory["<< i << "]: \n" << std::endl;
1440  (ds.qHistory[i])->printPetraObject(Xyce::dout());
1441  Xyce::dout() << std::endl;
1442  }
1443  Xyce::dout() << "\n sNewtonCorrectionPtr: " << std::endl;
1444  ds.sNewtonCorrectionPtr->printPetraObject(Xyce::dout());
1445  Xyce::dout() << std::endl;
1446  Xyce::dout() << "\n nextStatePtr: " << std::endl;
1447  ds.nextStatePtr->printPetraObject(Xyce::dout());
1448  Xyce::dout() << std::endl;
1449  for (int i=0; i<=sec.maxOrder_ ; ++i)
1450  {
1451  Xyce::dout() << "\n sHistory["<< i << "]: \n" << std::endl;
1452  (ds.sHistory[i])->printPetraObject(Xyce::dout());
1453  Xyce::dout() << std::endl;
1454  }
1455  Xyce::dout() << Xyce::section_divider << std::endl;
1456  }
1457 }
1458 
1459 //-----------------------------------------------------------------------------
1460 // Function : BackwardDifferentiation15::restoreHistory
1461 // Purpose : Restore history array after a failed step
1462 // Special Notes :
1463 // Scope : public
1464 // Creator : Todd Coffey, SNL
1465 // Creation Date : 03/08/04
1466 //-----------------------------------------------------------------------------
1468 {
1469  // undo preparation of history array for prediction
1470  for (int i=sec.nscsco_;i<=sec.currentOrder_;++i)
1471  {
1472  (ds.xHistory[i])->scale(1/sec.beta_[i]);
1473  (ds.qHistory[i])->scale(1/sec.beta_[i]);
1474  (ds.sHistory[i])->scale(1/sec.beta_[i]);
1475  (ds.stoHistory[i])->scale(1/sec.beta_[i]);
1476  (ds.leadCurrentHistory[i])->scale(1/sec.beta_[i]);
1477  (ds.leadDeltaVHistory[i])->scale(1/sec.beta_[i]);
1478  }
1479  for (int i=1;i<=sec.currentOrder_;++i)
1480  {
1481  sec.psi_[i-1] = sec.psi_[i] - (sec.currentTimeStep);
1482  }
1483  if (DEBUG_TIME && isActive(Diag::TIME_HISTORY))
1484  {
1485  Xyce::dout() << std::endl;
1486  Xyce::dout() << Xyce::section_divider << std::endl;
1487  Xyce::dout() <<
1488  " BackwardDifferentiation15::restoreHistory" << std::endl;
1489  for (int i=1;i<=sec.currentOrder_;++i)
1490  Xyce::dout() << "\n sec.psi_[i] = " << sec.psi_[i] << std::endl;
1491  for (int i=0; i<=sec.maxOrder_ ; ++i)
1492  {
1493  Xyce::dout() << "\n xHistory["<< i << "]: \n" << std::endl;
1494  (ds.xHistory[i])->printPetraObject(Xyce::dout());
1495  Xyce::dout() << std::endl;
1496  }
1497  for (int i=0; i<=sec.maxOrder_ ; ++i)
1498  {
1499  Xyce::dout() << "\n qHistory["<< i << "]: \n" << std::endl;
1500  (ds.qHistory[i])->printPetraObject(Xyce::dout());
1501  Xyce::dout() << std::endl;
1502  }
1503  for (int i=0; i<=sec.maxOrder_ ; ++i)
1504  {
1505  Xyce::dout() << "\n sHistory["<< i << "]: \n" << std::endl;
1506  (ds.sHistory[i])->printPetraObject(Xyce::dout());
1507  Xyce::dout() << std::endl;
1508  }
1509  Xyce::dout() << Xyce::section_divider << std::endl;
1510  }
1511 }
1512 
1513 //-----------------------------------------------------------------------------
1514 // Function : BackwardDifferentiation15::updateCoeffs
1515 // Purpose : Update method coefficients
1516 // Special Notes :
1517 // Scope : public
1518 // Creator : Todd Coffey, SNL
1519 // Creation Date : 03/08/04
1520 //-----------------------------------------------------------------------------
1522 {
1523  // synchronize with Step Error Control
1524 // sec.psi_[0] = sec.currentTimeStep;
1525  if (DEBUG_TIME && isActive(Diag::TIME_COEFFICIENTS))
1526  {
1527  Xyce::dout() << std::endl;
1528  Xyce::dout() << Xyce::section_divider << std::endl;
1529  Xyce::dout() << " BackwardDifferentiation15::updateCoeffs" << std::endl;
1530  Xyce::dout() << " currentTimeStep = " << sec.currentTimeStep << std::endl;
1531  Xyce::dout() << " numberOfSteps_ = " << sec.numberOfSteps_ << std::endl;
1532  Xyce::dout() << " currentOrder_ = " << sec.currentOrder_ << std::endl;
1533  Xyce::dout() << " nscsco_ = " << sec.nscsco_ << std::endl;
1534  Xyce::dout() << " psi_[0] = " << sec.psi_[0] << std::endl;
1535  }
1536 
1537  // If the number of steps taken with constant order and constant stepsize is
1538  // more than the current order + 1 then we don't bother to update the
1539  // coefficients because we've reached a constant step-size formula. When
1540  // this is is not true, then we update the coefficients for the variable
1541  // step-sizes.
1543  sec.nscsco_ = 0;
1544  sec.nscsco_ = std::min(sec.nscsco_+1,sec.usedOrder_+2);
1545  if (sec.currentOrder_+1 >= sec.nscsco_)
1546  {
1547  sec.beta_[0] = 1.0;
1548  sec.alpha_[0] = 1.0;
1549  double temp1 = sec.currentTimeStep;
1550  sec.sigma_[0] = 1.0;
1551  sec.gamma_[0] = 0.0;
1552  for (int i=1;i<=sec.currentOrder_;++i)
1553  {
1554  double temp2 = sec.psi_[i-1];
1555  sec.psi_[i-1] = temp1;
1556  sec.beta_[i] = sec.beta_[i-1]*sec.psi_[i-1]/temp2;
1557  temp1 = temp2 + sec.currentTimeStep;
1558  sec.alpha_[i] = (sec.currentTimeStep)/temp1;
1559  sec.sigma_[i] = (i+1)*sec.sigma_[i-1]*sec.alpha_[i];
1560  sec.gamma_[i] = sec.gamma_[i-1]+sec.alpha_[i-1]/(sec.currentTimeStep);
1561  }
1562  sec.psi_[sec.currentOrder_] = temp1;
1563  sec.alphas_ = 0.0;
1564  sec.alpha0_ = 0.0;
1565  for (int i=0;i<sec.currentOrder_;++i)
1566  {
1567  sec.alphas_ = sec.alphas_ - 1.0/(i+1.0);
1568  sec.alpha0_ = sec.alpha0_ - sec.alpha_[i];
1569  }
1572  sec.ck_ = std::max(sec.ck_,sec.alpha_[sec.currentOrder_]);
1573  }
1574  if (DEBUG_TIME && isActive(Diag::TIME_COEFFICIENTS))
1575  {
1576  Xyce::dout() << " nscsco_ = " << sec.nscsco_ << std::endl;
1577  Xyce::dout() << " beta_[0] = " << sec.beta_[0] << std::endl;
1578  Xyce::dout() << " beta_[1] = " << sec.beta_[1] << std::endl;
1579  Xyce::dout() << " beta_[2] = " << sec.beta_[2] << std::endl;
1580  Xyce::dout() << " beta_[3] = " << sec.beta_[3] << std::endl;
1581  Xyce::dout() << " beta_[4] = " << sec.beta_[4] << std::endl;
1582  Xyce::dout() << " alpha_[0] = " << sec.alpha_[0] << std::endl;
1583  Xyce::dout() << " alpha_[1] = " << sec.alpha_[1] << std::endl;
1584  Xyce::dout() << " alpha_[2] = " << sec.alpha_[2] << std::endl;
1585  Xyce::dout() << " alpha_[3] = " << sec.alpha_[3] << std::endl;
1586  Xyce::dout() << " alpha_[4] = " << sec.alpha_[4] << std::endl;
1587  Xyce::dout() << " alphas_ = " << sec.alphas_ << std::endl;
1588  Xyce::dout() << " alpha0_ = " << sec.alpha0_ << std::endl;
1589  Xyce::dout() << " gamma_[0] = " << sec.gamma_[0] << std::endl;
1590  Xyce::dout() << " gamma_[1] = " << sec.gamma_[1] << std::endl;
1591  Xyce::dout() << " gamma_[2] = " << sec.gamma_[2] << std::endl;
1592  Xyce::dout() << " gamma_[3] = " << sec.gamma_[3] << std::endl;
1593  Xyce::dout() << " gamma_[4] = " << sec.gamma_[4] << std::endl;
1594  Xyce::dout() << " psi_[0] = " << sec.psi_[0] << std::endl;
1595  Xyce::dout() << " psi_[1] = " << sec.psi_[1] << std::endl;
1596  Xyce::dout() << " psi_[2] = " << sec.psi_[2] << std::endl;
1597  Xyce::dout() << " psi_[3] = " << sec.psi_[3] << std::endl;
1598  Xyce::dout() << " psi_[4] = " << sec.psi_[4] << std::endl;
1599  Xyce::dout() << " sigma_[0] = " << sec.sigma_[0] << std::endl;
1600  Xyce::dout() << " sigma_[1] = " << sec.sigma_[1] << std::endl;
1601  Xyce::dout() << " sigma_[2] = " << sec.sigma_[2] << std::endl;
1602  Xyce::dout() << " sigma_[3] = " << sec.sigma_[3] << std::endl;
1603  Xyce::dout() << " sigma_[4] = " << sec.sigma_[4] << std::endl;
1604  Xyce::dout() << " ck_ = " << sec.ck_ << std::endl;
1605  Xyce::dout() << Xyce::section_divider << std::endl;
1606  }
1607 }
1608 
1609 //-----------------------------------------------------------------------------
1610 // Function : BackwardDifferentiation15::initialize
1611 // Purpose : Initialize method with initial solution & step-size
1612 // Special Notes :
1613 // Scope : public
1614 // Creator : Todd Coffey, SNL
1615 // Creation Date : 3/09/04
1616 //-----------------------------------------------------------------------------
1617 void
1619  const TIAParams & tia_params)
1620 {
1621  // we assume the solution vector is available here
1622  // Note that I'm using currSolutionPtr instead of
1623  // nextSolutionPtr because this is the first step.
1624 
1625  // Update next stop time from StepErrorControl:
1626  // ERK. Commenting this out, as it is already called from Analysis::AnalysisManager,
1627  // right before this initialize call. It should not be called 2x, as
1628  // it is history dependent (unfortunately), so calling it 2x in a row changes
1629  // the stop time to a different number.
1630  // sec.updateStopTime();
1631 
1632  // Choose initial step-size
1633  double time_to_stop = sec.stopTime - sec.currentTime;
1634  double currentTimeStep;
1635  if (tia_params.constantTimeStepFlag)
1636  {
1637  currentTimeStep = 0.1 * time_to_stop;
1638  currentTimeStep = std::min(sec.startingTimeStep, currentTimeStep);
1639  sec.currentTimeStep = currentTimeStep;
1640  }
1641  else
1642  {
1643  // compute an initial step-size based on rate of change in the
1644  // solution initially
1645 #ifdef Xyce_INCOMPLETE_2LEVEL_NORMS
1646  double dnorm_q = 0.0;
1647  (ds.qHistory[1])->wRMSNorm(*ds.qErrWtVecPtr, &dnorm_q);
1648 #else
1649  double dnorm_q = ds.delta_x_errorNorm_q1();
1650 #endif
1651  if (dnorm_q > 0.0) // time-dependent DAE
1652  {
1653  currentTimeStep = std::min(sec.h0_max_factor_*std::abs(time_to_stop),sqrt(2.0)/(sec.h0_safety_*dnorm_q));
1654  }
1655  else // non-time-dependent DAE
1656  {
1657  currentTimeStep = sec.h0_max_factor_*std::abs(time_to_stop);
1658  }
1659  // choose min of user specified value and our value:
1660  if (sec.startingTimeStep > 0.0)
1661  currentTimeStep = std::min(sec.startingTimeStep, currentTimeStep);
1662  // check for maximum step-size:
1663  double rh = std::abs(currentTimeStep)*sec.h_max_inv_;
1664  if (rh>1.0) currentTimeStep = currentTimeStep/rh;
1665 
1666 
1667  // Apply this new stepsize only if it is smaller than the one preceding
1668  // the breakpoint, but only do this if this is a non-DCOP breakpoint.
1669  if (sec.currentTime != sec.initialTime) // if not DCOP:
1670  {
1671  sec.currentTimeStep = std::min(sec.lastTimeStep, currentTimeStep);
1672  }
1673  else // else if DCOP:
1674  {
1675  sec.currentTimeStep = currentTimeStep;
1676  }
1677  }
1678 
1679  sec.currentTimeStepRatio = 1.0;
1681 
1685 
1687  sec.stepAttemptStatus = true;
1688 
1689 // sec.tolAimFac_ = 0.5;
1690 
1692 
1693  // x history
1694  *(ds.xHistory[0]) = *(ds.currSolutionPtr);
1695  (ds.xHistory[1])->putScalar(0.0); // no need to multiply by dt here
1696 
1697  // q history
1698  *(ds.qHistory[0]) = *(ds.daeQVectorPtr);
1699  *(ds.qHistory[1]) = *(ds.daeFVectorPtr);
1700  (ds.qHistory[1])->scale(-sec.currentTimeStep);
1701 
1702  // state history
1703  *(ds.sHistory[0]) = *(ds.currStatePtr);
1704  (ds.sHistory[1])->putScalar(0.0);
1705 
1706  // store history
1707  *(ds.stoHistory[0]) = *(ds.currStorePtr);
1708  (ds.stoHistory[1])->putScalar(0.0);
1709 
1710  // lead current Q compontent history
1712  (ds.stoLeadCurrQHistory[1])->putScalar(0.0);
1713 
1714  // lead current and junction voltage history
1716  (ds.leadCurrentHistory[1])->putScalar(0.0);
1717 
1719  (ds.leadCurrentQHistory[1])->putScalar(0.0);
1720 
1722  (ds.leadDeltaVHistory[1])->putScalar(0.0);
1723 
1724  // Coefficient initialization
1725  sec.numberOfSteps_ = 0; // number of total time integration steps taken
1726  sec.currentOrder_ = 1;
1727  sec.usedOrder_ = 1;
1728  sec.psi_[0] = sec.currentTimeStep;
1729  sec.cj_ = 1/sec.psi_[0];
1730  sec.nscsco_ = 0;
1731  if (DEBUG_TIME &&isActive(Diag::TIME_HISTORY))
1732  {
1733  Xyce::dout() << std::endl;
1734  Xyce::dout() << Xyce::section_divider << std::endl;
1735  Xyce::dout() << " BackwardDifferentiation15::initialize" << std::endl;
1736  Xyce::dout() << "\n xHistory: \n" << std::endl;
1737  (ds.xHistory[0])->printPetraObject(Xyce::dout());
1738  Xyce::dout() << std::endl;
1739  (ds.xHistory[1])->printPetraObject(Xyce::dout());
1740  Xyce::dout() << std::endl;
1741  Xyce::dout() << "\n qHistory: \n" << std::endl;
1742  (ds.qHistory[0])->printPetraObject(Xyce::dout()); // lead current and junction voltage history
1743  Xyce::dout() << std::endl;
1744  (ds.qHistory[1])->printPetraObject(Xyce::dout());
1745  Xyce::dout() << std::endl;
1746  Xyce::dout() << "\n sHistory: \n" << std::endl;
1747  (ds.sHistory[0])->printPetraObject(Xyce::dout());
1748  Xyce::dout() << std::endl;
1749  (ds.sHistory[1])->printPetraObject(Xyce::dout());
1750  Xyce::dout() << std::endl;
1751  Xyce::dout() << "\n" << "currentTimeStep = " << currentTimeStep << "\n" << std::endl;
1752  Xyce::dout() << "\n" << "time_to_stop = " << time_to_stop << "\n" << std::endl;
1753  Xyce::dout() << Xyce::section_divider << std::endl;
1754  }
1755 }
1756 
1757 //-----------------------------------------------------------------------------
1758 // Function : BackwardDifferentiation15::setTwoLevelTimeInfo
1759 // Purpose :
1760 // Special Notes :
1761 // Scope : public
1762 // Creator : Eric Keiter, SNL
1763 // Creation Date : 03/01/07
1764 //-----------------------------------------------------------------------------
1766  (const TimeIntInfo & tiInfo)
1767 {
1768  // set initial step-size
1769  double time_to_stop = sec.stopTime - sec.currentTime;
1770 
1771 
1772  // x history
1773  *(ds.xHistory[0]) = *(ds.currSolutionPtr);
1774  (ds.xHistory[1])->putScalar(0.0); // no need to multiply by dt here
1775 
1776  // q history
1777  *(ds.qHistory[0]) = *(ds.daeQVectorPtr);
1778  *(ds.qHistory[1]) = *(ds.daeFVectorPtr);
1779  (ds.qHistory[1])->scale(-sec.currentTimeStep);
1780 
1781  // state history
1782  *(ds.sHistory[0]) = *(ds.nextStatePtr);
1783  (ds.sHistory[1])->putScalar(0.0);
1784 
1785  // store history
1786  *(ds.stoHistory[0]) = *(ds.nextStatePtr);
1787  (ds.stoHistory[1])->putScalar(0.0);
1788 
1789  // lead current Q compontent history
1790  *(ds.stoLeadCurrQHistory[0]) = *(ds.nextStoreLeadCurrQPtr);
1791  (ds.stoLeadCurrQHistory[1])->putScalar(0.0);
1792 
1793  // lead current and junction voltage history
1794  *(ds.leadCurrentHistory[0]) = *(ds.currLeadCurrentPtr);
1795  (ds.leadCurrentHistory[1])->putScalar(0.0);
1796 
1797  *(ds.leadCurrentQHistory[0]) = *(ds.currLeadCurrentQPtr);
1798  (ds.leadCurrentQHistory[1])->putScalar(0.0);
1799 
1800  *(ds.leadDeltaVHistory[0]) = *(ds.currLeadDeltaVPtr);
1801  (ds.leadDeltaVHistory[1])->putScalar(0.0);
1802 
1803  // Coefficient initialization
1804  sec.numberOfSteps_ = 0; // number of total time integration steps taken
1805  sec.usedOrder_ = 1;
1806  sec.psi_[0] = sec.currentTimeStep;
1807  sec.cj_ = 1/sec.psi_[0];
1808  sec.nscsco_ = 0;
1809 
1810 }
1811 
1812 
1813 //-----------------------------------------------------------------------------
1814 // Function : BackwardDifferentiation15::checkReduceOrder()
1815 // Purpose : check whether to reduce order independent of local error test
1816 // Special Notes :
1817 // Scope : public
1818 // Creator : Todd Coffey, SNL
1819 // Creation Date : 06/08/04
1820 //-----------------------------------------------------------------------------
1822 {
1823 
1824 // This routine puts its output in sec.newOrder_
1825 
1826 // This routine changes the following variables:
1827 // sec.Ek_, sec.Tk_, sec.Est_, sec.newOrder_, ds.delta_x, ds.delta_q,
1828 // sec.Ekm1_, sec.Tkm1_, sec.Ekm2_, sec.Tkm2_
1829 
1830 // This routine reads but does not change the following variables:
1831 // sec.currentOrder_, sec.sigma_, ds.newtonCorrectionPtr, ds.qNewtonCorrectionPtr,
1832 // ds.errWtVecPtr, ds.qErrWtVecPtr, ds.xHistory, ds.qHistory
1833 
1834  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
1835  {
1836  Xyce::dout() << std::endl;
1837  Xyce::dout() << Xyce::section_divider << std::endl;
1838  Xyce::dout() << " BackwardDifferentiation15::checkReduceOrder" << std::endl;
1839  }
1840 
1841  // 03/11/04 tscoffe: I only want to run this block after a step has been
1842  // attempted, but I want to do this regardless of the status from the local
1843  // error test.
1844  // 03/10/04 tscoffe: Decide whether to reduce the order before considering
1845  // the local error test result.
1846 #ifndef Xyce_USE_Q_NORM
1847  //double dnorm_x = 0.0;
1848  //ds.newtonCorrectionPtr->wRMSNorm(&dnorm_x); // delta = newtonCorrection
1849  //double dnorm_x *= sec.ck_;
1850  //double dnorm = dnorm_x;
1851  double dnorm_x = sec.estOverTol_;
1852  double dnorm = dnorm_x;
1853 #else
1854  double dnorm_x = 0.0, dnorm_q = 0.0;
1855  ds.newtonCorrectionPtr->wRMSNorm(*ds.errWtVecPtr, &dnorm_x); // delta = newtonCorrection
1856  ds.qNewtonCorrectionPtr->wRMSNorm(*ds.qErrWtVecPtr, &dnorm_q); // dnorm = norm of delta
1857  double dnorm = sqrt(0.5*dnorm_x*dnorm_x+0.5*dnorm_q*dnorm_q);
1858 #endif
1859 
1860  sec.Ek_ = sec.sigma_[sec.currentOrder_]*dnorm;
1861  sec.Tk_ = (sec.currentOrder_+1)*sec.Ek_;
1862  sec.Est_ = sec.Ek_;
1864  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
1865  {
1866  Xyce::dout() << " Est_= " << sec.Est_ << std::endl;
1867  Xyce::dout() << " Ek_= " << sec.Ek_ << std::endl;
1868  Xyce::dout() << " dnorm = " << dnorm << std::endl;
1869  Xyce::dout() << " sigma[order] = " << sec.sigma_[sec.currentOrder_] << std::endl;
1870  Xyce::dout() << " Tk_= " << sec.Tk_ << std::endl;
1871  }
1872 
1873  if (sec.currentOrder_>1)
1874  {
1875 
1876 #ifndef Xyce_USE_Q_NORM
1877  ds.delta_x->linearCombo(1.0,*(ds.xHistory[sec.currentOrder_]),1.0,*ds.newtonCorrectionPtr);
1878 #ifdef Xyce_INCOMPLETE_2LEVEL_NORMS
1879  ds.delta_x->wRMSNorm(*ds.errWtVecPtr, &dnorm_x);
1880  dnorm_x *= sec.ck_;
1881 #else
1882  dnorm_x = sec.ck_ * ds.delta_x_errorNorm_m1();
1883 #endif
1884  dnorm = dnorm_x;
1885 #else
1886  ds.delta_x->linearCombo(1.0,*(ds.xHistory[sec.currentOrder_]),1.0,*ds.newtonCorrectionPtr);
1887  ds.delta_q->linearCombo(1.0,*(ds.qHistory[sec.currentOrder_]),1.0,*ds.qNewtonCorrectionPtr);
1888  ds.delta_x->wRMSNorm(*ds.errWtVecPtr, &dnorm_x);
1889  ds.delta_q->wRMSNorm(*ds.qErrWtVecPtr, &dnorm_q);
1890  dnorm = sqrt(0.5*dnorm_x*dnorm_x+0.5*dnorm_q*dnorm_q);
1891 #endif
1892 
1893  sec.Ekm1_ = sec.sigma_[sec.currentOrder_-1]*dnorm;
1895  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
1896  {
1897  Xyce::dout() << " Ekm1_= " << sec.Ekm1_ << std::endl;
1898  Xyce::dout() << " Tkm1_= " << sec.Tkm1_ << std::endl;
1899  }
1900 
1901  if (sec.currentOrder_>2)
1902  {
1903 #ifndef Xyce_USE_Q_NORM
1904  ds.delta_x->linearCombo(1.0,*(ds.xHistory[sec.currentOrder_-1]),1.0,*ds.delta_x);
1905 #ifdef Xyce_INCOMPLETE_2LEVEL_NORMS
1906  ds.delta_x->wRMSNorm(*ds.errWtVecPtr, &dnorm_x);
1907  dnorm_x *= sec.ck_;
1908 #else
1909  dnorm_x = sec.ck_ * ds.delta_x_errorNorm_m2();
1910 #endif
1911  dnorm = dnorm_x;
1912 #else
1913  ds.delta_x->linearCombo(1.0,*(ds.xHistory[sec.currentOrder_-1]),1.0,*ds.delta_x);
1914  ds.delta_q->linearCombo(1.0,*(ds.qHistory[sec.currentOrder_-1]),1.0,*ds.delta_q);
1915  ds.delta_x->wRMSNorm(*ds.errWtVecPtr, &dnorm_x);
1916  ds.delta_q->wRMSNorm(*ds.qErrWtVecPtr, &dnorm_q);
1917  dnorm = sqrt(0.5*dnorm_x*dnorm_x+0.5*dnorm_q*dnorm_q);
1918 #endif
1919 
1920  sec.Ekm2_ = sec.sigma_[sec.currentOrder_-2]*dnorm;
1922  if (std::max(sec.Tkm1_,sec.Tkm2_)<=sec.Tk_)
1923  {
1924  sec.newOrder_--;
1925  sec.Est_ = sec.Ekm1_;
1926  }
1927  }
1928  else if (sec.Tkm1_ <= sec.Tkm1_Tk_safety_ * sec.Tk_)
1929  {
1930  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
1931  {
1932  Xyce::dout() << " Tkm1_Tk_safety= " << sec.Tkm1_Tk_safety_ << std::endl;
1933  Xyce::dout() << " Tkm1_= " << sec.Tkm1_ << std::endl;
1934  Xyce::dout() << " Tk_= " << sec.Tk_ << std::endl;
1935  Xyce::dout() << " Tk_*safety= " << sec.Tk_*sec.Tkm1_Tk_safety_ << std::endl;
1936  }
1937 
1938  sec.newOrder_--;
1939  sec.Est_ = sec.Ekm1_;
1940  }
1941  }
1942  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
1943  {
1944  Xyce::dout() << " newOrder = " << sec.newOrder_ << std::endl;
1945  Xyce::dout() << Xyce::section_divider << std::endl;
1946  }
1947 }
1948 
1949 //-----------------------------------------------------------------------------
1950 // Function : BackwardDifferentiation15::rejectStep()
1951 // Purpose : code to restore history, choose new order/step-size
1952 // Special Notes :
1953 // Scope : public
1954 // Creator : Todd Coffey, SNL
1955 // Creation Date : 06/07/04
1956 //-----------------------------------------------------------------------------
1957 void
1959  const TIAParams & tia_params)
1960 {
1961 // This routine puts its output in newTimeStep_ and sec.newOrder_
1962 
1963 // This routine changes the following variables:
1964 // lastAttemptedTimeStep, sec.initialPhase_, sec.nef_, sec.psi_, newTimeStep_,
1965 // sec.newOrder_, sec.currentOrder_, currentTimeStep_, ds.xHistory,
1966 // ds.qHistory, nextTimePt, nextTime, currentTimeStepRatio,
1967 // currentTimeStepSum, nextTimePt
1968 
1969 // This routine reades but does not change the following variables:
1970 // stepAttemptStatus, sec.r_factor_, sec.r_safety_, sec.Est_, sec.r_fudge_, sec.r_min_, sec.r_max_,
1971 // minTimeStep, maxTimeStep, currentTime, stopTime, lastTimeStep
1972 
1973  // First we decide if we'll reduce the order independent of the local error test:
1974  checkReduceOrder();
1975 
1976  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
1977  {
1978  Xyce::dout() << std::endl;
1979  Xyce::dout() << Xyce::section_divider << std::endl;
1980  Xyce::dout() << " BackwardDifferentiation15::rejectStep" << std::endl;
1981  }
1982 
1983  // Only update the time step if we are NOT running constant stepsize.
1984  bool adjustStep = !tia_params.constantTimeStepFlag;
1985 
1987 
1988  double newTimeStep_ = sec.currentTimeStep;
1989  double rr = 1.0; // step size ratio = new step / old step
1990  if ((sec.stepAttemptStatus == false) && (adjustStep))
1991  {
1992  sec.initialPhase_ = false;
1993  sec.nef_++;
1994  restoreHistory();
1995 
1996  if ((sec.newtonConvergenceStatus <= 0))
1997  {
1998  /// 11/11/05 erkeite: If the Newton solver fails, don't
1999  // rely on the error estimate - it may be full of Nan's.
2000  rr = sec.r_min_;
2001  newTimeStep_ = rr * sec.currentTimeStep;
2002 
2003  if (sec.nef_ > 2) sec.newOrder_ = 1;//consistent with block below.
2004  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
2005  Xyce::dout() << "rejectStep 1" << std::endl;
2006  }
2007  else
2008  {
2009  // 03/11/04 tscoffe: Here is the block for choosing order &
2010  // step-size when the local error test FAILS (but Newton
2011  // succeeded).
2012  if (sec.nef_ == 1) // first local error test failure
2013  {
2014 #ifndef Xyce_USE_Q_NORM
2015  rr = sec.r_factor_*pow(sec.r_safety_*(sec.Est_+sec.r_fudge_),-1.0/(sec.newOrder_+1.0));
2016  rr = std::max(sec.r_min_,std::min(sec.r_max_,rr));
2017 #else
2018  rr = sec.r_factor_*pow(sec.r_safety_*sec.Est_+sec.r_fudge_,-1.0/(sec.newOrder_+1.0));
2019  rr = Xycemax(sec.r_min_,Xycemin(sec.r_max_,rr));
2020 #endif
2021  newTimeStep_ = rr * sec.currentTimeStep;
2022  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
2023  Xyce::dout() << "rejectStep 2" << std::endl;
2024  }
2025  else if (sec.nef_ == 2) // second Dae failure
2026  {
2027  rr = sec.r_min_;
2028  newTimeStep_ = rr * sec.currentTimeStep;
2029  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
2030  Xyce::dout() << "rejectStep 3" << std::endl;
2031  }
2032  else if (sec.nef_ > 2) // third and later failures
2033  {
2034  sec.newOrder_ = 1;
2035  rr = sec.r_min_;
2036  newTimeStep_ = rr * sec.currentTimeStep;
2037  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
2038  Xyce::dout() << "rejectStep 4" << std::endl;
2039  }
2040  }
2041  if (sec.newOrder_ >= sec.minOrder_)
2042  {
2044  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
2045  Xyce::dout() << "rejectStep 5" << std::endl;
2046  }
2047  if (sec.numberOfSteps_ == 0) // still first step
2048  {
2049  sec.psi_[0] = newTimeStep_;
2050  (ds.xHistory[1])->scale(rr);
2051  (ds.qHistory[1])->scale(rr);
2052  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
2053  Xyce::dout() << "rejectStep 6" << std::endl;
2054  }
2055  if (DEBUG_TIME && isActive(Diag::TIME_STEP) && isActive(Diag::TIME_COEFFICIENTS))
2056  {
2057  Xyce::dout() << " currentTimeStep = " << sec.currentTimeStep << std::endl;
2058  Xyce::dout() << " numberOfSteps_ = " << sec.numberOfSteps_ << std::endl;
2059  Xyce::dout() << " currentOrder_ = " << sec.currentOrder_ << std::endl;
2060  Xyce::dout() << " nscsco_ = " << sec.nscsco_ << std::endl;
2061  Xyce::dout() << " alpha_[0] = " << sec.alpha_[0] << std::endl;
2062  Xyce::dout() << " alpha_[1] = " << sec.alpha_[1] << std::endl;
2063  Xyce::dout() << " alpha_[2] = " << sec.alpha_[2] << std::endl;
2064  Xyce::dout() << " alpha_[3] = " << sec.alpha_[3] << std::endl;
2065  Xyce::dout() << " alpha_[4] = " << sec.alpha_[4] << std::endl;
2066  Xyce::dout() << " psi_[0] = " << sec.psi_[0] << std::endl;
2067  Xyce::dout() << " psi_[1] = " << sec.psi_[1] << std::endl;
2068  Xyce::dout() << " psi_[2] = " << sec.psi_[2] << std::endl;
2069  Xyce::dout() << " psi_[3] = " << sec.psi_[3] << std::endl;
2070  Xyce::dout() << " psi_[4] = " << sec.psi_[4] << std::endl;
2071  Xyce::dout() << " sigma_[0] = " << sec.sigma_[0] << std::endl;
2072  Xyce::dout() << " sigma_[1] = " << sec.sigma_[1] << std::endl;
2073  Xyce::dout() << " sigma_[2] = " << sec.sigma_[2] << std::endl;
2074  Xyce::dout() << " sigma_[3] = " << sec.sigma_[3] << std::endl;
2075  Xyce::dout() << " sigma_[4] = " << sec.sigma_[4] << std::endl;
2076  Xyce::dout() << " rr = " << rr << std::endl;
2077  Xyce::dout() << " r_factor_ = " << sec.r_factor_ << std::endl;
2078  Xyce::dout() << " r_safety_ = " << sec.r_safety_ << std::endl;
2079  Xyce::dout() << " Est_ = " << sec.Est_ << std::endl;
2080  Xyce::dout() << " r_fudge_ = " << sec.r_fudge_ << std::endl;
2081  Xyce::dout() << " newOrder_ = " << sec.newOrder_ << std::endl;
2082  Xyce::dout() << " currentTimeStep = " << sec.currentTimeStep << std::endl;
2083  Xyce::dout() << " newTimeStep_ = " << newTimeStep_ << std::endl;
2084  }
2085  }
2086  else if ((sec.stepAttemptStatus == false) & (!adjustStep))
2087  {
2088  std::string tmp = " BackwardDifferentiation15:rejectStep: Warning: Local error test failed with constant step-size.\n";
2089  Xyce::dout() << tmp << std::endl;
2090  }
2091 
2092  // If the step needs to be adjusted:
2093  if (adjustStep)
2094  {
2095  newTimeStep_ = std::max(newTimeStep_, sec.minTimeStep);
2096  newTimeStep_ = std::min(newTimeStep_, sec.maxTimeStep);
2097 
2098  double nextTimePt = sec.currentTime + newTimeStep_;
2099 
2100  if (nextTimePt > sec.stopTime)
2101  {
2102  nextTimePt = sec.stopTime;
2103  newTimeStep_ = sec.stopTime - sec.currentTime;
2104  }
2105 
2106  sec.nextTime = nextTimePt;
2107 
2108  sec.currentTimeStepRatio = newTimeStep_/sec.lastTimeStep;
2109  sec.currentTimeStepSum = newTimeStep_ + sec.lastTimeStep;
2110 
2111  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
2112  {
2113  Xyce::dout() << " newTimeStep_ = " << newTimeStep_ << std::endl;
2114  Xyce::dout() << " nextTime = " << sec.nextTime << std::endl;
2115  }
2116 
2117  sec.currentTimeStep = newTimeStep_;
2118  }
2119  else // if time step is constant for this step:
2120  {
2121  double nextTimePt = sec.currentTime + sec.currentTimeStep;
2122 
2123  if (nextTimePt > sec.stopTime)
2124  {
2125  nextTimePt = sec.stopTime;
2127  }
2128 
2131 
2132  sec.nextTime = nextTimePt;
2133  }
2134  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
2135  {
2136  Xyce::dout() << Xyce::section_divider << std::endl;
2137  }
2138 }
2139 
2140 //-----------------------------------------------------------------------------
2141 // Function : BackwardDifferentiation15::rejectStepForHabanero
2142 // Purpose : step rejection, but from an outside program (Habanero API)
2143 // Special Notes :
2144 // Scope : public
2145 // Creator : Eric Keiter, SNL
2146 // Creation Date : 08/11/09
2147 //-----------------------------------------------------------------------------
2149 {
2150  restoreHistory();
2152 }
2153 
2154 //-----------------------------------------------------------------------------
2155 // Function : BackwardDifferentiation15::completeStep()
2156 // Purpose : code to update history, choose new order/step-size
2157 // Special Notes :
2158 // Scope : public
2159 // Creator : Todd Coffey, SNL
2160 // Creation Date : 06/07/04
2161 //-----------------------------------------------------------------------------
2163 {
2164  enum {TIAAction_UNSET, TIAAction_LOWER, TIAAction_MAINTAIN, TIAAction_RAISE};
2165 
2166  sec.numberOfSteps_ ++;
2167  sec.nef_ = 0;
2170  // First we decide if we'll reduce the order independent of the local error test:
2171  checkReduceOrder();
2172 
2173  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
2174  {
2175  Xyce::dout() << std::endl;
2176  Xyce::dout() << Xyce::section_divider << std::endl;
2177  Xyce::dout() << " BackwardDifferentiation15::completeStep" << std::endl;
2178  }
2179 
2180  // Only update the time step if we are NOT running constant stepsize.
2181  bool adjustStep = !tia_params.constantTimeStepFlag;
2182 
2184 
2185  double newTimeStep_ = sec.currentTimeStep;
2186  double rr = 1.0; // step size ratio = new step / old step
2187  // 03/11/04 tscoffe: Here is the block for choosing order & step-size when
2188  // the local error test PASSES (and Newton succeeded).
2190  sec.lastTimeStepRatio = sec.currentTimeStepRatio; // copied from calcTStep1
2191  sec.lastTimeStepSum = sec.currentTimeStepSum; // copied from calcTStep1
2192  int orderDiff = sec.currentOrder_ - sec.usedOrder_;
2196  {
2197  // If we reduced our order or reached max order then move to the next phase
2198  // of integration where we don't automatically double the step-size and
2199  // increase the order.
2200  sec.initialPhase_ = false;
2201  }
2202  if (sec.initialPhase_)
2203  {
2204  sec.currentOrder_++;
2205  newTimeStep_ = sec.h_phase0_incr_ * sec.currentTimeStep;
2206  }
2207  else // not in the initial phase of integration
2208  {
2209  int action = TIAAction_UNSET;
2210  if (sec.newOrder_ == sec.currentOrder_-1)
2211  action = TIAAction_LOWER;
2212  else if (sec.newOrder_ == sec.maxOrder_)
2213  action = TIAAction_MAINTAIN;
2214  else if ((sec.currentOrder_+1>=sec.nscsco_) || (orderDiff == 1))
2215  {
2216  // If we just raised the order last time then we won't raise it again
2217  // until we've taken sec.currentOrder_+1 steps at order sec.currentOrder_.
2218  action = TIAAction_MAINTAIN;
2219  }
2220  else // consider changing the order
2221  {
2222 #ifndef Xyce_USE_Q_NORM
2223  ds.delta_x->linearCombo(1.0,*ds.newtonCorrectionPtr,-1.0,*(ds.xHistory[sec.currentOrder_+1]));
2224 #ifdef Xyce_INCOMPLETE_2LEVEL_NORMS
2225  double dnorm_x = 0.0;
2226  ds.delta_x->wRMSNorm(*ds.errWtVecPtr, &dnorm_x);
2227  dnorm_x *= sec.ck_;
2228 #else
2229  double dnorm_x = sec.ck_ * ds.delta_x_errorNorm_p1();
2230 #endif
2231  double dnorm = dnorm_x;
2232 #else
2233  ds.delta_x->linearCombo(1.0,*ds.newtonCorrectionPtr,-1.0,*(ds.xHistory[sec.currentOrder_+1]));
2234  ds.delta_q->linearCombo(1.0,*ds.qNewtonCorrectionPtr,-1.0,*(ds.qHistory[sec.currentOrder_+1]));
2235  double dnorm_x = 0.0, dnorm_q = 0.0;
2236  ds.delta_x->wRMSNorm(*ds.errWtVecPtr, &dnorm_x);
2237  ds.delta_q->wRMSNorm(*ds.qErrWtVecPtr, &dnorm_q);
2238  double dnorm = sqrt(0.5*dnorm_x*dnorm_x+0.5*dnorm_q*dnorm_q);
2239 #endif
2240 
2241  sec.Tkp1_ = dnorm;
2243  if (sec.currentOrder_ == 1)
2244  {
2245  if (sec.Tkp1_ >= sec.Tkp1_Tk_safety_ * sec.Tk_)
2246  action = TIAAction_MAINTAIN;
2247  else
2248  action = TIAAction_RAISE;
2249  }
2250  else
2251  {
2252  if (sec.Tkm1_ <= std::min(sec.Tk_,sec.Tkp1_))
2253  action = TIAAction_LOWER;
2254  else if (sec.Tkp1_ >= sec.Tk_)
2255  action = TIAAction_MAINTAIN;
2256  else
2257  action = TIAAction_RAISE;
2258  }
2259  }
2260  if (sec.currentOrder_ < sec.minOrder_)
2261  {
2262  action = TIAAction_RAISE;
2263  }
2264  else if ((sec.currentOrder_ == sec.minOrder_) && (action == TIAAction_LOWER))
2265  {
2266  action = TIAAction_MAINTAIN;
2267  }
2268  if (action == TIAAction_RAISE)
2269  {
2270  sec.currentOrder_++;
2271  sec.Est_ = sec.Ekp1_;
2272  }
2273  else if (action == TIAAction_LOWER)
2274  {
2275  sec.currentOrder_--;
2276  sec.Est_ = sec.Ekm1_;
2277  }
2278  newTimeStep_ = sec.currentTimeStep;
2279 
2280  // ERK: if errorAnalysisOption==NO_LOCAL_TRUNCATED_ESTIMATES, that means that we're not using LTE to determine the
2281  // new step size. We're only considering whether or not the Newton solve succeeded.
2282  // If we are in this function, then it succeeded, as otherwise we'd be in the "rejectStep"
2283  // function.
2285  {
2286  rr = 0.4/(sec.r_min_);
2287  newTimeStep_ = rr*sec.currentTimeStep;
2288  }
2289  else
2290  {
2291 #ifndef Xyce_USE_Q_NORM
2292  rr = pow(sec.r_safety_*(sec.Est_+sec.r_fudge_),-1.0/(sec.currentOrder_+1.0));
2293 #else
2294  rr = pow(sec.r_safety_*sec.Est_+sec.r_fudge_,-1.0/(sec.currentOrder_+1.0));
2295 #endif
2296 
2297  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
2298  {
2299  Xyce::dout() << " currentOrder_ = " << sec.currentOrder_ << std::endl;
2300  Xyce::dout() << " r_safety = " << sec.r_safety_ << std::endl;
2301  Xyce::dout() << " r_fudge_ = " << sec.r_fudge_ << std::endl;
2302  Xyce::dout() << " r_hincr_ = " << sec.r_hincr_ << std::endl;
2303  Xyce::dout() << " r_hincr_test_ = " << sec.r_hincr_test_ << std::endl;
2304  Xyce::dout() << " Est = " << sec.Est_ << std::endl;
2305  Xyce::dout() << " Ekp1_ = " << sec.Ekp1_ << std::endl;
2306  Xyce::dout() << " Ekm1_ = " << sec.Ekm1_ << std::endl;
2307  Xyce::dout() << " Tkp1_ = " << sec.Tkp1_ << std::endl;
2308  Xyce::dout() << " raw rr = " << rr << std::endl;
2309  }
2310 
2311  if (rr >= sec.r_hincr_test_)
2312  {
2313  rr = sec.r_hincr_;
2314  newTimeStep_ = rr*sec.currentTimeStep;
2315  }
2316  else if (rr <= 1)
2317  {
2318  rr = std::max(sec.r_min_,std::min(sec.r_max_,rr));
2319  newTimeStep_ = rr*sec.currentTimeStep;
2320  }
2321  }
2322  }
2323  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
2324  {
2325  Xyce::dout() << " initialPhase_ = " << sec.initialPhase_ << std::endl;
2326  Xyce::dout() << " rr = " << rr << std::endl;
2327  Xyce::dout() << " currentTimeStep = " << sec.currentTimeStep << std::endl;
2328  Xyce::dout() << " currentTime = " << sec.currentTime << std::endl;
2329  Xyce::dout() << " nextTime = " << sec.nextTime << std::endl;
2330  Xyce::dout() << " newTimeStep_ = " << newTimeStep_ << std::endl;
2331  Xyce::dout() << " minTimeStep = " << sec.minTimeStep << std::endl;
2332  Xyce::dout() << " maxTimeStep = " << sec.maxTimeStep << std::endl;
2333  }
2334 
2335  // 03/22/04 tscoffe: Note that updating the history has nothing to do with
2336  // the step-size and everything to do with the newton correction vectors.
2337  updateHistory();
2338 
2339 
2340  // 12/01/05 tscoffe: This is necessary to avoid currentTimeStep == 0 right
2341  // before a breakpoint. So I'm checking to see if currentTime is identically
2342  // equal to stopTime, in which case we are right before a breakpoint and we
2343  // should not adjust currentStepSize because that would result in
2344  // currentStepSize == 0.
2345  if (sec.currentTime < sec.stopTime)
2346  {
2347  // If the step needs to be adjusted:
2348  if (adjustStep)
2349  {
2350  newTimeStep_ = std::max(newTimeStep_, sec.minTimeStep);
2351  newTimeStep_ = std::min(newTimeStep_, sec.maxTimeStep);
2352 
2353  double nextTimePt = sec.currentTime + newTimeStep_;
2354 
2355  if (nextTimePt > sec.stopTime)
2356  {
2357  nextTimePt = sec.stopTime;
2358  newTimeStep_ = sec.stopTime - sec.currentTime;
2359  }
2360 
2361  sec.nextTime = nextTimePt;
2362 
2363  sec.currentTimeStepRatio = newTimeStep_/sec.lastTimeStep;
2364  sec.currentTimeStepSum = newTimeStep_ + sec.lastTimeStep;
2365 
2366  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
2367  {
2368  Xyce::dout() << " nextTime = " << sec.nextTime << std::endl;
2369  Xyce::dout() << " newTimeStep_ = " << newTimeStep_ << std::endl;
2370  }
2371 
2372  sec.currentTimeStep = newTimeStep_;
2373  }
2374  else // if time step is constant for this step:
2375  {
2376  double nextTimePt = sec.currentTime + sec.currentTimeStep;
2377 
2378  if (nextTimePt > sec.stopTime)
2379  {
2380  nextTimePt = sec.stopTime;
2382  }
2383 
2386 
2387  sec.nextTime = nextTimePt;
2388  }
2389  }
2390  if (DEBUG_TIME && isActive(Diag::TIME_STEP))
2391  {
2392  Xyce::dout() << Xyce::section_divider << std::endl;
2393  }
2394 
2395 // 11/02/04 tscoffe: This should be done at the beginning of an integration
2396 // stop rather than at the end, so its been moved into
2397 // ControlAlgorithm::transientLoop_
2398  // Update next stop time in StepErrorControl:
2399  // sec.updateStopTime();
2400 }
2401 
2402 //-----------------------------------------------------------------------------
2403 // Function : BackwardDifferentiation15::updateStateDeriv
2404 // Purpose :
2405 // Special Notes :
2406 // Scope : public
2407 // Creator : Todd Coffey, SNL
2408 // Creation Date : 11/17/05
2409 //-----------------------------------------------------------------------------
2411 {
2412  // dS/dt = spn0 - (sec.alpha_/hn)(S(x)-sn0)
2413  ds.nextStateDerivPtr->linearCombo(1.0,*ds.nextStatePtr,-1.0,*ds.sn0Ptr);
2415 }
2416 
2417 //-----------------------------------------------------------------------------
2418 // Function : BackwardDifferentiation15::updateLeadCurrent
2419 // Purpose : calculates lead currents in store vector with
2420 // the storeLeadCurrQVec.
2421 // Special Notes :
2422 // Scope : public
2423 // Creator : Richard Schiek, Electrical Systems Modeling, SNL
2424 // Creation Date : 03/22/2013
2425 //-----------------------------------------------------------------------------
2427 {
2428  // dStoreQ/dt = spn0 - (sec.alpha_/hn)(S(x)-sn0)
2430  linearCombo(1.0,*ds.nextStoreLeadCurrQPtr,-1.0,*ds.stoQn0Ptr);
2433  ds.nextStorePtr->linearCombo(1.0,*ds.nextStorePtr,1.0,*ds.nextStoreLeadCurrQDerivPtr);
2434 }
2435 
2436 //-----------------------------------------------------------------------------
2437 // Function : BackwardDifferentiation15::updateLeadCurrentVec
2438 // Purpose : calculates lead currents in lead current vector with
2439 // the ladCurrQVec.
2440 // Special Notes :
2441 // Scope : public
2442 // Creator : Richard Schiek, Electrical Systems Modeling, SNL
2443 // Creation Date : 03/22/2013
2444 //-----------------------------------------------------------------------------
2446 {
2447  // dStoreQ/dt = spn0 - (sec.alpha_/hn)(S(x)-sn0)
2449  linearCombo(1.0,*ds.nextLeadCurrentQPtr,-1.0,*ds.leadCurrentQn0Ptr);
2453 }
2454 
2455 
2456 //-----------------------------------------------------------------------------
2457 // Function : BackwardDifferentiation15::getInitialQnorm
2458 // Purpose : Needed by 2-level solves.
2459 // Special Notes :
2460 // Scope : public
2461 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2462 // Creation Date : 03/18/07
2463 //-----------------------------------------------------------------------------
2465 {
2466  tle.q1HistorySum = ds.partialSum_q1();
2467 }
2468 
2469 //-----------------------------------------------------------------------------
2470 // Function : BackwardDifferentiation15::setupTwoLevelError
2471 // Purpose : Needed by 2-level solves.
2472 // Special Notes :
2473 // Scope : public
2474 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2475 // Creation Date : 03/15/07
2476 //-----------------------------------------------------------------------------
2478 {
2479  tle.xErrorSum = ds.partialErrorNormSum ();
2484  tle.innerSize = ds.globalLength ();
2485 
2486  if (DEBUG_TIME && isActive(Diag::TIME_ERROR))
2487  Xyce::dout() << tle;
2488 }
2489 
2490 //-----------------------------------------------------------------------------
2491 // Function : TimeIntegrationMethod::partialTimeDeriv
2492 // Purpose :
2493 // Special Notes :
2494 // Scope : public
2495 // Creator :
2496 // Creation Date : 1/20/07
2497 //-----------------------------------------------------------------------------
2499 {
2500  if (sec.currentTimeStep < 1e-30)
2501  {
2502  Xyce::Report::UserWarning() << "Excessively small current time step, incorrectly returning with large value";
2503 
2504  return leadingCoeff * 1.e+30;
2505  }
2506 
2507  return leadingCoeff / sec.currentTimeStep;
2508 }
2509 } // namespace TimeIntg
2510 } // namespace Xyce
2511 
Linear::Vector * sNewtonCorrectionPtr
BackwardDifferentiation15(const TIAParams &tia_params, StepErrorControl &step_error_control, DataStore &data_store)
Linear::Vector * nextLeadCurrentQPtr
Linear::Vector * leadCurrentQn0Ptr
Linear::Vector * tmpLeadDeltaVPtr
Linear::Vector * stoNewtonCorrectionPtr
Linear::Vector * qErrWtVecPtr
Pure virtual class to augment a linear system.
std::vector< double > dOdpVec_
std::vector< double > scaled_dOdpVec_
StepErrorControl & sec
Reference to step-error control object.
Linear::Vector * tmpStaVectorPtr
Linear::Vector * currStorePtr
std::vector< double > scaled_dOdpAdjVec_
std::vector< Linear::Vector * > leadDeltaVHistory
Linear::Vector * tmpSolVectorPtr
ScalarT Xycemax(ScalarT f1, ScalarT f2)
Definition: N_DEV_Diode.h:71
Linear::Vector * leadCurrentpn0Ptr
Linear::Vector * leadCurrentNewtonCorrectionPtr
double partialSum_m2(int currentOrder)
int errorAnalysisOption
Error analysis option.
bool interpolateSolution(double timepoint, Linear::Vector *tmpSolVectorPtr, std::vector< Linear::Vector * > &historyVec)
Linear::Vector * tmpStoVectorPtr
std::vector< Linear::Vector * > qHistory
Linear::Vector * currStatePtr
std::vector< double > objectiveVec_
std::vector< Linear::Vector * > leadCurrentHistory
bool constantTimeStepFlag
Constant time step integration flag.
Linear::Vector * leadDeltaVn0Ptr
Linear::Vector * leadCurrentn0Ptr
Linear::Vector * daeQVectorPtr
Linear::Vector * tmpLeadCurrentVectorPtr
bool printWaMPDEOutputSolution(Analysis::OutputMgrAdapter &outputManagerAdapter, const double time, Linear::Vector *solnVecPtr, const std::vector< double > &fastTimes, const int phiGID)
double partialSum_p1(int currentOrder, int maxOrder)
Linear::Vector * stopn0Ptr
Linear::Vector * leadCurrentQpn0Ptr
Linear::Vector * daeFVectorPtr
double leadingCoeff
Time-integration method leading coefficient value.
Linear::Vector * qNewtonCorrectionPtr
Linear::Vector * currLeadCurrentQPtr
Linear::Vector * nextStoreLeadCurrQDerivPtr
bool saveOutputSolution(Analysis::OutputMgrAdapter &outputManagerAdapter, const TIAParams &tia_params, Linear::Vector *solnVecPtr, const double saveTime, const bool doNotInterpolate)
Linear::Vector * leadCurrentQNewtonCorrectionPtr
Linear::Vector * errWtVecPtr
Linear::Matrix * dFdxMatrixPtr
Linear::Matrix * JMatrixPtr
static TimeIntegrationMethod * factory(const TIAParams &tia_params, StepErrorControl &step_error_control, DataStore &data_store)
Linear::Vector * nextStatePtr
std::vector< Linear::Vector * > leadCurrentQHistory
void tranOutput(double time, Linear::Vector &currSolutionPtr, Linear::Vector &stateVecPtr, Linear::Vector &storeVecPtr, Linear::Vector &lead_current_vector, Linear::Vector &junction_voltage_vector, std::vector< double > &objectiveVec_, std::vector< double > &dOdpVec_, std::vector< double > &dOdpAdjVec_, std::vector< double > &scaled_dOdpVec_, std::vector< double > &scaled_dOdpAdjVec_, bool skipPrintLineOutput=false)
bool printMPDEOutputSolution(Analysis::OutputMgrAdapter &outputManagerAdapter, const double time, Linear::Vector *solnVecPtr, const std::vector< double > &fastTimes)
Linear::Vector * dFdxdVpVectorPtr
Linear::Vector * currLeadDeltaVPtr
Linear::Vector * currStoreLeadCurrQPtr
Linear::Vector * stoLeadCurrQNewtonCorrectionPtr
bool interpolateMPDESolution(std::vector< double > &timepoint, Linear::Vector *tmpSolVectorPtr)
Linear::Vector * nextSolutionPtr
Linear::Vector * RHSVectorPtr
Linear::Vector * tmpXn0BPtr
Linear::Vector * nextStorePtr
Linear::Vector * stoQn0Ptr
double timept_
Keep track of last interpolation point in printMPDEOutputSolution.
Linear::Vector * dQdxdVpVectorPtr
bool printOutputSolution(Analysis::OutputMgrAdapter &outputManagerAdapter, const TIAParams &tia_params, const double time, Linear::Vector *solnVecPtr, const bool doNotInterpolate, const std::vector< double > &outputInterpolationTimes, bool skipPrintLineOutput)
Linear::Vector * currLeadCurrentPtr
std::vector< double > dOdpAdjVec_
Linear::Vector * nextLeadCurrentQDerivPtr
Linear::Vector * newtonCorrectionPtr
Linear::Vector * tmpXn0APtr
Linear::Vector * currSolutionPtr
std::vector< Linear::Vector * > stoHistory
Linear::Vector * stoQpn0Ptr
Linear::Vector * nextStoreLeadCurrQPtr
Linear::Vector * nextStateDerivPtr
std::vector< Linear::Vector * > xHistory
void outputDCOP(const Linear::Vector &solution)
Linear::Matrix * dQdxMatrixPtr
double partialSum_m1(int currentOrder)
ScalarT Xycemin(ScalarT f1, ScalarT f2)
Definition: N_DEV_Diode.h:74
Linear::Vector * daeBVectorPtr
Linear::Vector * leadDeltaVpn0Ptr
Linear::Vector * leadDeltaVNewtonCorrectionPtr
std::vector< Linear::Vector * > stoLeadCurrQHistory
DataStore & ds
Reference to the TIA data-store object.
Linear::Vector * nextLeadCurrentPtr
std::vector< Linear::Vector * > sHistory