Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
N_DEV_Xygra.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_Xygra.C,v $
27 //
28 // Purpose : Provide a linking device for coupling to Alegra
29 // simulations.
30 //
31 // Special Notes : Alegra uses API calls to set conductance and source
32 // information used to construct F (or RHS), and to retrieve
33 // nodal voltages.
34 //
35 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
36 //
37 // Creation Date : 08/18/08
38 //
39 // Revision Information:
40 // ---------------------
41 //
42 // Revision Number: $Revision: 1.45 $
43 //
44 // Revision Date : $Date: 2014/05/13 22:32:15 $
45 //
46 // Current Owner : $Author: tvrusso $
47 //-------------------------------------------------------------------------
48 #include <Xyce_config.h>
49 
50 // ---------- Standard Includes ----------
51 #include <N_UTL_Misc.h>
52 
53 #include <sstream>
54 
55 // ---------- Xyce Includes ----------
56 #include <N_DEV_DeviceOptions.h>
57 #include <N_DEV_DeviceMaster.h>
58 #include <N_DEV_ExternData.h>
59 #include <N_DEV_MatrixLoadData.h>
60 #include <N_DEV_SolverState.h>
61 #include <N_DEV_Xygra.h>
62 #include <N_DEV_Message.h>
63 #include <N_ERH_ErrorMgr.h>
64 
65 #include <N_LAS_Vector.h>
66 #include <N_LAS_Matrix.h>
67 
68 namespace Xyce {
69 namespace Device {
70 
71 template<>
73 {
74  addPar ("NAME", "COIL0", &XygraCoilData::name);
75  addPar ("NUMWINDINGS", 1, &XygraCoilData::numWindings);
76 }
77 
79  static ParametricData<XygraCoilData> parMap;
80 
81  return parMap;
82 }
83 
84 
85 //-----------------------------------------------------------------------------
86 // Function : XygraCoilData::XygraCoilData
87 // Purpose : constructor
88 // Special Notes :
89 // Scope : public
90 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
91 // Creation Date : 9/11/2008
92 //-----------------------------------------------------------------------------
94  : CompositeParam(getParametricData()),
95  name("coil"),
96  numWindings(1)
97 {}
98 
99 //-----------------------------------------------------------------------------
100 // Function : XygraCoilData::processParams
101 // Purpose :
102 // Special Notes :
103 // Scope : public
104 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
105 // Creation Date : 9/11/2008
106 //-----------------------------------------------------------------------------
108 {
109 }
110 
111 #ifdef Xyce_DEBUG_DEVICE
112 //-----------------------------------------------------------------------------
113 // Function : operator<<
114 // Purpose : "<<" operator for XygraCoilData
115 // Special Notes :
116 // Scope : public
117 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
118 // Creation Date : 9/11/2008
119 //-----------------------------------------------------------------------------
120 std::ostream & operator<<(std::ostream & os, const XygraCoilData & xcd)
121 {
122  os << " XygraCoilData for: name = " << xcd.getName() <<
123  " numWindings=" << xcd.getNumWindings() <<
124  std::endl;
125 
126  return os;
127 }
128 #endif
129 
130 
131 
132 
133 namespace Xygra {
134 
135 
137 {
138  // Set up configuration constants:
140 }
141 
143 {}
144 
145 
146 // Class Instance
147 //-----------------------------------------------------------------------------
148 // Function : Instance::processParams
149 // Purpose :
150 // Special Notes :
151 // Scope : public
152 // Creator : Tom Russo
153 // Creation Date : 8/18/2008
154 //-----------------------------------------------------------------------------
156 {
157  // If there are any time dependent parameters, set their values at for
158  // the current time.
159 
160  // now set the temperature related stuff.
161  //updateTemperature(temp);
162 
163  return true;
164 }
165 
166 //-----------------------------------------------------------------------------
167 // Function : Instance::updateTemperature
168 // Purpose :
169 // Special Notes :
170 // Scope : public
171 // Creator : Tom Russo, Component Information and Models
172 // Creation Date : 8/18/2008
173 //-----------------------------------------------------------------------------
174 bool Instance::updateTemperature ( const double & temp)
175 {
176  bool bsuccess = true;
177  return bsuccess;
178 }
179 
180 //-----------------------------------------------------------------------------
181 // Function : Instance::Instance
182 // Purpose : constructor
183 // Special Notes :
184 // Scope : public
185 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
186 // Creation Date : 8/18/2008
187 //-----------------------------------------------------------------------------
189  const Configuration & configuration,
190  const InstanceBlock & IB,
191  Model & Miter,
192  const FactoryBlock & factory_block)
193 
194  : DeviceInstance(IB, configuration.getInstanceParameters(), factory_block),
195  model_(Miter),
196  t0_(0),
197  t1_(0)
198 {
199  numExtVars = IB.numExtVars; // we have as many as were specified on the
200  // instance line
201  numIntVars = 0;
202  numStateVars = 0;
203 
204  // Start with both vectors empty. We'll only make them the right size
205  // when they get set from setConductances or setSources, so we can tell
206  // whether to bother using them. If not the right size, no contribution
207  // from those terms.
208  theSourceVector_.clear();
209  theConductanceMatrix_.clear();
210  theKMatrix_.clear();
211  k0_.clear();
212  k1_.clear();
213  s0_.clear();
214  s1_.clear();
215 
216 
217  // Set params to constant default values:
218  setDefaultParams ();
219 
220  // Set params according to instance line and constant defaults from metadata:
221  setParams (IB.params);
222 
223  // Set any non-constant parameter defaults:
224 
225  //if (!given("TEMP"))
226  // temp = getDeviceOptions().temp.dVal();
227 
228  // Calculate any parameters specified as expressions:
230 
231  // calculate dependent (ie computed) params and check for errors:
232  processParams ();
233 
234 
235  int totalNumIntVars=0;
236  totalNumWindings = 0;
237  if (!coilDataVec.empty())
238  {
239 #ifdef Xyce_DEBUG_DEVICE
240  Xyce::dout() << " We were given a coil spec." << std::endl;
241  Xyce::dout() << " There were " << coilDataVec.size() << " coils." << std::endl;
242 #endif
243 
244  // numExtVars is apparently 0 for the default device (which is never
245  // used except for parameter output) and its associated coilDataVec always
246  // has one. So skip this test if numExtVars==0.
247 
248  if ( numExtVars != 0 && numExtVars != coilDataVec.size()*2)
249  {
250  UserError0(*this) << "Xygra Device " << getName() << "has "<< coilDataVec.size() << " coils and " << numExtVars << " external nodes. Number of external nodes should be twice number of coils.";
251  }
252 
253  nCoils=coilDataVec.size();
254  nWindings.resize(nCoils);
255  coilNames.resize(nCoils);
256  for ( int i = 0; i < nCoils; ++i)
257  {
258 #ifdef Xyce_DEBUG_DEVICE
259  Xyce::dout() << " Coil["<< i << "] name is " << coilDataVec[i]->getName() << ", has " << coilDataVec[i]->getNumWindings() << " windings. " << std::endl;
260 #endif // Xyce_DEBUG_DEVICE
261  totalNumIntVars += coilDataVec[i]->getNumWindings() - 1;
262  nWindings[i] = coilDataVec[i]->getNumWindings();
263  coilNames[i] = coilDataVec[i]->getName();
265  }
266 
267 #ifdef Xyce_DEBUG_DEVICE
268  Xyce::dout() << " We would have " << totalNumIntVars << " internal vars " << std::endl;
269 #endif
270  }
271  else
272  {
273  // if no coil spec given, each pair of external nodes corresponds to a
274  // one-winding coil.
275  nCoils=numExtVars/2;
276  nWindings.resize(nCoils,1);
278  if (nCoils*2 != numExtVars)
279  {
280  std::ostringstream ost;
281 
282  ost << "Instance::Instance:";
283  ost << "Number of nodes given to device " << getName() << "is not even."
284  << std::endl;
285  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL, ost.str() );
286  }
287 
288  }
289  // we'll use these in mapping between winding currents/dV's and nodal
290  // contributions
291  coilExtStart.resize(nCoils);
292  coilIntStart.resize(nCoils);
294 
295  // set up numIntVars:
296  numIntVars = totalNumIntVars;
297 
298  // Now that we have computed our numIntVars, it's OK to
299  // set up jacStamp. For now, we'll have to assume a full (dense) Jacobian
300  // maybe there's a way to get this done later, but I think not, because
301  // topology needs to know it too soon, and we won't know the real structure
302  // until it's too late to use it.
303  //
304  setupJacStamp_();
305 
306  // set up numStateVars:
307  numStateVars = 0;
308 }
309 
310 //-----------------------------------------------------------------------------
311 // Function : Instance::~Instance
312 // Purpose : destructor
313 // Special Notes :
314 // Scope : public
315 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
316 // Creation Date : 8/18/2008
317 //-----------------------------------------------------------------------------
319 {
320 }
321 
322 //-----------------------------------------------------------------------------
323 // Function : Instance::setupJacStamp_
324 // Purpose : Utility function to set up the jacobian stamp
325 // Special Notes : Just makes a dense jacobian stamp for now
326 // Scope : private
327 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
328 // Creation Date : 8/18/08
329 //-----------------------------------------------------------------------------
331 {
332  int numNodes = numExtVars+numIntVars;
333  jacStamp_.resize(numNodes);
334  for (int i=0; i<numNodes; ++i)
335  {
336  jacStamp_[i].resize(numNodes);
337  for (int j=0; j<numNodes; ++j)
338  {
339  jacStamp_[i][j]=j;
340  }
341  }
342 }
343 
344 //-----------------------------------------------------------------------------
345 // Function : Instance::setConductances
346 // Purpose : take matrix of conductances, copy into our local array
347 // Special Notes : The matrix is dense
348 // Scope : public
349 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
350 // Creation Date : 8/18/08
351 //-----------------------------------------------------------------------------
352 bool Instance::setConductances(const std::vector< std::vector<double> > &cM )
353 {
354  int numNodes = numExtVars+numIntVars;
355  // Sanity check:
356  if (cM.size() != numNodes)
357  {
358  std::ostringstream ost;
359 
360  ost << "Instance::setConductances:";
361  ost << " Input matrix passed to device " << getName()
362  << " (" << cM.size()
363  << ") does not have number of rows required by netlist specification ("
364  << numNodes << ")." << std::endl;
365  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL, ost.str());
366  }
367  theConductanceMatrix_.resize(numNodes);
368  for (int i=0; i<numNodes; ++i)
369  {
370  if (cM[i].size() != numNodes)
371  {
372  std::ostringstream ost;
373 
374  ost << "Instance::setConductances:";
375  ost << " row " << i << "of matrix passed to device " << getName()
376  << " has " << cM[i].size()
377  << " columns instead of number required by netlist specification ("
378  << numNodes << ")." << std::endl;
379  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL, ost.str());
380  }
381 
382 #ifdef Xyce_DEBUG_DEVICE
384  {
385  Xyce::dout() << std::endl << subsection_divider << std::endl;
386  Xyce::dout() << " Device " << getName() << " setConductances called for time " << getSolverState().currTime << std::endl;
387  Xyce::dout() << std::endl << subsection_divider << std::endl;
388  }
389 #endif
390 
391  theConductanceMatrix_[i].resize(numNodes);
392  theConductanceMatrix_[i]=cM[i];
393  }
394  return true;
395 }
396 
397 //-----------------------------------------------------------------------------
398 // Function : Instance::setK
399 // Purpose : take matrix of K values, copy into our local array
400 // Special Notes : The matrix is dense
401 // Scope : public
402 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
403 // Creation Date : 8/18/08
404 //-----------------------------------------------------------------------------
405 bool Instance::setK(const std::vector< std::vector<double> > &kM ,
406  const double t)
407 {
408  std::vector<std::vector<double> > * kPtr;
409 
410  // Decide which of our two K's we're setting
411  if (t==0 || t == getSolverState().currTime)
412  {
413  kPtr = &k0_;
414  t0_=t;
415  }
416  else
417  {
418  kPtr = &k1_;
419  k0_=k1_; // copy old "future" K to "current" K, because we're resetting
420  // future
421  t0_=t1_; // save old "future" time
422  t1_=t; // set new one
423  }
424 
425  // Sanity check:
426  if (kM.size() != totalNumWindings)
427  {
428  std::ostringstream ost;
429 
430  ost << "Instance::setK:";
431  ost << " Input matrix passed to device " << getName()
432  << " (" << kM.size()
433  << ") does not have number of rows required by netlist specification ("
434  << totalNumWindings << ")." << std::endl;
435  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL, ost.str());
436  }
437 
438  for (int i=0; i<totalNumWindings; ++i)
439  {
440  if (kM[i].size() != totalNumWindings)
441  {
442  std::ostringstream ost;
443 
444  ost << "Instance::setK:";
445  ost << " row " << i << "of matrix passed to device " << getName()
446  << " has " << kM[i].size()
447  << " columns instead of number required by netlist specification ("
448  << totalNumWindings << ")." << std::endl;
449  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL, ost.str());
450  }
451  }
452 
453  // Sanity check is done, the matrix we're given fits our needs. Now just
454  // copy it.
455  (*kPtr) = kM;
456 
457  // If this is the first call, we have to set K1 properly.
458  if (t==0)
459  {
460  k1_ = k0_; // initialize k1
461  t1_=t0_;
462  }
463 
464 #ifdef Xyce_DEBUG_DEVICE
466  {
467  Xyce::dout() << std::endl << subsection_divider << std::endl;
468  Xyce::dout() << " Device " << getName() << " setK called for time " << getSolverState().currTime << std::endl;
469  Xyce::dout() << std::endl << subsection_divider << std::endl;
470  }
471 #endif
472  return true;
473 }
474 
475 //-----------------------------------------------------------------------------
476 // Function : Instance::getVoltages
477 // Purpose : Copy the values of this devices' nodal voltages
478 // into the provided array.
479 // Special Notes :
480 // Scope : public
481 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
482 // Creation Date : 8/18/08
483 //-----------------------------------------------------------------------------
484 bool Instance::getVoltages( std::vector< double > &nV )
485 {
486  bool bsuccess=true;
487  N_LAS_Vector * solVectorPtr = extData.nextSolVectorPtr;
488  int numNodes = numExtVars + numIntVars;
489  nV.resize(numNodes);
490 
491  // We will output these in a different order than we have them stored,
492  // so that all of a coil's nodes are in a predictable order:
493  // Coil1 positive
494  // [coil1 internal nodes]
495  // coil1 negative
496  // coil2 positive [...etc....]
497  int offset = 0;
498  for (int coil=0; coil < nCoils; ++coil)
499  {
500  nV[offset++] = (*solVectorPtr)[li_Nodes_[coilExtStart[coil]]];
501  for (int winding=0; winding< nWindings[coil]-1; ++winding)
502  {
503  nV[offset++] = (*solVectorPtr)[li_Nodes_[coilIntStart[coil]+winding]];
504  }
505  nV[offset++] = (*solVectorPtr)[li_Nodes_[coilExtStart[coil]+1]];
506  }
507 
508  return bsuccess;
509 }
510 
511 //-----------------------------------------------------------------------------
512 // Function : Instance::getCoilWindings
513 // Purpose : return individual winding counts for each coil in provided
514 // array
515 // Special Notes :
516 // Scope : public
517 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
518 // Creation Date : 9/15/08
519 //-----------------------------------------------------------------------------
520 void Instance::getCoilWindings( std::vector< int > &cW )
521 {
522  cW = nWindings;
523  return;
524 }
525 
526 //-----------------------------------------------------------------------------
527 // Function : Instance::getCoilNames
528 // Purpose : return individual names for each coil in provided
529 // array
530 // Special Notes :
531 // Scope : public
532 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
533 // Creation Date : 9/29/08
534 //-----------------------------------------------------------------------------
535 void Instance::getCoilNames( std::vector< std::string > &cN )
536 {
537  cN = coilNames;
538  return;
539 }
540 
541 //-----------------------------------------------------------------------------
542 // Function : Instance::setSources
543 // Purpose : take vector of source terms, copy into our local array
544 // Special Notes :
545 // Scope : public
546 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
547 // Creation Date : 8/18/08
548 //-----------------------------------------------------------------------------
549 bool Instance::setSources(const std::vector< double > &sV,
550  const double t)
551 {
552  int numNodes = numExtVars + numIntVars;
553 
554  std::vector<double> * sPtr;
555 
556 #ifdef Xyce_DEBUG_DEVICE
557  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
558  {
559  Xyce::dout() << std::endl << subsection_divider << std::endl;
560  Xyce::dout() << " Device " << getName() << " setSources called for time " << getSolverState().currTime << " with value t= " << t << std::endl;
561  Xyce::dout() << std::endl << subsection_divider << std::endl;
562  }
563 #endif
564 
565  // Decide which of our two S's we're setting
566  if (t==0 || t == getSolverState().currTime)
567  {
568  sPtr = &s0_;
569  t0_=t;
570 #ifdef Xyce_DEBUG_DEVICE
571  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
572  {
573  Xyce::dout() << " setting source s0 for t=" << t << std::endl;
574  }
575 #endif
576  }
577  else
578  {
579  sPtr = &s1_;
580  s0_=s1_; // copy old "future" S to "current" S, because we're resetting
581  // future
582  t0_=t1_; // save old "future" time
583  t1_=t; // set new one
584 #ifdef Xyce_DEBUG_DEVICE
585  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
586  {
587  Xyce::dout() << " setting source s1 for t=" << t << std::endl;
588  }
589 #endif
590  }
591 
592  // Sanity check:
593  if (sV.size() != totalNumWindings)
594  {
595  std::ostringstream ost;
596 
597  ost << "Instance::setSources:";
598  ost << " Input vector passed to device " << getName()
599  << " (" << sV.size()
600  << ") does not have number of rows required by netlist specification ("
601  << totalNumWindings << ")." << std::endl;
602  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL, ost.str());
603  }
604 
605  // Sanity check passes, copy the vector
606  (*sPtr) = sV;
607  // If this is the first call, we have to set S1 properly.
608  if (t==0)
609  {
610  s1_ = s0_; // initialize k1
611  t1_=t0_;
612  }
613 
614 
615  return true;
616 }
617 
618 //-----------------------------------------------------------------------------
619 // Function : Instance::interpolateSandK_
620 // Purpose : use s0,k0,t0, s1, k1, t1 to interpolate S and K to current
621 // time
622 // Special Notes :
623 // Scope : private
624 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
625 // Creation Date : 9/15/2008
626 //-----------------------------------------------------------------------------
628 {
629  // if S has been set at all:
630  if (!s0_.empty())
631  {
633  if (getSolverState().currTime > t0_ && !s1_.empty() && t0_ != t1_)
634  {
635  double fac=(getSolverState().currTime - t0_)/(t1_-t0_);
636  for (int i=0;i<totalNumWindings; ++i)
637  {
638  theSourceVector_[i] += (s1_[i]-s0_[i])*fac;
639 #ifdef Xyce_DEBUG_DEVICE
641  {
642  Xyce::dout() << " interpolated source for t=" << getSolverState().currTime << std::endl;
643  Xyce::dout() << " source vector is: " << std::endl;
644  Xyce::dout() << " s0["<<i<<"] = " << s0_[i] << std::endl;
645  Xyce::dout() << " s1["<<i<<"] = " << s1_[i] << std::endl;
646  Xyce::dout() << " fac = " << fac << std::endl;
647  Xyce::dout() << " s["<<i<<"] = " << theSourceVector_[i] << std::endl;
648  }
649 #endif
650  }
651  }
652  }
653 
654  // if K has been set at all:
655  if (!k0_.empty())
656  {
658  if (getSolverState().currTime > t0_ && !k1_.empty() && t0_ != t1_)
659  {
660  double fac=(getSolverState().currTime - t0_)/(t1_-t0_);
661  for (int i=0;i<totalNumWindings; ++i)
662  {
663  for (int j=0;i<totalNumWindings; ++i)
664  {
665  theKMatrix_[i][j] += (k1_[i][j]-k0_[i][j])*fac;
666  }
667  }
668  }
669  }
670 }
671 
672 //-----------------------------------------------------------------------------
673 // Function : Instance::registerLIDs
674 // Purpose :
675 // Special Notes :
676 // Scope : public
677 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
678 // Creation Date : 8/18/2008
679 //-----------------------------------------------------------------------------
680 void Instance::registerLIDs(const std::vector<int> & intLIDVecRef,
681  const std::vector<int> & extLIDVecRef)
682 {
683  AssertLIDs(intLIDVecRef.size() == numIntVars);
684  AssertLIDs(extLIDVecRef.size() == numExtVars);
685 
686 #ifdef Xyce_DEBUG_DEVICE
687  if (getDeviceOptions().debugLevel > 0)
688  {
689  Xyce::dout() << std::endl << section_divider << std::endl;
690  Xyce::dout() << " Instance::registerLIDs" << std::endl;
691  Xyce::dout() << " name = " << getName() << std::endl;
692  }
693 #endif
694 
695  int numNodes = numExtVars + numIntVars;
696 
697  // copy over the global ID lists.
698  intLIDVec = intLIDVecRef;
699  extLIDVec = extLIDVecRef;
700 
701  li_Nodes_.resize(numNodes);
702 
703  int extVar=0;
704  int intVar=0;
705  int theVar=0;
706 
707  // First comes the external nodes
708  for (int coil=0; coil<nCoils; ++coil)
709  {
710  coilExtStart[coil] = theVar;
711  li_Nodes_[theVar++] = extLIDVec[extVar++];
712  li_Nodes_[theVar++] = extLIDVec[extVar++];
713  }
714  // now the internals
715 
716  for (int coil=0; coil<nCoils; ++coil)
717  {
718  coilIntStart[coil] = theVar;
719  for( int i=0; i< nWindings[coil]-1; ++i)
720  {
721  li_Nodes_[theVar++] = intLIDVec[intVar++];
722  }
723  }
724 
725  // This doesn't really belong in registerLIDs, but since it's only here that
726  // we've calculated everything we need to know, and we need this stuff
727  // later, this is a good place to do it.
728 
729  int globalWinding=0;
730  for (int coil=0; coil<nCoils; ++coil)
731  {
732  for ( int coilWinding=0; coilWinding<nWindings[coil]; coilWinding++)
733  {
734  int posNode;
735  int negNode;
736  if (coilWinding==0)
737  {
738  posNode=coilExtStart[coil];
739  }
740  else
741  {
742  posNode=coilIntStart[coil]+(coilWinding-1);
743  }
744  if (coilWinding==nWindings[coil]-1)
745  {
746  negNode=coilExtStart[coil]+1;
747  }
748  else
749  {
750  negNode=coilIntStart[coil]+coilWinding;
751  }
752  windingNodes[globalWinding++] = std::pair<int,int>(posNode,negNode);
753  }
754  }
755 
756 #ifdef Xyce_DEBUG_DEVICE
757  if (getDeviceOptions().debugLevel > 0 )
758  {
759  for (int i=0; i<numNodes; ++i)
760  {
761  Xyce::dout() << " li_Nodes_[" <<i << "] = " << li_Nodes_[i] << std::endl;
762  }
763 
764  for (int winding=0; winding<totalNumWindings; winding++)
765  {
766  Xyce::dout() << "Winding " << winding << " between node "
767  << windingNodes[winding].first << " and "
768  << windingNodes[winding].second << std::endl;
769  }
770  }
771 #endif
772 
773 #ifdef Xyce_DEBUG_DEVICE
774  if (getDeviceOptions().debugLevel > 0 )
775  {
776  Xyce::dout() << section_divider << std::endl;
777  }
778 #endif
779 }
780 
781 //-----------------------------------------------------------------------------
782 // Function : Instance::getIntNameMap
783 // Purpose :
784 // Special Notes :
785 // Scope : public
786 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
787 // Creation Date : 8/18/2008
788 //-----------------------------------------------------------------------------
789 std::map<int,std::string> & Instance::getIntNameMap ()
790 {
791  // set up the internal name map, if it hasn't been already.
792 
793  if (intNameMap.empty() && numIntVars != 0)
794  {
795  std::string tmpstr;
796  // set up the internal name map
797 
798  for (int coil = 0; coil< nCoils; ++coil)
799  {
800  if (nWindings[coil]>1)
801  {
802  // this coil has internal nodes
803  for (int nodeOffset=1; nodeOffset<nWindings[coil]; ++nodeOffset)
804  {
805  int localIndex=li_Nodes_[coilIntStart[coil]+nodeOffset-1];
806  std::ostringstream ost;
807  ost << "coil" << coil << "_Internal" << nodeOffset;
808  intNameMap[localIndex] = spiceInternalName(getName(), ost.str());
809  }
810  }
811  }
812  }
813 
814 
815  return intNameMap;
816 }
817 
818 //-----------------------------------------------------------------------------
819 // Function : Instance::registerStateLIDs
820 // Purpose :
821 // Special Notes :
822 // Scope : public
823 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
824 // Creation Date : 8/18/2008
825 //-----------------------------------------------------------------------------
826 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef )
827 {
828  AssertLIDs(staLIDVecRef.size() == numStateVars);
829 
830  // copy over the global ID lists.
831  staLIDVec = staLIDVecRef;
832 }
833 
834 //-----------------------------------------------------------------------------
835 // Function : Instance::jacobianStamp
836 // Purpose :
837 // Special Notes :
838 // Scope : public
839 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
840 // Creation Date : 8/18/2008
841 //-----------------------------------------------------------------------------
842 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
843 {
844  return jacStamp_;
845 }
846 
847 //-----------------------------------------------------------------------------
848 // Function : Instance::registerJacLIDs
849 // Purpose :
850 // Special Notes :
851 // Scope : public
852 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
853 // Creation Date : 8/18/2008
854 //-----------------------------------------------------------------------------
855 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
856 {
857  DeviceInstance::registerJacLIDs( jacLIDVec );
858  int numNodes=numExtVars+numIntVars;
859  A_Equ_NodeOffsets_.resize(numNodes);
860  for (int equ=0; equ < numNodes; ++equ)
861  {
862  A_Equ_NodeOffsets_[equ].resize(numNodes);
863  for (int node=0; node < numNodes; ++node)
864  {
865  A_Equ_NodeOffsets_[equ][node] = jacLIDVec[equ][node];
866  }
867  }
868 
869 }
870 
871 //-----------------------------------------------------------------------------
872 // Function : Instance::updatePrimaryState
873 // Purpose :
874 // Special Notes :
875 // Scope : public
876 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
877 // Creation Date : 8/18/2008
878 //-----------------------------------------------------------------------------
880 {
881  bool bsuccess = true;
882 
883 #ifdef Xyce_DEBUG_DEVICE
884  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
885  {
886  Xyce::dout() << "Instance::updatePrimaryState" <<std::endl;
887  }
888 #endif
889  bsuccess = updateIntermediateVars();
890  return bsuccess;
891 }
892 
893 //-----------------------------------------------------------------------------
894 // Function : Instance::updateSecondaryState
895 // Purpose :
896 // Special Notes :
897 // Scope : public
898 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
899 // Creation Date : 8/18/2008
900 //-----------------------------------------------------------------------------
902 {
903  bool bsuccess = true;
904 
905  return bsuccess;
906 }
907 
908 
909 //-----------------------------------------------------------------------------
910 // Function : Instance::updateIntermediateVars
911 // Purpose :
912 // Special Notes :
913 // Scope : public
914 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
915 // Creation Date : 9/12/2008
916 //-----------------------------------------------------------------------------
918 {
919 
920  bool bsuccess=true;
921  int numNodes=numIntVars+numExtVars;
922  N_LAS_Vector * solVectorPtr = extData.nextSolVectorPtr;
923 
924 
925 #ifdef Xyce_DEBUG_DEVICE
926 
927  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
928  {
929  Xyce::dout() << subsection_divider << std::endl;
930  Xyce::dout() << "Instance::updateIntermediateVars "<<std::endl;
931  Xyce::dout() << " name = " << getName() << std::endl;
932  }
933 #endif
934 
935  if (getSolverState().newtonIter == 0) // start of new timestep
936  {
938  }
939 
940  if (solutionVars.size() != numNodes)
941  {
942  // set up all the Fad vectors with the right sizes
943  // We only need to do this the first time around
944  solutionVars.resize(numNodes);
945  fContributions.resize(numNodes);
946  dV.resize(totalNumWindings);
948 
949  // Now, we have to loop over all those vectors and do "resize" operations
950  // on every element in them --- this sets the number of derivatives
951  // on the "DFad" type
952  for (int node=0 ; node<numNodes ; ++node)
953  {
954  solutionVars[node].resize(numNodes);
955  fContributions[node].resize(numNodes);
956  }
957  for (int winding=0 ; winding<totalNumWindings ; ++winding)
958  {
959  dV[winding].resize(numNodes);
960  windingCurrents[winding].resize(numNodes);
961  }
962  }
963  // initialize all the contributions to zero (automatically zeros derivs)
964  for (int node=0; node<numNodes; ++node)
965  {
966  fContributions[node] = 0.0;
967  }
968 
969  // same for the windings:
970  for (int winding=0; winding<totalNumWindings; ++winding)
971  {
972  windingCurrents[winding] = 0.0;
973  }
974 
975 
976  // Extract solution variables and set as DFad independent variables:
977  // (diff sets the row of the derivatives matrix to the identity row
978  for (int node=0; node<numNodes; ++node)
979  {
980  solutionVars[node] = (*solVectorPtr)[li_Nodes_[node]];
981  solutionVars[node].diff(node,numNodes);
982 #ifdef Xyce_DEBUG_DEVICE
983  Xyce::dout() << "solutionVar[" << node << "] = " << solutionVars[node] << std::endl;
984 #endif
985  }
986 
987  // Now compute winding dV's:
988  for (int winding=0; winding<totalNumWindings; ++winding)
989  {
990  int posNode=windingNodes[winding].first;
991  int negNode=windingNodes[winding].second;
992  dV[winding] = solutionVars[posNode]-solutionVars[negNode];
993  }
994 
995  // Now compute winding currents:
996  // I_i=S_i + sum(j=0,totalNumWindings,K_ij*dV_j)
997  for (int windingI=0; windingI<totalNumWindings; ++windingI)
998  {
999  // we might nave no source vector
1000  if (!theSourceVector_.empty())
1001  windingCurrents[windingI] = theSourceVector_[windingI];
1002 
1003  // we might nave no K matrix
1004  if (!theKMatrix_.empty())
1005  {
1006  for (int windingJ=0; windingJ<totalNumWindings; ++windingJ)
1007  {
1008  windingCurrents[windingI] += theKMatrix_[windingI][windingJ]*dV[windingJ];
1009  }
1010  }
1011  }
1012 
1013  // Now assemble the contributions for the nodes:
1014  for (int winding=0; winding<totalNumWindings; ++winding)
1015  {
1016  int posNode=windingNodes[winding].first;
1017  int negNode=windingNodes[winding].second;
1018 #ifdef Xyce_DEBUG_DEVICE
1019  Xyce::dout() << "Winding " << winding << " adding " << windingCurrents[winding]
1020  << "to contribution to node " << posNode << " and subtracting same "
1021  << " from node " << negNode << std::endl;
1022 #endif
1023  fContributions[posNode] += windingCurrents[winding];
1024  fContributions[negNode] -= windingCurrents[winding];
1025  }
1026 
1027 #ifdef Xyce_DEBUG_DEVICE
1028  Xyce::dout() << " Contributions for device " << getName() << std::endl;
1029  for (int node=0; node<numNodes; ++node)
1030  {
1031  Xyce::dout() << " F[" << node << "] = " << fContributions[node] << std::endl;
1032  }
1033  Xyce::dout() << "Winding potential drops and currents: " << std::endl;
1034  for (int winding=0; winding<totalNumWindings; ++winding)
1035  {
1036  Xyce::dout() << " dV[" << winding << "] = " << dV[winding] << std::endl;
1037  Xyce::dout() << " I[" << winding << "] = " << windingCurrents[winding] << std::endl;
1038  }
1039 #endif
1040 
1041  return bsuccess;
1042 }
1043 
1044 //-----------------------------------------------------------------------------
1045 // Function : Instance::loadDAEQVector
1046 //
1047 // Purpose : Loads the Q-vector contributions for a single
1048 // instance.
1049 //
1050 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1051 // which the system of equations is represented as:
1052 //
1053 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1054 //
1055 // Scope : public
1056 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1057 // Creation Date : 8/18/2008
1058 //-----------------------------------------------------------------------------
1060 {
1061  bool bsuccess = true;
1062 
1063  N_LAS_Vector * solVectorPtr = extData.nextSolVectorPtr;
1064  N_LAS_Vector * staVectorPtr = extData.nextStaVectorPtr;
1065 
1066  return bsuccess;
1067 }
1068 
1069 
1070 
1071 //-----------------------------------------------------------------------------
1072 // Function : Instance::loadDAEFVector
1073 //
1074 // Purpose : Loads the F-vector contributions for a single
1075 // instance.
1076 //
1077 // Special Notes :
1078 //
1079 // Scope : public
1080 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1081 // Creation Date : 8/18/2008
1082 //-----------------------------------------------------------------------------
1084 {
1085  bool bsuccess=true;
1086 
1087  N_LAS_Vector * daeFVecPtr = extData.daeFVectorPtr;
1088  int numNodes = numExtVars+numIntVars;
1089 
1090 #ifdef Xyce_DEBUG_DEVICE
1091 
1092  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1093  {
1094  Xyce::dout() << subsection_divider << std::endl;
1095  Xyce::dout() << "Instance::loadDAEFVector "<<std::endl;
1096  Xyce::dout() << " name = " << getName() << std::endl;
1097  }
1098 #endif
1099 
1100  for (int node=0; node<numNodes; ++node)
1101  {
1102  (*daeFVecPtr)[li_Nodes_[node]] += fContributions[node].val();
1103 #ifdef Xyce_DEBUG_DEVICE
1104  Xyce::dout() << " fVec[" << node << "] += "
1105  << fContributions[node].val() << std::endl;
1106  Xyce::dout() << " loaded into local ID " << li_Nodes_[node] << std::endl;
1107 #endif
1108  }
1109 
1110  return bsuccess;
1111 }
1112 
1113 //-----------------------------------------------------------------------------
1114 // Function : Instance::loadDAEdQdx
1115 //
1116 // Purpose : Loads the Q-vector contributions for a single
1117 // instance.
1118 // Scope : public
1119 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1120 // Creation Date : 8/18/2008
1121 //-----------------------------------------------------------------------------
1123 {
1124  bool bsuccess = true;
1125 
1126  // N_LAS_Matrix * dQdxMatPtr = extData.dQdxMatrixPtr;
1127 
1128  return bsuccess;
1129 }
1130 
1131 
1132 
1133 //-----------------------------------------------------------------------------
1134 // Function : Instance::loadDAEdFdx ()
1135 //
1136 // Purpose : Loads the F-vector contributions for a single
1137 // instance.
1138 //
1139 // Special Notes :
1140 //
1141 // Scope : public
1142 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1143 // Creation Date : 8/18/2008
1144 //-----------------------------------------------------------------------------
1146 {
1147  bool bsuccess = true;
1148 
1149  N_LAS_Matrix * dFdxMatPtr = extData.dFdxMatrixPtr;
1150  N_LAS_Vector * staVectorPtr = extData.nextStaVectorPtr;
1151  N_LAS_Vector * solVectorPtr = extData.nextSolVectorPtr;
1152 
1153  int numNodes = numExtVars+numIntVars;
1154 #ifdef Xyce_DEBUG_DEVICE
1155 
1156  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1157  {
1158  Xyce::dout() << subsection_divider << std::endl;
1159  Xyce::dout() << "Instance::loadDAEdFdx "<<std::endl;
1160  Xyce::dout() << " name = " << getName() << std::endl;
1161  }
1162 #endif
1163 
1164 #if 0
1165  // Problem: In orginal Xygra testing, I tried to have multi-winding,
1166  // source-only coils. This lead to the problem where internal nodes were
1167  // completely floating, and lead to singular jacobians. My initial reaction
1168  // was to populate the diagonals of the jacobian for source-only
1169  // coils. This is The Wrong Thing To Do.
1170  // It breaks the completely acceptable case of source-only single-winding
1171  // "coils" such as those needed by Emphasis, leading to nonlinear convergence
1172  // failures on what should be a completely linear problem.
1173  //
1174  // There should be something sane to do for multi-winding source-only
1175  // coils, but these are probably not going to be an important issue for now.
1176  // So punt it.
1177  if (theKMatrix_.empty())
1178  {
1179  for (int equ=0; equ < numNodes; ++equ)
1180  {
1181  (*dFdxMatPtr)[li_Nodes_[equ]][A_Equ_NodeOffsets_[equ][equ]] += 1.0;
1182  }
1183  }
1184  else
1185 #endif
1186  {
1187  // Using Sacado differentiation, set the dFdX terms
1188  for (int equ=0; equ < numNodes; ++equ)
1189  {
1190  for (int node=0; node < numNodes; ++node)
1191  {
1192  (*dFdxMatPtr)[li_Nodes_[equ]][A_Equ_NodeOffsets_[equ][node]]
1193  += fContributions[equ].dx(node);
1194 #ifdef Xyce_DEBUG_DEVICE
1195  Xyce::dout() << " dFdX[" << equ << "]["<<node<<"] += "
1196  << fContributions[equ].dx(node) << std::endl;
1197 #endif
1198  }
1199  }
1200  }
1201 
1202  return bsuccess;
1203 }
1204 
1205 //-----------------------------------------------------------------------------
1206 // Function : Instance::setIC
1207 // Purpose :
1208 // Special Notes :
1209 // Scope : public
1210 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1211 // Creation Date : 8/18/2008
1212 //-----------------------------------------------------------------------------
1214 {
1215  bool bsuccess = true;
1216 
1217  return bsuccess;
1218 }
1219 
1220 //-----------------------------------------------------------------------------
1221 // Function : Instance::varTypes
1222 // Purpose :
1223 // Special Notes :
1224 // Scope : public
1225 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1226 // Creation Date : 8/18/2008
1227 //-----------------------------------------------------------------------------
1228 void Instance::varTypes( std::vector<char> & varTypeVec )
1229 {
1230  //varTypeVec.resize(1);
1231  //varTypeVec[0] = 'I';
1232 }
1233 
1234 //-----------------------------------------------------------------------------
1235 // Function : Instance::constructComposite
1236 // Purpose :
1237 // Special Notes :
1238 // Scope : public
1239 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1240 // Creation Date : 9/11/2008
1241 //-----------------------------------------------------------------------------
1242 CompositeParam *Instance::constructComposite(const std::string & cName, const std::string & pName)
1243 {
1244  if (cName == "COIL")
1245  {
1246  XygraCoilData *xcd = new XygraCoilData ();
1247  coilDataVec.push_back(xcd);
1248  return (static_cast<CompositeParam *> (xcd));
1249  }
1250  else
1251  {
1252  std::string msg =
1253  "Instance::constructComposite: unrecognized composite name: ";
1254  msg += cName;
1255  N_ERH_ErrorMgr::report ( N_ERH_ErrorMgr::DEV_FATAL,msg);
1256  }
1257  // never reached
1258  return NULL;
1259 }
1260 
1261 //-----------------------------------------------------------------------------
1262 // Function : Model::processParams
1263 // Purpose :
1264 // Special Notes :
1265 // Scope : public
1266 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1267 // Creation Date : 8/18/2008
1268 //-----------------------------------------------------------------------------
1270 {
1271  return true;
1272 }
1273 
1274 //----------------------------------------------------------------------------
1275 // Function : Model::processInstanceParams
1276 // Purpose :
1277 // Special Notes :
1278 // Scope : public
1279 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1280 // Creation Date : 8/18/2008
1281 //----------------------------------------------------------------------------
1283 {
1284 
1285  std::vector<Instance*>::iterator iter;
1286  std::vector<Instance*>::iterator first = instanceContainer.begin();
1287  std::vector<Instance*>::iterator last = instanceContainer.end();
1288 
1289  for (iter=first; iter!=last; ++iter)
1290  {
1291  (*iter)->processParams();
1292  }
1293 
1294  return true;
1295 }
1296 
1297 //-----------------------------------------------------------------------------
1298 // Function : Model::Model
1299 // Purpose : block constructor
1300 // Special Notes :
1301 // Scope : public
1302 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1303 // Creation Date : 8/18/2008
1304 //-----------------------------------------------------------------------------
1306  const Configuration & configuration,
1307  const ModelBlock & MB,
1308  const FactoryBlock & factory_block)
1309  : DeviceModel(MB, configuration.getModelParameters(), factory_block)
1310 {
1311 
1312  // // Set up mapping from param names to class variables:
1313  // if (parMap.empty())
1314  // {
1315  // // Set up double precision variables:
1316 
1317  // }
1318 
1319  // Set params to constant default values:
1320  setDefaultParams ();
1321 
1322  // Set params according to .model line and constant defaults from metadata:
1323  setModParams (MB.params);
1324 
1325  // Set any non-constant parameter defaults:
1326  //if (!given("TNOM"))
1327  // tnom = getDeviceOptions().tnom;
1328 
1329  // Calculate any parameters specified as expressions:
1331 
1332  // calculate dependent (ie computed) params and check for errors:
1333 
1334  processParams ();
1335 }
1336 
1337 //-----------------------------------------------------------------------------
1338 // Function : Model::~Model
1339 // Purpose : destructor
1340 // Special Notes :
1341 // Scope : public
1342 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1343 // Creation Date : 8/18/2008
1344 //-----------------------------------------------------------------------------
1346 {
1347  std::vector<Instance*>::iterator iter;
1348  std::vector<Instance*>::iterator first = instanceContainer.begin();
1349  std::vector<Instance*>::iterator last = instanceContainer.end();
1350 
1351  for (iter=first; iter!=last; ++iter)
1352  {
1353  delete (*iter);
1354  }
1355 
1356 }
1357 
1358 // additional Declarations
1359 
1360 //-----------------------------------------------------------------------------
1361 // Function : Model::printOutInstances
1362 // Purpose : debugging tool.
1363 // Special Notes :
1364 // Scope : public
1365 // Creator : Tom Russo, SNL, Electrical and Microsystems Modeling
1366 // Creation Date : 8/18/2008
1367 //-----------------------------------------------------------------------------
1368 std::ostream &Model::printOutInstances(std::ostream &os) const
1369 {
1370  std::vector<Instance*>::const_iterator iter;
1371  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
1372  std::vector<Instance*>::const_iterator last = instanceContainer.end();
1373 
1374  int i, isize;
1375  isize = instanceContainer.size();
1376 
1377  os << std::endl;
1378  os << "Number of Xygra instances: " << isize << std::endl;
1379  os << " name=\t\tmodelName\tParameters" << std::endl;
1380  for (i=0, iter=first; iter!=last; ++iter, ++i)
1381  {
1382  os << " " << i << ": " << (*iter)->getName() << "\t";
1383  os << getName();
1384  os << std::endl;
1385  }
1386 
1387  os << std::endl;
1388 
1389  return os;
1390 }
1391 
1392 //-----------------------------------------------------------------------------
1393 // Function : Model::forEachInstance
1394 // Purpose :
1395 // Special Notes :
1396 // Scope : public
1397 // Creator : David Baur
1398 // Creation Date : 2/4/2014
1399 //-----------------------------------------------------------------------------
1400 /// Apply a device instance "op" to all instances associated with this
1401 /// model
1402 ///
1403 /// @param[in] op Operator to apply to all instances.
1404 ///
1405 ///
1406 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
1407 {
1408  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1409  op(*it);
1410 }
1411 
1412 
1413 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
1414 {
1415 
1416  return new DeviceMaster<Traits>(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
1417 }
1418 
1420 {
1422  .registerDevice("xygra", 1)
1423  .registerModelType("xygra", 1);
1424 }
1425 
1426 } // namespace Xygra
1427 } // namespace Device
1428 } // namespace Xyce