Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
N_ANP_Transient.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-2014 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_ANP_Transient.C,v $
27 // Purpose : Transient analysis functions.
28 // Special Notes :
29 // Creator : Richard Schiek, SNL, Electrical and Microsystem Modeling
30 // Creation Date : 01/24/08
31 //
32 // Revision Information:
33 // ---------------------
34 // Revision Number: $Revision: 1.135.2.4 $
35 // Revision Date : $Date: 2014/08/28 16:25:38 $
36 // Current Owner : $Author: erkeite $
37 //-----------------------------------------------------------------------------
38 
39 #include <Xyce_config.h>
40 
41 #include <sstream>
42 #include <iomanip>
43 
44 #include <N_ANP_Transient.h>
45 
46 #include <N_ANP_AnalysisManager.h>
47 #include <N_ANP_Report.h>
48 #include <N_ERH_Progress.h>
49 #include <N_IO_CmdParse.h>
50 #include <N_IO_OutputMgr.h>
51 #include <N_IO_RestartMgr.h>
52 #include <N_LAS_System.h>
53 #include <N_LOA_Loader.h>
54 #include <N_MPDE_Manager.h>
55 #include <N_NLS_ReturnCodes.h>
56 #include <N_TIA_DataStore.h>
57 #include <N_TIA_StepErrorControl.h>
59 #include <N_UTL_ExpressionData.h>
60 #include <N_UTL_NoCase.h>
61 #include <N_UTL_Timer.h>
62 
63 
64 namespace Xyce {
65 namespace Analysis {
66 
67 //-----------------------------------------------------------------------------
68 // Function : Transient::Transient( AnalysisManager * )
69 // Purpose : constructor
70 // Special Notes :
71 // Scope : public
72 // Creator : Rich Schiek, SNL
73 // Creation Date : 3/11/06
74 //-----------------------------------------------------------------------------
76  : AnalysisBase(analysis_manager),
77  Util::ListenerAutoSubscribe<StepEvent>(&analysis_manager),
78  comm_(analysis_manager.getPDSComm().comm()),
79  initialIntegrationMethod_(TIAMethod_ONESTEP),
80  firstTranOutput_(true),
81  isPaused(false),
82  dcopFlag_(true),
83  startDCOPtime(0.0),
84  endTRANtime(0.0),
85  gui_(false),
86  historyTrackingOn_(true),
87  maxTimeStepExpressionGiven_(false),
88  maxTimeStepExpressionAsString_(""),
89  firstTime(true),
90  oldPercentComplete(0.0),
91  startSimTime(-1.0),
92  dcStats(0),
93  tranStats(0)
94 {
95  gui_ = analysisManager_.getCommandLine().argExists("-gui");
96 
97  // initialize this to an empty vector
99 }
100 
101 void Transient::notify(const StepEvent &event)
102 {
103  if (event.state_ == StepEvent::STEP_STARTED)
104  {
106 
109  dcopFlag_ = false;
111 
112  if (historyTrackingOn_)
113  {
114  // these set_size calls will also "reset" the queue.
115  timeQueue_.set_size( queueSize_ );
116  timeStepQueue_.set_size( queueSize_ );
117  stepStatusQueue_.set_size( queueSize_ );
118  estErrorOverTolQueue_.set_size( queueSize_ );
123  }
124  }
125 }
126 
127 //-----------------------------------------------------------------------------
128 // Function : Transient::setAnalysisParams
129 // Purpose :
130 // Special Notes : These are from the .TRAN statement.
131 // Scope : public
132 // Creator : Eric Keiter, SNL
133 // Creation Date : 6/21/10
134 //-----------------------------------------------------------------------------
135 bool Transient::setAnalysisParams(const Util::OptionBlock & paramsBlock)
136 {
137  for (Util::ParameterList::const_iterator it = paramsBlock.getParams().begin(), end = paramsBlock.getParams().end(); it != end; ++it)
138  {
139  if ((*it).uTag() == "TSTART")
140  {
141  tiaParams_.tStart = (*it).getImmutableValue<double>();
142  tiaParams_.tStartGiven = true;
143  }
144  else if ((*it).uTag() == "TSTOP")
145  {
146  tiaParams_.finalTime = (*it).getImmutableValue<double>();
147  }
148  else if ((*it).uTag() == "TSTEP")
149  {
150  tiaParams_.userSpecified_startingTimeStep = (*it).getImmutableValue<double>();
151  }
152  else if ((*it).uTag() == "NOOP" ||
153  (*it).uTag() == "UIC")
154  {
155  tiaParams_.NOOP = 1;
156  }
157  else if ((*it).uTag() == "DTMAX")
158  {
159  tiaParams_.maxTimeStep = (*it).getImmutableValue<double>();
161 #ifdef Xyce_DEBUG_ANALYSIS
162  if (tiaParams_.debugLevel > 0)
163  {
164  dout() << "setting maxTimeStep = " << tiaParams_.maxTimeStep << std::endl;
165  }
166 #endif
167  }
168  else if ((*it).uTag() == "MAXTIMEEXPRESSION")
169  {
170  // an expression was given which should specify what
171  // max time step to use based on the current simulation
172  // time. The expected format of this is
173  // {schedule( t0, max_del_t0, t1, max_del_t1, ...)}
174  // we'll just store the expression as a string for now
175  // as we need to make sure other classes are up and running
176  // before we can create the actual expression. That will
177  // happen in Transient class as it will ultimately use this
179  maxTimeStepExpressionAsString_ = (*it).stringValue();
180  }
181  }
182 
184  {
185  UserFatal(*this) << "Final time of " << tiaParams_.finalTime
186  << " is earlier or same as start time of " << tiaParams_.tStart << std::endl
187  << " Check netlist for invalid .TRAN specification";
188  }
189 
190  // if starting time steps is baloney, set then to a default value.
191  // ERK. This trap is redudant with an identical one in step error
192  // control.
194  {
196  }
197 
198 #ifdef Xyce_DEBUG_ANALYSIS
199  if (tiaParams_.debugLevel > 0)
200  {
201  dout() << std::endl
202  << section_divider << std::endl
203  << " Transient simulation parameters" << std::endl
204  << " initial time = " << tiaParams_.initialTime << std::endl
205  << " final time = " << tiaParams_.finalTime << std::endl
206  << " starting time step = " << tiaParams_.userSpecified_startingTimeStep << std::endl
207  << " tStart (time of first output) = " << tiaParams_.tStart << std::endl;
208 
209  if (!(tiaParams_.NOOP))
210  {
211  dout() << " NOOP/UIC is NOT set" << std::endl;
212  }
213  else
214  {
215  dout() << " NOOP/UIC is set" << std::endl;
216  }
217 
218  dout() << section_divider << std::endl;
219  }
220 #endif
221 
223  {
224  // set-up expression object for getting a user specified, time dependent
225  // max time step value
227  maxTimeStepExpressionRCPtr_ = rcp( new Util::ExpressionData( maxTimeStepExpressionAsString_) );
228  }
229 
230  // queueSize_ should can be set from the .options timeint line. Use default in tiaParams
231  // as that will be overwritten if the user set it via .options. Also, if it's less than
232  // or equal to zero assume that the user wants this turned off.
233  // We'll store the attempted time step, time step status,
234  // estimated error over tolerance, non-linear solver status and non-linear solver norm
235  // for each step, up to the last queueSize_ steps.
236 
238  {
239  historyTrackingOn_ = true;
241  timeQueue_.set_size( queueSize_ );
242  timeStepQueue_.set_size( queueSize_ );
243  stepStatusQueue_.set_size( queueSize_ );
244  estErrorOverTolQueue_.set_size( queueSize_ );
249  }
250  else
251  {
252  historyTrackingOn_ = false;
253  }
254 
255  return true;
256 }
257 
258 //-----------------------------------------------------------------------------
259 // Function : Transient::run()
260 // Purpose :
261 // Special Notes :
262 // Scope : public
263 // Creator : Rich Schiek, SNL
264 // Creation Date : 3/11/06
265 //-----------------------------------------------------------------------------
267 {
268  bool bsuccess = true;
269  isPaused = false;
270 
272  resetForHB();
273 
274  bsuccess = bsuccess & init();
275  bsuccess = bsuccess & loopProcess();
276 
277  // if processing the loop failed,
278  // then skip finish step
279  if( bsuccess )
280  {
281  bsuccess = bsuccess & finish();
282  }
283 
284  return bsuccess;
285 }
286 
287 //-----------------------------------------------------------------------------
288 // Function : Transient::init()
289 // Purpose :
290 // Special Notes :
291 // Scope : public
292 // Creator : Rich Schiek, SNL
293 // Creation Date : 3/11/06
294 //-----------------------------------------------------------------------------
296 {
297  bool bsuccess = true;
298 
299  if (sensFlag_)
300  {
302  }
303 
306  {
308  }
309 
310  if (!tiaParams_.resume)
311  {
313  if(dcopFlag_)
314  {
316  }
317  else
318  {
320  }
321 
322  doubleDCOPFlag_ = loader_.getDoubleDCOPFlag();
324 
325  if (analysisManager_.getRestartManager().isRestart())
326  {
328 
331 
332  dcopFlag_ = false;
334 
335 #ifdef Xyce_PARALLEL_MPI
336  // Update vectors with off proc values.
337  linearSystem_.updateExternValsSolnVector(analysisManager_.getTIADataStore()->nextSolutionPtr);
338  linearSystem_.updateExternValsSolnVector(analysisManager_.getTIADataStore()->currSolutionPtr);
339  linearSystem_.updateExternValsStateVector(analysisManager_.getTIADataStore()->nextStatePtr);
340  linearSystem_.updateExternValsStateVector(analysisManager_.getTIADataStore()->currStatePtr);
341  linearSystem_.updateExternValsStoreVector(analysisManager_.getTIADataStore()->nextStorePtr);
342  linearSystem_.updateExternValsStoreVector(analysisManager_.getTIADataStore()->currStorePtr);
343 #endif
344 
345  // Set the nonlinear solver parameters to those appropriate for the
346  // transient solution. If starting from here, we're not doing a DCOP
347  // calculation first - we're jumping right into the transient.
349  }
350  else
351  {
352  if (dcopFlag_)
353  {
354  // Get set to do the operating point.
357  }
358  else // otherwise NOOP/UIC
359  {
362  }
363 
364  // This setInitialGuess call is to up an initial guess in the
365  // devices that have them (usually PDE devices). This is DIFFERENT
366  // than an initial condition.
368 
370  {
371  beginningIntegration = true;
372  }
373 
374  // 12/13/07 tscoffe/tmei: .ic should not be applied to MPDE currently.
375  // A new mechanism must be set up for this, e.g. .mpde_ic
377  {
378  // If available, set initial solution. This may be from a DCOP restart,
379  // a .IC, or a .NODESET line. These can be used in both the UIC/NOOP
380  // case, as well as the DCOP case, so they need to be outside the if-statement.
383  }
384 
386  {
387  // this "initializeProblem" call is to set the IC's in devices that
388  // have them. This is done IN PLACE of the operating point.
389  loader_.initializeProblem
405 
406  // Do this to populate the q-vector:
407  // since we're also skipping the DC OP, this call will
408  // also force the loader to propagate the state vector to the
409  // device manager which updates state vector seen by the devices.
410  nonlinearEquationLoader_.loadRHS();
411  }
412 
413  // Set a constant history.
417 
418 #ifdef Xyce_PARALLEL_MPI
419  // Update vectors with off proc values.
420  linearSystem_.updateExternValsSolnVector(analysisManager_.getTIADataStore()->nextSolutionPtr);
421  linearSystem_.updateExternValsSolnVector(analysisManager_.getTIADataStore()->currSolutionPtr);
422  linearSystem_.updateExternValsStateVector(analysisManager_.getTIADataStore()->nextStatePtr);
423  linearSystem_.updateExternValsStateVector(analysisManager_.getTIADataStore()->currStatePtr);
424  linearSystem_.updateExternValsStoreVector(analysisManager_.getTIADataStore()->nextStorePtr);
425  linearSystem_.updateExternValsStoreVector(analysisManager_.getTIADataStore()->currStorePtr);
426 #endif
427 
428  // if we are skipping the DCOP, but .sens was requested, then call this here.
430  {
433 
435  }
436 
437  if (!dcopFlag_ && !tiaParams_.resume)
438  {
439  // Now do a NOOP output. ERK: 08/30/2007 This isn't the best place to
440  // put this, but it will have to do for now. If this isn't here, then
441  // NOOP/UIC simulations don't output at t=0.0 in the *prn file.
442  noopOutputs ();
443  }
444 
445  stepNumber = 0;
446  tranStepNumber = 0;
448  }
449  }
450  else
451  {
453  {
454  // we're resuming from a previous transient simulation
455  // this is an ugly side effect of the analysis manager's deleting
456  // the transient object after it retured in a paused state
457  // need to fix this in Xyce 6.0 . RLS 12/22/2009
458  dcopFlag_=false;
459 
460  // we default firstTranOutput_ to true to force the first time point to be output
461  // however, if we're resuming, then we need this to be false
462  // this is really a defect of a paused simulation's Transient object
463  // being deleted by the AnalysisManager and then a new one being created
464  // when the simulation is resumed. Need to fully fix this. RLS 12/22/2009
465  firstTranOutput_ = false;
466  }
467 
468  // in a 2 level problem, we can be asked to resume
469  // without first making the integration method. So
470  // catch that.
471  if (workingIntgMethod_->getIntegMethodPtr() == NULL)
472  {
475  }
476 
477 #ifdef Xyce_DEBUG_ANALYSIS
478  if (tiaParams_.debugLevel > 0)
479  dout() << " transient loop called with resume true " << std::endl;
480 #endif
481  }
482 
484 
485  if (!tiaParams_.resume)
486  {
487  // if we're resuming, this was already done prior to pausing, and doing
488  // it again screws us up
489  double suggestedMaxTime=0.0;
491  {
493 
494  suggestedMaxTime = maxTimeStepExpressionRCPtr_->evaluate(comm_, outputManagerAdapter_.getOutputManager().getCircuitTime(),
496  }
497  stepErrorControl_->updateMaxTimeStep( suggestedMaxTime );
500  }
501 
502  // reset min error tracking variables
503  // if the step number is less than zero we'll assume there is no valid
504  // min. estimated error over tol or an associated time step. This frees us
505  // from putting Machine::Big here and trying to do something with that.
507  minEstErrorOverTol = 0.0;
509 
510  return bsuccess;
511 }
512 
513 //-----------------------------------------------------------------------------
514 // Function : Transient::loopProcess()
515 // Purpose : Conduct the time stepping loop.
516 // Special Notes :
517 // Scope : public
518 // Creator : Rich Schiek, SNL
519 // Creation Date : 3/11/06
520 //-----------------------------------------------------------------------------
522 {
523  bool bsuccess = true;
524 
525  static_cast<Xyce::Util::Notifier<AnalysisEvent> &>(analysisManager_).publish(AnalysisEvent(AnalysisEvent::INITIALIZE, AnalysisEvent::TRAN));
526 
527  // Transient time stepping loop:
528  while (!(stepErrorControl_->isFinished()))
529  {
530 #ifdef Xyce_VERBOSE_TIME
531  printStepHeader(Xyce::lout());
532 #endif
533  printProgress(Xyce::lout());
534 
535  // ------------------------------------------------------------------------
536  // If the flag is set to switch integration methods, do that here.
537  // For example, switch from operating point to transient backward euler.
538 
540  {
542  }
543 
544  // ------------------------------------------------------------------------
545  // Set the step size, current time and next time.
546 
548 
549 #ifdef Xyce_DEBUG_ANALYSIS
550  if (tiaParams_.debugLevel > 0)
551  {
552  dout() << std::endl;
553  dout() << "Transient::loopProcess()" << std::endl;
554  dout() << "beginningIntegration = " << beginningIntegration << std::endl;
555  dout() << "stepErrorControl_->stepAttemptStatus = " << stepErrorControl_->stepAttemptStatus << std::endl;
556  }
557 #endif
558 
559  if (beginningIntegration &&
561  {
562  // ------------------------------------------------------------------------
563  // 07/29/04 TSC: initial step-size selection is now done in the
564  // integration method initialize call under the DAE formulation. This
565  // segregates codes changes better and makes sense to do as an
566  // initialization step even if its changed later.
568  double suggestedMaxTime=0.0;
570  {
571  suggestedMaxTime = maxTimeStepExpressionRCPtr_->evaluate(comm_, outputManagerAdapter_.getOutputManager().getCircuitTime(),
573  }
574  stepErrorControl_->updateMaxTimeStep( suggestedMaxTime );
576  }
577 
578  // ------------------------------------------------------------------------
579  // If we've switched the integration method, we need to obtain the
580  // corrector derivative only after we've updated the TimeInfo.
582  {
585  }
586 
587 #ifdef Xyce_VERBOSE_TIME
588  if (!dcopFlag_)
590 #endif
591 
592  // ------------------------------------------------------------------------
593  // Set the nonlinear solver parameters to those appropriate for the
594  // transient solution, if neccessary.
595  if (!dcopFlag_)
596  {
598  }
599 
600  // Ask the method to update its coefficients
602 
604 
605  // ------------------------------------------------------------------------
606  // Perform the time step:
608 
609  // ------------------------------------------------------------------------
611  {
613  }
615  {
617  bsuccess = false;
618  break;
619  }
620  // Transient
621  else
622  {
624  {
626  }
627  else if( (tiaParams_.passNLStall == true) &&
630  {
631  // potentially a VERY dangerous options.
632  // if the non-linear solver is stalling, and we're very close to a min
633  // time step, then calls this failure a pass
635  {
636  {
637  UserWarning(*this) << "Nonlinear solver stalled. Calling this a pass";
638  }
639 
641  }
642  // another VERY dangerous options.
643  // if the non-linear solver is reporting too big of an update, and we're very close to a min
644  // time step, then calls this failure a pass
646  {
647  {
648  UserWarning(*this) << "Update too big. Calling this a pass";
649  }
650 
652  }
653  // another VERY dangerous options.
654  // if the non-linear solver is not converging in the max number of steps,
655  // and we're very close to a min time step, then calls this failure a pass
656  //
657  // if( stepErrorControl_->newtonConvergenceStatus == -1)
658  // {
659  // Report::UserWarning0() << "Too many steps, calling this a pass";
660  // processSuccessfulStep();
661  // }
662  else
663  {
664  // process this failed step as we would have by default.
665  bool b1 = processFailedStep();
666  if (!b1)
667  {
668  bsuccess = false;
669  break;
670  }
671  }
672  }
673  else // stepAttemptStatus (ie do this if the step FAILED)
674  {
675  bool b1 = processFailedStep();
676  if (!b1)
677  {
678  bsuccess = false;
679  break;
680  }
681  } // stepAttemptStatus
682 
683  } // transient
684 
685 #ifdef Xyce_DEBUG_ANALYSIS
686  if (tiaParams_.debugLevel > 0)
687  {
688  dout() << std::endl;
689  dout() << " Here we are, just before checking whether to pause. " << std::endl;
690  dout() << " minTimeStep = " << stepErrorControl_->minTimeStep << std::endl;
691  dout() << " final time = " << tiaParams_.finalTime << std::endl;
692  dout() << " pause time = " << analysisManager_.getPauseTime() << std::endl;
693  dout() << " initial time = " << stepErrorControl_->initialTime << std::endl;
694  dout() << " current time = " << stepErrorControl_->currentTime << std::endl;
696  {
697  dout() << " Pause time and current time equal " << std::endl;
698  }
699  else
700  {
701  dout() << " difference between current and pause times is "
703  }
705  {
706  dout() << " Pause time and initial time equal " << std::endl;
707  }
708  }
709 #endif
710 
712  {
713  // Failure at this point only indicates that the simulation
714  // is paused and may be resumed.
715 #ifdef Xyce_DEBUG_ANALYSIS
716  if (tiaParams_.debugLevel > 0)
717  {
718  dout() << "Transient::loopProcess(): pausing simulation " << std::endl;
719  }
720 #endif
722  isPaused = true;
723  bsuccess = true;
724  break;
725  }
726 
727  // If the exit time has been exceeded, exit.
728  if (tiaParams_.exitTime != 0.0 &&
730  {
731  lout() << "Exit time exceeded. Exiting transient loop\n" << std::endl;
732  bsuccess = true;
733  break;
734  }
735 
736  if (tiaParams_.exitStep != -1 &&
737  static_cast<int>(stepNumber) == tiaParams_.exitStep)
738  {
739  lout() << "Exit step. Exiting transient loop\n" << std::endl;
740  bsuccess = true;
741  break;
742  }
743 
744  } // end of time loop
747 
748  static_cast<Xyce::Util::Notifier<AnalysisEvent> &>(analysisManager_).publish(AnalysisEvent(AnalysisEvent::FINISH, AnalysisEvent::TRAN));
749 
750  return bsuccess;
751 }
752 
753 
754 //-----------------------------------------------------------------------------
755 // Function : Transient::mixedSignalStep
756 // Purpose :
757 // Special Notes : Habanero API function
758 // Scope : public
759 // Creator : Eric Keiter, SNL
760 // Creation Date : 3/04/09
761 //-----------------------------------------------------------------------------
763 {
765  return true;
766 }
767 
768 //-----------------------------------------------------------------------------
769 // Function : Transient::preStepDetails
770 // Purpose :
771 // Special Notes : Habanero API function
772 // Scope : private_
773 // Creator : Eric Keiter, SNL
774 // Creation Date : 3/04/09
775 //-----------------------------------------------------------------------------
776 void Transient::preStepDetails(double maxTimeStepFromHabanero)
777 {
778 #ifdef Xyce_VERBOSE_TIME
779  printStepHeader(Xyce::lout());
780 #endif
781  printProgress(Xyce::lout());
782 
783  // ------------------------------------------------------------------------
784  // If the flag is set to switch integration methods, do that here.
785  // For example, switch from operating point to transient backward euler.
786 
788  {
790  }
791 
792  // ------------------------------------------------------------------------
793  // Set the step size, current time and next time.
795 
796  // ------------------------------------------------------------------------
797  // If a max time is set from Habanero, impose it now that stopTime is updated.
798  if (maxTimeStepFromHabanero > 0)
799  {
800  double currentTimeStep = Xycemin(maxTimeStepFromHabanero, stepErrorControl_->currentTimeStep);
801  stepErrorControl_->setTimeStep(currentTimeStep);
802  }
803 
804 #ifdef Xyce_DEBUG_ANALYSIS
805  if (tiaParams_.debugLevel > 0)
806  {
807  dout() << std::endl;
808  dout() << "Transient::loopProcess()" << std::endl;
809  dout() << "beginningIntegration = " << beginningIntegration << std::endl;
810  dout() << "stepErrorControl_->stepAttemptStatus = " << stepErrorControl_->stepAttemptStatus << std::endl;
811  }
812 #endif
813 
814 
815  if (beginningIntegration &&
817  {
818  // ------------------------------------------------------------------------
819  // 07/29/04 TSC: initial step-size selection is now done in the
820  // integration method initialize call under the DAE formulation. This
821  // segregates codes changes better and makes sense to do as an
822  // initialization step even if its changed later.
824  double suggestedMaxTime=0.0;
826  {
827  suggestedMaxTime = maxTimeStepExpressionRCPtr_->evaluate(comm_, outputManagerAdapter_.getOutputManager().getCircuitTime(),
829  }
830  stepErrorControl_->updateMaxTimeStep( suggestedMaxTime );
832  }
833 
834  // ------------------------------------------------------------------------
835  // If we've switched the integration method, we need to obtain the
836  // corrector derivative only after we've updated the TimeInfo.
838  {
841  }
842 
843 #ifdef Xyce_VERBOSE_TIME
844  if (!dcopFlag_)
845  {
847  }
848 #endif
849 
850  // ------------------------------------------------------------------------
851  // Set the nonlinear solver parameters to those appropriate for the
852  // transient solution, if neccessary.
853  if (!dcopFlag_)
854  {
856  }
857 
858  // Ask the method to update its coefficients
860 }
861 
862 //-----------------------------------------------------------------------------
863 // Function : Transient::finalizeStep
864 // Purpose :
865 // Special Notes : Habanero API function
866 // Scope : public
867 // Creator : Eric Keiter, SNL
868 // Creation Date : 3/04/09
869 //-----------------------------------------------------------------------------
871 {
872  bool recoverableFailureFlag = true;
873 
875  {
877  }
879  {
881  recoverableFailureFlag = false;
882  }
883  // Transient
884  else
885  {
887  {
889  }
890  else if( (tiaParams_.passNLStall == true) &&
893  {
894  // potentially a VERY dangerous options.
895  // if the non-linear solver is stalling, and we're very close to a min
896  // time step, then calls this failure a pass
897 
899  {
900  Report::UserWarning0() << "Nonlinear solver stalled, calling this a pass";
902  }
903  // another VERY dangerous options.
904  // if the non-linear solver is reporting too big of an update, and we're very close to a min
905  // time step, then calls this failure a pass
907  {
908  Report::UserWarning0() << "Update too big, calling this a pass";
910  }
911  // another VERY dangerous options.
912  // if the non-linear solver is not converging in the max number of steps,
913  // and we're very close to a min time step, then calls this failure a pass
914  //
915  // if( stepErrorControl_->newtonConvergenceStatus == -1)
916  // {
917  // Report::UserWarning0() << "?Too many steps, calling this a pass";
918  // processSuccessfulStep();
919  // }
920  else
921  {
922  // process this failed step as we would have by default.
923  recoverableFailureFlag = processFailedStep();
924  }
925  }
926  else // stepAttemptStatus (ie do this if the step FAILED)
927  {
928  recoverableFailureFlag = processFailedStep();
929  }
930  } // transient
931 
932 #ifdef Xyce_DEBUG_ANALYSIS
933  if (tiaParams_.debugLevel > 0)
934  {
935  dout() << std::endl;
936  dout() << " Here we are, just before checking whether to pause. " << std::endl;
937  dout() << " minTimeStep = " << stepErrorControl_->minTimeStep << std::endl;
938  dout() << " final time = " << tiaParams_.finalTime << std::endl;
939  dout() << " pause time = " << analysisManager_.getPauseTime() << std::endl;
940  dout() << " initial time = " << stepErrorControl_->initialTime << std::endl;
941  dout() << " current time = " << stepErrorControl_->currentTime << std::endl;
943  {
944  dout() << " Pause time and current time equal " << std::endl;
945  }
946  else
947  {
948  dout() << " difference between current and pause times is " << analysisManager_.getPauseTime() - stepErrorControl_->currentTime << std::endl;
949  }
951  {
952  dout() << " Pause time and initial time equal " << std::endl;
953  }
954  }
955 #endif
956 
958  {
959  // Failure at this point only indicates that the simulation
960  // is paused and may be resumed.
961 #ifdef Xyce_DEBUG_ANALYSIS
962  if (tiaParams_.debugLevel > 0)
963  {
964  dout() << "Transient::loopProcess(): pausing simulation " << std::endl;
965  }
966 #endif
968  isPaused = true;
969  recoverableFailureFlag = false;
970  }
971 
972  // If the exit time has been exceeded, exit.
973  if (tiaParams_.exitTime != 0.0 &&
975  {
976 
977  lout() << "Exit time exceeded. Exiting transient loop\n" << std::endl;
978  recoverableFailureFlag = false;
979  }
980 
981  if (tiaParams_.exitStep != -1 &&
982  static_cast<int>(stepNumber) == tiaParams_.exitStep)
983  {
984  lout() <<"Exit step. Exiting transient loop\n" << std::endl;
985  recoverableFailureFlag = false;
986  }
987 
988  return recoverableFailureFlag;
989 }
990 
991 //-----------------------------------------------------------------------------
992 // Function : Transient::processSuccessfulDCOP()
993 // Purpose :
994 // Special Notes :
995 // Scope : public
996 // Creator : Rich Schiek, SNL
997 // Creation Date : 3/11/06
998 //-----------------------------------------------------------------------------
1000 {
1001  bool bsuccess = true;
1002 
1003  loader_.stepSuccess(analysisManager_.getCurrentMode());
1004 
1005  if (sensFlag_ && !firstDoubleDCOPStep_() )
1006  {
1009  }
1010 
1012 
1013  // Communicate down to the device level that the step has been accepted.
1014  // This must be done before the "times" get rotated, and certainly before
1015  // the vectors get rotated. The primary target for this call is the
1016  // transmission line device, which needs to know when it has a valid
1017  // solution so it can save history. (And now the ADC/DAC devices too)
1018  // needs to happen before dcopFlag_ is set to false.
1019  loader_.acceptStep();
1020 
1021  // Reset some settings (to switch from DCOP to transient, if not the
1022  // first step of a "double" DCOP.
1023  if ( firstDoubleDCOPStep_ () ) // (pde-only)
1024  {
1025  dcopFlag_ = true;
1028  }
1029  else
1030  {
1031  dcopFlag_ = false;
1035  beginningIntegration = true;
1036  }
1037 
1041 
1043 
1044  tranopOutputs ();
1045 
1046  // Now that output has been called, update the doubleDCOP step
1047  // if neccessary. (Only matters for pde problems)
1049 
1050  //Test and save restart if necessary
1052  {
1053  if (DEBUG_RESTART)
1054  dout() << "\n " << analysisManager_.getCommandLine().getArgumentValue("netlist")
1055  << " Calling dumpRestartData" << std::endl;
1056 
1058 
1059  if (DEBUG_RESTART)
1060  dout() << " Done Calling dumpRestartData" << std::endl;
1061  }
1062 
1063  // This output call is for device-specific output, such as .OP,
1064  // or internal plot output from PDE(TCAD) devices.
1065  loader_.output();
1066 
1069 
1070  return bsuccess;
1071 }
1072 
1073 //-----------------------------------------------------------------------------
1074 // Function : Transient::processSuccessfulStep()
1075 // Purpose :
1076 // Special Notes :
1077 // Scope : public
1078 // Creator : Rich Schiek, SNL
1079 // Creation Date : 3/11/06
1080 //-----------------------------------------------------------------------------
1082 {
1084 
1085  loader_.stepSuccess(analysisManager_.getCurrentMode());
1086 
1087  if( historyTrackingOn_ )
1088  {
1089  // store status of this step
1092  stepStatusQueue_.push_back( 1 );
1098  }
1099 
1100  if (sensFlag_ )
1101  {
1104  }
1105 
1106 #ifdef Xyce_DEBUG_ANALYSIS
1107  if (tiaParams_.debugLevel > 0)
1108  {
1109  dout() << " Transient::processSuccessfulStep()" << std::endl
1110  << "Newton step succeeded:" << std::endl
1111  << "nextSolutionPtr: " << std::endl;
1112 
1113  analysisManager_.getTIADataStore()->nextSolutionPtr->printPetraObject(dout());
1114  dout() << std::endl;
1115  }
1116 #endif
1117  // Set things up for the next time step, based on if this one was
1118  // successful.
1119 
1120  // This output call is for device-specific output (like from a PDE device,
1121  // outputting mesh-based tecplot files). It will only work in parallel if on
1122  // a machine where all processors have I/O capability.
1123  // Note: this output needs to happen before the "times" get rotated.
1124  loader_.output();
1125 
1126  // Communicate down to the device level that the step has been accepted.
1127  // This must be done before the "times" get rotated, and certainly before
1128  // the vectors get rotated. The primary target for this call is the
1129  // transmission line device, which needs to know when it has a valid
1130  // solution so it can save history.
1131  loader_.acceptStep();
1132 
1133  // current time will get updated in completeStep(). We'll save its value
1134  // for the moment so it can be saved if needed with the rest of the
1135  // solution if tiaParams_.saveTimeStepsFlag is set.
1136  // This fixes an off by one bug in getting the right time value and
1137  // keeps the real solutions associated with that value too.
1138  double currentTime = stepErrorControl_->currentTime;
1139  double suggestedMaxTime=0.0;
1141  {
1142  suggestedMaxTime = maxTimeStepExpressionRCPtr_->evaluate(comm_, outputManagerAdapter_.getOutputManager().getCircuitTime(),
1144  }
1145  stepErrorControl_->updateMaxTimeStep( suggestedMaxTime );
1148 
1149 #ifdef Xyce_VERBOSE_TIME
1150  if (tiaParams_.debugLevel > 0)
1151  {
1152  dout() << "Transient Analysis: accepting time step" << std::endl;
1153  }
1154 #endif // Xyce_VERBOSE_TIME
1155 
1157 
1158 #ifdef Xyce_VERBOSE_TIME
1160  {
1161  dout().precision(15);
1162  dout() << "ERROROPTION=1: TimeStepLimitedbyBP = " << tiaParams_.TimeStepLimitedbyBP << "\n" << std::endl;
1163  dout() << "ERROROPTION=1: NL Its = " << stepErrorControl_->nIterations << "\n" << std::endl;
1164  dout() << "ERROROPTION=1: New DeltaT = " << stepErrorControl_->currentTimeStep << "\n" << std::endl;
1165  }
1166 #endif // Xyce_VERBOSE_TIME
1167 
1168  stepNumber += 1;
1169  tranStepNumber += 1;
1172 
1176 
1177  // --------------------------------------------------------------------
1178  // Check to see if we have hit the end or a discontinuity point. The
1179  // next discontinuity point is represented by the stopTime variable.
1180 
1181  // Note: make sure that when we check for discontinuity point, we take
1182  // into account the possibility of roundoff error. Use the same bpTol
1183  // as is used in function updateBreakPoints.
1184  double bpTol = analysisManager_.getBreakpointTol();
1185 
1186  if (tiaParams_.bpEnable)
1187  {
1189  double timeDiff2 = stepErrorControl_->currentTime - tiaParams_.finalTime;
1190  timeDiff1 = fabs(timeDiff1);
1191  timeDiff2 = fabs(timeDiff2);
1192 
1193 #ifdef Xyce_DEBUG_ANALYSIS
1194  if (tiaParams_.debugLevel > 0)
1195  {
1196  dout() << " Checking whether to set breakpointrestartstep" << std::endl;
1197  dout() << " current - stop = " << timeDiff1 << std::endl;
1198  dout() << " current - final = " << timeDiff2 << std::endl;
1199  dout() << " bpTol = " << bpTol << std::endl;
1200  if (timeDiff1 <= bpTol && timeDiff2 > bpTol)
1201  dout() << " setting breakPointRestartStep to " << tranStepNumber;
1202  }
1203 #endif
1204  if (timeDiff1 <= bpTol && timeDiff2 > bpTol)
1205  {
1207  }
1208  }
1209 
1211  {
1212  beginningIntegration = true;
1213  }
1214  else
1215  {
1216  beginningIntegration = false;
1217  }
1218 
1220  {
1222  }
1224  {
1227  }
1228 
1230  {
1231  analysisManager_.getTIADataStore()->timeSteps.push_back(currentTime);
1233  N_LAS_Vector * aVecPtr = new N_LAS_Vector( *(analysisManager_.getTIADataStore()->currSolutionPtr) );
1234  analysisManager_.getTIADataStore()->fastTimeSolutionVec.push_back( aVecPtr );
1235  aVecPtr = new N_LAS_Vector( *(analysisManager_.getTIADataStore()->currStatePtr) );
1236  analysisManager_.getTIADataStore()->fastTimeStateVec.push_back( aVecPtr );
1237  aVecPtr = new N_LAS_Vector( *(analysisManager_.getTIADataStore()->daeQVectorPtr) );
1238  analysisManager_.getTIADataStore()->fastTimeQVec.push_back( aVecPtr );
1239  aVecPtr = new N_LAS_Vector( *(analysisManager_.getTIADataStore()->currStorePtr) );
1240  analysisManager_.getTIADataStore()->fastTimeStoreVec.push_back( aVecPtr );
1241  }
1242 
1243  // 03/16/04 tscoffe: This is where the solution pointers are rotated.
1245 
1246 #ifdef Xyce_DEBUG_ANALYSIS
1247 #ifdef Xyce_DEBUG_TIME
1248  if (tiaParams_.debugLevel > 1)
1250 #endif
1251 #endif
1252 
1253  tranStepOutputs ();
1254 
1255  // Test and save restart if necessary
1258 
1260 
1261  // reset min error tracking variables
1262  // if the step number is less than zero we'll assume there is no valid
1263  // min. estimated error over tol or an associated time step. This frees us
1264  // from putting Machine::Big here and trying to do something with that.
1266 
1267  return true;
1268 }
1269 
1270 
1271 //-----------------------------------------------------------------------------
1272 // Function : Transient::processFailedStep
1273 // Purpose :
1274 // Special Notes :
1275 // Scope : public
1276 // Creator : Rich Schiek, SNL
1277 // Creation Date : 3/11/06
1278 //-----------------------------------------------------------------------------
1280 {
1281  bool bsuccess = true;
1282 
1284 
1285  if( historyTrackingOn_ )
1286  {
1287  // store status of this step
1290  stepStatusQueue_.push_back( 0 );
1296  }
1297 
1298  // save some info about this step
1299  double estOverTol = stepErrorControl_->getEstOverTol();
1300  if( (stepNumberAtMinEstErrorOverTol < 0) || ( estOverTol < minEstErrorOverTol ) )
1301  {
1302  // our first failed step, so automatically save info
1306  }
1307 
1308  loader_.stepFailure(analysisManager_.getCurrentMode());
1309 
1310 #ifdef Xyce_VERBOSE_TIME
1311  // DO NOT REMOVE THIS OUTPUT LINE. It is depended upon by the TIA/ERROROPTION
1312  // test case, which will fail if this output doesn't happen.
1313  dout() << "Transient Analysis: rejecting time step" << std::endl;
1314 #endif // Xyce_VERBOSE_TIME
1315 
1317 
1318 #ifdef Xyce_VERBOSE_TIME
1320  {
1321  dout().precision(15);
1322  dout() << "ERROROPTION=1: TimeStepLimitedbyBP = " << tiaParams_.TimeStepLimitedbyBP << "\n" << std::endl;
1323  dout() << "ERROROPTION=1: NL Its = " << stepErrorControl_->nIterations << "\n" << std::endl;
1324  dout() << "ERROROPTION=1: New DeltaT = " << stepErrorControl_->currentTimeStep << "\n" << std::endl;
1325  }
1326 #endif // Xyce_VERBOSE_TIME
1327 
1328 #ifdef Xyce_DEBUG_ANALYSIS
1329  if (tiaParams_.debugLevel > 0)
1330  {
1331  dout() << " Transient::processFailedStep" << std::endl
1332  << "Newton step failed:" << std::endl
1333  << "nextSolutionPtr: " << std::endl;
1334  analysisManager_.getTIADataStore()->nextSolutionPtr->printPetraObject(dout());
1335  dout() << std::endl;
1336  }
1337 #endif
1340 
1342  {
1343 #ifdef Xyce_DEBUG_ANALYSIS
1344  if (tiaParams_.debugLevel > 0)
1345  {
1346  dout() << "currTimeStep: " << stepErrorControl_->currentTimeStep << std::endl;
1347  dout() << "minTimeStep: " << stepErrorControl_->minTimeStep << std::endl;
1348  }
1349 #endif
1350 
1351  // before we exit with a time step too small error, check if minTimeStepRecoveryCounter is greater than zero
1352  // if it is, then the user wants us to try to accept the step that had the minimum
1353  // estimated error over tol.
1355  {
1356  lout() << "Attempting to retake and accept step where estimated error over tolerance was: " << minEstErrorOverTol
1357  << " and time step was: " << timeStepAtMinEstErrorOverTol << std::endl;
1358 
1361  }
1362  else
1363  {
1364  outputQueuedData();
1365  lout() << "Time step too small near step number: " << stepNumber << " Exiting transient loop.\n" << std::endl;
1366 
1367  bsuccess = false;
1368  }
1369  }
1370 
1372  {
1373  outputQueuedData();
1374  lout() << "Newton solver failed in constant time step mode. Exiting transient loop.\n" << std::endl;
1375 
1376  bsuccess = false;
1377  }
1378 
1379  if (tiaParams_.exitStep != -1 &&
1380  static_cast<int>(stats_.successStepsThisParameter_) == (tiaParams_.exitStep - 1))
1381  {
1382  outputQueuedData();
1383  lout() << "Exit Step. Exiting transient loop\n" << std::endl;
1384  bsuccess = false;
1385  }
1386 #ifdef Xyce_VERBOSE_TIME
1387  if (!bsuccess)
1388  {
1389  endTRANtime = analysisManager_.getXyceTranTimer().elapsedTime();
1390  tranStats = saveLoopInfo();
1392  }
1393 #endif
1394 
1395  return bsuccess;
1396 }
1397 
1398 //-----------------------------------------------------------------------------
1399 // Function : Transient::processFailedDCOP
1400 // Purpose :
1401 // Special Notes :
1402 // Scope : public
1403 // Creator : Rich Schiek, SNL
1404 // Creation Date : 3/11/06
1405 //-----------------------------------------------------------------------------
1407 {
1408  bool bsuccess = true;
1409 
1410  loader_.stepFailure(analysisManager_.getCurrentMode());
1411 
1412  // DC Operating Point failed.
1415 
1416  lout() << "DC Operating Point Failed. Exiting transient loop" << std::endl;
1417 
1418  return bsuccess;
1419 }
1420 
1421 //-----------------------------------------------------------------------------
1422 // Function : Transient::finish
1423 // Purpose :
1424 // Special Notes :
1425 // Scope : public
1426 // Creator : Rich Schiek, SNL
1427 // Creation Date : 3/11/06
1428 //-----------------------------------------------------------------------------
1430 {
1431  bool bsuccess = true;
1432 
1434  {
1436  dsPtr_->timeSteps.push_back(stepErrorControl_->currentTime);
1437  dsPtr_->timeStepsBreakpointFlag.push_back(beginningIntegration);
1438  N_LAS_Vector * aVecPtr = new N_LAS_Vector( *(dsPtr_->currSolutionPtr) );
1439  dsPtr_->fastTimeSolutionVec.push_back( aVecPtr );
1440  aVecPtr = new N_LAS_Vector( *(dsPtr_->currStatePtr) );
1441  dsPtr_->fastTimeStateVec.push_back( aVecPtr );
1442  aVecPtr = new N_LAS_Vector( *(dsPtr_->daeQVectorPtr) );
1443  dsPtr_->fastTimeQVec.push_back( aVecPtr );
1444  aVecPtr = new N_LAS_Vector( *(dsPtr_->currStorePtr) );
1445  dsPtr_->fastTimeStoreVec.push_back( aVecPtr );
1446  }
1447 
1448  if (!isPaused)
1449  {
1450 #ifdef Xyce_DEBUG_ANALYSIS
1451  dout() << "Calling finishOutput" << std::endl;
1452 #endif
1454 
1455  // This output call is for device-specific output (like from a PDE device,
1456  // outputting mesh-based tecplot files). It will only work in parallel if on
1457  // a machine where all processors have I/O capability, as devices are
1458  // local to a processor.
1459  loader_.finishOutput();
1460 
1462  }
1463 
1464  return bsuccess;
1465 }
1466 
1467 //-----------------------------------------------------------------------------
1468 // Function : Transient::handlePredictor
1469 // Purpose :
1470 // Special Notes :
1471 // Scope : private
1472 // Creator : Eric Keiter, SNL
1473 // Creation Date : 06/24/2013
1474 //-----------------------------------------------------------------------------
1476 {
1480 
1481 #ifdef Xyce_DEBUG_ANALYSIS
1482 #ifdef Xyce_DEBUG_TIME
1483  if (tiaParams_.debugLevel > 1)
1484  {
1485  dout() << " Transient::handlePredictor" << std::endl;
1488  }
1489 #endif
1490 #endif
1491 
1492  // Now, in case this is the upper level of a 2-level sim, tell the
1493  // inner solve to do its prediction:
1494  loader_.startTimeStep ();
1495 
1496  return true;
1497 }
1498 
1499 //-----------------------------------------------------------------------------
1500 // Function : Transient::resetForHB()
1501 // Purpose : When doing initial transient run, some analyses require
1502 // a reset function
1503 // they can fill this in if needed.
1504 // Special Notes :
1505 // Scope : public
1506 // Creator : T. Mei, SNL, Parallel Computational Sciences
1507 // Creation Date : 2/26/09
1508 //-----------------------------------------------------------------------------
1510 {
1514  dcopFlag_ = false;
1516 
1517  if (historyTrackingOn_)
1518  {
1519  // these set_size calls will also "reset" the queue.
1520  timeQueue_.set_size( queueSize_ );
1521  timeStepQueue_.set_size( queueSize_ );
1522  stepStatusQueue_.set_size( queueSize_ );
1523  estErrorOverTolQueue_.set_size( queueSize_ );
1528  }
1529 
1530  return true;
1531 }
1532 
1533 
1534 //-----------------------------------------------------------------------------
1535 // Function : Transient::finalVerboseOutput
1536 // Purpose :
1537 // Special Notes :
1538 // Scope : public
1539 // Creator : Rich Schiek, SNL
1540 // Creation Date : 3/11/06
1541 //-----------------------------------------------------------------------------
1543 {
1544  bool bsuccess = true;
1545 
1546  lout() << "***** Problem read in and set up time: " << analysisManager_.getSolverStartTime() << " seconds" << std::endl;
1547 
1549  {
1550  double time;
1552  {
1554  }
1555  else
1556  {
1557  time = endTRANtime - startDCOPtime;
1558  }
1559  lout() << " ***** DCOP time: " << time << " seconds. Breakdown follows:" << std::endl;
1560 
1561  printLoopInfo(0, dcStats);
1562  }
1563 
1566  {
1567  lout() << " ***** Transient Stepping time: " << endTRANtime-analysisManager_.getStartTranTime() << " seconds. Breakdown follows:" << std::endl;
1568 
1570  }
1571 
1572  return bsuccess;
1573 }
1574 
1575 //-----------------------------------------------------------------------------
1576 // Function : Transient::outputQueuedData
1577 // Purpose :
1578 // Special Notes :
1579 // Scope : public
1580 // Creator : Rich Schiek, SNL
1581 // Creation Date : 3/11/06
1582 //-----------------------------------------------------------------------------
1584 {
1585  if( historyTrackingOn_ )
1586  {
1587 #ifndef Xyce_PARALLEL_MPI
1588  // if necessary set up the names map.
1589  const Xyce::NodeNamePairMap & nodeNames = outputManagerAdapter_.getAllNodes();
1590  int nodeNameSize = nodeNames.size();
1591  nameVec_.resize(nodeNameSize+1,"gnd");
1592  Xyce::NodeNamePairMap::const_iterator mapI, mapEnd;
1593  mapEnd = nodeNames.end();
1594  mapI = nodeNames.begin();
1595  for ( ; mapI != mapEnd ; ++mapI)
1596  {
1597  nameVec_[(*mapI).second.first] = (*mapI).first;
1598  }
1599 #endif
1600 
1601  // get the current non-linear solver return codes
1603 
1604  lout() << " *** Transient failure history: " << std::endl;
1606  {
1607  // truncation error is not used here so est err over tol is not useful in the output
1608  lout() << "Time Time Step Non-Linear Solver node node" << std::endl;
1609  lout() << "(sec) Step Status Status Iters ||F|| index name" << std::endl;
1610  }
1611  else
1612  {
1613  lout() << "Time Time Step EstErr Non-Linear Solver node node" << std::endl;
1614  lout() << "(sec) Step Status OverTol Status Iters ||F|| index name" << std::endl;
1615  }
1616 
1617  for( int i=0; i<queueSize_; i++ )
1618  {
1619  int fieldWidth=10;
1620  lout() << std::scientific << std::setprecision(fieldWidth-7) << std::setfill(' ') << std::right << std::setw( fieldWidth )
1621  << timeQueue_.at_from_tail(i) << " "
1622  << timeStepQueue_.at_from_tail(i) << " ";
1623  if( stepStatusQueue_.at_from_tail(i) == 1 )
1624  {
1625  lout() << "pass ";
1626  }
1627  else
1628  {
1629  lout() << "fail ";
1630  }
1632  {
1633  }
1634  else
1635  {
1636  lout() << estErrorOverTolQueue_.at_from_tail(i) << " ";
1637  }
1638  int nlStatus = nonlinearSolverStatusQueue_.at_from_tail(i);
1639  lout() << std::setw(7) << std::right;
1640  if( nlStatus == nlReturnCodes.normTooSmall )
1641  {
1642  lout() << "P:s nrm";
1643  }
1644  else if( nlStatus == nlReturnCodes.normalConvergence)
1645  {
1646  lout() << "pass ";
1647  }
1648  else if( nlStatus == nlReturnCodes.nearConvergence )
1649  {
1650  lout() << "P:near ";
1651  }
1652  else if( nlStatus == nlReturnCodes.smallUpdate )
1653  {
1654  lout() << "P:s up ";
1655  }
1656  else if( nlStatus == nlReturnCodes.nanFail )
1657  {
1658  lout() << "F:NaN ";
1659  }
1660  else if( nlStatus == nlReturnCodes.tooManySteps )
1661  {
1662  lout() << "F:max s";
1663  }
1664  else if( nlStatus == nlReturnCodes.tooManyTranSteps )
1665  {
1666  lout() << "F:max s";
1667  }
1668  else if( nlStatus == nlReturnCodes.updateTooBig )
1669  {
1670  lout() << "F:big u";
1671  }
1672  else if( nlStatus == nlReturnCodes.stalled )
1673  {
1674  lout() << "F:stall";
1675  }
1676  else if( nlStatus == nlReturnCodes.wrmsExactZero )
1677  {
1678  lout() << "F:n zro";
1679  }
1680  else if( nlStatus == nlReturnCodes.innerSolveFailed )
1681  {
1682  lout() << "F:in Fl";
1683  }
1684  else
1685  {
1686  lout() << "code=" <<
1687  nonlinearSolverStatusQueue_.at_from_tail(i) << " ";
1688  }
1689 
1690  lout() << std::right << std::setw( 4 )
1691  << nonlinearSolverNumIterationsQueue_.at_from_tail(i) << " "
1692  << nonlinearSolverMaxNormQueue_.at_from_tail(i) ;
1693 
1694  int outIndex = nonlinearSolverMaxNormIndexQueue_.at_from_tail(i) ;
1695  lout() << std::right << std::fixed << std::setw( 7 ) << outIndex;
1696 
1697  std::string outIndexName("");
1698  if (!(nameVec_.empty()))
1699  {
1700  int nsize = nameVec_.size();
1701  if (nsize > outIndex && outIndex >=0)
1702  {
1703  outIndexName = nameVec_[outIndex];
1704  }
1705  }
1706  else
1707  {
1708  outIndexName = "N/A";
1709  }
1710  lout() << std::left << " " << outIndexName;
1711  lout() << std::endl;
1712  }
1713  }
1714 }
1715 
1716 //-----------------------------------------------------------------------------
1717 // Function : Transient::takeAnIntegrationStep_
1718 // Purpose : Take a transient integration step.
1719 // Special Notes :
1720 // Scope : private
1721 // Creator : Richard Schiek, SNL, Electrical and Microsystem Modeling
1722 // Creation Date : 01/24/08
1723 //-----------------------------------------------------------------------------
1725 {
1726  handlePredictor();
1727  loader_.updateSources();
1729 
1730 #ifdef Xyce_DEBUG_ANALYSIS
1731  dout() << "Transient::takeAnIntegrationStep_: newtonConvergenceStatus = " << stepErrorControl_->newtonConvergenceStatus << std::endl;
1732 #endif
1733 
1738 }
1739 
1740 //-----------------------------------------------------------------------------
1741 // Function : Transient::twoLevelStep
1742 //
1743 // Purpose : Take a transient integration step, for inner 2-level solve.
1744 //
1745 // Special Notes : Same as takeAnIntegrationStep, but does not do the
1746 // prediction. (that is in handlePredictor_).
1747 //
1748 // The prediction is handled separately, as for a 2-level
1749 // solve, you only want to do the prediction on the first
1750 // solve of the attempted time step.
1751 //
1752 // Scope : public
1753 // Creator :
1754 // Creation Date : 3/11/06
1755 //-----------------------------------------------------------------------------
1757 {
1758  loader_.updateSources();
1761 
1764 
1765  endTRANtime = analysisManager_.getXyceTranTimer().elapsedTime();
1766  tranStats = saveLoopInfo();
1767 
1769 }
1770 
1771 //-----------------------------------------------------------------------------
1772 // Function : Transient::retakeAndAcceptTimeStep
1773 // Purpose : Do a requested time step and accept it
1774 // Special Notes :
1775 // Scope : public
1776 // Creator : Rich Schiek, Electrical and Microsystems Modeling
1777 // Creation Date : 01/23/09
1778 //-----------------------------------------------------------------------------
1779 bool Transient::retakeAndAcceptTimeStep( double aTimeStep )
1780 {
1781  bool bsuccess=true;
1782  // This function was put in place to handle the following situation.
1783  // If a series of time steps are rejected because the estimated error
1784  // over tol. is too high, Xyce may exit if the next time step falls under
1785  // the minTimeStep. A user could adjust the tolerances of a simulation
1786  // to try and get around this, but in UQ studies where there are 1,000s of
1787  // simulations, it can be difficult to get all of them to run. So,
1788  // if the user has set the netlist option timeint MINTIMESTEPRECOVERY=<int>
1789  // and we're about to exit because the time step has fallen under the minTimeStep
1790  // we will try and retake the time step that had the min. est. error over tol.
1791  // and accept that.
1792  //
1793  // At this point, Transient::processFailedStep() has already determined
1794  // that the preconditions outlined above are in place (i.e. the user requested
1795  // this and we're about to exit with a time step too small error), so lets
1796  // try the step that had the min. est error over tol.
1797 
1798  // set time step
1800 
1801  // take step
1803 
1804  // can't accept step if the non-linear solver failed
1806  {
1807  lout() << "Time step too small near step number: " << stepNumber << " Exiting transient loop.\n" << std::endl;
1808  bsuccess = false;
1809  }
1810  else
1811  {
1813  }
1814  return bsuccess;
1815 }
1816 
1817 //-----------------------------------------------------------------------------
1818 // Function : Transient::printStepHeader()
1819 // Purpose : Prints out time step information.
1820 // Special Notes :
1821 // Scope : public
1822 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1823 // Creation Date : 6/26/00
1824 //-----------------------------------------------------------------------------
1825 void Transient::printStepHeader(std::ostream &os)
1826 {
1827  if (VERBOSE_TIME) {
1828  os << "***** " << (DEBUG_ANALYSIS ? analysisManager_.getCommandLine().getArgumentValue("netlist") : "") << " ";
1829 
1830  if (dcopFlag_)
1831  {
1832  os << "Start of DCOP STEP # ";
1833  }
1834  else
1835  {
1837  {
1839  {
1840  os << "Start of Time Step (INITIAL STEP) # ";
1841  }
1842  else
1843  {
1844  os << "Start of Time Step (DISCONTINUITY STEP) # ";
1845  }
1846  }
1847  else
1848  {
1850  {
1851  os << "Start of Time Step (AFTER FAILED STEP) # ";
1852  }
1853  else
1854  {
1855  os << "Start of Time Step (AFTER SUCCESS STEP) # ";
1856  }
1857  }
1858  }
1859 
1860  os << stats_.successStepsThisParameter_ + 1 << std::endl;
1861  }
1862 }
1863 
1864 //-----------------------------------------------------------------------------
1865 // Function : Transient::printProgress()
1866 // Purpose : Outputs run completion percentage and estimated
1867 // time-to-completion.
1868 //
1869 // Special Notes : This will need some fixing to work with .STEP.
1870 //
1871 // Scope : public
1872 // Creator : Scott A. Hutchinson, SNL, Computational Sciences
1873 // Creation Date : 06/07/2002
1874 //-----------------------------------------------------------------------------
1875 void Transient::printProgress(std::ostream &os)
1876 {
1878  {
1879  // Percent of the overall requested simulation time which is completed.
1880  double percentComplete;
1881  // Average CPU time per time step.
1882  double aveCPUTimePerStep;
1883  // Average clock time per time step.
1884  double aveSimTimePerStep;
1885  // Estimated CPU time to complete the simulation.
1886  double estCompletionTime = 0.0;
1887 
1888  // Report the beginning of the DC OP calculation. First call in OP.
1889  if (dcopFlag_)
1890  {
1892  if (gui_)
1893  {
1894  Report::signalProgress("Xyce in DC Operating Point Calculation");
1895  }
1896  os << "***** Beginning DC Operating Point Calculation...\n" << std::endl;
1897  }
1898  else if (firstTime && stats_.successStepsThisParameter_ == 1)
1899  {
1901  dcStats = saveLoopInfo();
1902  firstTime = false;
1903  if (gui_)
1904  {
1905  Report::signalProgress("Xyce in Transient Calculation");
1906  }
1907  os << "***** Beginning Transient Calculation...\n" << std::endl;
1908  }
1910  {
1911  if (startSimTime == -1.0)
1913 
1914  double diff1 = fabs(stepErrorControl_->currentTime - tiaParams_.initialTime);
1915  double diff2 = fabs(tiaParams_.finalTime - tiaParams_.initialTime);
1916 
1917  // 02/05/08 tscoffe: optimization differences after the TIA_REFACTOR
1918  // caused a floating point difference here and this resolves that
1919  // difference. After the refactor is merged back onto the main trunk, this
1920  // stuff should be removed.
1921  percentComplete = 100.0 * diff1/diff2;
1922 
1923  if (fabs(percentComplete - oldPercentComplete) > 1.0)
1924  {
1925  oldPercentComplete = percentComplete;
1926 
1927  aveCPUTimePerStep = analysisManager_.getXyceTranTimer().elapsedTime() /
1929  aveSimTimePerStep = (stepErrorControl_->currentTime - startSimTime) /
1931 
1932  if (aveSimTimePerStep > Util::MachineDependentParams::MachineEpsilon())
1933  estCompletionTime = aveCPUTimePerStep *
1935  aveSimTimePerStep;
1936 
1937  if (!gui_)
1938  {
1939  os << "***** Percent complete: " << percentComplete << " %" << std::endl;
1940  }
1941 
1942  if (estCompletionTime > Util::MachineDependentParams::MachineEpsilon())
1943  {
1944  unsigned int days, hours, minutes, seconds;
1945  days = static_cast<int> (estCompletionTime / 86400);
1946  hours = static_cast<int> ((estCompletionTime - days * 86400) / 3600);
1947  minutes = static_cast<int> ((estCompletionTime - days * 86400 - hours * 3600) / 60);
1948  seconds = static_cast<int> (estCompletionTime - days * 86400 - hours * 3600 - minutes * 60);
1949 
1950  char timeStr[256];
1951  for (char *c = timeStr; c != timeStr + sizeof(timeStr); ++c)
1952  *c = 0;
1953 
1954 #ifdef Xyce_PARALLEL_MPI
1955  // get current local system time
1956  time_t t = time( NULL );
1957  struct tm * now = localtime( &t );
1958 
1959  // format and display output
1960  if ( ( t != (time_t)-1 ) && ( strftime( timeStr, 255, "%c", now ) != 0 ) )
1961  {
1962  os << "***** Current system time: " << timeStr << std::endl;
1963  }
1964 
1965  else
1966  {
1967  os << "***** Current system time could not be determined." << std::endl;
1968  }
1969 #endif
1970 
1971  if (days > 0)
1972  sprintf(timeStr, "%3d days, %2d hrs., %2d min., %2d sec.", days, hours, minutes, seconds);
1973  else if (hours > 0)
1974  sprintf(timeStr, "%2d hrs., %2d min., %2d sec.", hours, minutes, seconds);
1975  else if (minutes > 0)
1976  sprintf(timeStr, "%2d min., %2d sec.", minutes, seconds);
1977  else
1978  sprintf(timeStr, "%2d sec.", seconds);
1979 
1980  if (gui_)
1981  {
1982  std::ostringstream ost;
1983  ost << "Xyce transient ";
1984  if (percentComplete < 10)
1985  ost.precision(2);
1986  else
1987  ost.precision(3);
1988  ost << percentComplete
1989  << "%% complete ... Estimated time to completion: "
1990  << timeStr << std::endl;
1991  Report::signalProgress(ost.str());
1992  }
1993  else
1994  {
1995  os << "***** Estimated time to completion: " << timeStr << std::endl << std::endl;
1996  }
1997  }
1998  }
1999  }
2000  }
2001 }
2002 
2003 //-----------------------------------------------------------------------------
2004 // Function : Transient::noopOutputs
2005 // Purpose :
2006 // Special Notes :
2007 // Scope : public
2008 // Creator : Eric Keiter, SNL, Electrical and Microsystems Modeling
2009 // Creation Date : 8/31/2007
2010 //-----------------------------------------------------------------------------
2012 {
2013  if( testOutputTime_() )
2014  {
2015  if ( !firstDoubleDCOPStep_ () )
2016  {
2017  bool printIC = true;
2018  if (printIC)
2019  {
2025  objectiveVec_,
2027  }
2028  if (analysisManager_.getMPDEManager() && analysisManager_.getMPDEManager()->getMPDEFlag() && !analysisManager_.getMPDEManager()->getMPDEIcFlag())
2029  {
2030  // output the operating point if we can in MPDE mode
2032  }
2033  }
2035  }
2036 }
2037 
2038 //-----------------------------------------------------------------------------
2039 // Function : Transient::tranopOutputs
2040 // Purpose :
2041 // Special Notes :
2042 // Scope : public
2043 // Creator : Eric Keiter, SNL, Electrical and Microsystems Modeling
2044 // Creation Date : 8/31/2007
2045 //-----------------------------------------------------------------------------
2047 {
2048  //Test and output if necessary
2049  if( testOutputTime_() )
2050  {
2051  // Make sure this isn't the NLP step of a PDE DCOP.
2052  if ( !firstDoubleDCOPStep_ () )
2053  {
2054 #ifdef Xyce_DEBUG_ANALYSIS
2055  dout() << "Calling conventional TRANOP outputs!" << std::endl;
2056 #endif
2061  objectiveVec_,
2063 
2065  // check this - may be a mistake.
2066  }
2068  }
2069 
2070  // SAVE and DCOP restart:
2072  {
2074  }
2075 }
2076 
2077 //-----------------------------------------------------------------------------
2078 // Function : Transient::tranStepOutputs
2079 // Purpose :
2080 // Special Notes :
2081 // Scope : public
2082 // Creator : Eric Keiter, SNL, Electrical and Microsystems Modeling
2083 // Creation Date : 8/31/2007
2084 //-----------------------------------------------------------------------------
2086 {
2087  // The printOutputSolution function will sometimes perform
2088  // interpolations between the current step and the previous step,
2089  // if the integrator is using a high order of integration during
2090  // a new-DAE simulation.
2091 
2092  // If the user has specified tstart, and this happens to be
2093  // the first output of the simulation (at t=tstart, instead of
2094  // t=0) the force the interpolator to *not* interpolate, even
2095  // if it is doing so normally.
2096  bool doNotInterpolate=
2098 
2099 #ifdef Xyce_DEBUG_ANALYSIS
2100  if (tiaParams_.debugLevel > 0)
2101  {
2102  if (doNotInterpolate)
2103  {
2104  dout() << "doNotInterpolate is TRUE!" << std::endl;
2105  }
2106  else
2107  {
2108  dout() << "doNotInterpolate is FALSE!" << std::endl;
2109  }
2110  }
2111 #endif
2112 
2113  if (testOutputTime_())
2114  {
2115  if (analysisManager_.getMPDEManager() && analysisManager_.getMPDEManager()->blockAnalysisFlag())
2116  {
2117 #ifdef Xyce_DEBUG_ANALYSIS
2118  if (tiaParams_.debugLevel > 0)
2119  {
2120  dout() << "Calling MPDE outputs!" << std::endl;
2121  }
2122 #endif
2124 
2125  // If we are actually in the MPDE phase, rather than the initial
2126  // condition, then output here.
2127  if (analysisManager_.getMPDEManager()->getMPDEFlag()==true && tiaParams_.outputInterpMPDE)
2128  {
2129  if (analysisManager_.getMPDEManager()->getWaMPDEFlag()==false)
2130  {
2131  std::vector<double> fastTimes = analysisManager_.getMPDEManager()->getFastTimePoints();
2135  fastTimes );
2136  }
2137  else
2138  {
2139  std::vector<double> fastTimes = analysisManager_.getMPDEManager()->getFastTimePoints();
2140  int phiGID = analysisManager_.getMPDEManager()->getPhiGID();
2144  fastTimes, phiGID );
2145  }
2146  }
2147  // uncomment the following else block to get mpde initial
2148  // condition calculations printed out
2149  else
2150  {
2151  // try normal new dae output
2156  doNotInterpolate,
2158  false) ;
2159  }
2160  }
2161  else
2162  {
2167  doNotInterpolate,
2169  false) ;
2170  }
2171 
2172  firstTranOutput_ = false;
2173 
2175  }
2176  else
2177  {
2178  // just call the output manager to udpate non print line elements
2183  doNotInterpolate,
2185  true) ;
2186  }
2187 
2188  // SAVE output:
2190  {
2194  analysisManager_.getSaveTime(), doNotInterpolate);
2195  }
2196 }
2197 
2198 //-----------------------------------------------------------------------------
2199 // Function : Transient::testOutputTime_
2200 // Purpose :
2201 // Special Notes :
2202 // Scope : public
2203 // Creator : Rob Hoekstra, SNL, Parallel ComputationalSciences.
2204 // Creation Date : 07/31/01
2205 //-----------------------------------------------------------------------------
2207 {
2208  bool flag;
2209 
2210 #ifdef Xyce_DEBUG_ANALYSIS
2211  if (tiaParams_.debugLevel > 0)
2212  {
2213  dout().width(21); dout().precision(13); dout().setf(std::ios::scientific);
2214  dout() << "Transient::testOutputTime. secPtr_->currentTime = " << stepErrorControl_->currentTime << std::endl;
2215  dout() << "Transient::testOutputTime. tStart = " << tiaParams_.tStart << std::endl;
2216  dout() << "Transient::testOutputTime. nextOutputTime_ = " << analysisManager_.getNextOutputTime() << std::endl;
2217  for (int i=0;i<analysisManager_.getOutputIntervals().size();++i)
2218  {
2219  dout() << "outputIntervals_["<<i<<"].first = " << analysisManager_.getOutputIntervals()[i].first;
2220  dout() << std::endl;
2221  }
2222  dout() << std::endl;
2223  }
2224 #endif
2225 
2227  {
2228  flag = false;
2229  }
2231  {
2232  flag = true;
2233  }
2234  else if (analysisManager_.getInitialOutputInterval() == 0.0)
2235  {
2236  flag = true;
2237  }
2239  {
2240  flag = false;
2241  }
2242  else
2243  {
2244  flag = true;
2245  }
2246 
2247  return flag;
2248 }
2249 
2250 //-----------------------------------------------------------------------------
2251 // Function : Transient::updateOutputTime_
2252 // Purpose : Advance output time so it is the next one after currTime
2253 // Special Notes : formerly part of testOutputTime_
2254 // Scope : public
2255 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
2256 // Creation Date : 02/14/07
2257 //-----------------------------------------------------------------------------
2258 void Transient::updateOutputTime_(double currTime)
2259 {
2260  // We only need to bother with this if the user has specified output control
2261  // options
2263  {
2264  if (analysisManager_.getOutputIntervals().empty())
2265  {
2266  // Only an initial interval was specified
2267  while (analysisManager_.getNextOutputTime() <= currTime)
2269  }
2270  else if (currTime < analysisManager_.getOutputIntervals()[0].first)
2271  {
2272  // Multiple intervals, but we're still in the first one
2273  while (analysisManager_.getNextOutputTime() <= currTime)
2277  }
2278  else
2279  {
2280  // Multiple intervals specified, we're past the first one
2281  std::pair<double, double> currInterval, nextInterval;
2282  int size = analysisManager_.getOutputIntervals().size();
2283  for (int i = 0; i < size; ++i)
2284  if (analysisManager_.getOutputIntervals()[i].first <= currTime)
2285  {
2286  currInterval = analysisManager_.getOutputIntervals()[i];
2287  if ((i+1) < static_cast<int>(analysisManager_.getOutputIntervals().size()))
2288  nextInterval = analysisManager_.getOutputIntervals()[i+1];
2289  }
2290  int step = static_cast<int> ((currTime-currInterval.first) /
2291  currInterval.second);
2292  analysisManager_.setNextOutputTime(currInterval.first + (step+1)*currInterval.second);
2293  if (nextInterval.first && (nextInterval.first!=currInterval.first)
2294  && (analysisManager_.getNextOutputTime()>=nextInterval.first))
2295  analysisManager_.setNextOutputTime(nextInterval.first);
2296  }
2297 
2300  }
2301 }
2302 
2303 //-----------------------------------------------------------------------------
2304 // Function : Transient::computeOutputInterpolationTimes_
2305 // Purpose : When we pass "nextOutputTime_", we might have skipped
2306 // over points where output was requested. Make a list of
2307 // those times so we can interpolate to them.
2308 // Special Notes :
2309 // Scope : public
2310 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling.
2311 // Creation Date : 02/14/07
2312 //-----------------------------------------------------------------------------
2314 {
2315  double t;
2316  outputInterpolationTimes_.clear();
2317  // if there are no output control options specified, we do nothing.
2319  {
2320  if (analysisManager_.getOutputIntervals().empty() || currTime <= analysisManager_.getOutputIntervals()[0].first)
2321  {
2322  // we're either in the first interval, or there only *is* one interval
2324  while (t < currTime)
2325  {
2326  outputInterpolationTimes_.push_back(t);
2328  }
2329 
2330  if( (t - currTime) <= 100 * Util::MachineDependentParams::MachinePrecision() )
2331  {
2332  outputInterpolationTimes_.push_back(currTime);
2333  }
2334 
2335  if( (t - tiaParams_.finalTime) > 100 * Util::MachineDependentParams::MachinePrecision() )
2336  {
2337  // tack on finalTime or we'll miss it
2339  }
2340  }
2341  else // we're out of the first interval, and there is more than one
2342  {
2343  int outInt,lastInt;
2344 
2345  lastInt=analysisManager_.getOutputIntervals().size()-1;
2346 
2347  // find which interval nextOutputTime_ is in
2348  for (outInt=0;
2349  outInt<lastInt&&analysisManager_.getOutputIntervals()[outInt+1].first<=analysisManager_.getNextOutputTime();
2350  ++outInt) ;
2351 
2353  while (t <= currTime)
2354  {
2355  outputInterpolationTimes_.push_back(t);
2356  t += analysisManager_.getOutputIntervals()[outInt].second;
2357  if (outInt != lastInt && t >= analysisManager_.getOutputIntervals()[outInt+1].first)
2358  {
2359  ++outInt;
2360  t = analysisManager_.getOutputIntervals()[outInt].first;
2361  }
2362  }
2363  }
2364  }
2365 }
2366 
2367 } // namespace Analysis
2368 } // namespace Xyce