Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
N_DEV_SW.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_SW.C,v $
27 //
28 // Purpose :
29 //
30 // Special Notes : "Creator and Creation Date" are actually the dates
31 // this file was created. When it was created it was
32 // just a placeholder.
33 // Actual implementation of the Xyce voltage controlled
34 // switch occurred on 5/22/2001, and was done by Tom Russo,
35 // SNL, Component Information and Models.
36 //
37 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
38 //
39 // Creation Date : 02/28/00
40 //
41 // Revision Information:
42 // ---------------------
43 //
44 // Revision Number: $Revision: 1.161 $
45 //
46 // Revision Date : $Date: 2014/05/22 17:40:30 $
47 //
48 // Current Owner : $Author: erkeite $
49 //----------------------------------------------------------------------------
50 
51 #include <Xyce_config.h>
52 
53 
54 // ---------- Standard Includes ----------
55 
56 #ifdef HAVE_CMATH
57 #include <cmath>
58 #else
59 #include <math.h>
60 #endif
61 
62 // ---------- Xyce Includes ----------
63 #include <N_DEV_DeviceOptions.h>
64 #include <N_DEV_ExternData.h>
65 #include <N_DEV_MatrixLoadData.h>
66 #include <N_DEV_SW.h>
67 #include <N_DEV_SolverState.h>
68 #include <N_DEV_Message.h>
69 #include <N_ERH_ErrorMgr.h>
70 
71 #include <N_LAS_Matrix.h>
72 #include <N_LAS_Vector.h>
73 
74 #include <N_UTL_Expression.h>
75 
76 namespace Xyce {
77 namespace Device {
78 
79 
80 namespace SW {
81 
82 
84 {
85 // Set up double precision variables:
86  p.addPar ("CONTROL", 0.0, false, ParameterType::SOLN_DEP,
88  NULL, U_NONE,CAT_NONE,"");
89 
90  // Set up non-double precision variables:
91  p.addPar ("ON", false, &SW::Instance::ON);
92  p.addPar ("OFF", false, &SW::Instance::OFF);
93 }
94 
96 {
97  p.addPar ("RON", 1.0, false, ParameterType::NO_DEP,
99  NULL,U_OHM,CAT_NONE,"On resistance");
100 
101  p.addPar ("ROFF", 1.0e6, false, ParameterType::NO_DEP,
103  NULL,U_OHM,CAT_NONE,"Off resistance");
104 
105  p.addPar ("VON", 1.0, false, ParameterType::NO_DEP,
107  NULL,U_VOLT,CAT_NONE,"On voltage");
108 
109  p.addPar ("VOFF", 0.0, false, ParameterType::NO_DEP,
111  NULL,U_VOLT,CAT_NONE,"Off voltage");
112 
113  p.addPar ("ION", 0.001, false, ParameterType::NO_DEP,
115  NULL,U_AMP,CAT_NONE,"On current");
116 
117  p.addPar ("IOFF", 0.0, false, ParameterType::NO_DEP,
119  NULL,U_AMP,CAT_NONE,"Off current");
120 
121  p.addPar ("ON", 1.0, false, ParameterType::NO_DEP,
122  &SW::Model::ON,
123  NULL,U_NONE,CAT_NONE,"On control value");
124 
125  p.addPar ("OFF", 0.0, false, ParameterType::NO_DEP,
127  NULL,U_NONE,CAT_NONE,"Off control value");
128 }
129 
130 
131 // Class Instance
132 //-----------------------------------------------------------------------------
133 // Function : Instance::processParams
134 // Purpose :
135 // Special Notes :
136 // Scope : public
137 // Creator : Dave Shirley, PSSI
138 // Creation Date : 03/16/05
139 //-----------------------------------------------------------------------------
140 
142 {
143  return true;
144 }
145 
146 //-----------------------------------------------------------------------------
147 // Function : Instance::Instance
148 // Purpose : constructor
149 // Special Notes :
150 // Scope : public
151 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
152 // Creation Date : 3/16/00
153 //-----------------------------------------------------------------------------
155  const Configuration & configuration,
156  const InstanceBlock & IB,
157  Model & SWiter,
158  const FactoryBlock & factory_block)
159  : DeviceInstance(IB, configuration.getInstanceParameters(), factory_block),
160  model_(SWiter),
161  R(0.0),
162  ON(false),
163  G(0.0),
164  SW_STATE(0.0),
165  switch_state(0.0),
166  li_switch_state(-1),
167  li_Pos(-1),
168  li_Neg(-1),
169  li_store_dev_i(-1),
170  APosEquPosNodeOffset(-1),
171  APosEquNegNodeOffset(-1),
172  ANegEquPosNodeOffset(-1),
173  ANegEquNegNodeOffset(-1),
174  fPosEquPosNodePtr(0),
175  fPosEquNegNodePtr(0),
176  fNegEquPosNodePtr(0),
177  fNegEquNegNodePtr(0),
178  Exp_ptr(0)
179 {
180  numIntVars = 0;
181  numExtVars = 2;
182  numStateVars = 1;
183  numLeadCurrentStoreVars = 1; // for device lead current if needed.
184 
185  jacStamp.resize(2);
186  jacStamp[0].resize(2);
187  jacStamp[0][0]=0;
188  jacStamp[0][1]=1;
189  jacStamp[1].resize(2);
190  jacStamp[1][0]=0;
191  jacStamp[1][1]=1;
192 
193  // Set params to constant default values:
194  setDefaultParams ();
195 
196  // Set params according to instance line and constant defaults from metadata:
197  setParams (IB.params);
198 
199  // Set any non-constant parameter defaults:
200  if (given("OFF"))
201  {
202  if (given("ON"))
203  {
204  UserError0(*this) << "Cannot specify both 'on' and off' for switch";
205  }
206  ON = !OFF;
207  }
208  if (!given("CONTROL"))
209  {
210  UserError0(*this) << "Must specify 'control' for switch";
211  }
212 
213  std::vector<Depend>::const_iterator d;
214  std::vector<Depend>::const_iterator begin = getDependentParams().begin();
215  std::vector<Depend>::const_iterator end = getDependentParams().end();
216 
217  for (d = begin ; d != end ; ++d)
218  {
219  if (d->name == "CONTROL")
220  {
221  expNumVars = d->n_vars;
222  expBaseVar = d->lo_var;
223  Exp_ptr = d->expr;
224 
225  expNumDdt = Exp_ptr->getNumDdt();
226  ddtVals.resize(expNumDdt);
227  li_ddt.resize(expNumDdt);
229 
230  jacStamp[0].resize(2+expNumVars);
231  jacStamp[1].resize(2+expNumVars);
232  for( int i = 0; i < expNumVars; ++i )
233  {
234  jacStamp[0][2+i] = 2+i;
235  jacStamp[1][2+i] = 2+i;
236  }
237  expVarDerivs.resize(expNumVars);
238  myVarVals.resize(expNumVars);
239  }
240  }
241 
242  // Calculate any parameters specified as expressions:
244 
245  // calculate dependent (ie computed) params and check for errors:
246  processParams ();
247 }
248 
249 //-----------------------------------------------------------------------------
250 // Function : Instance::~Instance
251 // Purpose : destructor
252 // Special Notes :
253 // Scope : public
254 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
255 // Creation Date : 3/16/00
256 //-----------------------------------------------------------------------------
258 {
259 }
260 
261 //-----------------------------------------------------------------------------
262 // Function : Instance::registerLIDs
263 // Purpose :
264 // Special Notes :
265 // Scope : public
266 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
267 // Creation Date : 6/20/02
268 //-----------------------------------------------------------------------------
269 void Instance::registerLIDs( const std::vector<int> & intLIDVecRef,
270  const std::vector<int> & extLIDVecRef)
271 {
272  AssertLIDs(intLIDVecRef.size() == numIntVars);
273  AssertLIDs(extLIDVecRef.size() == numExtVars);
274 
275  // copy over the global ID lists.
276  intLIDVec = intLIDVecRef;
277  extLIDVec = extLIDVecRef;
278 
279  // now use these lists to obtain the indices into the
280  // linear algebra entities. This assumes an order.
281  // For the matrix indices, first do the rows.
282 
283  li_Pos = extLIDVec[0];
284  li_Neg = extLIDVec[1];
285 
286 }
287 
288 //-----------------------------------------------------------------------------
289 // Function : Instance::registerStateLIDs
290 // Purpose : Note that the SW does not have any state vars.
291 // Special Notes :
292 // Scope : public
293 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
294 // Creation Date : 06/20/02
295 //-----------------------------------------------------------------------------
296 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef )
297 {
298  AssertLIDs(staLIDVecRef.size() == numStateVars);
299 
300  // copy over the global ID lists:
301  staLIDVec = staLIDVecRef;
302  li_switch_state = staLIDVec[0];
303  for (int i=0 ; i<expNumDdt ; ++i)
304  {
305  li_ddt[i] = staLIDVecRef[i+1];
306  }
307 }
308 
309 
310 //-----------------------------------------------------------------------------
311 // Function : N_DEV_SWInstance::registerStoreLIDs
312 // Purpose : One store var for device current.
313 // Special Notes :
314 // Scope : public
315 // Creator : Richard Schiek, Electrical Systems Modeling
316 // Creation Date : 04/05/2013
317 //-----------------------------------------------------------------------------
318 void N_DEV_SWInstance::registerStoreLIDs(const std::vector<int> & stoLIDVecRef )
319 {
320  AssertLIDs(stoLIDVecRef.size() == getNumStoreVars());
321 
322  if( loadLeadCurrent )
323  {
324  li_store_dev_i = stoLIDVecRef[0];
325  }
326 }
327 
328 //-----------------------------------------------------------------------------
329 // Function : N_DEV_SWInstance::getStoreNameMap
330 // Purpose :
331 // Special Notes :
332 // Scope : public
333 // Creator : Richard Schiek, Electrical Systems Modeling
334 // Creation Date : 04/05/2013
335 //-----------------------------------------------------------------------------
336 std::map<int,std::string> & N_DEV_SWInstance::getStoreNameMap ()
337 {
338  // set up the internal name map, if it hasn't been already.
339  if( loadLeadCurrent && storeNameMap.empty ())
340  {
341  storeNameMap[ li_store_dev_i ] = spiceStoreName(getName(), "DEV_I");
342  }
343 
344  return storeNameMap;
345 }
346 
347 
348 //-----------------------------------------------------------------------------
349 // Function : Instance::getDepSolnVars
350 // Purpose :
351 // Special Notes :
352 // Scope : public
353 // Creator : Rob Hoekstra, SNL, Parallel Computational Sciences
354 // Creation Date : 06/06/01
355 //-----------------------------------------------------------------------------
356 const std::vector<std::string> & Instance::getDepSolnVars()
357 {
359 }
360 
361 
362 //-----------------------------------------------------------------------------
363 // Function : Instance::jacobianStamp
364 // Purpose :
365 // Special Notes :
366 // Scope : public
367 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
368 // Creation Date : 09/2/02
369 //-----------------------------------------------------------------------------
370 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
371 {
372  return jacStamp;
373 }
374 
375 //-----------------------------------------------------------------------------
376 // Function : Instance::registerJacLIDs
377 // Purpose :
378 // Special Notes :
379 // Scope : public
380 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
381 // Creation Date : 09/2/02
382 //-----------------------------------------------------------------------------
383 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
384 {
385  DeviceInstance::registerJacLIDs( jacLIDVec );
386 
387  APosEquPosNodeOffset = jacLIDVec[0][0];
388  APosEquNegNodeOffset = jacLIDVec[0][1];
389  ANegEquPosNodeOffset = jacLIDVec[1][0];
390  ANegEquNegNodeOffset = jacLIDVec[1][1];
391 
394  for( int i = 0; i < expNumVars; ++i )
395  {
396  APosEquControlNodeOffset[i] = jacLIDVec[0][2+i];
397  ANegEquControlNodeOffset[i] = jacLIDVec[1][2+i];
398  }
399 }
400 
401 //-----------------------------------------------------------------------------
402 // Function : Instance::setupPointers
403 // Purpose :
404 // Special Notes :
405 // Scope : public
406 // Creator : Eric Keiter, SNL
407 // Creation Date : 11/30/08
408 //-----------------------------------------------------------------------------
410 {
411 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
412  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
413  N_LAS_Matrix & dQdx = *(extData.dQdxMatrixPtr);
414 
419 
422  for( int i = 0; i < expNumVars; ++i )
423  {
426  }
427 #endif
428 }
429 
430 //-----------------------------------------------------------------------------
431 // Function : Instance::updatePrimaryState
432 // Purpose :
433 // Special Notes :
434 // Scope : public
435 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
436 // Creation Date : 01/29/01
437 //-----------------------------------------------------------------------------
439 {
440  double * staVec = extData.nextStaVectorRawPtr;
441  bool bsuccess = updateIntermediateVars ();
442 
443  // obtain the current value of the switch state
445 
446  staVec[li_switch_state] = switch_state;
447 
448  return bsuccess;
449 }
450 
451 //-----------------------------------------------------------------------------
452 // Function : Instance::updateSecondaryState
453 // Purpose :
454 // Special Notes :
455 // Scope : public
456 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
457 // Creation Date : 01/29/01
458 //-----------------------------------------------------------------------------
460 {
461  double current_state;
462  double control;
463  int i;
464 
465  double * solVec = extData.nextSolVectorRawPtr;
466 
467  // Get time derivatives from time integrator, and evaluate expression to get
468  // derivatives with respect to independent quantities
469 
470  if (expNumDdt > 0)
471  {
472  double * staDerivVec = extData.nextStaDerivVectorRawPtr;
473 
474  for (i=0 ; i<expNumDdt ; ++i)
475  {
476  ddtVals[i] = staDerivVec[li_ddt[i]];
477  }
478  Exp_ptr->setDdtDerivs(ddtVals);
479  }
480  // Evaluate Expression with corrected time derivative values
481 
482  Exp_ptr->evaluate( expVal, expVarDerivs );
483  control = expVal;
484 
485  // This is not really correct, an interim hack. This is supposed
486  // to be where we deal with the specification of ON or OFF from the
487  // netlist.
488  if (getSolverState().initJctFlag)
489  {
490  if (ON)
491  current_state = 1;
492  else
493  current_state = 0;
494  }
495  else
496  {
497  current_state = (control-model_.OFF)*model_.dInv;
498  }
499 
500  v_pos = solVec[li_Pos];
501  v_neg = solVec[li_Neg];
502 
503  if (current_state >= 1.0)
504  {
505  R = model_.RON;
506  G = 1.0/R;
507  for (i=0 ; i<expNumVars ; ++i)
508  expVarDerivs[i] = 0;
509  }
510  else if ( current_state <= 0.0)
511  {
512  R = model_.ROFF;
513  G = 1.0/R;
514  for (i=0 ; i<expNumVars ; ++i)
515  expVarDerivs[i] = 0;
516  }
517  else
518  {
519  current_state = 2*current_state - 1;
520  G = exp(-model_.Lm - 0.75*model_.Lr*current_state +
521  0.25*model_.Lr*current_state*current_state*current_state);
522  R = 1.0/G;
523  for (i=0 ; i<expNumVars ; ++i)
524  {
525  expVarDerivs[i] = G * (1.5 * (current_state*current_state-1) * model_.Lr *
526  model_.dInv * expVarDerivs[i]);
527  }
528  }
529 
530  return true;
531 }
532 
533 //-----------------------------------------------------------------------------
534 // Function : Instance::updateIntermediateVars
535 // Purpose : update intermediate variables for one switch instance
536 // Special Notes :
537 // Scope : public
538 // Creator : Tom Russo, Component Information and Models
539 // Creation Date : 1/10/01
540 //-----------------------------------------------------------------------------
542 {
543  // Get values of the arguments for ddt() calls in expression so that the derivatives
544  // can be determined by the time integration class
545  if (expNumDdt > 0)
546  {
547  double * staVec = extData.nextStaVectorRawPtr;
548 
549  Exp_ptr->getDdtVals (ddtVals);
550  for (int i=0 ; i<expNumDdt ; ++i)
551  {
552  staVec[li_ddt[i]] = ddtVals[i];
553  }
554  }
555 
556  return true;
557 }
558 
559 //-----------------------------------------------------------------------------
560 // Function : Instance::loadDAEFVector
561 //
562 // Purpose : Loads the F-vector contributions for a single
563 // resistor instance.
564 //
565 // Special Notes :
566 //
567 // Scope : public
568 // Creator : Eric R. Keiter, SNL, Electrical and Microsystems Modeling
569 // Creation Date : 11/13/05
570 //-----------------------------------------------------------------------------
572 {
573  double * fVec = extData.daeFVectorRawPtr;
574 
575  // load RHS vector element for the positive circuit node KCL equ.
576  double coef = (v_pos-v_neg)*G;
577 
578  fVec[li_Pos] += coef;
579  fVec[li_Neg] += -coef;
580  if( loadLeadCurrent )
581  {
582  double * stoVec = extData.nextStoVectorRawPtr;
583  stoVec[li_store_dev_i] = coef;
584  }
585 
586  return true;
587 }
588 
589 //-----------------------------------------------------------------------------
590 // Function : Instance::loadDAEdFdx ()
591 //
592 // Purpose : Loads the F-vector contributions for a single
593 // resistor instance.
594 //
595 // Special Notes :
596 //
597 // Scope : public
598 // Creator : Eric R. Keiter, SNL, Electrical and Microsystems Modeling
599 // Creation Date : 11/13/05
600 //-----------------------------------------------------------------------------
602 {
603  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
604 
605  dFdx[li_Pos][APosEquPosNodeOffset] += G;
606  dFdx[li_Pos][APosEquNegNodeOffset] -= G;
607  dFdx[li_Neg][ANegEquPosNodeOffset] -= G;
608  dFdx[li_Neg][ANegEquNegNodeOffset] += G;
609 
610  if( expNumVars )
611  {
612  for( int i = 0; i < expNumVars; ++i )
613  {
616  }
617  }
618 
619  return true;
620 }
621 
622 //-----------------------------------------------------------------------------
623 // Function : Model::Model
624 // Purpose : constructor
625 // Special Notes :
626 // Scope : public
627 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
628 // Creation Date : 5/16/00
629 //-----------------------------------------------------------------------------
631  const Configuration & configuration,
632  const ModelBlock & MB,
633  const FactoryBlock & factory_block)
634  : DeviceModel(MB, configuration.getModelParameters(), factory_block),
635  dtype(1),
636  RON(0.0),
637  ROFF(0.0),
638  ON(0.0),
639  OFF(0.0)
640 {
641  if (getType() != "")
642  {
643  if (getType() == "SWITCH" ) {
644  dtype = 1;
645  }
646  else if (getType() == "ISWITCH") {
647  dtype = 2;
648  }
649  else if (getType() == "VSWITCH") {
650  dtype = 3;
651  }
652  else
653  {
654  UserError0(*this) << "Unrecognized model type " << getType();
655  }
656  }
657 
658 
659  // Set params to constant default values:
660  setDefaultParams ();
661 
662  // Set params according to .model line and constant defaults from metadata:
663  setModParams (MB.params);
664 
665  // Set any non-constant parameter defaults:
666 
667  // Calculate any parameters specified as expressions:
669 
670  // calculate dependent (ie computed) params and check for errors:
671 
672  if (dtype == 2)
673  {
674  if (!given("ON"))
675  ON = ION;
676  if (!given("OFF"))
677  OFF = IOFF;
678  }
679  else if (dtype == 3)
680  {
681  if (!given("ON"))
682  ON = VON;
683  if (!given("OFF"))
684  OFF = VOFF;
685  }
686 
687  processParams();
688 }
689 
690 //-----------------------------------------------------------------------------
691 // Function : Model::processParams
692 // Purpose :
693 // Special Notes :
694 // Scope : public
695 // Creator : Dave Shirley, PSSI
696 // Creation Date : 03/16/05
697 //-----------------------------------------------------------------------------
699 {
700  double del;
701  Lm = log (sqrt(RON*ROFF));
702  Lr = log (RON/ROFF);
703 
704  del = ON-OFF;
705 
706  if (del < 0 && del > -1e-12)
707  del = -1e-12;
708  if (del >= 0 && del < 1e-12)
709  del = 1e-12;
710  dInv = 1.0/del;
711 
712  return true;
713 }
714 
715 //----------------------------------------------------------------------------
716 // Function : Model::processInstanceParams
717 // Purpose :
718 // Special Notes :
719 // Scope : public
720 // Creator : Dave Shirely, PSSI
721 // Creation Date : 03/23/06
722 //----------------------------------------------------------------------------
724 {
725 
726  std::vector<Instance*>::iterator iter;
727  std::vector<Instance*>::iterator first = instanceContainer.begin();
728  std::vector<Instance*>::iterator last = instanceContainer.end();
729 
730  for (iter=first; iter!=last; ++iter)
731  {
732  (*iter)->processParams();
733  }
734 
735  return true;
736 }
737 
738 //-----------------------------------------------------------------------------
739 // Function : Model::~Model
740 // Purpose : destructor
741 // Special Notes :
742 // Scope : public
743 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
744 // Creation Date : 3/16/00
745 //-----------------------------------------------------------------------------
747 {
748  std::vector<Instance*>::iterator iter;
749  std::vector<Instance*>::iterator first = instanceContainer.begin();
750  std::vector<Instance*>::iterator last = instanceContainer.end();
751 
752  for (iter=first; iter!=last; ++iter)
753  delete (*iter);
754 }
755 
756 //-----------------------------------------------------------------------------
757 // Function : Model::printOutInstances
758 // Purpose : debugging tool.
759 // Special Notes :
760 // Scope : public
761 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
762 // Creation Date : 4/03/00
763 //-----------------------------------------------------------------------------
764 std::ostream &Model::printOutInstances(std::ostream &os) const
765 {
766  std::vector<Instance*>::const_iterator iter;
767  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
768  std::vector<Instance*>::const_iterator last = instanceContainer.end();
769 
770  int i;
771  os << std::endl;
772  os << " name model name Parameters" << std::endl;
773  for (i=0, iter=first; iter!=last; ++iter, ++i)
774  {
775  os << " " << i << ": " << (*iter)->getName() << " ";
776  os << getName();
777  os << " R = " << (*iter)->R;
778  os << " G = " << (*iter)->G;
779  os << " State = " << (*iter)->SW_STATE;
780  os << std::endl;
781  }
782 
783  os << std::endl;
784 
785  return os;
786 }
787 
788 //-----------------------------------------------------------------------------
789 // Function : Model::forEachInstance
790 // Purpose :
791 // Special Notes :
792 // Scope : public
793 // Creator : David Baur
794 // Creation Date : 2/4/2014
795 //-----------------------------------------------------------------------------
796 /// Apply a device instance "op" to all instances associated with this
797 /// model
798 ///
799 /// @param[in] op Operator to apply to all instances.
800 ///
801 ///
802 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
803 {
804  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
805  op(*it);
806 }
807 
808 
809 //-----------------------------------------------------------------------------
810 // SW Master functions:
811 //-----------------------------------------------------------------------------
812 
813 //-----------------------------------------------------------------------------
814 // Function : Master::updateState
815 // Purpose :
816 // Special Notes :
817 // Scope : public
818 // Creator : Eric Keiter, SNL
819 // Creation Date : 11/26/08
820 //-----------------------------------------------------------------------------
821 bool Master::updateState (double * solVec, double * staVec, double * stoVec)
822 {
823  bool bsuccess = true;
824 
825  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
826  {
827  Instance & si = *(*it);
828 
829  bool btmp = si.updateIntermediateVars ();
830  bsuccess = bsuccess && btmp;
831 
832  // obtain the current value of the switch state
833  si.switch_state = si.SW_STATE;
834  staVec[si.li_switch_state] = si.switch_state;
835  }
836 
837  return bsuccess;
838 }
839 
840 //-----------------------------------------------------------------------------
841 // Function : Master::updateSecondaryState
842 // Purpose :
843 // Special Notes :
844 // Scope : public
845 // Creator : Eric Keiter, SNL
846 // Creation Date : 11/26/08
847 //-----------------------------------------------------------------------------
848 bool Master::updateSecondaryState ( double * staDerivVec, double * stoVec )
849 {
850  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
851  {
852  Instance & si = *(*it);
853 
854  double current_state;
855  double control;
856  double * solVec = si.extData.nextSolVectorRawPtr;
857 
858  // Get time derivatives from time integrator, and evaluate expression to get
859  // derivatives with respect to independent quantities
860 
861  if (si.expNumDdt > 0)
862  {
863  for (int i=0 ; i<si.expNumDdt ; ++i)
864  {
865  si.ddtVals[i] = staDerivVec[si.li_ddt[i]];
866  }
867  si.Exp_ptr->setDdtDerivs(si.ddtVals);
868  }
869  // Evaluate Expression with corrected time derivative values
870 
871  si.Exp_ptr->evaluate( si.expVal, si.expVarDerivs );
872  control = si.expVal;
873 
874  // This is not really correct, an interim hack. This is supposed
875  // to be where we deal with the specification of ON or OFF from the
876  // netlist.
877  if (getSolverState().initJctFlag)
878  {
879  if (si.ON)
880  current_state = 1;
881  else
882  current_state = 0;
883  }
884  else
885  {
886  current_state = (control-si.getModel().OFF)*si.getModel().dInv;
887  }
888 
889  si.v_pos = solVec[si.li_Pos];
890  si.v_neg = solVec[si.li_Neg];
891 
892  if (current_state >= 1.0)
893  {
894  si.R = si.getModel().RON;
895  si.G = 1.0/si.R;
896  for (int i=0 ; i<si.expNumVars ; ++i)
897  si.expVarDerivs[i] = 0;
898  }
899  else if ( current_state <= 0.0)
900  {
901  si.R = si.getModel().ROFF;
902  si.G = 1.0/si.R;
903  for (int i=0 ; i<si.expNumVars ; ++i)
904  si.expVarDerivs[i] = 0;
905  }
906  else
907  {
908  current_state = 2*current_state - 1;
909  si.G = exp(-si.getModel().Lm - 0.75*si.getModel().Lr*current_state +
910  0.25*si.getModel().Lr*current_state*current_state*current_state);
911  si.R = 1.0/si.G;
912  for (int i=0 ; i<si.expNumVars ; ++i)
913  {
914  si.expVarDerivs[i] = si.G * (1.5 * (current_state*current_state-1) * si.getModel().Lr *
915  si.getModel().dInv * si.expVarDerivs[i]);
916  }
917  }
918  }
919 
920  return true;
921 }
922 
923 //-----------------------------------------------------------------------------
924 // Function : Master::loadDAEVectors
925 // Purpose :
926 // Special Notes :
927 // Scope : public
928 // Creator : Eric Keiter, SNL
929 // Creation Date : 11/26/08
930 //-----------------------------------------------------------------------------
931 bool Master::loadDAEVectors (double * solVec, double * fVec, double *qVec, double * bVec, double * storeLeadF, double * storeLeadQ)
932 {
933  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
934  {
935  Instance & si = *(*it);
936  // F-vector:
937  double coef = (si.v_pos-si.v_neg)*si.G;
938  fVec[si.li_Pos] += coef;
939  fVec[si.li_Neg] += -coef;
940  if( si.loadLeadCurrent )
941  {
942  storeLeadF[si.li_store_dev_i] = coef;
943  }
944  // Q-vector:
945  }
946  return true;
947 }
948 
949 //-----------------------------------------------------------------------------
950 // Function : Master::loadDAEMatrices
951 // Purpose :
952 // Special Notes :
953 // Scope : public
954 // Creator : Eric Keiter, SNL
955 // Creation Date : 11/26/08
956 //-----------------------------------------------------------------------------
957 bool Master::loadDAEMatrices (N_LAS_Matrix & dFdx, N_LAS_Matrix & dQdx)
958 {
959  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
960  {
961  Instance & si = *(*it);
962 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
963 
964  *si.fPosEquPosNodePtr += si.G;
965  *si.fPosEquNegNodePtr -= si.G;
966  *si.fNegEquPosNodePtr -= si.G;
967  *si.fNegEquNegNodePtr += si.G;
968 
969  if( si.expNumVars )
970  {
971  for( int j = 0; j < si.expNumVars; ++j )
972  {
973  *si.fPosEquControlNodePtr[j] += (si.v_pos-si.v_neg) * si.expVarDerivs[j];
974  *si.fNegEquControlNodePtr[j] -= (si.v_pos-si.v_neg) * si.expVarDerivs[j];
975  }
976  }
977 #else
978 
979  dFdx[si.li_Pos][si.APosEquPosNodeOffset] += si.G;
980  dFdx[si.li_Pos][si.APosEquNegNodeOffset] -= si.G;
981  dFdx[si.li_Neg][si.ANegEquPosNodeOffset] -= si.G;
982  dFdx[si.li_Neg][si.ANegEquNegNodeOffset] += si.G;
983 
984  if( si.expNumVars )
985  {
986  for( int i = 0; i < si.expNumVars; ++i )
987  {
988  dFdx[si.li_Pos][si.APosEquControlNodeOffset[i]] += (si.v_pos-si.v_neg) * si.expVarDerivs[i];
989  dFdx[si.li_Neg][si.ANegEquControlNodeOffset[i]] -= (si.v_pos-si.v_neg) * si.expVarDerivs[i];
990  }
991  }
992 #endif
993  }
994  return true;
995 }
996 
997 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
998 {
999 
1000  return new Master(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
1001 }
1002 
1004 {
1006  .registerDevice("s", 1)
1007 
1008 #ifdef Xyce_OLD_SWITCH
1009  .registerModelType("sw", 1)
1010 #else
1011  .registerModelType("switch", 1)
1012  .registerModelType("iswitch", 1)
1013  .registerModelType("vswitch", 1)
1014 #endif
1015  ;
1016 }
1017 
1018 } // namespace SW
1019 } // namespace Device
1020 } // namespace Xyce