Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
N_DEV_DeviceMgr.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_DEV_DeviceMgr.C,v $
27 //
28 // Purpose :
29 //
30 // Special Notes :
31 //
32 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
33 //
34 // Creation Date : 02/28/00
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.633.2.2 $
40 //
41 // Revision Date : $Date: 2014/08/25 20:12:49 $
42 //
43 // Current Owner : $Author: dgbaur $
44 //-------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 
48 #include <algorithm>
49 #include <sstream>
50 #include <stdexcept>
51 
52 #include <N_ANP_AnalysisManager.h>
53 #include <N_DEV_Algorithm.h>
54 #include <N_DEV_Const.h>
55 #include <N_DEV_DeviceMgr.h>
57 #include <N_DEV_ExternDevice.h>
58 #include <N_DEV_InstanceName.h>
59 #include <N_DEV_Op.h>
60 #include <N_DEV_Print.h>
61 #include <N_DEV_RegisterDevices.h>
62 #include <N_DEV_Source.h>
63 #include <N_ERH_ErrorMgr.h>
64 #include <N_ERH_Message.h>
65 #include <N_IO_CmdParse.h>
66 #include <N_IO_Op.h>
67 #include <N_IO_OutputMgr.h>
68 #include <N_LAS_Builder.h>
69 #include <N_LAS_Matrix.h>
70 #include <N_LAS_System.h>
71 #include <N_PDS_Comm.h>
72 #include <N_PDS_MPI.h>
73 #include <N_PDS_Manager.h>
74 #include <N_UTL_Algorithm.h>
75 #include <N_UTL_Op.h>
76 
77 // These are slowly being removed as DeviceMgr should not depend on Devices. Devices should plug in to DeviceMgr.
78 #include <N_DEV_Bsrc.h>
79 #include <N_DEV_ISRC.h>
80 #include <N_DEV_MOSFET_B3.h>
81 #include <N_DEV_MOSFET_B3SOI.h>
82 #include <N_DEV_MOSFET_B4.h>
83 #include <N_DEV_Resistor.h>
84 #include <N_DEV_Resistor3.h>
85 #include <N_DEV_Vsrc.h>
86 
87 
88 namespace Xyce {
89 namespace Device {
90 
91 namespace {
92 
93 // structs related to options registration
94 struct OptionsReg : public IO::PkgOptionsReg
95 {
96  OptionsReg(DeviceMgr * mgr) : devMgr(mgr) {}
97 
98  bool operator()(const Util::OptionBlock & options)
99  {return devMgr->registerOptions(options);}
100 
101  DeviceMgr * devMgr;
102 };
103 
104 struct SensOptionsReg : public IO::PkgOptionsReg
105 {
106  SensOptionsReg(DeviceMgr * mgr) : devMgr(mgr) {}
107 
108  bool operator()(const Util::OptionBlock & options)
109  {return devMgr->registerSensParams(options);}
110 
111  DeviceMgr * devMgr;
112 };
113 
114 struct TimeOptionsReg : public IO::PkgOptionsReg
115 {
116  TimeOptionsReg(DeviceMgr * mgr) : devMgr(mgr) {}
117 
118  bool operator()(const Util::OptionBlock & options)
119  {return devMgr->registerTimeOptions(options);}
120 
121  DeviceMgr * devMgr;
122 };
123 
124 // .TRAN
125 struct TransAnalysisReg : public IO::PkgOptionsReg
126 {
127  TransAnalysisReg(DeviceMgr * mgr) : Mgr(mgr) {}
128 
129  bool operator()(const Util::OptionBlock & options)
130  {return Mgr->setTranAnalysisParams(options);}
131 
132  DeviceMgr * Mgr;
133 };
134 
135 // .DC
136 struct DCAnalysisReg : public IO::PkgOptionsReg
137 {
138  DCAnalysisReg(DeviceMgr * mgr) : Mgr(mgr) {}
139 
140  bool operator()(const Util::OptionBlock & options)
141  {return Mgr->setDCAnalysisParams(options);}
142 
143  DeviceMgr * Mgr;
144 };
145 
146 // .OP
147 struct OPAnalysisReg : public IO::PkgOptionsReg
148 {
149  OPAnalysisReg(DeviceMgr * mgr) : Mgr(mgr) {}
150 
151  bool operator()(const Util::OptionBlock & options)
152  {return Mgr->setOPAnalysisParams(options);}
153 
154  DeviceMgr * Mgr;
155 };
156 
157 // .STEP
158 struct STEPAnalysisReg : public IO::PkgOptionsReg
159 {
160  STEPAnalysisReg(DeviceMgr * mgr) : Mgr(mgr) {}
161 
162  bool operator()(const Util::OptionBlock & options)
163  {return Mgr->setSTEPAnalysisParams(options);}
164 
165  DeviceMgr * Mgr;
166 };
167 
168 // .MPDE
169 struct MPDE_AnalysisReg : public IO::PkgOptionsReg
170 {
171  MPDE_AnalysisReg(DeviceMgr * devMgr) : devMgr_(devMgr) {}
172 
173  bool operator()(const Util::OptionBlock & options)
174  {return devMgr_->setMPDEAnalysisParams(options);}
175 
176  DeviceMgr * devMgr_;
177 };
178 
179 // .HB
180 struct HB_AnalysisReg : public IO::PkgOptionsReg
181 {
182  HB_AnalysisReg(DeviceMgr * devMgr) : devMgr_(devMgr) {}
183 
184  bool operator()(const Util::OptionBlock & options)
185  {return devMgr_->setHBAnalysisParams(options);}
186 
187  DeviceMgr * devMgr_;
188 };
189 
190 // .AC
191 struct AC_AnalysisReg : public IO::PkgOptionsReg
192 {
193  AC_AnalysisReg(DeviceMgr * devMgr) : devMgr_(devMgr) {}
194 
195  bool operator()(const Util::OptionBlock & options)
196  {return devMgr_->setACAnalysisParams(options);}
197 
198  DeviceMgr * devMgr_;
199 };
200 
201 // .MOR
202 struct MOR_AnalysisReg : public IO::PkgOptionsReg
203 {
204  MOR_AnalysisReg(DeviceMgr * devMgr) : devMgr_(devMgr) {}
205 
206  bool operator()(const Util::OptionBlock & options)
207  {return devMgr_->setMORAnalysisParams(options);}
208 
209  DeviceMgr * devMgr_;
210 };
211 
212 // ----------------------------------------------------------------------------
213 // Function : setupIOName
214 //
215 // Purpose : This function takes the device instance name and creates
216 // an appropriate "outputName" to be used for file outputs.
217 //
218 // Special Notes :
219 // Scope : public
220 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
221 // Creation Date : 04/26/2013
222 // ----------------------------------------------------------------------------
223 const std::string setupIOName(const InstanceName &entity_name)
224 {
225  return entity_name.getDeviceName();
226 }
227 
228 DeviceEntity *findDeviceEntity(EntityTypeIdDeviceMap::const_iterator begin, EntityTypeIdDeviceMap::const_iterator end, const std::string entity_name) {
229  for (EntityTypeIdDeviceMap::const_iterator it = begin; it != end; ++it) {
230  DeviceEntity *device_entity = (*it).second->findInstance(InstanceName(entity_name));
231  if (device_entity)
232  return device_entity;
233 
234  device_entity = (*it).second->findModel(ModelName(entity_name));
235  if (device_entity)
236  return device_entity;
237  }
238 
239  return 0;
240 }
241 
242 } // namespace <unnamed>
243 
244 struct DeviceGlobalParameterOpBuilder : public Util::Op::Builder
245 {
246  typedef std::list<Util::Param> ParameterList;
247 
249  : deviceManager_(device_manager)
250  {}
251 
253  {}
254 
255  virtual void registerCreateFunctions(Util::Op::BuilderManager &builder_manager) const
256  {
257  builder_manager.addCreateFunction<DeviceMgrGlobalParameterOp>();
258  }
259 
260  virtual Util::Op::Operator *makeOp(ParameterList::const_iterator &it) const
261  {
262  Util::Op::Operator *new_op = 0;
263  const std::string &param_tag = (*it).tag();
264  const std::string &param_string = (*it).stringValue();
265 
266  if (param_tag == "GLOBAL_PARAMETER") {
267  new_op = new DeviceMgrGlobalParameterOp(param_string, deviceManager_, param_string);
268  new_op->addArg(param_string);
269  }
270  else
271  {
272  const double *result = deviceManager_.findGlobalPar(param_tag);
273  if (result)
274  {
275  // Refactor: [DGB] Should use the address.
276  new_op = new DeviceMgrGlobalParameterOp(param_tag, deviceManager_, param_tag);
277  }
278  }
279 
280  return new_op;
281  }
282 
283 private:
285 };
286 
287 struct DeviceEntityOpBuilder : public Util::Op::Builder
288 {
289  typedef std::list<Util::Param> ParameterList;
290 
291  DeviceEntityOpBuilder(const DeviceMgr &device_manager)
292  : deviceManager_(device_manager)
293  {}
294 
296  {}
297 
298  virtual void registerCreateFunctions(Util::Op::BuilderManager &builder_manager) const
299  {
300  builder_manager.addCreateFunction<DeviceEntityParameterOp>();
301  }
302 
303  virtual Util::Op::Operator *makeOp(ParameterList::const_iterator &it) const {
304  Util::Op::Operator *new_op = 0;
305  const std::string &param_tag = (*it).tag();
306  const std::string &param_string = (*it).stringValue();
307 
308  const DeviceEntity *device_entity = deviceManager_.getDeviceEntity(param_tag);
309  if (device_entity)
310  {
311  std::string param_name = Util::paramNameFromFullParamName(param_tag);
312  new_op = new DeviceEntityParameterOp(param_tag, *device_entity, param_name);
313  }
314 
315  return new_op;
316  }
317 
318 private:
320 };
321 
322 namespace {
323 
324 typedef std::list<Util::Param> ParameterList;
325 
326 void parameterNameAndArgs(std::string &name, std::vector<std::string> &args, ParameterList::const_iterator &it)
327 {
328  const std::string &param_tag = (*it).tag();
329 
330  if (param_tag[0] == 'V' || param_tag[0] == 'I' || param_tag[0] == 'N')
331  {
332  std::ostringstream oss;
333  oss << param_tag << "(";
334  int arg_count = (*it).getImmutableValue<int>();
335  for (int i = 0; i < arg_count; ++i)
336  {
337  ++it;
338  if (i != 0)
339  oss << ",";
340  oss << (*it).tag();
341  args.push_back((*it).tag());
342  }
343  oss << ")";
344  name = oss.str();
345  }
346 }
347 
348 } // namespace <unnamed>
349 
350 struct DeviceMgrOpBuilder : public Util::Op::Builder
351 {
352  DeviceMgrOpBuilder(const DeviceMgr &device_manager)
353  : deviceManager_(device_manager)
354  {}
355 
357  {}
358 
359  virtual Util::Op::Operator *makeOp(ParameterList::const_iterator &it) const {
360  Util::Op::Operator *new_op = 0;
361  const std::string &param_tag = (*it).tag();
362  const std::string &param_string = (*it).stringValue();
363 
364  if (deviceManager_.findParam(param_tag))
365  {
366  new_op = new DeviceMgrParameterOp(param_tag, deviceManager_, param_tag);
367  }
368  // else
369  // {
370  // // Get arguments and build pretty name
371  // std::vector<std::string> args;
372  // std::string name;
373  // parameterNameAndArgs(name, args, it);
374 
375  // // this is confusing. While the solution vector and state/store vector's
376  // // use maps with modified device names(specifically where the device
377  // // type is always first as in "D:subcircuitname:devciename" as apposed to
378  // // "subcircuitname:Ddevicename", the device manager does not use the modified
379  // // device name to find a device. So, when we set up the device name below
380  // // use the "nodeName" rather than the "modifiedDeviceName".
381  // std::string store_name = args[0] + ":DEV_" + param_tag;
382  // // have to repeat this check for spaces as in I(YPDE NAME)
383  // std::string::size_type space = store_name.find_first_of(" ");
384  // if (space != std::string::npos)
385  // {
386  // if (space == 4 && store_name.substr(0, 4) == "YPDE")
387  // {
388  // store_name.replace(4, 1, ":");
389  // }
390  // }
391 
392  // if (deviceManager_.findParam(store_name))
393  // {
394  // new_op = new DeviceMgrParameterOp(param_tag, deviceManager_, store_name);
395  // }
396 
397  // std::string ppde("YPDE!" + store_name);
398  // if (!new_op && deviceManager_.findParam(ppde))
399  // {
400  // {
401  // new_op = new DeviceMgrParameterOp(param_tag, deviceManager_, ppde);
402  // }
403  // }
404  // if (new_op)
405  // new_op->addArg(args[0]);
406  // }
407 
408  return new_op;
409  }
410 
411 private:
413 };
414 
415 //-----------------------------------------------------------------------------
416 // Function : DeviceMgr::registerOutputMgr
417 // Purpose :
418 // Special Notes :
419 // Scope : public
420 // Creator : Dave Shirley, PSSI
421 // Creation Date : 8/15/06
422 //-----------------------------------------------------------------------------
423 bool DeviceMgr::registerOutputMgr (IO::OutputMgr * tmp_outputMgrPtr)
424 {
425  outputMgrPtr_ = tmp_outputMgrPtr;
426 
427  outputMgrPtr_->getOpBuilderManager().addBuilder(new DeviceGlobalParameterOpBuilder(*this));
428  outputMgrPtr_->getOpBuilderManager().addBuilder(new DeviceEntityOpBuilder(*this));
429 
430  return outputMgrPtr_ != 0;
431 }
432 
433 //-----------------------------------------------------------------------------
434 // Function : DeviceMgr::registerMeasureMgr
435 // Purpose :
436 // Special Notes :
437 // Scope : public
438 // Creator : Dave Shirley, PSSI
439 // Creation Date : 8/15/06
440 //-----------------------------------------------------------------------------
441 bool DeviceMgr::registerMeasureMgr (IO::Measure::Manager * measure_manager)
442 {
443  measureManager_ = measure_manager;
444 
445  return measureManager_ != 0;
446 }
447 
448 //-----------------------------------------------------------------------------
449 // Function : DeviceMgr::registerAnalysisManager
450 // Purpose :
451 // Special Notes :
452 // Scope : public
453 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
454 // Creation Date : 3/16/00
455 //-----------------------------------------------------------------------------
457 {
458  anaIntPtr_ = tmp_anaIntPtr;
459 
460  if (anaIntPtr_)
461  static_cast<Xyce::Util::Notifier<Analysis::StepEvent> &>(*anaIntPtr_).subscribe(*this);
462 
463  return anaIntPtr_ != 0;
464 }
465 //-----------------------------------------------------------------------------
466 // Function : DeviceMgr::factory
467 // Purpose : factory function
468 // Special Notes :
469 // Scope : public
470 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
471 // Creation Date : 3/16/00
472 //-----------------------------------------------------------------------------
473 DeviceMgr * DeviceMgr::factory(IO::CmdParse & cp)
474 {
475  return new DeviceMgr(cp);
476 }
477 
478 //-----------------------------------------------------------------------------
479 // Function : DeviceMgr::DeviceMgr
480 // Purpose : constructor
481 // Special Notes :
482 // Scope : private
483 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
484 // Creation Date : 3/16/00
485 //-----------------------------------------------------------------------------
486 DeviceMgr::DeviceMgr(IO::CmdParse &command_line)
487  : commandLine_(command_line),
488  devOptions_(),
489  icLoads_(NULL),
490  devSensPtr_(new DeviceSensitivities(*this, devOptions_)),
491  calledBeforeCSPI (false),
492  sensFlag_(false),
493  linearSystemFlag_(true),
494  firstDependent_(true),
495  externalStateFlag_(false),
496  parameterChanged_(false),
497  breakPointInstancesInitialized(false),
498  timeParamsProcessed_(0.0),
499  nonTrivialDeviceMaskFlag(false),
500  dotOpOutputFlag(false),
501  numJacStaVectorPtr_(0),
502  numJacSolVectorPtr_(0),
503  numJacStoVectorPtr_(0),
504  diagonalVectorPtr_(0),
505  globals_(solState_.globals_)
506 {
527 
528  passThroughParamsMap_[ "MOSFET_ALL:GAINSCALE" ] = 1;
529  passThroughParamsMap_[ "MOSFET_ALL:NLTERMSCALE" ] = 1;
530  passThroughParamsMap_[ "MOSFET1:GAINSCALE" ] = 1;
531  passThroughParamsMap_[ "MOSFET1:NLTERMSCALE" ] = 1;
532 
533  devOptions_.setupDefaultOptions(command_line);
534  devOptions_.applyCmdLineOptions(command_line);
535 
536  solState_.debugTimeFlag = true;
537 }
538 
539 //-----------------------------------------------------------------------------
540 // Function : DeviceMgr::~DeviceMgr
541 // Purpose : destructor
542 // Special Notes :
543 // Scope : public
544 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
545 // Creation Date : 3/16/00
546 //-----------------------------------------------------------------------------
548 {
549  delete numJacStaVectorPtr_;
550  delete numJacSolVectorPtr_;
551  delete numJacStoVectorPtr_;
552  delete diagonalVectorPtr_;
553 
559 
560  delete externData_.tmpdIdXPtr;
561  delete externData_.tmpdQdXPtr;
562 
563  for (EntityTypeIdDeviceMap::iterator it = deviceMap_.begin(), end = deviceMap_.end(); it != end; ++it)
564  delete (*it).second;
565 
566  for (ArtificialParameterMap::iterator it = artificialParameterMap_.begin(), end = artificialParameterMap_.end(); it != end; ++it)
567  delete (*it).second;
568 
569  delete icLoads_;
570  delete devSensPtr_;
571 }
572 
573 //-----------------------------------------------------------------------------
574 // Function : DeviceMgr::registerPkgOptionsMgr
575 // Purpose :
576 // Special Notes :
577 // Scope : public
578 // Creator : Richard Schiek, Electrical and Mems Modeling
579 // Creation Date : 10/20/2008
580 //-----------------------------------------------------------------------------
581 bool DeviceMgr::registerPkgOptionsMgr(IO::PkgOptionsMgr *pkgOptPtr)
582 {
583  pkgOptMgrPtr_ = pkgOptPtr;
584 
585  std::string netListFile("");
586 
587  if (commandLine_.getArgumentValue(std::string("netlist")) != "")
588  {
589  netListFile = commandLine_.getArgumentValue(std::string("netlist"));
590  }
591 
592  pkgOptMgrPtr_->submitRegistration(
593  "DEVICE", netListFile, new OptionsReg(this));
594 
595  pkgOptMgrPtr_->submitRegistration(
596  "SENS", netListFile, new SensOptionsReg(this));
597 
598  pkgOptMgrPtr_->submitRegistration(
599  "TIMEINT", netListFile, new TimeOptionsReg(this));
600 
601  // different analysis types.
602  pkgOptMgrPtr_->submitRegistration(
603  "TRAN", netListFile, new TransAnalysisReg(this));
604 
605  pkgOptMgrPtr_->submitRegistration(
606  "DC", netListFile, new DCAnalysisReg(this));
607 
608  pkgOptMgrPtr_->submitRegistration(
609  "OP", netListFile, new OPAnalysisReg(this));
610 
611  pkgOptMgrPtr_->submitRegistration(
612  "STEP", netListFile, new STEPAnalysisReg(this));
613 
614  // MPDE specific netlist lines
615  pkgOptMgrPtr_->submitRegistration(
616  "MPDE", netListFile, new MPDE_AnalysisReg(this));
617 
618  // HB Specific netlist lines
619  pkgOptMgrPtr_->submitRegistration(
620  "HB", netListFile, new HB_AnalysisReg(this));
621 
622  // AC Specific netlist lines
623  pkgOptMgrPtr_->submitRegistration(
624  "AC", netListFile, new AC_AnalysisReg(this));
625 
626  // MOR Specific netlist lines
627  pkgOptMgrPtr_->submitRegistration(
628  "MOR", netListFile, new MOR_AnalysisReg(this));
629 
630  return true;
631 }
632 
633 //-----------------------------------------------------------------------------
634 // Function : DeviceMgr::registerSensParams
635 // Purpose :
636 // Special Notes :
637 // Scope : public
638 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
639 // Creation Date : 6/03/02
640 //-----------------------------------------------------------------------------
641 bool DeviceMgr::registerSensParams (const Util::OptionBlock & OB)
642 {
643  sensFlag_ = true;
644 
645  if (DEBUG_DEVICE && devOptions_.debugLevel > 0)
646  {
647  dout() << "DeviceMgr::registerSensParams called!" <<std::endl;
648  }
649 
650  return devSensPtr_->registerSensParams (OB);
651 }
652 
653 
654 //-----------------------------------------------------------------------------
655 // Function : DeviceMgr::registerLeadCurrentRequests
656 // Purpose : this function is called from the output manager (through the
657 // device interface) to inform the device package of the devices
658 // for which lead currents have been requested. The device
659 // manager will take care of doing isolated F and Q loads for
660 // these devices so the lead currents can be calculated
661 // Special Notes :
662 // Scope : public
663 // Creator : Richard Schiek, SNL, Electrical Systems Modeling
664 // Creation Date : 03/20/13
665 //-----------------------------------------------------------------------------
666 bool DeviceMgr::setLeadCurrentRequests(const std::set<std::string> & deviceNames)
667 {
668  // this is called prior to fully constructing the devices. So for now
669  // save the list
670  devicesNeedingLeadCurrentLoads_ = deviceNames;
671 
672  if (DEBUG_DEVICE && devOptions_.debugLevel > 0)
673  {
674  if (! devicesNeedingLeadCurrentLoads_.empty())
675  {
676  dout() << "DeviceMgr::registerLeadCurrentRequests Devices for which lead currents were requested: ";
677  for (std::set<std::string>::iterator it = devicesNeedingLeadCurrentLoads_.begin(), end = devicesNeedingLeadCurrentLoads_.end(); it != end; ++it)
678  {
679  dout() << (*it) << " ";
680  }
681  dout() << std::endl;
682  }
683  }
684 
685  return true;
686 }
687 
688 //-----------------------------------------------------------------------------
689 // Function : DeviceMgr::setTranAnalysisParams
690 // Purpose :
691 // Special Notes :
692 // Scope : public
693 // Creator : Eric Keiter, SNL
694 // Creation Date : 10/14/11
695 //-----------------------------------------------------------------------------
696 bool DeviceMgr::setTranAnalysisParams (const Util::OptionBlock & OB)
697 {
698  solState_.TRANspecified = true;
699  return true;
700 }
701 
702 //-----------------------------------------------------------------------------
703 // Function : DeviceMgr::setDCAnalysisParams
704 // Purpose :
705 // Special Notes :
706 // Scope : public
707 // Creator : Eric Keiter, SNL
708 // Creation Date : 10/14/11
709 //-----------------------------------------------------------------------------
710 bool DeviceMgr::setDCAnalysisParams (const Util::OptionBlock & OB)
711 {
712  solState_.DCspecified = true;
713  return true;
714 }
715 
716 //-----------------------------------------------------------------------------
717 // Function : DeviceMgr::setOPAnalysisParams
718 // Purpose :
719 // Special Notes :
720 // Scope : public
721 // Creator : Eric Keiter, SNL
722 // Creation Date : 10/14/11
723 //-----------------------------------------------------------------------------
724 bool DeviceMgr::setOPAnalysisParams (const Util::OptionBlock & OB)
725 {
726  solState_.OPspecified = true;
727  return true;
728 }
729 
730 //-----------------------------------------------------------------------------
731 // Function : DeviceMgr::setSTEPAnalysisParams
732 // Purpose :
733 // Special Notes :
734 // Scope : public
735 // Creator : Eric Keiter, SNL
736 // Creation Date : 10/14/11
737 //-----------------------------------------------------------------------------
738 bool DeviceMgr::setSTEPAnalysisParams (const Util::OptionBlock & OB)
739 {
740  solState_.STEPspecified = true;
741  return true;
742 }
743 
744 //-----------------------------------------------------------------------------
745 // Function : DeviceMgr::setMPDEAnalysisParams
746 // Purpose :
747 // Special Notes :
748 // Scope : public
749 // Creator : Eric Keiter, SNL
750 // Creation Date : 10/14/11
751 //-----------------------------------------------------------------------------
752 bool DeviceMgr::setMPDEAnalysisParams (const Util::OptionBlock & OB)
753 {
754  solState_.MPDEspecified = true;
755  return true;
756 }
757 
758 //-----------------------------------------------------------------------------
759 // Function : DeviceMgr::setHBAnalysisParams
760 // Purpose :
761 // Special Notes :
762 // Scope : public
763 // Creator : Eric Keiter, SNL
764 // Creation Date : 10/14/11
765 //-----------------------------------------------------------------------------
766 bool DeviceMgr::setHBAnalysisParams (const Util::OptionBlock & OB)
767 {
768  solState_.HBspecified = true;
769  return true;
770 }
771 
772 //-----------------------------------------------------------------------------
773 // Function : DeviceMgr::setACAnalysisParams
774 // Purpose :
775 // Special Notes :
776 // Scope : public
777 // Creator : Eric Keiter, SNL
778 // Creation Date : 10/14/11
779 //-----------------------------------------------------------------------------
780 bool DeviceMgr::setACAnalysisParams (const Util::OptionBlock & OB)
781 {
782  solState_.ACspecified = true;
783  return true;
784 }
785 
786 //-----------------------------------------------------------------------------
787 // Function : DeviceMgr::setMORAnalysisParams
788 // Purpose :
789 // Special Notes :
790 // Scope : public
791 // Creator : Heidi Thornquist and Ting Mei, SNL
792 // Creation Date : 5/30/12
793 //-----------------------------------------------------------------------------
794 bool DeviceMgr::setMORAnalysisParams (const Util::OptionBlock & OB)
795 {
796  solState_.MORspecified = true;
797  return true;
798 }
799 
800 
801 //-----------------------------------------------------------------------------
802 // Function : DeviceMgr::getFastSourcePeriod
803 // Purpose :
804 // Special Notes :
805 // Scope : public
806 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
807 // Creation Date : 3/27/04
808 //-----------------------------------------------------------------------------
809 std::vector<double> DeviceMgr::getFastSourcePeriod(std::vector<std::string> &sourceNames)
810 {
811  int numFastSrcs = sourceNames.size();
812 
813  // Setup return of source periods
814  std::vector<double> srcPeriods(numFastSrcs);
815 
816  // Now loop over them, and mark them.
817  for(int i = 0; i < numFastSrcs; ++i)
818  {
819  std::map<std::string, SourceInstance *, LessNoCase>::iterator iterFS = indepSourcePtrMap_.find(sourceNames[i]);
820  if (iterFS != indepSourcePtrMap_.end())
821  {
822  SourceInstance * SIPtr = iterFS->second;
823  srcPeriods[i] = SIPtr->period();
824  }
825  else
826  {
827 #ifndef Xyce_PARALLEL_MPI
828  Report::UserError message;
829  message << "Unable to find source: " << fastSourceNames_[i] << "\n"
830  << "Potential names are: ";
831  for (std::map<std::string,SourceInstance*, LessNoCase>::const_iterator it = indepSourcePtrMap_.begin(); it != indepSourcePtrMap_.end(); ++it)
832  message << (*it).first << " ";
833 #endif
834  }
835  }
836 
837  Parallel::AllReduce(pdsMgrPtr_->getPDSComm()->comm(), MPI_MAX, srcPeriods);
838 
839 // #ifdef Xyce_PARALLEL_MPI
840 // // Collect all the periods from all the processors, assuming periods are positive values.
841 // std::vector<double> tmpSrcPeriods( srcPeriods );
842 // pdsMgrPtr_->getPDSComm()->maxAll( &tmpSrcPeriods[0], &srcPeriods[0], numFastSrcs );
843 // #endif
844 
845  return srcPeriods;
846 }
847 
848 
849 //-----------------------------------------------------------------------------
850 // Function : DeviceMgr::registerFastSources
851 // Purpose :
852 // Special Notes :
853 // Scope : public
854 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
855 // Creation Date : 3/27/04
856 //-----------------------------------------------------------------------------
857 std::vector<double> DeviceMgr::registerFastSources(std::vector<std::string> &sourceNames)
858 {
859  int numFastSrcs = sourceNames.size();
860  //Setup return of source periods
861  std::vector<double> srcPeriods;
862 
863  if (numFastSrcs > 0)
864  {
865  srcPeriods.resize(numFastSrcs, 0.0);
866 
867  // Default case, the sources are explicitely listed on the .option line
868  fastSourceNames_.resize(numFastSrcs);
869  std::copy(sourceNames.begin(), sourceNames.end(), fastSourceNames_.begin());
870 
871  // Now loop over them, and mark them.
872  for(int i = 0; i < numFastSrcs; ++i)
873  {
874  std::map<std::string,SourceInstance*, LessNoCase>::iterator iterFS = indepSourcePtrMap_.find(fastSourceNames_[i]);
875  if (iterFS != indepSourcePtrMap_.end())
876  {
877  SourceInstance * SIPtr = iterFS->second;
878  SIPtr->setFastSourceFlag (true);
879  srcPeriods[i] = SIPtr->period();
880  }
881  else
882  {
883 #ifndef Xyce_PARALLEL_MPI
884  Report::UserError message;
885  message << "Unable to find source: " << fastSourceNames_[i] << "\n"
886  << "Potential names are: ";
887  for (std::map<std::string,SourceInstance*, LessNoCase>::const_iterator it = indepSourcePtrMap_.begin(); it != indepSourcePtrMap_.end(); ++it)
888  message << (*it).first << " ";
889 #endif
890  }
891  }
892 
893  }
894  else
895  {
896  // tscoffe/tmei 09/16/08
897  // Special case: Use all sources
898  // Compute the total number of fast sources for all processors.
899  // NOTE: In parallel, this will not work correctly if more than one processor has fast sources.
900  int myNumFastSrcs = indepSourceInstancePtrVec_.size();
901  pdsMgrPtr_->getPDSComm()->sumAll( &myNumFastSrcs, &numFastSrcs, 1 );
902  srcPeriods.resize(numFastSrcs, -1.0);
903  for (int i=0 ; i<myNumFastSrcs ; ++i) {
904  indepSourceInstancePtrVec_[i]->setFastSourceFlag(true);
905  srcPeriods[i] = indepSourceInstancePtrVec_[i]->period();
906  }
907  }
908 
909  Parallel::AllReduce(pdsMgrPtr_->getPDSComm()->comm(), MPI_MAX, srcPeriods);
910 
911  return srcPeriods;
912 }
913 
914 
915 //-----------------------------------------------------------------------------
916 // Function : DeviceMgr::deRegisterFastSources
917 // Purpose : reverses the effect of registerFastSources
918 // Special Notes :
919 // Scope : public
920 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
921 // Creation Date : 06/12/2013
922 //-----------------------------------------------------------------------------
923 void DeviceMgr::deRegisterFastSources (std::vector<std::string> &sourceNames)
924 {
925  int numFastSrcs = sourceNames.size();
926 
927  if (numFastSrcs > 0)
928  {
929  // Default case, the sources are explicitely listed on the .option line
930  fastSourceNames_.resize(numFastSrcs);
931  std::copy(sourceNames.begin(), sourceNames.end(), fastSourceNames_.begin());
932 
933  // Now loop over them, and mark them.
934  for(int i = 0; i < numFastSrcs; ++i)
935  {
936  std::map<std::string,SourceInstance*, LessNoCase>::iterator iterFS = indepSourcePtrMap_.find(fastSourceNames_[i]);
937  if (iterFS != indepSourcePtrMap_.end())
938  {
939  SourceInstance * SIPtr = iterFS->second;
940  SIPtr->setFastSourceFlag (false);
941  }
942  else
943  {
944 #ifndef Xyce_PARALLEL_MPI
945  Report::DevelFatal message;
946  message.in("DeviceMgr::deRegisterFastSources");
947  message << "Unable to find source: " << fastSourceNames_[i] << std::endl
948  << "Potential names are: ";
949  for (std::map<std::string,SourceInstance*, LessNoCase>::const_iterator it = indepSourcePtrMap_.begin(); it != indepSourcePtrMap_.end(); ++it)
950  message << (*it).first << " ";
951 #endif
952  }
953  }
954  }
955  else
956  {
957  // Special case: Use all sources
958  numFastSrcs = indepSourceInstancePtrVec_.size();
959  for (int i=0 ; i<numFastSrcs ; ++i) {
960  indepSourceInstancePtrVec_[i]->setFastSourceFlag(false);
961  }
962  }
963  return;
964 }
965 
966 //-----------------------------------------------------------------------------
967 // Function : DeviceMgr::deactivateSlowSources
968 // Purpose : traverse fast source list and remove any slow sources from
969 // the deviceArray
970 // Special Notes :
971 // Scope : public
972 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
973 // Creation Date : 3/22/07
974 //-----------------------------------------------------------------------------
976 {
977  // first back-up a copy of the deviceArray so we can edit out
978  // the slow sources
981 
982  // erase the existing list of sources
984 
985  // now copy back only those that are fast sources
986  std::vector<SourceInstance*>::iterator iter;
987  std::vector<SourceInstance*>::iterator begin =indepSourceInstanceBackupPtrVec_.begin();
988  std::vector<SourceInstance*>::iterator end =indepSourceInstanceBackupPtrVec_.end();
989  for (iter=begin; iter!=end;++iter)
990  {
991  if ((*iter)->getFastSourceFlag())
992  {
993  indepSourceInstancePtrVec_.push_back(*iter);
994  }
995  }
996 
997 }
998 
999 //-----------------------------------------------------------------------------
1000 // Function : DeviceMgr::activateSlowSources
1001 // Purpose : restore any slow sources to the device array.
1002 // Special Notes :
1003 // Scope : public
1004 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
1005 // Creation Date : 3/22/07
1006 //-----------------------------------------------------------------------------
1008 {
1009  // restore the independent source list from backup
1013 }
1014 
1015 //-----------------------------------------------------------------------------
1016 // Function : DeviceMgr::setMPDEFlag
1017 // Purpose :
1018 // Special Notes :
1019 // Scope : public
1020 // Creator : Richard Schiek, SNL, Parallel Computational Sciences
1021 // Creation Date : 07/21/08
1022 //-----------------------------------------------------------------------------
1023 void DeviceMgr::setMPDEFlag(bool flagVal)
1024 {
1025  solState_.mpdeOnFlag = flagVal;
1026 }
1027 
1028 //-----------------------------------------------------------------------------
1029 // Function : DeviceMgr::setBlockAnalysisFlag
1030 // Purpose :
1031 // Special Notes :
1032 // Scope : public
1033 // Creator : Richard Schiek, SNL, Parallel Computational Sciences
1034 // Creation Date : 07/21/08
1035 //-----------------------------------------------------------------------------
1037 {
1038  solState_.blockAnalysisFlag = flagVal;
1040 }
1041 
1042 //-----------------------------------------------------------------------------
1043 // Function : DeviceMgr::setFastTime
1044 // Purpose :
1045 // Special Notes :
1046 // Scope : public
1047 // Creator : Richard Schiek, SNL, Parallel Computational Sciences
1048 // Creation Date : 07/21/08
1049 //-----------------------------------------------------------------------------
1050 void DeviceMgr::setFastTime(double timeVal)
1051 {
1052  solState_.currFastTime = timeVal;
1053 }
1054 
1055 //-----------------------------------------------------------------------------
1056 // Function : DeviceMgr::initializeAll
1057 // Purpose : This function, via the LAS system class, sets up
1058 // the pointers to the various linear algebra entities.
1059 // Special Notes :
1060 // Scope : public
1061 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1062 // Creation Date : 6/12/00
1063 //-----------------------------------------------------------------------------
1065 {
1066  bool bsuccess = true;
1067 
1069 
1070  // nullify ptrs that are passed in at each step (see the loadDAEVectors function args)
1087 
1088  if (DEBUG_DEVICE) {
1089  // get f vector pointer:
1090  externData_.fVectorPtr = lasSysPtr_->getFVector();
1091  bsuccess = bsuccess && (externData_.fVectorPtr != 0);
1092 
1093  // create Jdxp vector pointer:
1094  externData_.JdxpVectorPtr = lasSysPtr_->getJDXPVector();
1095  bsuccess = bsuccess && (externData_.JdxpVectorPtr != 0);
1096  }
1097 
1098 #ifdef Xyce_DEBUG_VOLTLIM
1099  // get test matrix: (old DAE)
1100  externData_.JTestMatrixPtr = lasSysPtr_->getJacTestMatrix();
1101  bsuccess = bsuccess && (externData_.JTestMatrixPtr != 0);
1102 
1103  // get test matrix:
1104  externData_.FTestMatrixPtr = lasSysPtr_->getdFdxTestMatrix();
1105  bsuccess = bsuccess && (externData_.FTestMatrixPtr != 0);
1106  externData_.QTestMatrixPtr = lasSysPtr_->getdQdxTestMatrix();
1107  bsuccess = bsuccess && (externData_.QTestMatrixPtr != 0);
1108 
1109  // get dxVoltlim vector pointer:
1110  externData_.dxVoltlimVectorPtr = lasSysPtr_->getDxVoltlimVector() ;
1111  bsuccess = bsuccess && (externData_.dxVoltlimVectorPtr != 0);
1112 
1113  // create Jdx2 vector pointer: (old DAE)
1114  externData_.Jdx2VectorPtr = lasSysPtr_->getJDX2Vector();
1115  bsuccess = bsuccess && (externData_.Jdx2VectorPtr != 0);
1116 
1117  // create Jdx2 vector pointer:
1118  externData_.Fdx2VectorPtr = lasSysPtr_->getFDX2Vector();
1119  bsuccess = bsuccess && (externData_.Fdx2VectorPtr != 0);
1120  externData_.Qdx2VectorPtr = lasSysPtr_->getQDX2Vector();
1121  bsuccess = bsuccess && (externData_.Qdx2VectorPtr != 0);
1122 #endif
1123 
1124  // get flag solution pointer-pointer:
1125  externData_.flagSolVectorPtr = lasSysPtr_->getFlagSolVector();
1126  bsuccess = bsuccess && (externData_.flagSolVectorPtr != 0);
1127 
1128  // get device mask pointer.
1129  externData_.deviceMaskVectorPtr = lasSysPtr_->getDeviceMaskVector ();
1130  bsuccess = bsuccess && (externData_.deviceMaskVectorPtr != 0);
1131 
1132  // create the temporary numerical jacobian vectors
1134  {
1135  numJacStaVectorPtr_ = lasSysPtr_->builder().createStateVector();
1136  numJacSolVectorPtr_ = lasSysPtr_->builder().createVector();
1137  numJacStoVectorPtr_ = lasSysPtr_->builder().createStoreVector();
1138 
1139  externData_.numJacRHSVectorPtr = lasSysPtr_->builder().createVector();
1140  externData_.numJacFVectorPtr = lasSysPtr_->builder().createVector();
1141  externData_.numJacQVectorPtr = lasSysPtr_->builder().createVector();
1142  externData_.perturbVectorPtr = lasSysPtr_->builder().createVector();
1143  externData_.numJacLoadFlagPtr = lasSysPtr_->builder().createVector();
1144  }
1145 
1146  externData_.tmpdIdXPtr = lasSysPtr_->builder().createVector();
1147  externData_.tmpdQdXPtr = lasSysPtr_->builder().createVector();
1148 
1149  // create a diagonal vector to be used for 2-level
1150  diagonalVectorPtr_ = lasSysPtr_->builder().createVector();
1151 
1153 
1154  // For Homotopy on block gainscale
1156 
1157 #ifdef Xyce_SIZEOF
1158  int size = sizeof(*this);
1159  dout() << "Size of device package after initializeAll = " << size << std::endl;
1160 #endif
1161 
1162  return bsuccess;
1163 }
1164 
1165 //-----------------------------------------------------------------------------
1166 // Function : DeviceMgr::resetForStepAnalysis
1167 // Purpose :
1168 // Special Notes : Some "resetForStep" functions (only HB so far) will
1169 // call dev->initializeAll. So, this must be called first.
1170 // Scope : public
1171 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1172 // Creation Date : 07/12/2013
1173 //-----------------------------------------------------------------------------
1174 
1176 {
1178  {
1190 
1194  }
1195 }
1196 
1197 //-----------------------------------------------------------------------------
1198 // Function : DeviceMgr::createDevice
1199 // Purpose : This function creates a single device based on the passed
1200 // index.
1201 // Special Notes :
1202 // Scope : protected
1203 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1204 // Creation Date : 3/16/00
1205 //-----------------------------------------------------------------------------
1207 {
1208  Device *device = 0;
1209 
1210  if (model_type_id.defined())
1211  {
1212  EntityTypeIdDeviceMap::const_iterator it = deviceMap_.find(model_type_id);
1213  if (it == deviceMap_.end())
1214  {
1216 
1217  const Configuration *configuration = Configuration::findConfiguration(model_type_id);
1218  device = configuration->createDevice(factory_block);
1219  deviceMap_[model_type_id] = device;
1220  devicePtrVec_.push_back(device);
1221 
1222  if (device->isPDEDevice())
1223  {
1224  pdeDevicePtrVec_.push_back(device);
1225  }
1226  }
1227  else
1228  device = (*it).second;
1229  }
1230 
1231  return *device;
1232 }
1233 
1234 //-----------------------------------------------------------------------------
1235 // Function : DeviceMgr::getModelGroup
1236 // Purpose : This function returns the device type index for a given
1237 // named string. This assumes that the device names used
1238 // in the simulation will obey the spice3f5 netlist language
1239 // convention.
1240 //
1241 // Special Notes :
1242 // Scope : public
1243 // Creator :
1244 // Creation Date : 3/16/00
1245 //-----------------------------------------------------------------------------
1246 /**
1247  * Return the ModelGroup of the device associated with the model type name or device type name.
1248  *
1249  * @param model_type_name model type name or device type name
1250  *
1251  * @return
1252  *
1253  * @author David G. Baur Raytheon Sandia National Laboratories 1355
1254  * @date Mon Sep 23 07:53:04 2013
1255  */
1256 EntityTypeId DeviceMgr::getModelGroup(const std::string &model_or_device_type_name)
1257 {
1258  return Configuration::getModelGroup(model_or_device_type_name);
1259 }
1260 
1261 //-----------------------------------------------------------------------------
1262 // Function : DeviceMgr::addDeviceModel
1263 // Purpose :
1264 // Special Notes :
1265 // Scope : public
1266 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1267 // Creation Date : 3/16/00
1268 //-----------------------------------------------------------------------------
1269 bool DeviceMgr::addDeviceModel(const ModelBlock & model_block)
1270 {
1271  ModelTypeId model_type;
1272  ModelTypeId model_group = Configuration::getModelGroup(model_block.getType());
1273 
1274  if (!model_block.getName().empty()) {
1275  model_type = Configuration::getModelType(model_block.getType(), model_block.getLevel());
1276 
1277  if (!model_type.defined())
1278  Report::UserError() << "There is no device " << model_block.getType() << " of level " << model_block.getLevel() << " to define model " << model_block.getName();
1279  }
1280 
1281  if (!model_type.defined())
1282  model_type = model_group;
1283 
1284  if (!model_type.defined())
1285  return false;
1286 
1288  Device &device = getDeviceByModelType(model_type);
1289  DeviceModel *device_model = device.addModel(model_block, factory_block);
1290 
1291  modelTypeMap_[model_block.getName()] = model_type;
1292  modelGroupMap_[model_block.getName()] = model_group;
1293 
1294  // add the various model vectors:
1295  if (device_model != 0)
1296  {
1297  modelVector_.push_back(device_model);
1298  modelGroupModelVector_[model_group].push_back(device_model);
1299  modelTypeModelVector_[model_type].push_back(device_model);
1300  }
1301 
1302  return device_model != 0;
1303 }
1304 
1305 
1306 std::pair<ModelTypeId, ModelTypeId>
1308  const InstanceBlock & instance_block)
1309 {
1310  // If the ModelName string is not a null string, use it to get the
1311  // device type index. Otherwise, use the name of the device itself to determine the device.
1312  ModelTypeId model_type;
1313  ModelTypeId model_group;
1314  if (instance_block.getModelName().empty())
1315  {
1316  model_type = getModelGroup(instance_block.getInstanceName().getDeviceType());
1317  model_group = model_type;
1318  }
1319  else
1320  {
1321  model_type = modelTypeMap_[instance_block.getModelName()];
1322  model_group = modelGroupMap_[instance_block.getModelName()];
1323  }
1324 
1325  if (!model_type.defined())
1326  {
1327  Report::UserError message;
1328  message << "Unable to determine type of device for instance name " << instance_block.getInstanceName();
1329  if (!instance_block.getModelName().empty())
1330  {
1331  message << " with model name " << instance_block.getModelName();
1332  }
1333  return std::pair<ModelTypeId, ModelTypeId>(ModelTypeId(), ModelTypeId());
1334  }
1335  else if (instance_block.bsourceFlag)
1336  {
1337  // This is an E, F, G, or H source that is to be treated as a B source,
1338  // set its type now to BSRC.
1339  model_type = Bsrc::Traits::modelType();
1340  }
1341 
1342  // Check if this is a simple resistor, but with a resistance of zero. If so,
1343  // then change the type to RESISTOR3. This variant of the resistor acts like
1344  // a voltage souce with zero voltage difference.
1346  {
1347  const double zeroResistanceValue = devOptions_.zeroResistanceTol;
1348  // loop over the parameters
1349  std::vector<Param>::const_iterator currentParam = instance_block.params.begin();
1350  std::vector<Param>::const_iterator endParam = instance_block.params.end();
1351  while(currentParam != endParam)
1352  {
1353  if ((currentParam->uTag() == "R"))
1354  {
1355  if (currentParam->given())
1356  {
1357  std::vector<std::string> variables, specials;
1358 
1359  // check if this is a time-dependent, or variable-dependent expression.
1360  // If it is, then skip.
1361  const Param * devPar = &(*(currentParam));
1362  const Util::Param * tmpPar = (dynamic_cast<const Util::Param*> (devPar));
1363  // only check if this is an expression-type parameter.
1364  if (tmpPar->getType() == Util::EXPR)
1365  {
1366  Util::Expression tmpExp = tmpPar->getValue<Util::Expression>();
1367  tmpExp.get_names(XEXP_VARIABLE, variables);
1368  tmpExp.get_names(XEXP_SPECIAL, specials);
1369  }
1370 
1371  if (specials.empty() && variables.empty())
1372  {
1373  if (fabs(currentParam->getImmutableValue<double>()) < devOptions_.zeroResistanceTol)
1374  {
1375  // change device type to be the level 3 resistor
1376  model_type = Resistor3::Traits::modelType();
1377  }
1378  }
1379  }
1380  break;
1381  }
1382  currentParam++;
1383  }
1384  }
1385 
1386  return std::pair<ModelTypeId, ModelTypeId>(model_type, model_group);
1387 }
1388 
1389 //-----------------------------------------------------------------------------
1390 // Function : DeviceMgr::verifyDeviceInstance
1391 // Purpose : This function verifies a device instance prior to
1392 // instantiating.
1393 //
1394 // Theoretically, we could do this in addDeviceInstance() and
1395 // not make a device if it fails some verification criteria (a
1396 // resistor with zero resistance is the primary case here).
1397 // However, later unlinking of redundant devices that are
1398 // connected to just one node is difficult after
1399 // addDeviceInstance() is called because the device instance
1400 // pointer can be placed in many other containers
1401 // It could be done, but this is a simpler first step to having the
1402 // device manager be in charge of device verification -- rather
1403 // than have it in toplogy or IO.
1404 //
1405 // Special Notes : return true if this device is ok to instantiate, false otherwise
1406 // Scope : public
1407 // Creator : Richard Schiek, Electrical and Microsystems Modeling
1408 // Creation Date : 2/18/2010
1409 //-----------------------------------------------------------------------------
1411 {
1412  ModelTypeId model_type;
1413  ModelTypeId model_group;
1414  std::pair<ModelTypeId, ModelTypeId> x = getModelType(instance_block);
1415  model_type = x.first;
1416  model_group = x.second;
1417 
1418  if (!model_type.defined())
1419  {
1420  Report::UserError message;
1421  message << "Unable to determine model type of device for instance name " << instance_block.getInstanceName();
1422  if (!instance_block.getModelName().empty())
1423  {
1424  message << " with model name" << instance_block.getModelName();
1425  }
1426 
1427  return false;
1428  }
1429 
1430  return true;
1431 }
1432 
1433 //-----------------------------------------------------------------------------
1434 // Function : DeviceMgr::addDeviceInstance
1435 // Purpose : addDeviceInstance will create a new instance of the
1436 // designated device type. This version of the function
1437 // accepts a parameter list as one of the arguments,
1438 // so it is assumed that a parameter instance will
1439 // also have to be allocated for it.
1440 //
1441 // Special Notes :
1442 // Scope : public
1443 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1444 // Creation Date : 3/16/00
1445 //-----------------------------------------------------------------------------
1447 {
1448  // If the ModelName string is not a null string, use it to get the
1449  // device type index. Otherwise, use the name of the device itself to determine the device.
1450  ModelTypeId model_type;
1451  ModelTypeId model_group;
1452  std::pair<ModelTypeId, ModelTypeId> x = getModelType(instance_block);
1453  model_type = x.first;
1454  model_group = x.second;
1455 
1456  if (!model_type.defined())
1457  {
1458  Report::UserError message;
1459  message << "Unable to determine type of device for instance name " << instance_block.getInstanceName();
1460  if (!instance_block.getModelName().empty())
1461  {
1462  message << " with model name " << instance_block.getModelName();
1463  }
1464 
1465  DeviceInstance *instance = 0;
1466  return instance;
1467  }
1468 
1469  // Add an instance of this type.
1470  Device &device = getDeviceByModelType(model_type);
1471  DeviceInstance *instance = device.addInstance(instance_block, FactoryBlock(devOptions_, solState_, matrixLoadData_, externData_, commandLine_));
1472 
1473  std::string outputName = setupIOName(instance->getName());
1474 
1475  if ((devicesNeedingLeadCurrentLoads_.find(outputName) != devicesNeedingLeadCurrentLoads_.end()) ||
1477  {
1478  instance->enableLeadCurrentCalc();
1479 
1480  if (DEBUG_DEVICE && devOptions_.debugLevel > 0)
1481  {
1482  dout() << "DeviceMgr::addDeviceInstance Enabling lead current load for device \""
1483  << instance->getName()
1484  << "\" -> \""
1485  << outputName
1486  << "\"" << std::endl;
1487  }
1488  }
1489  else if (DEBUG_DEVICE && devOptions_.debugLevel > 0)
1490  {
1491  dout() << "DeviceMgr::addDeviceInstance Cannot enable lead current load for device \""
1492  << instance->getName()
1493  << "\" -> \""
1494  << outputName
1495  << "\""
1496  << std::endl;
1497  }
1498 
1499  localDeviceCountMap_[device.getDefaultModelName()]++;
1500 
1501  linearSystemFlag_ = linearSystemFlag_ && device.isLinearDevice();
1502 
1503  solState_.PDESystemFlag = solState_.PDESystemFlag || device.isPDEDevice();
1504 
1505  // Set up the instance vectors. These are the main containers used in the load procedures.
1506  instancePtrVec_.push_back(instance);
1507 
1508  // set up the list of pde device instances
1509  // and the list of non-pde devices instances.
1510  if (device.isPDEDevice())
1511  {
1512  pdeInstancePtrVec_.push_back(instance);
1513  }
1514  else
1515  {
1516  nonPdeInstancePtrVec_.push_back(instance);
1517  }
1518 
1519  modelGroupInstanceVector_[model_group].push_back(instance);
1520  modelTypeInstanceVector_[model_type].push_back(instance);
1521 
1522  // set up the independent source map.
1523  if (model_type == Vsrc::Traits::modelType() || model_type == ISRC::Traits::modelType())
1524  {
1525  indepSourcePtrMap_[instance_block.getInstanceName().getEncodedName()] = dynamic_cast<SourceInstance*>(instance);
1526  indepSourceInstancePtrVec_.push_back(dynamic_cast<SourceInstance*>(instance));
1527  }
1528 
1529  if (instance->plotfileFlag ())
1530  {
1531  plotFileInstancePtrVec_.push_back(instance);
1532  }
1533 
1534  // Set up the vector of devices subject to the jacobian test.
1535  if (instance->getName() == devOptions_.testJacDeviceName)
1536  {
1537  testJacDevicePtrVec_.push_back(instance);
1538  }
1539 
1540  return instance;
1541 }
1542 
1543 //-----------------------------------------------------------------------------
1544 // Function : DeviceMgr::deleteDeviceInstance
1545 // Purpose :
1546 // Special Notes :
1547 // Scope : public
1548 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1549 // Creation Date : 3/08/01
1550 //-----------------------------------------------------------------------------
1551 bool DeviceMgr::deleteDeviceInstance(const std::string & name)
1552 {
1553  Report::DevelFatal().in("DeviceMgr::deleteDeviceInstance") << "Not ready with the new boilerplate-free device package";
1554 
1555  bool bsuccess = true;
1556 
1557  // bool tmpBool = true;
1558  // EntityTypeId type = getModelGroup(name);
1559 
1560  // DeviceMap::iterator it = deviceMap_.find(type);
1561  // if (it != deviceMap_.end()) {
1562  // // bsuccess &= (*it).second->deleteInstance(name);
1563  // DeviceEntity *entity = (*it).second->findEntity(name);
1564  // DeviceInstance *instance = dynamic_cast<DeviceInstance *>(entity);
1565  // if (instance)
1566  // bsuccess = (*it).second->deleteInstance(instance);
1567  // }
1568 
1569  // note as this is written it ignores lots of other containers
1570  // this may be used for clean up at the end of a run, but
1571  // it is not sufficient to use during simulation setup.
1572  //
1573  // need to remove pointer to the instance "name" from other arrays
1574  // candidate lists are:
1575  // InstanceVector instancePtrVec_;
1576  // InstanceVector bpInstancePtrVec_; // instances with breakpoints functions
1577  // InstanceVector pdeInstancePtrVec_;
1578  // InstanceVector nonPdeInstancePtrVec_;
1579  // InstanceVector mosfetInstancePtrVec_;
1580  // InstanceVector vsrcInstancePtrVec_;
1581  // InstanceVector bjtInstancePtrVec_;
1582  // std::map<std::string, VsrcInstance*> vsrcInstancePtrMap_;
1583  //
1584  // InstanceVector plotFileInstancePtrVec_;
1585  //
1586  // std::map<std::string,SourceInstance*> indepSourcePtrMap_;
1587  // std::vector<SourceInstance*> indepSourceInstancePtrVec_;
1588 
1589  return bsuccess;
1590 }
1591 
1592 //-----------------------------------------------------------------------------
1593 // Function : DeviceMgr::debugOutput1
1594 // Purpose :
1595 // Special Notes :
1596 // Scope : public
1597 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1598 // Creation Date : 1/29/07
1599 //-----------------------------------------------------------------------------
1601 {
1602  // dump the fvector and the jdxp vector to files.
1604  {
1605  // To match the numbering scheme of the NLS debug output files,
1606  // it is neccessary to add +1 to the newton iterartion number.
1607  int outIter = solState_.newtonIter + 1;
1608 
1609  // f-vector
1610  char fn_fv[256]; for (int ich = 0; ich < 256; ++ich) fn_fv[ich] = 0;
1611  sprintf(fn_fv, "fvector.%03d.txt", outIter);
1612 
1613  // Note: this needs to change sign to match Spice.
1614  (externData_.fVectorPtr)->scale(-1.0);
1615  (externData_.fVectorPtr)->writeToFile(fn_fv);
1616  (externData_.fVectorPtr)->scale(-1.0);
1617 
1618  // jdxp-vector
1619  char fn_jdxp[256]; for (int ich = 0; ich < 256; ++ich) fn_jdxp[ich] = 0;
1620  sprintf(fn_jdxp, "Jdxp.%03d.txt", outIter);
1621  (externData_.JdxpVectorPtr)->writeToFile(fn_jdxp);
1622 
1623 #ifdef Xyce_DEBUG_VOLTLIM
1624  // the voltlim dx vector.
1625  char fn_dxvl[256]; for (int ich = 0; ich < 256; ++ich) fn_dxvl[ich] = 0;
1626  sprintf(fn_dxvl, "dxVL.%03d.txt", outIter);
1627  (externData_.dxVoltlimVectorPtr)->writeToFile(fn_dxvl);
1628 
1629  // jdx2-vector
1630  char fn_jdx2[256]; for (int ich = 0; ich < 256; ++ich) fn_jdx2[ich] = 0;
1631  sprintf(fn_jdx2, "Jdx2.%03d.txt", outIter);
1632  (externData_.Jdx2VectorPtr)->writeToFile(fn_jdx2);
1633 #endif
1634 
1635  }
1636 }
1637 
1638 //-----------------------------------------------------------------------------
1639 // Function : DeviceMgr::debugOutput2
1640 // Purpose : new-dae version
1641 // Special Notes :
1642 // Scope : public
1643 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1644 // Creation Date : 10/19/08
1645 //-----------------------------------------------------------------------------
1647 {
1648  // dump the fvector and the jdxp vector to files.
1650  {
1651  // To match the numbering scheme of the NLS debug output files,
1652  // it is neccessary to add +1 to the newton iterartion number.
1653  int newtonIter = solState_.newtonIter + 1;
1654  int outputStepNumber = 0;
1655 
1656  if (solState_.tranopFlag)
1657  {
1658  outputStepNumber = 0;
1659  }
1660  else if (solState_.initTranFlag)
1661  {
1662  outputStepNumber = solState_.timeStepNumber+1;
1663  }
1664  else
1665  {
1666  outputStepNumber = solState_.timeStepNumber+1;
1667  }
1668 
1669 #ifdef Xyce_DEBUG_VOLTLIM
1670  // the voltlim dx vector.
1671  char fn_dxvl[256]; for (int ich = 0; ich < 256; ++ich) fn_dxvl[ich] = 0;
1672  sprintf(fn_dxvl, "dxVL.%03d.%03d.txt", outputStepNumber, newtonIter);
1673  (externData_.dxVoltlimVectorPtr)->writeToFile(fn_dxvl);
1674 
1675  // Fdx2-vector
1676  char fn_fdx2[256]; for (int ich = 0; ich < 256; ++ich) fn_fdx2[ich] = 0;
1677  sprintf(fn_fdx2, "Fdx2.%03d.%03d.txt", outputStepNumber, newtonIter);
1678  (externData_.Fdx2VectorPtr)->writeToFile(fn_fdx2);
1679 
1680  // Qdx2-vector
1681  char fn_qdx2[256]; for (int ich = 0; ich < 256; ++ich) fn_qdx2[ich] = 0;
1682  sprintf(fn_qdx2, "Qdx2.%03d.%03d.txt", outputStepNumber, newtonIter);
1683  (externData_.Qdx2VectorPtr)->writeToFile(fn_qdx2);
1684 #endif
1685 
1686  }
1687 }
1688 
1689 //-----------------------------------------------------------------------------
1690 // Function : DeviceMgr::setInitialGuess
1691 // Purpose : This is a function call that sets the initial guess for
1692 // devices that have initial guesses.
1693 //
1694 // Special Notes :
1695 //
1696 // Scope : public
1697 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1698 // Creation Date : 5/02/03
1699 //-----------------------------------------------------------------------------
1700 bool DeviceMgr::setInitialGuess (N_LAS_Vector * solVectorPtr)
1701 {
1702  bool bsuccess = true;
1703 
1704  if (solVectorPtr != 0)
1705  {
1706  externData_.nextSolVectorPtr = solVectorPtr;
1707 
1708  // if two-level, and just the inner problem, only load the PDE devices.
1709  InstanceVector::iterator iter;
1710  InstanceVector::iterator begin;
1711  InstanceVector::iterator end;
1712  begin = instancePtrVec_.begin ();
1713  end = instancePtrVec_.end ();
1714  for (iter=begin; iter!=end;++iter)
1715  {
1716  bool tmpBool = (*iter)->setInitialGuess ();
1717  bsuccess = bsuccess && tmpBool;
1718  }
1719  }
1720 
1721  return bsuccess;
1722 }
1723 
1724 
1725 //-----------------------------------------------------------------------------
1726 // Function : DeviceMgr::analyticSensitivitiesAvailable
1727 // Purpose :
1728 // Special Notes : Includes a reduce, so works in parallel.
1729 // Scope : public
1730 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1731 // Creation Date : 5/30/2014
1732 //-----------------------------------------------------------------------------
1734 {
1735  // This assumes that the only available analytic sensitivities are for
1736  // non-artificial parameters.
1737  DeviceEntity * device_entity = getDeviceEntity(name);
1738 
1739  int entityFound = (device_entity != 0);
1740  int available=0;
1741  if (entityFound)
1742  {
1743  std::string paramName = Util::paramNameFromFullParamName(name);
1744  available = device_entity->analyticSensitivityAvailable (paramName);
1745  }
1746  Parallel::AllReduce(pdsMgrPtr_->getPDSComm()->comm(), MPI_LOR, &available, 1);
1747 
1748  return static_cast<bool>(available);
1749 }
1750 
1751 //-----------------------------------------------------------------------------
1752 // Function : DeviceMgr::getAnalyticSensitivities
1753 // Purpose :
1754 // Special Notes :
1755 // Scope : public
1756 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1757 // Creation Date : 05/30/2014
1758 //-----------------------------------------------------------------------------
1760  (std::string & name,
1761  std::vector<double> & dfdpVec,
1762  std::vector<double> & dqdpVec,
1763  std::vector<double> & dbdpVec,
1764  std::vector<int> & FindicesVec,
1765  std::vector<int> & QindicesVec,
1766  std::vector<int> & BindicesVec)
1767 {
1768  // If not artificial, then search for the appropriate natural param(s).
1769  DeviceEntity * device_entity = getDeviceEntity(name);
1770 
1771  int entityFound = (device_entity != 0);
1772 
1773  if (entityFound)
1774  {
1775  bool found;
1776  std::string paramName = Util::paramNameFromFullParamName(name);
1777  found = device_entity->getAnalyticSensitivity (paramName,
1778  dfdpVec, dqdpVec, dbdpVec,
1779  FindicesVec, QindicesVec, BindicesVec);
1780  }
1781 
1782  return;
1783 }
1784 
1785 //-----------------------------------------------------------------------------
1786 // Function : DeviceMgr::setParam
1787 //
1788 // Purpose : This function sets named parameters (name) to a
1789 // specified value (val).
1790 //
1791 // Special Notes : Used for continuation calculations, as well as possibly
1792 // intrusive sensitivity/optimization calculations. It is
1793 // assumed that this is called after everything (devices,
1794 // solvers, etc.) is set up.
1795 //
1796 // The specified parameter can be either a natural or
1797 // artificial parameter.
1798 //
1799 //
1800 // Scope : public
1801 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1802 // Creation Date : 5/02/03
1803 //-----------------------------------------------------------------------------
1804 bool DeviceMgr::setParam(std::string & name, double val)
1805 {
1806  bool bsuccess = true, success = true;
1807 
1808  if (DEBUG_DEVICE && devOptions_.debugLevel > 0)
1809  {
1810  std::string netListFile("");
1811  if (commandLine_.getArgumentValue(std::string("netlist")) != "")
1812  {
1813  netListFile = commandLine_.getArgumentValue(std::string("netlist"));
1814  }
1815 
1816  dout() << netListFile << "\t\t";
1817  dout() << "DeviceMgr::setParam. ";
1818  dout() << name;
1819  dout() << " " << val;
1820  dout() << std::endl;
1821  }
1822 
1823  ArtificialParameterMap::iterator artificial_param_it = artificialParameterMap_.find(name);
1824  if (artificial_param_it != artificialParameterMap_.end())
1825  {
1826  (*artificial_param_it).second->setValue(*this, val);
1827  }
1828  else
1829  {
1830  GlobalParameterMap::iterator global_param_it = globals_.global_params.find(name);
1831  if (global_param_it != globals_.global_params.end())
1832  {
1833  if ((*global_param_it).second != val)
1834  {
1835  (*global_param_it).second = val;
1836  for (EntityVector::iterator it = dependentPtrVec_.begin(), end = dependentPtrVec_.end(); it != end; ++it)
1837  {
1838  if ((*it)->updateGlobalParameters(globals_.global_params));
1839  {
1840  (*it)->processParams();
1841  (*it)->processInstanceParams();
1842  }
1843  }
1844  }
1845  }
1846  else
1847  {
1848  // If not artificial, then search for the appropriate natural param(s).
1849  DeviceEntity * device_entity = getDeviceEntity(name);
1850 
1851  int entityFound = (device_entity != 0);
1852  if (entityFound)
1853  {
1854  bool found;
1855  std::string paramName = Util::paramNameFromFullParamName(name);
1856  if (paramName == "")
1857  {
1858  found = device_entity->setDefaultParam(val);
1859  }
1860  else
1861  {
1862  found = device_entity->setParam(paramName, val);
1863  }
1864 
1865  if (found)
1866  {
1867  device_entity->processParams (); // if this "entity" is a model, then need to
1868  // also do a "processParams" on the related instances.
1869  device_entity->processInstanceParams();
1870  }
1871 
1872  entityFound = found;
1873  }
1874 
1875  Parallel::AllReduce(pdsMgrPtr_->getPDSComm()->comm(), MPI_LOR, &entityFound, 1);
1876 
1877  if (entityFound == 0)
1878  {
1879  if (DEBUG_DEVICE)
1880  {
1881  Report::DevelWarning() << "DeviceMgr::setParam. Unable to find parameter " << name;
1882  }
1883  else
1884  {
1885  Report::UserError() << "Unable to find parameter " << name;
1886  }
1887  }
1888  }
1889  }
1890 
1891  // Certain parameters should be passed through to the inner solve,
1892  // if there is an inner circuit problem. The names of parameters
1893  // that should be passed through are stored in the map.
1894  if (passThroughParamsMap_.find(name) != passThroughParamsMap_.end())
1895  {
1896  ModelTypeInstanceVectorMap::const_iterator model_type_it = modelTypeInstanceVector_.find(ExternDevice::Traits::modelType());
1897  if (model_type_it != modelTypeInstanceVector_.end()) {
1898  for (InstanceVector::const_iterator it = (*model_type_it).second.begin(); it != (*model_type_it).second.end(); ++it)
1899  {
1900  ExternDevice::Instance &extern_device = static_cast<ExternDevice::Instance &>(*(*it));
1901 
1902  bool bs1 = extern_device.setInternalParam(name, val);
1903  }
1904  }
1905  }
1906 
1907  return bsuccess;
1908 }
1909 
1910 //-----------------------------------------------------------------------------
1911 // Function : DeviceMgr::getParam
1912 // Purpose : Returns the current value of a named parameter.
1913 //
1914 // Special Notes : This works in parallel.
1915 //
1916 // If the parameter is not found, this function sets val to
1917 // 0.0, and returns a "false" boolean. It does not invoke the
1918 // error handler.
1919 //
1920 // Scope : public
1921 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1922 // Creation Date : 9/13/04
1923 //-----------------------------------------------------------------------------
1924 bool DeviceMgr::getParam(const std::string & name, double & value) const
1925 {
1926  value = 0.0;
1927  bool entityFound = false;
1928 
1929  ArtificialParameterMap::const_iterator artificial_param_it = artificialParameterMap_.find(name);
1930  if (artificial_param_it != artificialParameterMap_.end())
1931  {
1932  value = (*artificial_param_it).second->getValue(*this);
1933  entityFound = true;
1934  }
1935  else
1936  {
1937  GlobalParameterMap::const_iterator global_param_it = globals_.global_params.find(name);
1938  if (global_param_it != globals_.global_params.end())
1939  {
1940  value = (*global_param_it).second;
1941  entityFound = true;
1942  }
1943  else
1944  {
1945  const DeviceEntity *device_entity = getDeviceEntity(name);
1946  entityFound = device_entity != 0;
1947 
1948  if (entityFound)
1949  {
1950  std::string paramName = Util::paramNameFromFullParamName(name);
1951  entityFound = device_entity->getParam(paramName, value);
1952  if (paramName == "")
1953  entityFound = true;
1954  }
1955 
1956  if (!entityFound)
1957  measureManager_->getMeasureValue(name, value, entityFound);
1958  }
1959  }
1960 
1961  return entityFound;
1962 }
1963 
1964 //-----------------------------------------------------------------------------
1965 // Function : DeviceMgr::findParam
1966 // Purpose : Returns the current value of a named parameter.
1967 // Special Notes :
1968 // Scope : public
1969 // Creator :
1970 // Creation Date :
1971 //-----------------------------------------------------------------------------
1972 bool DeviceMgr::findParam(const std::string & name) const
1973 {
1974  double value = 0.0;
1975  return getParam(name, value);
1976 }
1977 
1978 //-----------------------------------------------------------------------------
1979 // Function : DeviceMgr::getParamNoReduce
1980 // Purpose : Returns the current value of a named parameter.
1981 // Special Notes :
1982 // Scope : public
1983 // Creator :
1984 // Creation Date :
1985 //-----------------------------------------------------------------------------
1986 double DeviceMgr::getParamNoReduce(const std::string & name) const
1987 {
1988  double value = 0.0;
1989  return getParam(name, value);
1990 }
1991 
1992 //-----------------------------------------------------------------------------
1993 // Function : DeviceMgr::getParam
1994 // Purpose : Returns the current value of a named parameter.
1995 //
1996 // Special Notes : This works in parallel.
1997 //
1998 // Scope : public
1999 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2000 // Creation Date : 7/26/03
2001 //-----------------------------------------------------------------------------
2002 bool DeviceMgr::getParamAndReduce(const std::string & name, double & value) const
2003 {
2004  bool found = getParam(name, value);
2005  int found_count = found ? 1 : 0;
2006  Parallel::AllReduce(pdsMgrPtr_->getPDSComm()->comm(), MPI_SUM, &found_count, 1);
2007 
2008  if (found_count) {
2009  Parallel::AllReduce(pdsMgrPtr_->getPDSComm()->comm(), MPI_SUM, &value, 1);
2010  value /= found_count;
2011  }
2012 
2013  return found_count != 0;
2014 }
2015 
2016 //-----------------------------------------------------------------------------
2017 // Function : DeviceMgr::getParamAndReduce
2018 // Purpose : Returns the current value of a named parameter.
2019 // Special Notes :
2020 // Scope : public
2021 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2022 // Creation Date : 7/26/03
2023 //-----------------------------------------------------------------------------
2024 double DeviceMgr::getParamAndReduce(const std::string & name) const
2025 {
2026  double value = 0.0;
2027  bool found = getParamAndReduce(name, value);
2028 
2029  if (!found)
2030  {
2031  if (DEBUG_DEVICE)
2032  {
2033  Report::DevelWarning() <<
2034  "DeviceMgr::getParamAndReduce. Unable to find parameter " << name;
2035  }
2036  else
2037  {
2038  Report::UserError() << "Unable to find parameter " << name;
2039  }
2040  }
2041 
2042  return value;
2043 }
2044 
2045 //-----------------------------------------------------------------------------
2046 // Function : DeviceMgr::updateState
2047 // Purpose : This should be called prior to loadDAEVectors.
2048 // Special Notes :
2049 // Scope : public
2050 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2051 // Creation Date : 11/17/05
2052 //-----------------------------------------------------------------------------
2054  N_LAS_Vector * nextSolVectorPtr,
2055  N_LAS_Vector * currSolVectorPtr,
2056  N_LAS_Vector * lastSolVectorPtr,
2057  N_LAS_Vector * nextStaVectorPtr,
2058  N_LAS_Vector * currStaVectorPtr,
2059  N_LAS_Vector * lastStaVectorPtr,
2060  N_LAS_Vector * nextStoVectorPtr,
2061  N_LAS_Vector * currStoVectorPtr,
2062  N_LAS_Vector * lastStoVectorPtr
2063  )
2064 {
2065  bool bsuccess = true;
2066  bool tmpBool = true;
2067 
2068  tmpBool = setupSolverInfo_();
2069  bsuccess = bsuccess && tmpBool;
2070 
2071  // copy over the passed pointers:
2072  externData_.nextSolVectorPtr = nextSolVectorPtr;
2073  externData_.currSolVectorPtr = currSolVectorPtr;
2074  externData_.lastSolVectorPtr = lastSolVectorPtr;
2075  externData_.nextStaVectorPtr = nextStaVectorPtr;
2076  externData_.currStaVectorPtr = currStaVectorPtr;
2077  externData_.lastStaVectorPtr = lastStaVectorPtr;
2078  externData_.nextStoVectorPtr = nextStoVectorPtr;
2079  externData_.currStoVectorPtr = currStoVectorPtr;
2080  externData_.lastStoVectorPtr = lastStoVectorPtr;
2081 
2082 #ifdef Xyce_PARALLEL_MPI
2083  externData_.nextSolVectorPtr->importOverlap();
2084 #endif
2085 
2086  // Now reset the relevant RAW pointers:
2096 
2097 
2099 
2100  // if inner problem, only do the PDE loads.
2102  {
2103  // call all the intermediate vars loads:
2104  std::vector<Device*>::iterator iter;
2105  std::vector<Device*>::iterator begin = pdeDevicePtrVec_.begin ();
2106  std::vector<Device*>::iterator end = pdeDevicePtrVec_.end ();
2107  for (iter=begin; iter!=end;++iter)
2108  {
2109  tmpBool = (*iter)->updateState (externData_.nextSolVectorRawPtr,
2112  bsuccess = bsuccess && tmpBool;
2113  }
2114  }
2115  else
2116  {
2117  int numDevices = devicePtrVec_.size();
2118  for(int i=0; i< numDevices; ++i)
2119  {
2120  bsuccess=devicePtrVec_.at(i)->updateState (externData_.nextSolVectorRawPtr,
2123  }
2124  }
2125 
2127 
2128 #ifdef Xyce_PARALLEL_MPI
2129  externData_.nextStaVectorPtr->importOverlap();
2130  externData_.nextStoVectorPtr->importOverlap();
2131 #endif
2132 
2133  Report::safeBarrier(pdsMgrPtr_->getPDSComm()->comm());
2134 
2135  return true;
2136 }
2137 
2138 
2139 //-----------------------------------------------------------------------------
2140 // Function : DeviceMgr::loadDAEMatrices
2141 // Purpose : This function loads the various DAE related matrices to
2142 // set up the following expression:
2143 //
2144 // residual: f(x) = dQ/dt + F(x) - B(t) = 0
2145 //
2146 // jacobian: J(x) = d(dQ/dt)dx + dFdx
2147 // = d(dQdx)dt + dFdx
2148 //
2149 // Special Notes : ERK. This function is only called if using the new
2150 // (new-DAE) integrator. As such, it is also used for
2151 // MPDE. It is not used for the old (ODE) integrator.
2152 // The corresponding function for the old integrator
2153 // is loadJacobianMatrix
2154 //
2155 // Note that this function, unlike the loadJacobianMatrix
2156 // function *requires* that vector/matrix pointers
2157 // be passed in to the function. When
2158 // running in new-DAE or MPDE, we can't rely (much) on
2159 // registered vectors. (set up in initializeAll). In
2160 // particular, MPDE cycles through different vector and
2161 // matrix blocks, which each correspond to different
2162 // "fast" time points, and for each block the state
2163 // information is different.
2164 //
2165 // NOTE: This function assumes that all the load matrices
2166 // are zeroed out. That is, dFdx, dQdx are all zeros.
2167 //
2168 // If that isn't true, then this function will not produce
2169 // the correct answer. The reason for doing this
2170 // is MPDE. For the warped case, the entire linear system
2171 // needs to be zeroed out, but the full system includes
2172 // phase equations that never get passed in here.
2173 // That zeroing now happens upstream from here, in either
2174 // the MPDE loader or the time integrator.
2175 //
2176 // Scope : public
2177 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2178 // Creation Date : 03/03/04
2179 //-----------------------------------------------------------------------------
2181  (N_LAS_Vector * tmpSolVectorPtr,
2182  N_LAS_Vector * tmpStateVectorPtr,
2183  N_LAS_Vector * tmpStateDerivVectorPtr,
2184  N_LAS_Vector * tmpStoreVectorPtr,
2185  N_LAS_Matrix * tmpdQdxMatrixPtr,
2186  N_LAS_Matrix * tmpdFdxMatrixPtr)
2187 {
2188  bool bsuccess = true;
2189  bool tmpBool = true;
2190 
2191  // copy over the passed pointers:
2192  (externData_.nextSolVectorPtr) = tmpSolVectorPtr;
2193  bool resetRawMatrixPointers = true;
2194  if (
2195  (externData_.dQdxMatrixPtr == tmpdQdxMatrixPtr) &&
2196  (externData_.dFdxMatrixPtr == tmpdFdxMatrixPtr)
2197  )
2198  {
2199  resetRawMatrixPointers = false;
2200  }
2201  if (resetRawMatrixPointers)
2202  {
2203  externData_.dQdxMatrixPtr = tmpdQdxMatrixPtr;
2204  externData_.dFdxMatrixPtr = tmpdFdxMatrixPtr;
2205  }
2206 
2207  externData_.nextStaVectorPtr = tmpStateVectorPtr;
2208  externData_.nextStaDerivVectorPtr = tmpStateDerivVectorPtr;
2209  externData_.nextStoVectorPtr = tmpStoreVectorPtr;
2210 
2211  // setup the relevant RAW vector pointers:
2212  externData_.nextSolVectorRawPtr = &((*externData_.nextSolVectorPtr)[0]);
2213  externData_.nextStaVectorRawPtr = &((*externData_.nextStaVectorPtr)[0]);
2214  externData_.nextStaDerivVectorRawPtr = &((*externData_.nextStaDerivVectorPtr)[0]);
2215  externData_.nextStoVectorRawPtr = &((*externData_.nextStoVectorPtr)[0]);
2216 
2217 //#ifndef Xyce_NONPOINTER_MATRIX_LOAD
2218  // setup the relevant RAW matrix pointers (down in the devices that need them):
2219  if (resetRawMatrixPointers || solState_.blockAnalysisFlag)
2220  {
2221  this->setupRawMatrixPointers_();
2222  }
2223 //#endif
2224 
2225  InstanceVector::iterator iter;
2226  InstanceVector::iterator begin;
2227  InstanceVector::iterator end;
2228 
2229  // if this is an "inner problem" phase of a Two-Level Newton
2230  // simulation, then only load the PDE devices. Everything else just
2231  // gets "1" on the diagonal.
2232  //
2233  // Note, it is possible to just load 1's using a petra call, so I may
2234  // get rid of the "trivial" matrix stamp stuff soon.
2235 
2236  if (solState_.twoLevelNewtonCouplingMode==Nonlinear::INNER_PROBLEM)
2237  {
2238  begin = nonPdeInstancePtrVec_.begin();
2239  end = nonPdeInstancePtrVec_.end();
2240  for (iter=begin; iter!=end;++iter)
2241  {
2242  (*iter)->loadTrivialDAE_FMatrixStamp ();
2243  }
2244 
2245  begin = pdeInstancePtrVec_.begin();
2246  end = pdeInstancePtrVec_.end();
2247  for (iter=begin; iter!=end;++iter)
2248  {
2249  tmpBool = (*iter)->loadDAEdQdx();bsuccess = bsuccess && tmpBool;
2250  tmpBool = (*iter)->loadDAEdFdx();bsuccess = bsuccess && tmpBool;
2251  }
2252  }
2253  // Else, do a normal analytical matrix load.
2254  else
2255  {
2256  int numDevices = devicePtrVec_.size();
2257  for(int i=0; i< numDevices; ++i)
2258  {
2259  bsuccess=devicePtrVec_.at(i)->loadDAEMatrices
2260  (*(externData_.dFdxMatrixPtr) , *(externData_.dQdxMatrixPtr));
2261  }
2262  }
2263 
2264  // Run jacobian diagnostic.
2265  if (devOptions_.testJacobianFlag &&
2266  (solState_.timeStepNumber >= devOptions_.testJacStartStep &&
2267  solState_.timeStepNumber <= devOptions_.testJacStopStep)
2268  )
2269  {
2270  if (DEBUG_DEVICE)
2271  {
2272  devOptions_.debugLevel -= 2;
2273  }
2274 
2275  // Test just the specified device(s), if the user specified any.
2276  if ((devOptions_.testJacDeviceNameGiven))
2277  {
2278  begin = testJacDevicePtrVec_.begin();
2279  end = testJacDevicePtrVec_.end();
2280  }
2281  else // Test all the devices:
2282  {
2283  begin = instancePtrVec_.begin();
2284  end = instancePtrVec_.end();
2285  }
2286 
2287  for (iter=begin; iter!=end;++iter)
2288  {
2289  (*iter)->testDAEMatrices (nameVec_);
2290  }
2291 
2292  if (DEBUG_DEVICE)
2293  devOptions_.debugLevel += 2;
2294  }
2295 
2296  //Tell Jacobian, fill is complete allowing accumulation if necessary
2297  externData_.dQdxMatrixPtr->fillComplete();
2298  externData_.dFdxMatrixPtr->fillComplete();
2299 
2300  Report::safeBarrier(pdsMgrPtr_->getPDSComm()->comm());
2301 
2302  if (DEBUG_DEVICE && devOptions_.debugLevel > 1 && solState_.debugTimeFlag)
2303  {
2304  int newtonIter = solState_.newtonIter;
2305  dout() << section_divider << std::endl;
2306  dout() << "Q-matrix: nonlinear iteration = " << newtonIter << "\n";
2307  externData_.dQdxMatrixPtr->printPetraObject(dout());
2308  dout() << std::endl;
2309  dout() << section_divider << std::endl;
2310  dout() << "F-matrix: nonlinear iteration = " << newtonIter << "\n";
2311  externData_.dFdxMatrixPtr->printPetraObject(dout());
2312  dout() << std::endl;
2313  dout() << section_divider << std::endl;
2314  }
2315 
2316  return bsuccess;
2317 }
2318 
2319 //-----------------------------------------------------------------------------
2320 // Function : DeviceMgr::loadDAEVectors
2321 // Purpose : This function loads the various DAE related vectors to
2322 // set up the following expression:
2323 //
2324 // f(x) = dQ/dt + F(x) - B(t) = 0
2325 //
2326 // Special Notes : ERK. This function is only called if using the new
2327 // (new-DAE) integrator. As such, it is also used for
2328 // MPDE. It is not used for the old (ODE) integrator.
2329 // The corresponding function for the old integrator
2330 // is loadRHSVector.
2331 //
2332 // Note that this function, unlike the loadRHSVector
2333 // function *requires* that vectors be passed in. When
2334 // running in new-DAE or MPDE, we can't rely (much) on
2335 // registered vectors. (set up in initializeAll). In
2336 // particular, MPDE cycles through different vector and
2337 // matrix blocks, which each correspond to different
2338 // "fast" time points, and for each block the state
2339 // information is different.
2340 //
2341 // NOTE: This function assumes that all the load vectors
2342 // are zeroed out. That is, F, Q, B, dFdxdVp and dQdxVp
2343 // are all zeros.
2344 //
2345 // If that isn't true, then this function will not produce
2346 // the correct answer. The reason for doing this
2347 // is MPDE. For the warped case, the entire linear system
2348 // needs to be zeroed out, but the full system includes
2349 // phase equations that never get passed in here.
2350 //
2351 // That zeroing now happens upstream from here, in either
2352 // the MPDE loader or the time integrator.
2353 //
2354 // Scope : public
2355 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2356 // Creation Date : 01/26/03
2357 //-----------------------------------------------------------------------------
2359  (N_LAS_Vector * tmpSolVectorPtr,
2360  N_LAS_Vector * tmpCurrSolVectorPtr,
2361  N_LAS_Vector * tmpLastSolVectorPtr,
2362  N_LAS_Vector * tmpStaVectorPtr,
2363  N_LAS_Vector * tmpCurrStaVectorPtr,
2364  N_LAS_Vector * tmpLastStaVectorPtr,
2365  N_LAS_Vector * tmpStaDerivVectorPtr,
2366  N_LAS_Vector * tmpStoVectorPtr,
2367  N_LAS_Vector * tmpCurrStoVectorPtr,
2368  N_LAS_Vector * tmpLastStoVectorPtr,
2369  N_LAS_Vector * tmpStoLeadCurrQCompVectorPtr,
2370  N_LAS_Vector * tmpQVectorPtr,
2371  N_LAS_Vector * tmpFVectorPtr,
2372  N_LAS_Vector * tmpBVectorPtr,
2373  N_LAS_Vector * tmpdFdxdVpVectorPtr,
2374  N_LAS_Vector * tmpdQdxdVpVectorPtr)
2375 {
2376  bool bsuccess = true;
2377  bool tmpBool = true;
2378 
2379  // copy over the passed pointers:
2380  externData_.nextSolVectorPtr = tmpSolVectorPtr;
2381  externData_.currSolVectorPtr = tmpCurrSolVectorPtr;
2382  externData_.lastSolVectorPtr = tmpLastSolVectorPtr;
2383  externData_.daeQVectorPtr = tmpQVectorPtr;
2384  externData_.daeFVectorPtr = tmpFVectorPtr;
2385  externData_.daeBVectorPtr = tmpBVectorPtr;
2386  externData_.dFdxdVpVectorPtr = tmpdFdxdVpVectorPtr;
2387  externData_.dQdxdVpVectorPtr = tmpdQdxdVpVectorPtr;
2388  externData_.nextStaVectorPtr = tmpStaVectorPtr;
2389  externData_.currStaVectorPtr = tmpCurrStaVectorPtr;
2390  externData_.lastStaVectorPtr = tmpLastStaVectorPtr;
2391  externData_.storeLeadCurrQCompPtr = tmpStoLeadCurrQCompVectorPtr;
2392  externData_.nextStaDerivVectorPtr = tmpStaDerivVectorPtr;
2393  externData_.nextStoVectorPtr = tmpStoVectorPtr;
2394  externData_.currStoVectorPtr = tmpCurrStoVectorPtr;
2395  externData_.lastStoVectorPtr = tmpLastStoVectorPtr;
2396 
2397  // Make sure all boundary data is valid in the solution vector
2398 #ifdef Xyce_PARALLEL_MPI
2399  externData_.nextSolVectorPtr->importOverlap();
2400  externData_.nextStaDerivVectorPtr->importOverlap();
2401 #endif
2402 
2403  // Set up the relevant RAW Pointers:
2404  setupRawVectorPointers_ ();
2405 
2406  // call all the intermediate vars loads:
2407  std::vector<Device*>::iterator iter;
2408  std::vector<Device*>::iterator begin;
2409  std::vector<Device*>::iterator end;
2410 
2411  // if inner problem, only do the PDE loads.
2412  if (solState_.twoLevelNewtonCouplingMode==Nonlinear::INNER_PROBLEM)
2413  {
2414  begin = pdeDevicePtrVec_.begin ();
2415  end = pdeDevicePtrVec_.end ();
2416  }
2417  else
2418  {
2419  begin = devicePtrVec_.begin ();
2420  end = devicePtrVec_.end ();
2421  }
2422 
2423 #ifndef Xyce_EXCLUDE_SECONDARY_STATE
2424  for (iter=begin; iter!=end;++iter)
2425  {
2426  tmpBool = (*iter)->updateSecondaryState
2427  (externData_.nextStaDerivVectorRawPtr, externData_.nextStoVectorRawPtr);
2428  bsuccess = bsuccess && tmpBool;
2429  }
2430 #endif // Xyce_EXCLUDE_SECONDARY_STATE
2431 
2432 #ifdef Xyce_PARALLEL_MPI
2433  externData_.nextStaVectorPtr->importOverlap();
2434  externData_.nextStoVectorPtr->importOverlap();
2435 #endif
2436 
2437  if (solState_.twoLevelNewtonCouplingMode==Nonlinear::INNER_PROBLEM)
2438  {
2439  int numDevices = pdeDevicePtrVec_.size();
2440  for(int i=0; i< numDevices; ++i)
2441  {
2442  bsuccess=pdeDevicePtrVec_.at(i)->loadDAEVectors(externData_.nextSolVectorRawPtr,
2443  externData_.daeFVectorRawPtr,
2444  externData_.daeQVectorRawPtr,
2445  externData_.daeBVectorRawPtr,
2446  externData_.nextStoVectorRawPtr,
2447  externData_.storeLeadCurrQCompRawPtr);
2448  }
2449  }
2450  else
2451  {
2452  int numDevices = devicePtrVec_.size();
2453  for(int i=0; i< numDevices; ++i)
2454  {
2455  bsuccess=devicePtrVec_.at(i)->loadDAEVectors(externData_.nextSolVectorRawPtr,
2456  externData_.daeFVectorRawPtr,
2457  externData_.daeQVectorRawPtr,
2458  externData_.daeBVectorRawPtr,
2459  externData_.nextStoVectorRawPtr,
2460  externData_.storeLeadCurrQCompRawPtr);
2461  }
2462  }
2463 
2464  // dump to the screen:
2465  if (DEBUG_DEVICE && devOptions_.debugLevel > 1 && solState_.debugTimeFlag)
2466  {
2467  int newtonIter = solState_.newtonIter;
2468  dout() << "Q-vector: nonlinear iteration = " << newtonIter << "\n";
2469  externData_.daeQVectorPtr->printPetraObject(std::cout);
2470  dout() << std::endl;
2471  dout() << "F-vector: nonlinear iteration = " << newtonIter << "\n";
2472  externData_.daeFVectorPtr->printPetraObject(std::cout);
2473  dout() << std::endl;
2474 
2475  if (devOptions_.voltageLimiterFlag)
2476  {
2477  dout() << "\n\n dFdxdVp vector: nonlinear iteration = " << newtonIter << "\n";
2478  externData_.dFdxdVpVectorPtr->printPetraObject(std::cout);
2479  dout() << std::endl;
2480  dout() << "\n\n dQdxdVp vector: nonlinear iteration = " << newtonIter << "\n";
2481  externData_.dQdxdVpVectorPtr->printPetraObject(std::cout);
2482  dout() << std::endl;
2483  }
2484 
2485  debugOutput2();
2486  }
2487 
2488  // Update parallel if necessary
2489  externData_.daeQVectorPtr->fillComplete();
2490  externData_.daeFVectorPtr->fillComplete();
2491  externData_.dFdxdVpVectorPtr->fillComplete();
2492  externData_.dQdxdVpVectorPtr->fillComplete();
2493 
2494  Report::safeBarrier(pdsMgrPtr_->getPDSComm()->comm());
2495 
2496 #ifdef Xyce_SIZEOF
2497  int size = sizeof(*this);
2498  dout() << "Size of device package after vector load = " << size << std::endl;
2499 #endif
2500 
2501  return true;
2502 }
2503 
2504 //-----------------------------------------------------------------------------
2505 // Function : DeviceMgr::loadDeviceMask ()
2506 // Purpose : let devices set elements of a mask telling the time
2507 // integrator what equations should be ignored in taking
2508 // weighted norms for error control purposes.
2509 // Special Notes : Devices should *only* zero internal variables, and then
2510 // only those that absolutely should never be used to
2511 // control step size (e.g. excess phase variables in BJTs)
2512 // Scope : public
2513 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
2514 // Creation Date : 01/18/07
2515 //-----------------------------------------------------------------------------
2517 {
2518 
2519  // call all the intermediate vars loads:
2520  InstanceVector::iterator iter;
2521  InstanceVector::iterator begin;
2522  InstanceVector::iterator end;
2523 
2524  begin = instancePtrVec_.begin ();
2525  end = instancePtrVec_.end ();
2526 
2527  nonTrivialDeviceMaskFlag = false;
2528 
2529  for (iter=begin; iter!=end;++iter)
2530  {
2531  nonTrivialDeviceMaskFlag |= (*iter)->loadDeviceMask();
2532  }
2533 
2534  externData_.deviceMaskVectorPtr->fillComplete();
2535 
2536  // make sure the system's flag reflects ours:
2537  externData_.lasSysPtr->setNonTrivialDeviceMaskFlag(nonTrivialDeviceMaskFlag);
2538 
2539  return nonTrivialDeviceMaskFlag;
2540 }
2541 
2542 //-----------------------------------------------------------------------------
2543 // Function : DeviceMgr::addGlobalPar ()
2544 // Purpose :
2545 // Special Notes :
2546 // Scope : public
2547 // Creator : Dave Shirley, PSSI
2548 // Creation Date : 11/18/05
2549 //-----------------------------------------------------------------------------
2550 void DeviceMgr::addGlobalPar (const Util::Param & par)
2551 {
2552  if (par.getType() == Util::EXPR)
2553  {
2554  globals_.global_expressions.push_back(par.getValue<Util::Expression>());
2555  globals_.global_exp_names.push_back(par.uTag());
2556 
2557  Util::Expression &expression = globals_.global_expressions.back();
2558 
2559  std::vector<std::string> variables;
2560  expression.get_names(XEXP_VARIABLE, variables);
2561  std::vector<std::string> specials;
2562  expression.get_names(XEXP_SPECIAL, specials);
2563  if (!specials.empty())
2564  {
2565  expression.set_sim_time(solState_.currTime);
2566  }
2567 
2568  for (std::vector<std::string>::const_iterator it = variables.begin(),
2569  end = variables.end() ; it != end ; ++it)
2570  {
2571  expression.set_var(*it, globals_.global_params[*it]);
2572  }
2573 
2574  double val;
2575  expression.evaluateFunction(val);
2576  globals_.global_params[par.uTag()] = val;
2577  }
2578  else
2579  {
2580  globals_.global_params[par.uTag()] = par.getImmutableValue<double>();
2581  }
2582 }
2583 
2584 
2585 //-----------------------------------------------------------------------------
2586 // Function : DeviceMgr::getGlobalPar ()
2587 // Purpose :
2588 // Special Notes :
2589 // Scope : public
2590 // Creator : Rich Schie, SNL, Electrical Systems Modeling
2591 // Creation Date : 01/25/13
2592 //-----------------------------------------------------------------------------
2593 double DeviceMgr::getGlobalPar (const std::string & parName) const
2594 {
2595  double retVal = 0;
2596  GlobalParameterMap::const_iterator parLocItr = globals_.global_params.find(parName);
2597  if (parLocItr != globals_.global_params.end())
2598  {
2599  // extract the value for return
2600  retVal = parLocItr->second;
2601  }
2602  else
2603  {
2604  Report::UserError() << "Could not find global parameter \"" << parName << "\"";
2605  }
2606  return retVal;
2607 }
2608 
2609 //-----------------------------------------------------------------------------
2610 // Function : DeviceMgr::findGlobalPar
2611 // Purpose :
2612 // Special Notes :
2613 // Scope : public
2614 // Creator :
2615 // Creation Date :
2616 //-----------------------------------------------------------------------------
2617 const double *DeviceMgr::findGlobalPar (const std::string & parName) const
2618 {
2619  GlobalParameterMap::const_iterator it = globals_.global_params.find(parName);
2620  if (it != globals_.global_params.end())
2621  return &(*it).second;
2622 
2623  return 0;
2624 }
2625 
2626 //-----------------------------------------------------------------------------
2627 // Function : DeviceMgr::updateIntermediateVars_
2628 // Purpose : This function calls updateIntermediateVars
2629 // for the current devices.
2630 // Special Notes :
2631 // Scope : private
2632 // Creator : Rich Schiek, SNL, Parallel Computational Sciences
2633 // Creation Date : 12/14/2006
2634 //-----------------------------------------------------------------------------
2636 {
2637  bool bsuccess = true;
2638 
2639  InstanceVector::iterator iter;
2640  InstanceVector::iterator begin =instancePtrVec_.begin();
2641  InstanceVector::iterator end =instancePtrVec_.end();
2642  for (iter=begin; iter!=end;++iter)
2643  {
2644  (*iter)->updateIntermediateVars ();
2645  }
2646 
2647  return bsuccess;
2648 }
2649 
2650 //-----------------------------------------------------------------------------
2651 // Function : DeviceMgr::updatePrimaryState_
2652 // Purpose : This function updates primary states
2653 // for the present time step.
2654 // Special Notes :
2655 // Scope : private
2656 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2657 // Creation Date : 6/21/00
2658 //-----------------------------------------------------------------------------
2660 {
2661  bool bsuccess = true;
2662 
2663  InstanceVector::iterator iter;
2664  InstanceVector::iterator begin =instancePtrVec_.begin();
2665  InstanceVector::iterator end =instancePtrVec_.end();
2666  for (iter=begin; iter!=end;++iter)
2667  {
2668  (*iter)->updatePrimaryState ();
2669  }
2670 
2671  return bsuccess;
2672 }
2673 
2674 //-----------------------------------------------------------------------------
2675 // Function : DeviceMgr::updateSecondaryState_
2676 // Purpose : This function function updates secondary states
2677 // for the present time step.
2678 // Special Notes :
2679 // Scope : private
2680 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2681 // Creation Date : 6/21/00
2682 //-----------------------------------------------------------------------------
2684 {
2685  bool bsuccess = true;
2686 
2687  InstanceVector::iterator iter;
2688  InstanceVector::iterator begin =instancePtrVec_.begin();
2689  InstanceVector::iterator end =instancePtrVec_.end();
2690  for (iter=begin; iter!=end;++iter)
2691  {
2692  (*iter)->updateSecondaryState ();
2693  }
2694 
2695  return bsuccess;
2696 }
2697 
2698 //----------------------------------------------------------------------------
2699 // Function : DeviceMgr::updateDependentParameters_
2700 // Purpose : This function updates all dependent parameters for
2701 // the current time step.
2702 // Special Notes : This was evolved from updateTimeDependentParameters_
2703 // Scope : private
2704 // Creator : Dave Shirley
2705 // Creation Date : 08/17/06
2706 //----------------------------------------------------------------------------
2708 {
2709  bool bsuccess = true;
2710  N_LAS_Vector * solVectorPtr = externData_.nextSolVectorPtr;
2711 
2713  std::vector<Util::Expression> & ge = globals_.global_expressions;
2714 
2716  parameterChanged_ = true;
2717 
2718  // Update global params for new time and other global params
2719  int pos = 0;
2720  for (std::vector<Util::Expression>::iterator g_i = ge.begin(), g_end = ge.end();
2721  g_i != g_end; ++g_i)
2722  {
2723  bool changed = false;
2724  if (g_i->set_sim_time(solState_.currTime))
2725  changed = true;
2726 
2727  std::vector<std::string> variables;
2728  g_i->get_names(XEXP_VARIABLE, variables);
2729  for (std::vector<std::string>::iterator vs_i = variables.begin(), vs_end = variables.end();
2730  vs_i != vs_end; ++vs_i)
2731  {
2732  if (g_i->set_var(*vs_i, gp[*vs_i]))
2733  changed = true;
2734  }
2735 
2736  if (changed)
2737  {
2738  double val;
2739 
2740  parameterChanged_ = true;
2741  g_i->evaluateFunction(val);
2742  gp[globals_.global_exp_names[pos]] = val;
2743  }
2744  ++pos;
2745  }
2746 
2747  // do the models:
2748  if (firstDependent_)
2749  {
2750  firstDependent_ = false;
2751 
2752  dependentPtrVec_.clear();
2753 
2754  ModelVector::iterator iterM;
2755  ModelVector::iterator beginM =modelVector_.begin();
2756  ModelVector::iterator endM =modelVector_.end();
2757  for (iterM=beginM; iterM!=endM;++iterM)
2758  {
2759  if (!(*iterM)->getDependentParams().empty())
2760  {
2761  dependentPtrVec_.push_back(static_cast<DeviceEntity *>(*iterM));
2762  bool tmpBool = (*iterM)->updateGlobalParameters(gp);
2763  bsuccess = bsuccess && tmpBool;
2764  tmpBool = (*iterM)->updateDependentParameters (*solVectorPtr);
2765  bsuccess = bsuccess && tmpBool;
2766  (*iterM)->processParams();
2767  (*iterM)->processInstanceParams();
2768  }
2769  }
2770 
2771  // do the instances
2772  InstanceVector::iterator iter;
2773  InstanceVector::iterator begin =instancePtrVec_.begin();
2774  InstanceVector::iterator end =instancePtrVec_.end();
2775  for (iter=begin; iter!=end;++iter)
2776  {
2777  if (!(*iter)->getDependentParams().empty())
2778  {
2779  dependentPtrVec_.push_back(static_cast<DeviceEntity *>(*iter));
2780  bool tmpBool = (*iter)->updateGlobalParameters(gp);
2781  bsuccess = bsuccess && tmpBool;
2782  tmpBool = (*iter)->updateDependentParameters (*solVectorPtr);
2783  bsuccess = bsuccess && tmpBool;
2784  (*iter)->processParams();
2785  }
2786  }
2787  }
2788  else
2789  {
2790  EntityVector::iterator iter;
2791  EntityVector::iterator begin = dependentPtrVec_.begin();
2792  EntityVector::iterator end = dependentPtrVec_.end();
2793  for (iter=begin; iter!=end;++iter)
2794  {
2795  bool changed = false;
2796  if (parameterChanged_)
2797  {
2798  bool tmpBool = (*iter)->updateGlobalParameters(gp);
2799  changed = changed || tmpBool;
2800  bsuccess = bsuccess && tmpBool;
2801  }
2802  bool tmpBool = (*iter)->updateDependentParameters (*solVectorPtr);
2803  changed = changed || tmpBool;
2804  bsuccess = bsuccess && tmpBool;
2805  if (changed)
2806  {
2807  (*iter)->processParams();
2808  (*iter)->processInstanceParams();
2809  }
2810  }
2811  }
2813  parameterChanged_ = false;
2814 
2815  return bsuccess;
2816 }
2817 
2818 
2819 //-----------------------------------------------------------------------------
2820 // Function : DeviceMgr::loadBVectorsforAC
2821 // Purpose : This function loads the B-vector contributions for sources.
2822 // Special Notes :
2823 // Scope : public
2824 // Creator : Ting Mei, SNL
2825 // Creation Date :
2826 //-----------------------------------------------------------------------------
2827 bool DeviceMgr::loadBVectorsforAC(N_LAS_Vector * bVecRealPtr, N_LAS_Vector * bVecImagPtr)
2828 {
2829  bool bsuccess = true;
2830 
2831 // copy over the passed pointers:
2832  externData_.bVecRealPtr = bVecRealPtr;
2833  externData_.bVecImagPtr = bVecImagPtr;
2834 
2835 #ifdef Xyce_PARALLEL_MPI
2836  externData_.nextSolVectorPtr->importOverlap();
2837 #endif
2838  // Now reset the relevant RAW pointers:
2841 
2842  std::vector<SourceInstance*>::iterator vIter;
2843  std::vector<SourceInstance*>::iterator vBegin =indepSourceInstancePtrVec_.begin();
2844  std::vector<SourceInstance*>::iterator vEnd =indepSourceInstancePtrVec_.end();
2845  for (vIter=vBegin; vIter!=vEnd;++vIter)
2846  {
2847  (*vIter)->loadBVectorsforAC(externData_.bVecRealRawPtr, externData_.bVecImagRawPtr);
2848  }
2849 
2850  return bsuccess;
2851 }
2852 
2853 //-----------------------------------------------------------------------------
2854 // Function : DeviceMgr::getBMatrixEntriesforMOR()
2855 // Purpose : This function obtains the indices for the B-vector contributions for sources.
2856 // Special Notes :
2857 // Scope : public
2858 // Creator : Heidi Thornquist and Ting Mei, SNL
2859 // Creation Date :
2860 //-----------------------------------------------------------------------------
2861 bool DeviceMgr::getBMatrixEntriesforMOR(std::vector<int>& bMatEntriesVec,
2862  std::vector<int>& bMatPosEntriesVec)
2863 {
2864  bool bsuccess = true;
2865 
2866  int lpos, lneg, lbra;
2867  std::vector<SourceInstance *>::iterator vIter;
2868  std::vector<SourceInstance *>::iterator vBegin = indepSourceInstancePtrVec_.begin();
2869  std::vector<SourceInstance *>::iterator vEnd = indepSourceInstancePtrVec_.end();
2870 
2871  for (vIter=vBegin; vIter!=vEnd;++vIter)
2872  {
2873  Vsrc::Instance* vsrc = dynamic_cast<Vsrc::Instance *>(*vIter);
2874  if (vsrc != 0)
2875  {
2876  vsrc->getLIDs(lpos, lneg, lbra);
2877  bMatEntriesVec.push_back(lbra);
2878  bMatPosEntriesVec.push_back(lpos);
2879  }
2880  }
2881 
2882  return bsuccess;
2883 }
2884 
2885 //-----------------------------------------------------------------------------
2886 // Function : DeviceMgr::updateSources
2887 // Purpose : This function function updates sources for the present
2888 // time step.
2889 // Special Notes :
2890 // Scope : public
2891 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
2892 // Creation Date : 5/26/00
2893 //-----------------------------------------------------------------------------
2895 {
2896  bool bsuccess = true;
2897 
2898  setupSolverInfo_ ();
2899 
2900  std::vector<SourceInstance*>::iterator vIter;
2901  std::vector<SourceInstance*>::iterator vBegin = indepSourceInstancePtrVec_.begin();
2902  std::vector<SourceInstance*>::iterator vEnd = indepSourceInstancePtrVec_.end();
2903  for (vIter=vBegin; vIter!=vEnd; ++vIter)
2904  {
2905  (*vIter)->updateSource();
2906  }
2907 
2908  return bsuccess;
2909 }
2910 
2911 //-----------------------------------------------------------------------------
2912 // Function : DeviceMgr::setICs
2913 // Purpose : This function function sets initial conditions for devices
2914 // Special Notes :
2915 // Scope : public
2916 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
2917 // Creation Date : 9/13/00
2918 //-----------------------------------------------------------------------------
2920  N_LAS_Vector * tmpSolVectorPtr,
2921  N_LAS_Vector * tmpCurrSolVectorPtr,
2922  N_LAS_Vector * tmpLastSolVectorPtr,
2923  N_LAS_Vector * tmpStaVectorPtr,
2924  N_LAS_Vector * tmpCurrStaVectorPtr,
2925  N_LAS_Vector * tmpLastStaVectorPtr,
2926  N_LAS_Vector * tmpStaDerivVectorPtr,
2927  N_LAS_Vector * tmpStoVectorPtr,
2928  N_LAS_Vector * tmpCurrStoVectorPtr,
2929  N_LAS_Vector * tmpLastStoVectorPtr,
2930  N_LAS_Vector * tmpQVectorPtr,
2931  N_LAS_Vector * tmpFVectorPtr,
2932  N_LAS_Vector * tmpBVectorPtr,
2933  N_LAS_Vector * tmpdFdxdVpVectorPtr,
2934  N_LAS_Vector * tmpdQdxdVpVectorPtr)
2935 {
2936  bool bsuccess = true;
2937 
2938  // copy over the passed pointers:
2939  externData_.nextSolVectorPtr = tmpSolVectorPtr;
2940  externData_.currSolVectorPtr = tmpCurrSolVectorPtr;
2941  externData_.lastSolVectorPtr = tmpLastSolVectorPtr;
2942  externData_.daeQVectorPtr = tmpQVectorPtr;
2943  externData_.daeFVectorPtr = tmpFVectorPtr;
2944  externData_.daeBVectorPtr = tmpBVectorPtr;
2945  externData_.dFdxdVpVectorPtr = tmpdFdxdVpVectorPtr;
2946  externData_.dQdxdVpVectorPtr = tmpdQdxdVpVectorPtr;
2947  externData_.nextStaVectorPtr = tmpStaVectorPtr;
2948  externData_.currStaVectorPtr = tmpCurrStaVectorPtr;
2949  externData_.lastStaVectorPtr = tmpLastStaVectorPtr;
2950  externData_.nextStaDerivVectorPtr = tmpStaDerivVectorPtr;
2951  externData_.nextStoVectorPtr = tmpStoVectorPtr;
2952  externData_.currStoVectorPtr = tmpCurrStoVectorPtr;
2953  externData_.lastStoVectorPtr = tmpLastStoVectorPtr;
2954 
2955  // Make sure all boundary data is valid in the solution vector
2956 #ifdef Xyce_PARALLEL_MPI
2957  externData_.nextSolVectorPtr->importOverlap();
2958  externData_.nextStaDerivVectorPtr->importOverlap();
2959 #endif
2960 
2961  // if IC's on devices are set, we need to ensure that the
2962  // raw pointers are up to date first.
2964 
2965  for (InstanceVector::iterator iter = instancePtrVec_.begin();
2966  iter != instancePtrVec_.end(); ++iter)
2967  {
2968  (*iter)->setIC();
2969  }
2970 
2971  return bsuccess;
2972 }
2973 
2974 //-----------------------------------------------------------------------------
2975 // Function : DeviceMgr::output
2976 // Purpose :
2977 // Special Notes :
2978 // Scope : public
2979 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
2980 // Creation Date : 4/13/01
2981 //-----------------------------------------------------------------------------
2983 {
2984  bool bsuccess = true;
2985 
2986  InstanceVector::iterator iter;
2987  InstanceVector::iterator begin = plotFileInstancePtrVec_.begin ();
2988  InstanceVector::iterator end = plotFileInstancePtrVec_.end ();
2989  for (iter=begin; iter!=end;++iter)
2990  {
2991  bool tmpBool = (*iter)->outputPlotFiles ();
2992  bsuccess = bsuccess && tmpBool;
2993  }
2994 
2995  // only output .OP information once.
2997  {
2998  dotOpOutput();
2999  }
3000 
3001  return bsuccess;
3002 }
3003 
3004 //-----------------------------------------------------------------------------
3005 // Function : DeviceMgr::finishOutput
3006 // Purpose : Same as output, only this one forces the output.
3007 //
3008 // Special Notes : This function was neccessary with the implementation of
3009 // outputInterval. The final output, which needs to
3010 // happen after the transient is over, won't neccessarily
3011 // happen with outputInterval enabled.
3012 //
3013 // Scope : public
3014 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
3015 // Creation Date : 6/19/04
3016 //-----------------------------------------------------------------------------
3018 {
3019  bool bsuccess = true;
3020  bool tmpBool = true;
3021 
3022  solState_.forceFinalOutput = true;
3023  tmpBool = output ();
3024  bsuccess = bsuccess && tmpBool;
3025  solState_.forceFinalOutput = false;
3026 
3027  return bsuccess;
3028 }
3029 
3030 //-----------------------------------------------------------------------------
3031 // Function : DeviceMgr::dotOpOutput
3032 // Purpose :
3033 // Special Notes : This is a quick-and-dirty implementation, to get something
3034 // working quickly.
3035 // Scope : public
3036 // Creator : Eric R. Keiter, SNL
3037 // Creation Date : 5/3/12
3038 //-----------------------------------------------------------------------------
3040 {
3041  dotOpOutputFlag = true;
3042 
3043  std::map<std::string, Device *> device_map;
3044  for (EntityTypeIdDeviceMap::const_iterator it = deviceMap_.begin();
3045  it != deviceMap_.end(); ++it)
3046  {
3047  device_map[(*it).second->getName()] = (*it).second;
3048  }
3049 
3050  lout() << section_divider << "\n"
3051  << "Operating point information:";
3052 
3053  for (std::map<std::string, Device *>::const_iterator it = device_map.begin();
3054  it != device_map.end(); ++it)
3055  {
3056  Xyce::Device::printDotOpOutput(lout(), *(*it).second);
3057  }
3058 
3059  lout() << section_divider << std::endl;
3060 }
3061 
3062 //-----------------------------------------------------------------------------
3063 // Function : DeviceMgr::setGlobalFlags
3064 // Purpose :
3065 // Special Notes :
3066 // Scope : public
3067 // Creator : Eric R. Keiter, SNL
3068 // Creation Date : 11/2/12
3069 //-----------------------------------------------------------------------------
3071 {
3072  int pde_flag = solState_.PDESystemFlag ? 1 : 0;
3073 
3074  Parallel::AllReduce(pdsMgrPtr_->getPDSComm()->comm(), MPI_LOR, &pde_flag, 1);
3075 
3076  solState_.PDESystemFlag = pde_flag != 0;
3077 }
3078 
3079 //-----------------------------------------------------------------------------
3080 // Function : DeviceMgr::getBreakPoints
3081 // Purpose :
3082 // Special Notes :
3083 // Scope : public
3084 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
3085 // Creation Date : 6/08/01
3086 //-----------------------------------------------------------------------------
3087 bool DeviceMgr::getBreakPoints (std::vector<Util::BreakPoint> & breakPointTimes)
3088 {
3089  InstanceVector::iterator iterI;
3090  ModelVector::iterator iterM;
3091  bool bsuccess = true;
3092  bool tmpBool = true;
3093 
3094  tmpBool = setupSolverInfo_();
3095  bsuccess = bsuccess && tmpBool;
3097 
3098  // For some devices we only need to set breakpoints caused by discontinuities
3099  // in their parameters:
3100 
3101  for (iterM = modelVector_.begin() ; iterM != modelVector_.end() ; ++iterM)
3102  {
3103  if (!(*iterM)->getDependentParams().empty())
3104  {
3105  tmpBool = (*iterM)->getParamBreakpoints(breakPointTimes);
3106  bsuccess = bsuccess && tmpBool;
3107  }
3108  }
3109 
3110  for (iterI = instancePtrVec_.begin() ; iterI != instancePtrVec_.end() ; ++iterI)
3111  {
3112  if (!(*iterI)->getDependentParams().empty())
3113  {
3114  tmpBool = (*iterI)->getParamBreakpoints(breakPointTimes);
3115  bsuccess = bsuccess && tmpBool;
3116  }
3117  }
3118 
3119  // Breakpoints for global params:
3120  std::vector<Util::Expression>::iterator globalExp_i =
3121  globals_.global_expressions.begin();
3122  std::vector<Util::Expression>::iterator globalExp_end =
3124  for (; globalExp_i != globalExp_end; ++globalExp_i)
3125  {
3126  double bTime = globalExp_i->get_break_time();
3127  if (bTime > solState_.currTime)
3128  breakPointTimes.push_back(bTime);
3129  }
3130 
3132  {
3133  InstanceVector::iterator beginI = instancePtrVec_.begin ();
3134  InstanceVector::iterator endI = instancePtrVec_.end ();
3135 
3136  for (iterI=beginI;iterI!=endI;++iterI)
3137  {
3138  // this function returns false if it is the base class, and true otherwise.
3139  bool functionSetup = (*iterI)->getInstanceBreakPoints (breakPointTimes);
3140  if (functionSetup)
3141  {
3142  bpInstancePtrVec_.push_back(*iterI);
3143  }
3144  }
3146  }
3147  else
3148  {
3149  InstanceVector::iterator beginI = bpInstancePtrVec_.begin ();
3150  InstanceVector::iterator endI = bpInstancePtrVec_.end ();
3151  for (iterI=beginI;iterI!=endI;++iterI)
3152  {
3153  bool functionSetup = (*iterI)->getInstanceBreakPoints (breakPointTimes);
3154  }
3155  }
3156 
3157  ModelTypeInstanceVectorMap::const_iterator model_type_it =
3158  modelTypeInstanceVector_.find(ExternDevice::Traits::modelType());
3159  if (model_type_it != modelTypeInstanceVector_.end())
3160  {
3161  for (InstanceVector::const_iterator it = (*model_type_it).second.begin();
3162  it != (*model_type_it).second.end(); ++it)
3163  {
3164  ExternDevice::Instance &extern_device = static_cast<ExternDevice::Instance &>(*(*it));
3165 
3166  extern_device.getBreakPoints(breakPointTimes);
3167  }
3168  }
3169 
3170  return bsuccess;
3171 
3172 }
3173 
3174 //-----------------------------------------------------------------------------
3175 // Function : DeviceMgr::setupSolverInfo_
3176 //
3177 // Purpose :
3178 //
3179 // Special Notes : This function gets called a lot, and this can be kind of
3180 // confusing. Probably, this function is being used to handle
3181 // too many different types of data.
3182 //
3183 // For example, it gets called at the beginning
3184 // of the "updateSources" function. Why? Because the sources
3185 // need to know which step we are at, and/or what the current
3186 // time is, to do their update properly.
3187 //
3188 // However, at the moment, updateSources also provides
3189 // information that setupSolverInfo needs. Only after the
3190 // sources have been updated do we know if a sweep source has
3191 // been reset. And, the sweepSourceResetFlag is used by
3192 // setupSolverInfo, to set up the initJctFlag boolean.
3193 // So it will need to be called at least one more
3194 // time, at the beginning of the RHS load. (which it is).
3195 //
3196 // Anyway, any of the functions that are called from the
3197 // outside, such as: updateSources, loadRHSVector,
3198 // loadJacobianMatrix, etc.... have no way of knowing when,
3199 // w.r.t. the solvers they are being called. The only way
3200 // to do this properly is to have each of them request
3201 // the current solver state, before they go to do their
3202 // work. Hence, this function is called a lot.
3203 //
3204 // Unfortunately, this has led to a somewhat sloppy and
3205 // confusing interface between the solvers and the
3206 // device package. I wanted to avoid having a lot of
3207 // function arguments being passed around for each of
3208 // these functions, in part because the calling code
3209 // (NLS) doesn't know everything. - NLS knows about the newton
3210 // step, but it doesn't know the time step, for example.
3211 //
3212 // At some point I hope to refactor this.
3213 //
3214 // Scope : private
3215 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
3216 // Creation Date : 7/30/01
3217 //-----------------------------------------------------------------------------
3219 {
3220  bool bsuccess = true;
3221 
3222  N_TIA_TimeIntInfo & tiInfo = solState_.tiInfo;
3223  N_NLS_NonLinInfo & nlInfo = solState_.nlInfo;
3224 
3225  // Time integration info:
3226  anaIntPtr_->getTimeIntInfo(tiInfo);
3227  solState_.pdt = tiInfo.pdt;
3230  solState_.currTime = tiInfo.nextTime;
3231  solState_.finalTime = tiInfo.finalTime;
3233  solState_.bpTol = tiInfo.bpTol;
3234  solState_.currentOrder = tiInfo.currentOrder; // BNB
3235  solState_.usedOrder = tiInfo.usedOrder; // BNB
3236 
3237  if (solState_.mpdeOnFlag == 1)
3238  {
3239  solState_.dcopFlag = 0;
3240  solState_.initTranFlag = 1;
3242  }
3243  else
3244  {
3245  solState_.dcopFlag = tiInfo.dcopFlag;
3248  }
3249 
3251  solState_.acopFlag = tiInfo.acopFlag;
3252  solState_.tranopFlag = tiInfo.tranopFlag;
3256 
3258 // solState_.initTranFlag = tiInfo.initTranFlag;
3259 // solState_.beginIntegrationFlag = tiInfo.beginIntegrationFlag;
3260 
3264 
3265  // Nonlinear solver info:
3266  nlsMgrPtr_->getNonLinInfo(nlInfo);
3267  solState_.newtonIter = nlInfo.newtonIter;
3269 
3270  // Get LOCA-specific information. Note - in general, LOCA is only used for
3271  // steady state calculations - there isn't much point in using it
3272  // for transient. A common case is one where LOCA is used for the
3273  // tranOP, but not for the subsequent transient phase. The
3274  // locaEnabledFlag should switch from true to false under
3275  // that scenario, once the transient phase starts.
3277  if (solState_.locaEnabledFlag) // if no LOCA, these are 0, true, respectively.
3278  {
3282  }
3283  // Done with LOCA information.
3284 
3285  // Setup the initialize junctions flag.
3286  // The initJct flag should only be true if we are at the first Newton step of
3287  // an initial point in the calculation. Examples include:
3288  // - 1st Newton step of the DCOP initialization for transient (tranOp)
3289  // - 1st Newton step of first DC sweep step.
3290  // - 1st Newton step of a sweep that has been reset. That typically
3291  // happens if the sweep is multi-dimensional, and the inner loop has
3292  // cycled back to the beginning again.
3293  //
3294  bool resetFlag = (solState_.timeStepNumber==0) || (solState_.sweepSourceResetFlag);
3295 
3296  // Do this if using LOCA for a DC or tranop calculation.
3298  {
3299  resetFlag = resetFlag && (solState_.continuationStepNumber==0);
3300  }
3301 
3303  (solState_.newtonIter==0) &&
3305  !solState_.firstSolveComplete && resetFlag);
3306 
3307  // initFixFlag: try to mimic "MODEINITFIX" of SPICE. This is set if:
3308  // DCOP or TranOP
3309  // Not first iteration
3310  // Any device not converged
3311 
3313  !(allDevsConverged()) &&
3314  (solState_.newtonIter!=0) &&
3316  !solState_.firstSolveComplete && resetFlag);
3317 
3318  if (solState_.dcopFlag)
3319  {
3323  }
3324 
3325  // One final check. See if the "external state" has been set. If so,
3326  // check to see if it has the initJctFlag set. If not, then we probably
3327  // shouldn't either. The external state comes from a higher up level
3328  // in a multi-level newton solve.
3329  //
3330  // This should be made more detailed later.
3331  if (externalStateFlag_)
3332  {
3334  {
3336  }
3337  }
3338 
3339  // The first DCOP step of a "double DCOP" simulation is a special case,
3340  // in which the nonlinear poisson is solved in place of drift-diffusion
3341  // equations for the PDE devices. For this initialization problem, the
3342  // circuit subproblem should not be included.
3343  if ((solState_.doubleDCOPEnabled) &&
3344  (solState_.dcopFlag) &&
3345  (solState_.doubleDCOPStep == 0))
3346  {
3348  }
3349 
3350  // if necessary, set up the names vector
3352  {
3353  const NodeNamePairMap & nodeNames = outputMgrPtr_->getAllNodes();
3354  int nodeNameSize = nodeNames.size();
3355  nameVec_.resize(nodeNameSize+1,"gnd");
3356  NodeNamePairMap::const_iterator mapI, mapEnd;
3357  mapEnd = nodeNames.end();
3358  mapI = nodeNames.begin();
3359  for (; mapI != mapEnd ; ++mapI)
3360  {
3361  nameVec_[(*mapI).second.first] = (*mapI).first;
3362  }
3363  }
3364 
3365  if (DEBUG_DEVICE) {
3367  {
3368  dout() << solState_;
3369  }
3370 
3376  }
3377 
3378  return bsuccess;
3379 }
3380 
3381 //-----------------------------------------------------------------------------
3382 // Function : DeviceMgr::setupRawVectorPointers_
3383 // Purpose : set up raw pointers
3384 // Special Notes :
3385 // Scope : public
3386 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
3387 // Creation Date : 11/25/08
3388 //-----------------------------------------------------------------------------
3390 {
3391  if (externData_.daeQVectorPtr != 0)
3392  {
3394  }
3395 
3396  if (externData_.daeFVectorPtr != 0)
3397  {
3399  }
3400 
3401  if (externData_.daeBVectorPtr != 0)
3402  {
3404  }
3405 
3406  if (externData_.dFdxdVpVectorPtr != 0)
3407  {
3409  }
3410 
3411  if (externData_.dQdxdVpVectorPtr != 0)
3412  {
3414  }
3415 
3416  if (externData_.nextSolVectorPtr != 0)
3417  {
3419  }
3420 
3421  if (externData_.currSolVectorPtr != 0)
3422  {
3424  }
3425 
3426  if (externData_.lastSolVectorPtr != 0)
3427  {
3429  }
3430 
3431  if (externData_.nextStaVectorPtr != 0)
3432  {
3434  }
3435 
3436  if (externData_.currStaVectorPtr != 0)
3437  {
3439  }
3440 
3441  if (externData_.lastStaVectorPtr != 0)
3442  {
3444  }
3445 
3447  {
3449  }
3450 
3451  if (externData_.nextStoVectorPtr != 0)
3452  {
3454  }
3455 
3456  if (externData_.currStoVectorPtr != 0)
3457  {
3459  }
3460 
3461  if (externData_.lastStoVectorPtr != 0)
3462  {
3464  }
3465 
3467  {
3469  }
3470 
3471  return true;
3472 }
3473 
3474 //-----------------------------------------------------------------------------
3475 // Function : DeviceMgr::setupRawMatrixPointers_
3476 // Purpose : set up raw pointers for matrices
3477 // Special Notes :
3478 // Scope : public
3479 // Creator : Todd Coffey, 1414
3480 // Creation Date : 06/03/09
3481 //-----------------------------------------------------------------------------
3483 {
3484  InstanceVector::iterator iter;
3485  InstanceVector::iterator begin;
3486  InstanceVector::iterator end;
3487  begin = instancePtrVec_.begin();
3488  end = instancePtrVec_.end();
3489  for (iter=begin; iter!=end;++iter)
3490  {
3491  (*iter)->setupPointers();
3492  }
3493  return true;
3494 }
3495 
3496 //-----------------------------------------------------------------------------
3497 // Function : DeviceMgr::getMaxTimeStepSize
3498 // Purpose :
3499 // Special Notes :
3500 // Scope : public
3501 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
3502 // Creation Date : 7/31/01
3503 //-----------------------------------------------------------------------------
3505 {
3506  double maxStep = devOptions_.defaultMaxTimeStep;
3507 
3508  InstanceVector::iterator iter;
3509  InstanceVector::iterator begin =instancePtrVec_.begin();
3510  InstanceVector::iterator end =instancePtrVec_.end();
3511  for (iter=begin; iter!=end;++iter)
3512  {
3513  double step = (*iter)->getMaxTimeStepSize ();
3514  SourceInstance * srcInst = dynamic_cast<SourceInstance*>(*iter);
3515  if (!srcInst || !srcInst->getFastSourceFlag())
3516  maxStep = Xycemin(step, maxStep);
3517  }
3518 
3519  return maxStep;
3520 }
3521 
3522 
3523 //-----------------------------------------------------------------------------
3524 // Function : DeviceMgr::declareCurrentStepAsBreakpoint
3525 // Purpose : If during a device load, a device must act in a discontinuous
3526 // fashion, let the analysis manager know that this step should
3527 // be treated as such.
3528 // Special Notes :
3529 // Scope : public
3530 // Creator : Richard Schiek, Electrical and Microsystems Modeling
3531 // Creation Date : 3/5/2010
3532 //-----------------------------------------------------------------------------
3534 {
3536 }
3537 
3538 //-----------------------------------------------------------------------------
3539 // Function : DeviceMgr::enablePDEContinuation
3540 // Purpose : This function turns on the Continuation flag, which lets
3541 // the devices which are Continuation enabled know that they
3542 // need to set up their variable parameters.
3543 //
3544 // Special Notes : Currently, only PDE devices can take advantage of this
3545 // capability, and it is only used in the context of two-level
3546 // Newton.
3547 //
3548 // Scope : public
3549 // Creator : Eric R. Keiter, SNL, Computational Sciences
3550 // Creation Date : 10/22/02
3551 //-----------------------------------------------------------------------------
3553 {
3554  if (DEBUG_DEVICE)
3555  dout() << "DeviceMgr::enablePDEContinuation" << std::endl;
3556 
3557  bool bsuccess = true;
3561 
3562  InstanceVector::iterator iter;
3563  InstanceVector::iterator begin =instancePtrVec_.begin();
3564  InstanceVector::iterator end =instancePtrVec_.end();
3565 
3566  for (iter=begin; iter!=end;++iter)
3567  {
3568  bool tmpSuccess = (*iter)->enablePDEContinuation();
3569  bsuccess = bsuccess && tmpSuccess;
3570  }
3571 
3572  // if any of the devices feels that it needs more than the specified
3573  // number of continuation steps, re-do, with the new step number.
3575  {
3576  for (iter=begin; iter!=end;++iter)
3577  {
3578  bool tmpSuccess = (*iter)->enablePDEContinuation();
3579  bsuccess = bsuccess && tmpSuccess;
3580  }
3581  }
3582 
3583  int returnedSteps;
3584 
3585  if (!bsuccess) returnedSteps = -1;
3586  else returnedSteps = solState_.maxPDEContinuationSteps;
3587 
3588  return returnedSteps;
3589 }
3590 
3591 //-----------------------------------------------------------------------------
3592 // Function : DeviceMgr::disablePDEContinuation
3593 // Purpose :
3594 // Special Notes :
3595 // Scope : public
3596 // Creator : Eric R. Keiter, SNL, Computational Sciences
3597 // Creation Date : 10/22/02
3598 //-----------------------------------------------------------------------------
3600 {
3601  bool bsuccess = true;
3603 
3604  InstanceVector::iterator iter;
3605  InstanceVector::iterator begin =instancePtrVec_.begin();
3606  InstanceVector::iterator end =instancePtrVec_.end();
3607  for (iter=begin; iter!=end;++iter)
3608  {
3609  bool tmpSuccess = (*iter)->disablePDEContinuation();
3610  bsuccess = bsuccess && tmpSuccess;
3611  }
3612 
3613  return bsuccess;
3614 }
3615 
3616 //-----------------------------------------------------------------------------
3617 // Function : DeviceMgr::calcPDESubProblemInfo
3618 //
3619 // Purpose : Determines the number of PDE sub-problems.,
3620 //
3621 // This is mainly used/needed for 2-level problems.
3622 //
3623 // Also determines the number of interface nodes per
3624 // sub-problem (ie number of electrodes on each device).
3625 //
3626 // Special Notes : Need to modify to work correctly in parallel, probably.
3627 //
3628 // Scope : public
3629 // Creator : Eric R. Keiter, SNL, Computational Sciences
3630 // Creation Date : 12/03/02
3631 //-----------------------------------------------------------------------------
3633 {
3634  // now set up numInterfaceNodes_;
3635  numInterfaceNodes_.reserve(pdeInstancePtrVec_.size());
3636 
3637  for (InstanceVector::const_iterator it = pdeInstancePtrVec_.begin(), end = pdeInstancePtrVec_.end(); it != end; ++it)
3638  {
3639  numInterfaceNodes_.push_back((*it)->getNumExtVars());
3640  }
3641 
3642  calledBeforeCSPI = true;
3643 
3644  return true;
3645 }
3646 
3647 //-----------------------------------------------------------------------------
3648 // Function : DeviceMgr::getNumInterfaceNodes
3649 // Purpose : returns the vector calculaed in calcPDESubProblemInfo.
3650 // Special Notes :
3651 // Scope : public
3652 // Creator : Eric R. Keiter, SNL, Computational Sciences
3653 // Creation Date : 12/03/02
3654 //-----------------------------------------------------------------------------
3655 void DeviceMgr::getNumInterfaceNodes (std::vector<int> & numINodes)
3656 {
3657  if (!calledBeforeCSPI)
3658  {
3660  }
3661 
3662  int size = numINodes.size ();
3663  int size2 = numInterfaceNodes_.size();
3664 
3665  if (size < size2) numINodes.resize(size2);
3666 
3667  for (int i=0;i<size2;++i)
3668  {
3669  numINodes[i] = numInterfaceNodes_[i];
3670  }
3671 }
3672 
3673 //-----------------------------------------------------------------------------
3674 // Function : DeviceMgr::loadCouplingRHS
3675 // Purpose :
3676 // Special Notes :
3677 // Scope : public
3678 // Creator : Eric R. Keiter, SNL, Computational Sciences
3679 // Creation Date : 12/03/02
3680 //-----------------------------------------------------------------------------
3681 bool DeviceMgr::loadCouplingRHS (int iPDEDevice, int iElectrode, N_LAS_Vector * dfdvPtr)
3682 {
3683  return pdeInstancePtrVec_[iPDEDevice]->loadDFDV(iElectrode,dfdvPtr);
3684 }
3685 
3686 //-----------------------------------------------------------------------------
3687 // Function : DeviceMgr::calcCouplingTerms
3688 // Purpose :
3689 // Special Notes :
3690 // Scope : public
3691 // Creator : Eric R. Keiter, SNL, Computational Sciences
3692 // Creation Date : 12/03/02
3693 //-----------------------------------------------------------------------------
3694 bool DeviceMgr::calcCouplingTerms (int iPDEDevice, int iElectrode, const N_LAS_Vector * dxdvPtr)
3695 {
3696  return pdeInstancePtrVec_[iPDEDevice]->calcConductance(iElectrode, dxdvPtr);
3697 }
3698 
3699 //-----------------------------------------------------------------------------
3700 // Function : DeviceMgr::raiseDebugLevel
3701 // Purpose :
3702 // Special Notes :
3703 // Scope : public
3704 // Creator : Eric R. Keiter, SNL, Computational Sciences
3705 // Creation Date : 04/23/03
3706 //-----------------------------------------------------------------------------
3707 bool DeviceMgr::raiseDebugLevel(int increment)
3708 {
3709  if (DEBUG_DEVICE)
3710  devOptions_.debugLevel += increment;
3711 
3712  return true;
3713 }
3714 
3715 //-----------------------------------------------------------------------------
3716 // Function : DeviceMgr::getHomotopyBlockSize
3717 // Purpose : Returns the number of mosfet gainscale blocks (a value
3718 // in the device options).
3719 // Special Notes : Needed for block homotopy on gainscale.
3720 // Scope : public
3721 // Creator : Roger P. Pawlowski, SNL, Computational Sciences
3722 // Creation Date : 01/26/2005
3723 //-----------------------------------------------------------------------------
3725 {
3727 }
3728 
3729 //-----------------------------------------------------------------------------
3730 // Function : DeviceMgr::updateTemperature
3731 // Purpose :
3732 // Special Notes :
3733 // Scope : public
3734 // Creator : Eric R. Keiter, SNL, Computational Sciences
3735 // Creation Date : 10/26/04
3736 //-----------------------------------------------------------------------------
3738 {
3739  bool bsuccess = true, success = true;
3740 
3741  // convert to kelvin:
3742  double Ctemp = val;
3743  double Ktemp = val + CONSTCtoK;
3744 
3745  if (DEBUG_DEVICE && devOptions_.debugLevel > 0 && solState_.debugTimeFlag)
3746  dout() << "In DeviceMgr::updateTemperature. new C temp = " << Ctemp << " K temp = " << Ktemp << std::endl;
3747 
3748  // First set the global temp. This is used in each device if the "tempGiven"
3749  // variable is false. This should be in Kelvin.
3750  devOptions_.temp.setVal(Ktemp);
3751 
3752  {
3753  // loop over the bsim3 models and delete the size dep params.
3754  ModelTypeModelVectorMap::const_iterator model_type_it = modelTypeModelVector_.find(MOSFET_B3::Traits::modelType());
3755  if (model_type_it != modelTypeModelVector_.end())
3756  {
3757  for (ModelVector::const_iterator it = (*model_type_it).second.begin(); it != (*model_type_it).second.end(); ++it)
3758  {
3759  (*it)->clearTemperatureData ();
3760  }
3761  }
3762  }
3763 
3764  {
3765  // loop over the bsim4 models and delete the size dep params.
3766  ModelTypeModelVectorMap::const_iterator model_type_it = modelTypeModelVector_.find(MOSFET_B4::Traits::modelType());
3767  if (model_type_it != modelTypeModelVector_.end())
3768  {
3769  for (ModelVector::const_iterator it = (*model_type_it).second.begin(); it != (*model_type_it).second.end(); ++it)
3770  {
3771  (*it)->clearTemperatureData ();
3772  }
3773  }
3774  }
3775 
3776  {
3777  // loop over the b3soi models and delete the size dep params.
3778  ModelTypeModelVectorMap::const_iterator model_type_it = modelTypeModelVector_.find(MOSFET_B3SOI::Traits::modelType());
3779  if (model_type_it != modelTypeModelVector_.end())
3780  {
3781  for (ModelVector::const_iterator it = (*model_type_it).second.begin(); it != (*model_type_it).second.end(); ++it)
3782  {
3783  (*it)->clearTemperatureData ();
3784  }
3785  }
3786  }
3787 
3788  // Loop over all models, call processParams, with CTemp.
3789  // "XYCEADMS*TEMP is there to force Verilog devices, which might have
3790  // temperature dependence through "$temperature" instead of a "TEMP"
3791  // parameter, to work properly. If so, they need the temperature set in
3792  // Kelvin.
3793  std::string tname("TEMP");
3794  std::string tname2("XYCEADMSMODTEMP");
3795  std::string tname3("XYCEADMSINSTTEMP");
3796  for (ModelVector::const_iterator it = modelVector_.begin(); it != modelVector_.end(); ++it)
3797  {
3798  success = (*it)->setParam (tname, Ctemp);
3799  success = (*it)->setParam (tname2, Ktemp) || success;
3800  success = success && (*it)->processParams ();
3801  }
3802 
3803  // Loop over device instances, and set the temperature. This should be
3804  // in C, if going through processParams, and K if going through
3805  // the updateTemperature function.
3806  InstanceVector::const_iterator iter;
3807  InstanceVector::const_iterator begin;
3808  InstanceVector::const_iterator end;
3809 
3810  begin = instancePtrVec_.begin();
3811  end = instancePtrVec_.end();
3812  for (iter=begin; iter!=end;++iter)
3813  {
3814  success = (*iter)->setParam (tname, Ctemp);
3815  success = (*iter)->setParam (tname3, Ktemp) || success;
3816  success = success && (*iter)->processParams ();
3817  }
3818 
3819  return bsuccess;
3820 }
3821 
3822 //-----------------------------------------------------------------------------
3823 // Function : DeviceMgr::allDevsConverged
3824 // Purpose : Check whether any device has taken an action that renders
3825 // normal convergence checks invalid (i.e. that the current
3826 // step must be assumed unconverged).
3827 // Special Notes :
3828 // Scope : public
3829 // Creator : Tom Russo, SNL, Component Information and Models
3830 // Creation Date : 03/22/05
3831 //-----------------------------------------------------------------------------
3833 {
3834  int allDevsConv = true;
3835 
3836  // if two-level, and just the inner problem, only check the PDE devices,
3837  // coz those are all we loaded.
3838  InstanceVector::iterator iter;
3839  InstanceVector::iterator begin;
3840  InstanceVector::iterator end;
3842  {
3843  begin = pdeInstancePtrVec_.begin ();
3844  end = pdeInstancePtrVec_.end ();
3845  }
3846  else
3847  {
3848  begin = instancePtrVec_.begin ();
3849  end = instancePtrVec_.end ();
3850  }
3851 
3852  for (iter=begin; iter!=end;++iter)
3853  {
3854  bool tmpBool = (*iter)->isConverged();
3855  allDevsConv = allDevsConv && tmpBool;
3856  }
3857 
3858  Parallel::AllReduce(pdsMgrPtr_->getPDSComm()->comm(), MPI_LAND, &allDevsConv, 1);
3859 
3860  if (DEBUG_DEVICE && devOptions_.debugLevel > 0)
3861  {
3862  if (allDevsConv)
3863  {
3864  dout() << "All devices converged!" << std::endl;
3865  }
3866  else
3867  {
3868  dout() << "At least one device NOT converged!" << std::endl;
3869  }
3870  }
3871 
3872  return allDevsConv != 0;
3873 }
3874 
3875 //-----------------------------------------------------------------------------
3876 // Function : DeviceMgr::innerDevsConverged
3877 // Purpose :
3878 // Special Notes :
3879 // Scope : public
3880 // Creator : Eric Keiter, SNL
3881 // Creation Date : 03/22/06
3882 //-----------------------------------------------------------------------------
3884 {
3885  int innerDevsConv = true;
3886 
3887  ModelTypeInstanceVectorMap::const_iterator model_type_it = modelTypeInstanceVector_.find(ExternDevice::Traits::modelType());
3888  if (model_type_it != modelTypeInstanceVector_.end()) {
3889  for (InstanceVector::const_iterator it = (*model_type_it).second.begin(); it != (*model_type_it).second.end(); ++it)
3890  {
3891  ExternDevice::Instance &extern_device = static_cast<ExternDevice::Instance &>(*(*it));
3892 
3893  bool tmpFlag = extern_device.isInnerSolveConverged();
3894  innerDevsConv = innerDevsConv && tmpFlag;
3895  }
3896  }
3897 
3898  Parallel::AllReduce(pdsMgrPtr_->getPDSComm()->comm(), MPI_LAND, &innerDevsConv, 1);
3899 
3900  return innerDevsConv != 0;
3901 }
3902 
3903 //-----------------------------------------------------------------------------
3904 // Function : DeviceMgr::setupExternalDevices
3905 // Purpose : In parallel, we need to setup all external devices
3906 // and appropriately setup the list of instances
3907 // Special Notes :
3908 // Scope : public
3909 // Creator : Robert Hoekstra, SNL, Elec. & MicroSystems Modeling
3910 // Creation Date : 03/10/06
3911 //-----------------------------------------------------------------------------
3913 {
3914  N_PDS_Comm * pdsCommPtr = pdsMgrPtr_->getPDSComm();
3915 
3916 #ifdef Xyce_PARALLEL_MPI
3917  InstanceVector &extern_device_vector = modelTypeInstanceVector_[ExternDevice::Traits::modelType()];
3918 
3919  int procID = pdsCommPtr->procID();
3920  int numProc = pdsCommPtr->numProc();
3921 
3922  int numExt = extern_device_vector.size();
3923  int numExtTotal = 0;
3924  pdsCommPtr->sumAll(&numExt, &numExtTotal, 1);
3925 
3926  InstanceVector orig_extern_device_vector = extern_device_vector;
3927 
3928  //resetup the instance vector to have a size totally the global
3929  //number of ext devices
3930  if (numExtTotal > 0)
3931  {
3932  extern_device_vector.resize(numExtTotal);
3933 
3934  int loc = 0;
3935  for (int proc = 0; proc < numProc; ++proc)
3936  {
3937  int cnt = 0;
3938  if (proc == procID) cnt = numExt;
3939  pdsCommPtr->bcast(&cnt, 1, proc);
3940 
3941  for(int i = 0; i < cnt; ++i)
3942  {
3943  if (proc == procID)
3944  {
3945  ExternDevice::Instance &extern_device = static_cast<ExternDevice::Instance &>(*extern_device_vector[loc]);
3946  int size = extern_device.getInstanceBlock().packedByteCount();
3947  int bufSize = size+100;
3948  char *buf=new char[bufSize];
3949  pdsCommPtr->bcast(&size, 1, proc);
3950  int pos = 0;
3951  extern_device.getInstanceBlock().pack(buf, bufSize, pos, pdsCommPtr);
3952  pdsCommPtr->bcast(buf, size, proc);
3953  extern_device_vector[loc] = orig_extern_device_vector[i];
3954  delete [] buf;
3955  }
3956  else
3957  {
3958  int size = 0;
3959  pdsCommPtr->bcast(&size, 1, proc);
3960  int bufSize = size+100;
3961  char *buf=new char[bufSize];
3962  pdsCommPtr->bcast(buf, size, proc);
3963  int pos = 0;
3964  InstanceBlock instance_block;
3965  instance_block.unpack(buf, bufSize, pos, pdsCommPtr);
3966  extern_device_vector[loc] = addExtDeviceInstance_(instance_block);
3967  delete [] buf;
3968  }
3969  static_cast<ExternDevice::Instance *>(extern_device_vector[loc])->setOwningProc(proc);
3970  static_cast<ExternDevice::Instance *>(extern_device_vector[loc])->setComm(pdsCommPtr);
3971  ++loc;
3972  }
3973  }
3974 
3975  assert(loc == numExtTotal);
3976  }
3977 
3978 #else // not Xyce_PARALLEL_MPI
3979  ModelTypeInstanceVectorMap::const_iterator model_type_it = modelTypeInstanceVector_.find(ExternDevice::Traits::modelType());
3980  if (model_type_it != modelTypeInstanceVector_.end()) {
3981  for (InstanceVector::const_iterator it = (*model_type_it).second.begin(); it != (*model_type_it).second.end(); ++it)
3982  {
3983  ExternDevice::Instance &extern_device = static_cast<ExternDevice::Instance &>(*(*it));
3984 
3985  extern_device.setComm(pdsCommPtr);
3986  }
3987  }
3988 #endif // Xyce_PARALLEL_MPI
3989 
3990  return true;
3991 }
3992 
3993 //-----------------------------------------------------------------------------
3994 // Function : DeviceMgr::updateExternalDevices_
3995 // Purpose : Do the actual solve of the external devices
3996 // Special Notes :
3997 // Scope : public
3998 // Creator : Robert Hoekstra, SNL, Elec. & MicroSystems Modeling
3999 // Creation Date : 03/10/06
4000 //-----------------------------------------------------------------------------
4002 {
4003  ModelTypeInstanceVectorMap::const_iterator model_type_it = modelTypeInstanceVector_.find(ExternDevice::Traits::modelType());
4004  if (model_type_it != modelTypeInstanceVector_.end()) {
4005  for (InstanceVector::const_iterator it = (*model_type_it).second.begin(); it != (*model_type_it).second.end(); ++it)
4006  {
4007  ExternDevice::Instance &extern_device = static_cast<ExternDevice::Instance &>(*(*it));
4008 
4009  extern_device.runExternalDevice();
4010  }
4011  }
4012 }
4013 
4014 //-----------------------------------------------------------------------------
4015 // Function : DeviceMgr::addExtDeviceInstance_
4016 // Purpose : adds an external device instance on the processors
4017 // : that don't actually own it.
4018 // Special Notes :
4019 // Scope : public
4020 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
4021 // Creation Date : 3/16/06
4022 //-----------------------------------------------------------------------------
4023 ExternDevice::Instance *
4025 {
4026  ExternDevice::Instance *external_instance = 0;
4027 
4028  ModelTypeId model_type;
4029 
4030  if (instance_block.getModelName().empty())
4031  {
4032  model_type = getModelGroup(instance_block.getInstanceName().getDeviceType());
4033  }
4034  else
4035  {
4036  model_type = modelTypeMap_[instance_block.getModelName()];
4037  }
4038 
4039  if (!model_type.defined())
4040  {
4041  Report::UserError message;
4042  message << "Unable to determine type of device for instance name " << instance_block.getInstanceName();
4043  if (!instance_block.getModelName().empty())
4044  {
4045  message << " with model name " << instance_block.getModelName();
4046  }
4047  }
4048 
4049  // Add an instance of this type.
4050  Device &device = getDeviceByModelType(model_type);
4051  DeviceInstance *instance = device.addInstance(instance_block, FactoryBlock(devOptions_, solState_, matrixLoadData_, externData_, commandLine_));
4052 
4053  external_instance = static_cast<ExternDevice::Instance *>(instance);
4054 
4055  return external_instance;
4056 }
4057 
4058 //-----------------------------------------------------------------------------
4059 // Function : DeviceMgr::homotopyStepSuccess
4060 // Purpose :
4061 // Special Notes : Needed for 2-level
4062 // Scope : public
4063 // Creator : Eric R. Keiter, SNL
4064 // Creation Date : 03/20/06
4065 //-----------------------------------------------------------------------------
4067  (const std::vector<std::string> & paramNames,
4068  const std::vector<double> & paramVals)
4069 {
4070  ModelTypeInstanceVectorMap::const_iterator model_type_it = modelTypeInstanceVector_.find(ExternDevice::Traits::modelType());
4071  if (model_type_it != modelTypeInstanceVector_.end()) {
4072  for (InstanceVector::const_iterator it = (*model_type_it).second.begin(); it != (*model_type_it).second.end(); ++it)
4073  {
4074  ExternDevice::Instance &extern_device = static_cast<ExternDevice::Instance &>(*(*it));
4075 
4076  extern_device.homotopyStepSuccess (paramNames, paramVals);
4077  }
4078  }
4079 }
4080 
4081 //-----------------------------------------------------------------------------
4082 // Function : DeviceMgr::homotopyStepFailure
4083 // Purpose :
4084 // Special Notes : Needed for 2-level
4085 // Scope : public
4086 // Creator : Eric R. Keiter, SNL
4087 // Creation Date : 03/30/06
4088 //-----------------------------------------------------------------------------
4090 {
4091  ModelTypeInstanceVectorMap::const_iterator model_type_it = modelTypeInstanceVector_.find(ExternDevice::Traits::modelType());
4092  if (model_type_it != modelTypeInstanceVector_.end()) {
4093  for (InstanceVector::const_iterator it = (*model_type_it).second.begin(); it != (*model_type_it).second.end(); ++it)
4094  {
4095  ExternDevice::Instance &extern_device = static_cast<ExternDevice::Instance &>(*(*it));
4096 
4097  extern_device.homotopyStepFailure ();
4098  }
4099  }
4100 }
4101 
4102 //-----------------------------------------------------------------------------
4103 // Function : DeviceMgr::stepSuccess
4104 // Purpose :
4105 // Special Notes :
4106 // Scope : public
4107 // Creator : Eric R. Keiter, SNL
4108 // Creation Date : 03/12/06
4109 //-----------------------------------------------------------------------------
4111 {
4112  ModelTypeInstanceVectorMap::const_iterator model_type_it = modelTypeInstanceVector_.find(ExternDevice::Traits::modelType());
4113  if (model_type_it != modelTypeInstanceVector_.end()) {
4114  for (InstanceVector::const_iterator it = (*model_type_it).second.begin(); it != (*model_type_it).second.end(); ++it)
4115  {
4116  ExternDevice::Instance &extern_device = static_cast<ExternDevice::Instance &>(*(*it));
4117 
4118  extern_device.stepSuccess(analysis);
4119  }
4120  }
4121 }
4122 
4123 //-----------------------------------------------------------------------------
4124 // Function : DeviceMgr::stepFailure
4125 // Purpose :
4126 // Special Notes :
4127 // Scope : public
4128 // Creator : Eric R. Keiter, SNL
4129 // Creation Date : 03/12/06
4130 //-----------------------------------------------------------------------------
4132 {
4133  ModelTypeInstanceVectorMap::const_iterator model_type_it = modelTypeInstanceVector_.find(ExternDevice::Traits::modelType());
4134  if (model_type_it != modelTypeInstanceVector_.end()) {
4135  for (InstanceVector::const_iterator it = (*model_type_it).second.begin(); it != (*model_type_it).second.end(); ++it)
4136  {
4137  ExternDevice::Instance &extern_device = static_cast<ExternDevice::Instance &>(*(*it));
4138 
4139  extern_device.stepFailure(analysis);
4140  }
4141  }
4142 }
4143 
4144 //-----------------------------------------------------------------------------
4145 // Function : DeviceMgr::acceptStep
4146 // Purpose : Communicate to devices that the current step is accepted
4147 // Special Notes :
4148 // Scope : public
4149 // Creator : Tom Russo, SNL
4150 // Creation Date : 01/23/07
4151 //-----------------------------------------------------------------------------
4153 {
4154  // The time history for the LTRA device(s) has to be tracked
4155  // separately because it can be truncated if the user specifies that
4156  // option. This has to be called before
4157  // LTRAInstance::acceptStep(). Note that the DCOP is stored at
4158  // index zero and the first time step is stored at index 1 for the
4159  // time history vectors associated with the LTRA
4160  if (solState_.dcopFlag)
4161  {
4165  }
4166  else
4167  {
4170  {
4173  }
4175  }
4176 
4177  // make sure we have the right solver state. Putting this here
4178  // makes it essential that acceptStep be called BEFORE any changes have
4179  // been made to the solution or state vectors (e.g. rotating them) and
4180  // while "nextTime" in the solver still references the time for which the
4181  // solution vector is valid.
4182 
4183  bool tmpBool = setupSolverInfo_();
4185 
4186  for (InstanceVector::iterator iter = instancePtrVec_.begin(); iter != instancePtrVec_.end(); ++iter)
4187  {
4188  (*iter)->acceptStep();
4189  }
4190 
4191  // If the TRYCOMPACT option is set then the LTRA model will try to
4192  // compact the amount of data stored and speed up the convolutions. If
4193  // any of the LTRA instances request this, done in their acceptStep()
4194  // member function, then perform the time-step compaction here.
4196  {
4199 
4201 
4202  // reset the flag for the next time step
4203  solState_.ltraDoCompact = false;
4204  }
4205 }
4206 
4207 
4208 //-----------------------------------------------------------------------------
4209 // Function : DeviceMgr::getInitialQnorm
4210 // Purpose :
4211 // Special Notes :
4212 // Scope : public
4213 // Creator : Eric R. Keiter, SNL
4214 // Creation Date : 03/12/07
4215 //-----------------------------------------------------------------------------
4216 bool DeviceMgr::getInitialQnorm (std::vector<N_TIA_TwoLevelError> & tleVec)
4217 {
4218  bool bsuccess = true;
4219 
4220  ModelTypeInstanceVectorMap::const_iterator model_type_it = modelTypeInstanceVector_.find(ExternDevice::Traits::modelType());
4221  if (model_type_it != modelTypeInstanceVector_.end()) {
4222  int numExt = (*model_type_it).second.size();
4223 
4224  tleVec.resize(numExt);
4225  int iext = 0;
4226  for (InstanceVector::const_iterator it = (*model_type_it).second.begin(); it != (*model_type_it).second.end(); ++it, ++iext)
4227  {
4228  ExternDevice::Instance &extern_device = static_cast<ExternDevice::Instance &>(*(*it));
4229 
4230  bool bs1 = extern_device.getInitialQnorm(tleVec[iext]);
4231  bsuccess = bsuccess && bs1;
4232  }
4233  }
4234 
4235  return bsuccess;
4236 }
4237 
4238 //-----------------------------------------------------------------------------
4239 // Function : DeviceMgr::getInnerLoopErrorSums
4240 // Purpose :
4241 // Special Notes :
4242 // Scope : public
4243 // Creator : Eric R. Keiter, SNL
4244 // Creation Date : 03/12/06
4245 //-----------------------------------------------------------------------------
4247  std::vector<N_TIA_TwoLevelError> & tleVec)
4248 {
4249  bool bsuccess = true;
4250 
4251  ModelTypeInstanceVectorMap::const_iterator model_type_it = modelTypeInstanceVector_.find(ExternDevice::Traits::modelType());
4252  if (model_type_it != modelTypeInstanceVector_.end()) {
4253  int numExt = (*model_type_it).second.size();
4254 
4255  tleVec.resize(numExt);
4256  int iext = 0;
4257  for (InstanceVector::const_iterator it = (*model_type_it).second.begin(); it != (*model_type_it).second.end(); ++it, ++iext)
4258  {
4259  ExternDevice::Instance &extern_device = static_cast<ExternDevice::Instance &>(*(*it));
4260 
4261  bool bs1 = extern_device.getInnerLoopErrorSum(tleVec[iext]);
4262  bsuccess = bsuccess && bs1;
4263  }
4264  }
4265 
4266  return bsuccess;
4267 }
4268 
4269 //-----------------------------------------------------------------------------
4270 // Function : DeviceMgr::updateStateArrays()
4271 // Purpose :
4272 // Special Notes :
4273 // Scope : public
4274 // Creator : Eric R. Keiter, SNL
4275 // Creation Date : 03/12/06
4276 //-----------------------------------------------------------------------------
4278 {
4279  bool bsuccess = true;
4280 
4281  ModelTypeInstanceVectorMap::const_iterator model_type_it = modelTypeInstanceVector_.find(ExternDevice::Traits::modelType());
4282  if (model_type_it != modelTypeInstanceVector_.end()) {
4283  for (InstanceVector::const_iterator it = (*model_type_it).second.begin(); it != (*model_type_it).second.end(); ++it)
4284  {
4285  ExternDevice::Instance &extern_device = static_cast<ExternDevice::Instance &>(*(*it));
4286 
4287  bool bs1 = extern_device.updateStateArrays();
4288  bsuccess = bsuccess && bs1;
4289  }
4290  }
4291 
4292  return bsuccess;
4293 }
4294 
4295 
4296 //-----------------------------------------------------------------------------
4297 // Function : DeviceMgr::startTimeStep
4298 // Purpose :
4299 // Special Notes :
4300 // Scope : public
4301 // Creator : Eric R. Keiter, SNL
4302 // Creation Date : 03/20/06
4303 //-----------------------------------------------------------------------------
4305 {
4306  bool bsuccess = true;
4307  bool tmpBool = setupSolverInfo_();
4308 
4309  ModelTypeInstanceVectorMap::const_iterator model_type_it = modelTypeInstanceVector_.find(ExternDevice::Traits::modelType());
4310  if (model_type_it != modelTypeInstanceVector_.end()) {
4311  for (InstanceVector::const_iterator it = (*model_type_it).second.begin(); it != (*model_type_it).second.end(); ++it)
4312  {
4313  ExternDevice::Instance &extern_device = static_cast<ExternDevice::Instance &>(*(*it));
4314 
4315  bool bs1 = extern_device.startTimeStep ();
4316  bsuccess = bsuccess && bs1;
4317  }
4318  }
4319 
4320  return bsuccess;
4321 }
4322 
4323 
4324 //-----------------------------------------------------------------------------
4325 // Function : DeviceMgr::setExternalSolverState
4326 // Purpose :
4327 // Special Notes :
4328 // Scope : public
4329 // Creator : Eric R. Keiter, SNL
4330 // Creation Date : 03/20/06
4331 //-----------------------------------------------------------------------------
4333 {
4334  externalStateFlag_ = true;
4335  solStateExternal_ = ss;
4336 }
4337 
4338 //-----------------------------------------------------------------------------
4339 // Function : DeviceMgr::restartDataSize
4340 // Purpose :
4341 // Special Notes :
4342 // Scope : public
4343 // Creator : Eric R. Keiter, SNL
4344 // Creation Date : 06/26/2013
4345 //-----------------------------------------------------------------------------
4347 {
4348  int numdoubles = solState_.ltraTimePoints.size();
4349  int numSize_t = 3;
4350  int count = sizeof(double) * (numdoubles);
4351  count += sizeof(size_t) * numSize_t;
4352 
4353  // bump up size for unpacked data. This is an empirical multiplier.
4354  if (!pack)
4355  {
4356  count *= 3;
4357  }
4358 
4359  return count;
4360 }
4361 
4362 //-----------------------------------------------------------------------------
4363 // Function : DeviceMgr::dumpRestartData
4364 // Purpose : Output restart data.
4365 // Special Notes : This function is called by the restart manager to output
4366 // persistent data for the device package. It should NOT
4367 // include any data from individual devices, as that restart
4368 // data is collected elsewhere.
4369 // Scope :
4370 // Creator : Eric R. Keiter, SNL
4371 // Creation Date : 06/26/2013
4372 //-----------------------------------------------------------------------------
4374 (char * buf, int bsize, int & pos, N_PDS_Comm * comm, bool pack)
4375 {
4376  bool retval=true;
4377 
4378  if (pack)
4379  {
4380  size_t size=solState_.ltraTimePoints.size();
4381  comm->pack(&(solState_.ltraTimeIndex), 1, buf, bsize, pos);
4382  comm->pack(&(solState_.ltraTimeHistorySize), 1, buf, bsize, pos);
4383  comm->pack(&(size), 1, buf, bsize, pos);
4384  comm->pack(&(solState_.ltraTimePoints[0]), size, buf, bsize, pos);
4385  }
4386  else
4387  {
4388  int count = restartDataSize(false);
4389  int startIndex = pos;
4390  for(int i = startIndex; i < (startIndex+count); ++i) buf[i] = ' ';
4391 
4392  size_t size=solState_.ltraTimePoints.size();
4393  std::ostringstream ost;
4394  ost.width(24);ost.precision(16);ost.setf(std::ios::scientific);
4395  ost << solState_.ltraTimeIndex << " ";
4396  ost << solState_.ltraTimeHistorySize << " ";
4397 #ifdef Xyce_DEBUG_RESTART
4398  dout() <<
4399  "DeviceMgr::getRestartData: ltraTimeIndex = " << solState_.ltraTimeIndex <<std::endl;
4400  dout() <<
4401  "DeviceMgr::getRestartData: ltraTimeHistorySize = " << solState_.ltraTimeHistorySize <<std::endl;
4402 #endif
4403  ost << size << " ";
4404  for (int i=0;i<size;i++)
4405  {
4406  ost << solState_.ltraTimePoints[i] << " ";
4407 #ifdef Xyce_DEBUG_RESTART
4408  dout() <<
4409  "DeviceMgr::dumpRestartData: ltraTimePoints["<<i<<"] ="
4410  << solState_.ltraTimePoints[i]<<std::endl;
4411 #endif
4412  }
4413 
4414  std::string data(ost.str());
4415  for(unsigned int i = 0; i < data.length(); ++i) buf[startIndex+i] = data[i];
4416 
4417  // The line above copies the characters of the data string into buf,
4418  // but doesn't null-terminate buf.
4419  // it is essential to terminate the buffer with a null, or attempts
4420  // to construct a string object from it will get memory access problems.
4421  buf[startIndex+data.length()] = '\0';
4422  pos += data.length();
4423  }
4424 
4425  return retval;
4426 }
4427 
4428 //-----------------------------------------------------------------------------
4429 // Function : DeviceMgr::restoreRestartData
4430 // Purpose : Load restart data.
4431 // Special Notes :
4432 // Scope :
4433 // Creator : Eric R. Keiter, SNL
4434 // Creation Date : 06/26/2013
4435 //-----------------------------------------------------------------------------
4436 bool DeviceMgr::restoreRestartData(char * buf, int bsize, int & pos, N_PDS_Comm * comm, bool pack)
4437 {
4438  bool retval=true;
4439 
4440  if (pack)
4441  {
4442  comm->unpack(buf, bsize, pos, &(solState_.ltraTimeIndex), 1);
4443  comm->unpack(buf, bsize, pos, &(solState_.ltraTimeHistorySize), 1);
4444  size_t size=0;
4445  comm->unpack(buf, bsize, pos, &(size), 1);
4446  solState_.ltraTimePoints.resize(size);
4447  comm->unpack(buf, bsize, pos, &(solState_.ltraTimePoints[0]), size);
4448  }
4449  else
4450  {
4451  std::string str1(buf);
4452  int length = str1.size() - pos;
4453  std::string str2(str1,pos,length);
4454 
4455  std::istringstream ist(str2);
4456 
4457  ist >> solState_.ltraTimeIndex;
4459 #ifdef Xyce_DEBUG_RESTART
4460  dout() <<
4461  "DeviceMgr::restoreRestartData: ltraTimeIndex = " << solState_.ltraTimeIndex <<std::endl;
4462  dout() <<
4463  "DeviceMgr::restoreRestartData: ltraTimeHistorySize = " << solState_.ltraTimeHistorySize <<std::endl;
4464 #endif
4465  size_t size=0;
4466  ist >> size;
4467  solState_.ltraTimePoints.resize(size);
4468  for (int i=0;i<size;++i)
4469  {
4470  ist >> solState_.ltraTimePoints[i];
4471 #ifdef Xyce_DEBUG_RESTART
4472  dout() << "DeviceMgr::restoreRestartData: ltraTimePoints["<<i<<"] = " << solState_.ltraTimePoints[i] << std::endl;
4473 #endif
4474  }
4475 
4476  pos += ist.tellg();
4477  }
4478 
4479  return retval;
4480 }
4481 
4482 //-----------------------------------------------------------------------------
4483 // Function : DeviceMgr::getDeviceEntity
4484 // Purpose :
4485 // Special Notes :
4486 // Scope : public
4487 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
4488 // Creation Date : 5/02/03
4489 //-----------------------------------------------------------------------------
4490 DeviceEntity * DeviceMgr::getDeviceEntity(const std::string & full_param_name) const
4491 {
4492  std::string entity_name = Xyce::Util::entityNameFromFullParamName(full_param_name).getEncodedName();
4493 
4494  DeviceEntityMap::iterator it = parameterDeviceCache_.find(full_param_name);
4495  if (it == parameterDeviceCache_.end())
4496  {
4497  DeviceEntity *device_entity = findDeviceEntity(deviceMap_.begin(), deviceMap_.end(), entity_name);
4498  parameterDeviceCache_[full_param_name] = device_entity;
4499  return device_entity;
4500  }
4501  else if (!(*it).second)
4502  {
4503  DeviceEntity *device_entity = findDeviceEntity(deviceMap_.begin(), deviceMap_.end(), entity_name);
4504  (*it).second = device_entity;
4505  return device_entity;
4506  }
4507  else
4508  return (*it).second;
4509 }
4510 
4511 //-----------------------------------------------------------------------------
4512 // Function : DeviceMgr::addDevicesToCount
4513 // Purpose :
4514 // Special Notes :
4515 // Scope : public
4516 // Creator : Heidi Thornquist, SNL
4517 // Creation Date : 8/06/14
4518 //-----------------------------------------------------------------------------
4519 void DeviceMgr::addDevicesToCount(const std::map<std::string,int> & device_map)
4520 {
4521  // Add in devices to map for counting.
4522  std::map<std::string,int>::const_iterator dm_begin = device_map.begin();
4523  std::map<std::string,int>::const_iterator dm_end = device_map.end();
4524  std::map<std::string,int>::const_iterator dm_iter = dm_begin;
4525  for ( ; dm_iter != dm_end; ++dm_iter)
4526  {
4527  if ( localDeviceCountMap_[dm_iter->first] )
4528  {
4529  localDeviceCountMap_[dm_iter->first] += dm_iter->second;
4530  }
4531  else
4532  {
4533  localDeviceCountMap_[dm_iter->first] = dm_iter->second;
4534  }
4535  }
4536 }
4537 
4538 } // namespace Device
4539 } // namespace Xyce