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