Xyce  6.1
N_DEV_DeviceInstance.C
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 // Copyright Notice
3 //
4 // Copyright 2002 Sandia Corporation. Under the terms
5 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S.
6 // Government retains certain rights in this software.
7 //
8 // Xyce(TM) Parallel Electrical Simulator
9 // Copyright (C) 2002-2015 Sandia Corporation
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 //-----------------------------------------------------------------------------
24 
25 //-------------------------------------------------------------------------
26 // Filename : $RCSfile: N_DEV_DeviceInstance.C,v $
27 //
28 // Purpose : Implementation of the base device instance class.
29 //
30 // Special Notes :
31 //
32 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
33 //
34 // Creation Date : 03/30/00
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.208.2.1 $
40 //
41 // Revision Date : $Date: 2015/04/02 18:20:09 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 
48 #include <N_DEV_DeviceInstance.h>
49 
50 #include <N_DEV_Const.h>
51 #include <N_DEV_DeviceBlock.h>
52 #include <N_DEV_DeviceOptions.h>
53 #include <N_DEV_ExternData.h>
54 #include <N_DEV_ExternDevice.h>
55 #include <N_DEV_MatrixLoadData.h>
56 #include <N_DEV_Message.h>
58 #include <N_DEV_SolverState.h>
59 #include <N_ERH_ErrorMgr.h>
60 #include <N_LAS_Matrix.h>
61 #include <N_LAS_Vector.h>
62 #include <N_UTL_FeatureTest.h>
63 
64 namespace Xyce {
65 namespace Device {
66 
67 namespace {
68 static const std::vector<std::string> emptyList;
69 }
70 
71 //-----------------------------------------------------------------------------
72 // Function : DeviceInstance::DeviceInstance
73 // Purpose : instance block constructor
74 // Special Notes :
75 // Scope : public
76 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
77 // Creation Date : 3/30/00
78 //-----------------------------------------------------------------------------
80  const InstanceBlock & instance_block,
81  ParametricData<void> & parametric_data,
82  const FactoryBlock & factory_block)
83  : DeviceEntity(parametric_data, factory_block.solverState_, factory_block.deviceOptions_, instance_block.getNetlistLocation().getFilename(), instance_block.getNetlistLocation().getLineNumber()),
84  name_(instance_block.getInstanceName()),
85  psLoaded(false),
86  ssLoaded(false),
87  rhsLoaded(false),
88  origFlag(true),
89  mlData(factory_block.matrixLoadData_),
90  cols(factory_block.matrixLoadData_.cols),
91  vals(factory_block.matrixLoadData_.vals),
92  numIntVars(0),
93  numExtVars(2),
94  numStateVars(0),
95  numStoreVars(0),
96  numLeadCurrentVars(0),
97  numLeadCurrentStoreVars(0),
98  numBranchDataVars(0),
99  numBranchDataVarsIfAllocated(0),
100  configuredForLeadCurrent(false),
101  loadLeadCurrent(false),
102  mergeRowColChecked(false),
103  extData(factory_block.externData_),
104  numJacPtr(NULL)
105 {
106  devConMap.resize(2);
107  devConMap[0] = 1;
108  devConMap[1] = 1;
109  numJacPtr = new NumericalJacobian(factory_block.matrixLoadData_, factory_block.solverState_, factory_block.externData_, factory_block.deviceOptions_);
110 }
111 
112 //-----------------------------------------------------------------------------
113 // Function : DeviceInstance::~DeviceInstance
114 // Purpose : destructor
115 // Special Notes :
116 // Scope : public
117 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
118 // Creation Date : 3/30/00
119 //-----------------------------------------------------------------------------
121 {
122  delete numJacPtr;
123 }
124 
125 //-----------------------------------------------------------------------------
126 // Function : DeviceInstance::getDepSolnVars
127 //
128 // Purpose : This function configures a device to an auxiliary F & Q vector
129 // so that lead currents can be calculated for this device.c.
130 //
131 // Special Notes : This must be called soon after the constructor call
132 // before the store vector is allocated.
133 //
134 // Scope : public
135 // Creator : Richard Schiek, Electrical Systems Modeling
136 // Creation Date : 03/22/13
137 //-----------------------------------------------------------------------------
139 {
141  {
142  // indicated that this device is now configured for lead current calculation
143  // this avoids claiming too much space in the store vector if this function
144  // is called more than once for a device.
146 
147  // set device instance flag to indicate the need to load lead current
148  // data into store F & Q vectors
149  loadLeadCurrent = true;
150 
151  // request additional space in store vector for lead current vars
153 
154  // migrating the store vector calculation to the branch data vectors
156  }
157 }
158 
159 
160 //-----------------------------------------------------------------------------
161 // Function : N_DEV_DeviceInstance::getDepSolnVars
162 //
163 // Purpose : Topology uses this method to check for late dependencies
164 // due to such things as Expressions in the B-src.
165 //
166 // Special Notes : Returns empty list for devices that use this base method
167 //
168 // Scope : public
169 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
170 // Creation Date : 05/05/01
171 //-----------------------------------------------------------------------------
172 const std::vector<std::string> & DeviceInstance::getDepSolnVars()
173 {
174  return expVarNames;
175 }
176 
177 //-----------------------------------------------------------------------------
178 // Function : DeviceInstance::registerDepSolnLIDs
179 // Purpose : Allows registration of LIDs of nodes and instances that
180 // appear in expressions that occur in the device.
181 // Special Notes :
182 // Scope : public
183 // Creator : Dave Shirley, PSSI
184 // Creation Date : 03/15/05
185 //-----------------------------------------------------------------------------
187  const std::vector< std::vector<int> > & depSolnLIDVecRef)
188 {
189  int size = expVarLIDs.size();
190  if (size != depSolnLIDVecRef.size())
191  {
192  DevelFatal0(*this).in("DeviceInstance::registerDepSolnLIDs")
193  << "Inconsistent number of LIDs returned from topology";
194  }
195  for (int i = 0; i < size; ++i)
196  {
197  if (depSolnLIDVecRef[i].size() != 1)
198  {
199  UserError0(*this) << "Problem with value for " << expVarNames[i]
200  << ". This may be an incorrect usage of a lead current in place of a current through a voltage source.";
201  }
202  expVarLIDs[i] = depSolnLIDVecRef[i][0];
203  }
204 }
205 
206 //-----------------------------------------------------------------------------
207 // Function : DeviceInstance::registerDepSolnGIDs
208 //
209 // Purpose : This function allows global ID's to be registered
210 // with a device. These global ID's refer to the global
211 // indices for the solution vector. Given these ID's, the
212 // device can then also determine the (row,col) ID's needed
213 // to load the jacobian matrix.
214 //
215 // Special Notes : The method is used for late resolution of variables
216 // of dependency such as for B-source. Does nothing for
217 // devices using this base class method.
218 //
219 // Scope : public
220 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
221 // Creation Date : 05/05/01
222 //-----------------------------------------------------------------------------
224  const std::vector< std::vector<int> > & varList )
225 {
226  int size = expVarGIDs.size();
227  for (int i = 0; i < size; ++i)
228  {
229  expVarGIDs[i] = varList[i][0];
230  }
231 }
232 
233 //-----------------------------------------------------------------------------
234 // Function : DeviceInstance::registerJacLIDs
235 // Purpose :
236 // Special Notes :
237 // Scope : public
238 // Creator : Eric R. Keiter, SNL
239 // Creation Date :
240 //-----------------------------------------------------------------------------
242 {
243  if (getDeviceOptions().numericalJacobianFlag || getDeviceOptions().testJacobianFlag)
244  {
245  devJacLIDs = jacLIDVec;
246  }
247 }
248 
249 //-----------------------------------------------------------------------------
250 // Function : DeviceInstance::getDepStateVars
251 //
252 // Purpose : Topology uses this method to check for late dependencies
253 // due to such things as Expressions in the B-src.
254 //
255 // Special Notes : Returns empty list for devices that use this base method
256 //
257 // Scope : public
258 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
259 // Creation Date : 05/05/01
260 //-----------------------------------------------------------------------------
261 const std::vector<std::string> & DeviceInstance::getDepStateVars()
262 {
263  return emptyList;
264 }
265 
266 //-----------------------------------------------------------------------------
267 // Function : DeviceInstance::registerDepStateGIDs
268 //
269 // Purpose : This function allows global ID's to be registered
270 // with a device. These global ID's refer to the global
271 // indices for the solution vector. Given these ID's, the
272 // device can then also determine the (row,col) ID's needed
273 // to load the jacobian matrix.
274 //
275 // Special Notes : The method is used for late resolution of variables
276 // of dependency such as for B-source. Does nothing for
277 // devices using this base class method.
278 //
279 // Scope : public
280 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
281 // Creation Date : 05/05/01
282 //-----------------------------------------------------------------------------
284  const std::vector< std::vector<int> > & varList )
285 {
286  if( varList.size() != 0 )
287  {
288  Report::DevelFatal().in("DeviceInstance::registerDepStateGIDs")
289  << "Call to registerDepStateGIDs for a device which doesn't use it.";
290  }
291 }
292 
293 //-----------------------------------------------------------------------------
294 // Function : DeviceInstance::getDepStoreVars
295 //
296 // Purpose : Topology uses this method to check for late dependencies
297 // due to such things as Expressions in the B-src.
298 //
299 // Special Notes : Returns empty list for devices that use this base method
300 //
301 // Scope : public
302 // Creator : Eric Keiter
303 // Creation Date :
304 //-----------------------------------------------------------------------------
305 const std::vector<std::string> & DeviceInstance::getDepStoreVars()
306 {
307  return emptyList;
308 }
309 
310 //-----------------------------------------------------------------------------
311 // Function : DeviceInstance::registerDepStoreGIDs
312 //
313 // Purpose : This function allows global ID's to be registered
314 // with a device. These global ID's refer to the global
315 // indices for the solution vector. Given these ID's, the
316 // device can then also determine the (row,col) ID's needed
317 // to load the jacobian matrix.
318 //
319 // Special Notes : The method is used for late resolution of variables
320 // of dependency such as for B-source. Does nothing for
321 // devices using this base class method.
322 //
323 // Scope : public
324 // Creator : Eric Keiter
325 // Creation Date :
326 //-----------------------------------------------------------------------------
328  const std::vector< std::vector<int> > & varList )
329 {
330  if( varList.size() != 0 )
331  {
332  Report::DevelFatal().in("DeviceInstance::registerDepStoreGIDs")
333  << "Call to registerDepStoreGIDs for a device which doesn't use it.";
334  }
335 }
336 
337 //-----------------------------------------------------------------------------
338 // Function : DeviceInstance::getDepLeadCurrentVars
339 //
340 // Purpose : Topology uses this method to check for late dependencies
341 // due to such things as Expressions in the B-src.
342 //
343 // Special Notes : Returns empty list for devices that use this base method
344 //
345 // Scope : public
346 // Creator : Eric Keiter
347 // Creation Date :
348 //-----------------------------------------------------------------------------
349 const std::vector<std::string> & DeviceInstance::getDepLeadCurrentVars()
350 {
351  return emptyList;
352 }
353 
354 //-----------------------------------------------------------------------------
355 // Function : DeviceInstance::registerDepLeadCurrentGIDs
356 //
357 // Purpose : This function allows global ID's to be registered
358 // with a device. These global ID's refer to the global
359 // indices for the solution vector. Given these ID's, the
360 // device can then also determine the (row,col) ID's needed
361 // to load the jacobian matrix.
362 //
363 // Special Notes : The method is used for late resolution of variables
364 // of dependency such as for B-source. Does nothing for
365 // devices using this base class method.
366 //
367 // Scope : public
368 // Creator : Eric Keiter
369 // Creation Date :
370 //-----------------------------------------------------------------------------
372  const std::vector< std::vector<int> > & varList )
373 {
374  if( varList.size() != 0 )
375  {
376  Report::DevelFatal().in("DeviceInstance::registerDepLeadCurrentGIDs")
377  << "Call to registerDepLeadCurrentGIDs for a device which doesn't use it.";
378  }
379 }
380 
381 //-----------------------------------------------------------------------------
382 // Function : DeviceInstance::testDAEMatrices
383 // Purpose :
384 // Special Notes :
385 // Scope : public
386 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
387 // Creation Date : 12/15/06
388 //-----------------------------------------------------------------------------
389 bool DeviceInstance::testDAEMatrices(const std::vector<const std::string *> & nameVec)
390 {
391  bool bsuccess = true;
392 
393  // if necessary, consolodate the LIDs vector.
394  if (devLIDs.empty())
395  {
396  devLIDs = extLIDVec;
397  devLIDs.insert(devLIDs.end(), intLIDVec.begin(), intLIDVec.end());
398  devLIDs.insert(devLIDs.end(), expVarLIDs.begin(), expVarLIDs.end());
399  }
400 
401  bsuccess = numJacPtr->testDAEMatrices(*this, nameVec);
402 
403  return bsuccess;
404 }
405 
406 //-----------------------------------------------------------------------------
407 // Function : DeviceInstance::trivialStampLoader
408 // Purpose : This function contains most of the original
409 // loadTrivialMatrixStamp function. See comments above.
410 // Special Notes :
411 // Scope : public
412 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
413 // Creation Date : 05/25/05
414 //-----------------------------------------------------------------------------
415 bool DeviceInstance::trivialStampLoader (Linear::Matrix * matPtr)
416 {
417  std::vector<int>::const_iterator firstVar;
418  std::vector<int>::const_iterator lastVar;
419  std::vector<int>::const_iterator iterVar;
420 
421  int localRows = matPtr->getLocalNumRows();
422 
423  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
424  {
425  Xyce::dout() << std::endl
426  << "Loading trivial stamp for " << getName() << std::endl;
427  }
428 
429  if (cols.size() < 1) cols.resize(1);
430  if (vals.size() < 1) vals.resize(1);
431 
432  for (int i = 0; i < 2; ++i)
433  {
434  // do external vars first.
435  if (i==0)
436  {
437  firstVar = extLIDVec.begin ();
438  lastVar = extLIDVec.end ();
439  }
440  // then do internal vars.
441  else
442  {
443  firstVar = intLIDVec.begin ();
444  lastVar = intLIDVec.end ();
445  }
446 
447  for (iterVar=firstVar; iterVar!=lastVar; ++iterVar)
448  {
449  int row = *iterVar;
450 
451  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
452  {
453  Xyce::dout() << "matrix row = " << row << std::endl;
454  }
455  if (row < 0)
456  {
457  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
458  {
459  Xyce::dout() << "\tNOT loading this one - too small" << std::endl;
460  }
461  continue;
462  }
463 
464  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
465  {
466  Xyce::dout() << "\tloading this one" << std::endl;
467  }
468 
469  int count = 1;
470  vals[0] = 1.0;
471  cols[0] = row;
472 
473  //matPtr->putLocalRow(row, count, &vals[0], &cols[0]);
474  matPtr->replaceLocalRow(row, count, &vals[0], &cols[0]);
475  }
476  }
477 
478  return true;
479 }
480 
481 //-----------------------------------------------------------------------------
482 // Function : DeviceInstance::loadTrivialDAE_FMatrixStamp
483 // Purpose : See loadTrivialMatrixStamp - this is the same thing, except
484 // for the new-DAE F-Matrix.
485 // Special Notes :
486 // Scope : public
487 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
488 // Creation Date : 05/25/05
489 //-----------------------------------------------------------------------------
491 {
493 }
494 
495 //-----------------------------------------------------------------------------
496 // Function : DeviceInstance::zeroMatrixDiagonal
497 // Purpose : puts zeros into on matrix diagonal, but just for this
498 // device.
499 // Special Notes :
500 // Scope : public
501 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
502 // Creation Date : 05/25/05
503 //-----------------------------------------------------------------------------
504 bool DeviceInstance::zeroMatrixDiagonal (Linear::Matrix * matPtr)
505 {
506  std::vector<int>::const_iterator firstVar;
507  std::vector<int>::const_iterator lastVar;
508  std::vector<int>::const_iterator iterVar;
509 
510  int localRows = matPtr->getLocalNumRows();
511 
512  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
513  {
514  Xyce::dout() << std::endl
515  << "Zeroing the matrix diagonal for " << getName() << std::endl;
516  }
517 
518  if (cols.size() < 1) cols.resize(1);
519  if (vals.size() < 1) vals.resize(1);
520 
521  for (int i = 0; i < 2; ++i)
522  {
523  // do external vars first.
524  if (i == 0)
525  {
526  firstVar = extLIDVec.begin ();
527  lastVar = extLIDVec.end ();
528  }
529  // then do internal vars.
530  else
531  {
532  firstVar = intLIDVec.begin ();
533  lastVar = intLIDVec.end ();
534  }
535 
536  for (iterVar=firstVar; iterVar!=lastVar; ++iterVar)
537  {
538  int row = *iterVar;
539 
540  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
541  {
542  Xyce::dout() << "matrix row = " << row << std::endl;
543  }
544 
545  if (row < 0) continue;
546  if (row >= localRows) continue;
547 
548  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS))
549  {
550  Xyce::dout() << "\tloading this one" << std::endl;
551  }
552 
553  int count = 1;
554  vals[0] = 0.0;
555  cols[0] = row;
556 
557  matPtr->putLocalRow(row, count, &vals[0], &cols[0]);
558  }
559  }
560 
561  return true;
562 }
563 
564 //-----------------------------------------------------------------------------
565 // Function : DeviceInstance::enablePDEContinuation
566 // Purpose :
567 // Special Notes :
568 // Scope : public
569 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
570 // Creation Date : 07/23/03
571 //-----------------------------------------------------------------------------
572 bool DeviceInstance::enablePDEContinuation(int &max_PDE_continuation_steps)
573 {
574  return true;
575 }
576 
577 //-----------------------------------------------------------------------------
578 // Function : DeviceInstance::disablePDEContinuation
579 // Purpose :
580 // Special Notes :
581 // Scope : public
582 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
583 // Creation Date : 07/23/03
584 //-----------------------------------------------------------------------------
586 {
587  return true;
588 }
589 
590 //-----------------------------------------------------------------------------
591 // Function : DeviceInstance::setPDEContinuationAlpha
592 // Purpose :
593 // Special Notes :
594 // Scope : public
595 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
596 // Creation Date : 07/23/03
597 //-----------------------------------------------------------------------------
599 {}
600 
601 //-----------------------------------------------------------------------------
602 // Function : DeviceInstance::setPDEContinuationBeta
603 // Purpose :
604 // Special Notes :
605 // Scope : public
606 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
607 // Creation Date : 02/28/04
608 //-----------------------------------------------------------------------------
610 {}
611 
612 //-----------------------------------------------------------------------------
613 // Function : DeviceInstance::setInitialGuess
614 // Purpose :
615 // Special Notes :
616 // Scope : public
617 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
618 // Creation Date : 07/23/03
619 //-----------------------------------------------------------------------------
621 {
622  return true;
623 }
624 
625 //-----------------------------------------------------------------------------
626 // Function : DeviceInstance::getMaxTimeStepSize
627 // Purpose :
628 // Special Notes :
629 // Scope : public
630 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
631 // Creation Date : 07/23/03
632 //-----------------------------------------------------------------------------
634 {
636 }
637 
638 
639 //-----------------------------------------------------------------------------
640 // Function : DeviceInstance::jacStampMap
641 // Purpose : Compute Jacobian Stamp and Map for devices that can have merged nodes
642 // Special Notes :
643 // Scope : public
644 // Creator : Dave Shirley, PSSI
645 // Creation Date : 2/13/04
646 //-----------------------------------------------------------------------------
647 void
649  const JacobianStamp & stamp_parent,
650  std::vector<int> & map_parent,
651  JacobianStamp & map2_parent,
652  JacobianStamp & stamp,
653  std::vector<int> & map,
654  JacobianStamp & map2,
655  int from,
656  int to,
657  int original_size)
658 {
659  if (from <= to)
660  {
661  Report::DevelFatal().in("DeviceInstance::jacStampMap")
662  << "From index " << from << " <= " << " to index " << to;
663  }
664 
665  if (map_parent.size() == 0)
666  {
667  map_parent.resize(original_size);
668  map2_parent.resize(original_size);
669  for (int i = 0; i < original_size; ++i)
670  {
671  map_parent[i] = i;
672  map2_parent[i].resize(stamp_parent[i].size());
673  for (int j = 0; j < stamp_parent[i].size(); ++j)
674  {
675  map2_parent[i][j] = j;
676  }
677  }
678  }
679  map2.resize(original_size);
680 
681  // This is to merge the column that is being eliminated into the column it is merged.
682  // If extra elements are present then we must increment the map2 value for later
683  // elements. There are multiple cases depending what is populated.
684  for (int i = 0; i < original_size; ++i)
685  {
686  int f_index = -1;
687  int t_index = -1;
688  int p_row = map_parent[i];
689  for (int j = 0; j < stamp_parent[p_row].size(); ++j)
690  {
691  if (stamp_parent[p_row][j] == from)
692  f_index = j;
693  if (stamp_parent[p_row][j] == to)
694  t_index = j;
695  }
696  map2[i].resize(map2_parent[i].size());
697  int f_index2 = -1;
698  int t_index2 = -1;
699  for (int j = 0; j < map2_parent[i].size(); ++j)
700  {
701  map2[i][j] = map2_parent[i][j];
702  if (stamp_parent[p_row][map2[i][j]] == from)
703  f_index2 = j;
704  if (stamp_parent[p_row][map2[i][j]] == to)
705  t_index2 = j;
706  }
707  if (f_index >= 0)
708  {
709  if (t_index >= 0)
710  {
711  for (int j = 0; j < map2[i].size(); ++j)
712  {
713  if (map2[i][j] > f_index)
714  map2[i][j]--;
715  }
716  if (f_index2 >= 0 && t_index2 >= 0)
717  map2[i][f_index2] = map2[i][t_index2];
718  }
719  else
720  {
721  for (int j = 0; j < map2[i].size(); ++j)
722  {
723  if (stamp_parent[p_row][map2[i][j]] > to && stamp_parent[p_row][map2[i][j]] < from)
724  ++map2[i][j];
725  }
726  t_index = 0;
727  for (int j = 0; j < stamp_parent[p_row].size(); ++j)
728  {
729  if (to > stamp_parent[p_row][j])
730  ++t_index;
731  else
732  break;
733  }
734  if (f_index2 >= 0)
735  map2[i][f_index2] = t_index;
736  }
737  }
738  }
739  map.resize(original_size);
740  int p_size = stamp_parent.size();
741 
742  // This is to merge the row that is being eliminated into the row it is merged into
743  // if extra elements are present then we must increment the map2 value for later
744  // elements in the row
745  JacobianStamp map2_tmp = map2;
746  for (int i = 0; i < stamp_parent[from].size() && stamp_parent[from][i] < p_size-1; ++i)
747  {
748  bool new_col = false;
749  for (int j = 0; j<stamp_parent[to].size(); ++j)
750  {
751  if (j == 0)
752  new_col = true;
753  if (stamp_parent[from][i] == stamp_parent[to][j])
754  {
755  new_col = false;
756  break;
757  }
758  }
759  if (new_col)
760  {
761  for (int j = 0; j < map2[to].size(); ++j)
762  {
763  if (stamp_parent[to][map2_tmp[to][j]] > stamp_parent[from][i])
764  {
765  ++map2[to][j];
766  }
767  }
768  }
769  }
770 
771  stamp.resize(p_size-1);
772 
773  std::vector<int> dup(original_size);
774 
775  int f_mod = from;
776  for (int i = 1; i < original_size; ++i)
777  {
778  dup[i] = -1;
779  for (int j = 0; j < i; ++j)
780  {
781  if (map_parent[i] == map_parent[j])
782  {
783  dup[i] = j;
784  if (i <= f_mod)
785  ++f_mod;
786  break;
787  }
788  }
789  }
790 
791  for (int i = 0; i < f_mod; ++i)
792  map[i] = map_parent[i];
793  map[f_mod] = map[to];
794 
795  for (int i = f_mod + 1; i < original_size; ++i)
796  map[i] = map_parent[i]-1;
797 
798  for (int i = 1; i < original_size; ++i)
799  {
800  if (dup[i] >= 0)
801  map[i] = map[dup[i]];
802  }
803 
804 
805  // Now that we know where the row originally came from, we can do any renumbering
806  // needed in the map2 source row
807  map2_tmp = map2;
808  int map_2_from = from;
809  if (map[from] != map[to]) {
810  for (int i = from + 1; i < original_size; ++i) {
811  if (map[i] == map[to]) {
812  map_2_from = i;
813  break;
814  }
815  }
816  if (map_2_from == from) {
817  Report::DevelFatal().in("DeviceInstance::jacStampMap") << "Internal Error 2";
818  }
819  }
820 
821  for (int i = 0; i < stamp_parent[to].size() && stamp_parent[to][i] < p_size-1; ++i)
822  {
823  bool new_col = false;
824  for (int j = 0; j < stamp_parent[from].size(); ++j)
825  {
826  if (j == 0)
827  new_col = true;
828  if (stamp_parent[to][i] == stamp_parent[from][j])
829  {
830  new_col = false;
831  break;
832  }
833  }
834  if (new_col)
835  {
836  for (int j = 0; j < map2[map_2_from].size(); ++j)
837  {
838  if (stamp_parent[from][map2_tmp[map_2_from][j]] > stamp_parent[to][i])
839  {
840  ++map2[map_2_from][j];
841  }
842  }
843  }
844  }
845 
846  JacobianStamp fill(p_size);
847  for (int i = 0; i < p_size; ++i)
848  {
849  fill[i].resize(p_size);
850  for (int j = 0 ; j < p_size; ++j)
851  fill[i][j] = 0;
852  for (int j = 0; j < stamp_parent[i].size(); ++j)
853  fill[i][stamp_parent[i][j]] = 1;
854  }
855  for (int i = 0; i < p_size; ++i)
856  {
857  fill[to][i] += fill[from][i];
858  }
859  for (int i = 0; i < p_size; ++i)
860  {
861  fill[i][to] += fill[i][from];
862  }
863  for (int i = from; i < p_size - 1; ++i)
864  {
865  for (int j = 0; j < p_size; ++j)
866  fill[i][j] = fill[i+1][j];
867  for (int j = 0; j < p_size; ++j)
868  fill[j][i] = fill[j][i+1];
869  }
870  for (int i = 0; i < p_size - 1 ; ++i)
871  {
872  stamp[i].clear();
873  for (int j = 0; j < p_size - 1; ++j)
874  {
875  if (fill[i][j] > 0)
876  stamp[i].push_back(j);
877  }
878  }
879 }
880 
881 //-----------------------------------------------------------------------------
882 // Function : DeviceInstance::jacStampMap_fixOrder
883 //
884 // Purpose : This function corrects the compressed row column array so
885 // that the column indices are in ascending order.
886 //
887 // Special Notes : The reason for this function is that the
888 // DeviceInstance::jacStampMap function
889 // implicitly requires an ordered jacStamp to work correctly.
890 // Some devices (particularly devices that have meshes),
891 // will start out with an non-ordered stamp, at least in the
892 // column entries.
893 //
894 // Note, this does require the "map" argument, because,
895 // unlike the function DeviceInstance::jacStampMap,
896 // because this function doesn't change the row ordering,
897 // or remove or merge any rows.
898 //
899 // This function only changes the column ordering in the
900 // compressed row form of the jacStamp. It thus requires
901 // modifications to map2, which is essentially a column map.
902 //
903 // Scope : public
904 // Creator : Eric R. Keiter, SNL
905 // Creation Date : 2/01/08
906 //-----------------------------------------------------------------------------
907 void
909  const JacobianStamp & stamp_parent,
910  JacobianStamp & map2_parent,
911  JacobianStamp & stamp,
912  JacobianStamp & map2)
913 {
914  int current_size = stamp_parent.size();
915 
916  if (DEBUG_DEVICE && isActive(Diag::DEVICE_JACSTAMP) && getSolverState().debugTimeFlag)
917  {
918  Xyce::dout() << Xyce::section_divider << std::endl
919  << "Begin DeviceInstance::jacStampMap_fixOrder." << std::endl
920  << Xyce::section_divider << std::endl;
921  }
922 
923  // if this is the first time this function is called (for a particular device), then
924  // allocate the map and set up their trivial contents.
925  if (map2_parent.size() == 0)
926  {
927  map2_parent.resize(current_size);
928  for (int i = 0; i < current_size; ++i)
929  {
930  map2_parent[i].resize(stamp_parent[i].size());
931  for (int j = 0; j < stamp_parent[i].size(); ++j)
932  {
933  map2_parent[i][j] = j;
934  }
935  }
936  }
937 
938  stamp.clear();
939  map2.clear();
940 
941  // To make this simple, start out with a full, dense stamp.
942  JacobianStamp denseStamp(current_size);
943  for (int i = 0; i < current_size; ++i)
944  {
945  denseStamp[i].resize(current_size,-1);
946 
947  for (int j = 0; j < stamp_parent[i].size(); ++j)
948  {
949  int denseCol = stamp_parent[i][j];
950  denseStamp[i][denseCol] = j;
951  }
952  }
953 
954  // At this point, the denseStamp has been set up. Now use it to re-create the
955  // compressed-row stamp. By simply looping over the dense stamp, the column order
956  // in the compressed row stamp will automatically be ascending.
957  // map2 is set up here as well, by pulling the values out that we previously put into
958  // dense stamp.
959  stamp.resize(current_size);
960  map2.resize(current_size);
961  for (int i = 0; i < current_size; ++i)
962  {
963  for (int j = 0; j < current_size; ++j)
964  {
965  int colMapIndex = denseStamp[i][j];
966  if (colMapIndex!=-1)
967  {
968  stamp[i].push_back(j);
969  }
970  }
971 
972  int stampRowLength=stamp[i].size();
973  map2[i].resize(stampRowLength, 0);
974 
975  for (int j = 0, k = 0; j < current_size; ++j)
976  {
977  int colMapIndex = denseStamp[i][j];
978  if (colMapIndex!=-1 && colMapIndex < stampRowLength)
979  {
980  map2[i][colMapIndex] = k;
981  ++k;
982  }
983  }
984  }
985 
986  if (DEBUG_DEVICE && isActive(Diag::DEVICE_JACSTAMP) && getSolverState().debugTimeFlag)
987  {
988  Xyce::dout() << "From inside of DeviceInstance::jacStampMap_fixOrder:" << std::endl
989  << "The original parent stamp is:" << std::endl;
990  outputJacStamp(stamp_parent);
991  Xyce::dout() << "The new reduced stamp is:" << std::endl;
992  outputJacStamp(stamp);
993  Xyce::dout() << "The dense stamp is:" << std::endl;
994  outputJacStamp(denseStamp);
995 
996  Xyce::dout() << "The new map is:" << std::endl;
997  outputJacStamp(map2);
998 
999  Xyce::dout() << Xyce::section_divider << std::endl
1000  << "End DeviceInstance::jacStampMap_fixOrder."<<std::endl
1001  << Xyce::section_divider << std::endl;
1002  }
1003 }
1004 
1005 //-----------------------------------------------------------------------------
1006 // Function : DeviceInstance::outputJacStamp
1007 // Purpose : Output jacStamp (for debugging)
1008 // Special Notes :
1009 // Scope : public
1010 // Creator : Dave Shirley, PSSI
1011 // Creation Date : 01/19/06
1012 //-----------------------------------------------------------------------------
1013 void
1015  const JacobianStamp & jac)
1016 {
1017  for (int i = 0 ; i < jac.size(); ++i)
1018  {
1019  Xyce::dout() << "Row: " << i << " ::";
1020  for (int j = 0 ; j < jac[i].size(); ++j)
1021  Xyce::dout() << " " << jac[i][j];
1022 
1023  Xyce::dout() << std::endl;
1024  }
1025  Xyce::dout() << std::endl;
1026 }
1027 
1028 //-----------------------------------------------------------------------------
1029 // Function : DeviceInstance::outputJacMaps
1030 // Purpose : Output jacMap and jacMap2 (for debugging)
1031 // Special Notes :
1032 // Scope : public
1033 // Creator : Keith Santarelli, Electrical & Microsystems Modeling
1034 // Creation Date : 02/20/08
1035 //-----------------------------------------------------------------------------
1036 void
1038  const std::vector<int> & jacMap,
1039  const JacobianStamp & jacMap2)
1040 {
1041  for (int i = 0 ; i < jacMap.size(); ++i)
1042  {
1043  Xyce::dout() << "Row " << i << ": ";
1044  for (int j = 0; j < jacMap2[i].size(); j++)
1045  Xyce::dout() << jacMap[i]<< "," << jacMap2[i][j] << " ";
1046 
1047  Xyce::dout() << std::endl;
1048  }
1049 
1050  Xyce::dout() << std::endl;
1051 }
1052 
1053 //-----------------------------------------------------------------------------
1054 // Function : DeviceInstance::registerGIDData
1055 // Purpose : Insert GID data into 'indexPairList' object
1056 //
1057 // Special Notes : This information is neccessary for the numerical Jacobian.
1058 // It is only called once.
1059 //
1060 // The numerical jacobian may get confused by duplicate
1061 // matrix entries, in that it might load them 2x. For that
1062 // reason, this function checks for duplicates.
1063 //
1064 // Scope : public
1065 // Creator : Rob Hoekstra
1066 // Creation Date : 12/13/04
1067 //-----------------------------------------------------------------------------
1069  const std::vector<int> & counts,
1070  const IdVector & GIDs,
1071  const JacobianStamp & jacGIDs )
1072 {
1073  if (getDeviceOptions().numericalJacobianFlag)
1074  {
1075  indexPairList.clear();
1076 
1077  int extSize = counts[0];
1078  int intSize = counts[1];
1079  int expSize = counts[2];
1080  int size = GIDs.size();
1081 
1082  std::map<int,int> testIndexMap;
1083 
1084  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1085  {
1086  Xyce::dout() << "DeviceInstance::registerGIDData for " << getName() << std::endl
1087  << " extSize = " << extSize << std::endl
1088  << " intSize = " << intSize << std::endl
1089  << " expSize = " << expSize << std::endl
1090  << " GIDs.size = " << size << std::endl
1091  << " jacGIDs.size = " << jacGIDs.size () << std::endl
1092  << std::endl;
1093  }
1094 
1095  {
1096  int gid_index = 0;
1097 
1098  // Copy out external gids:
1099  extGIDList.clear ();
1100  for (; gid_index < extSize; ++gid_index )
1101  {
1102  if ( testIndexMap.find(GIDs[gid_index]) == testIndexMap.end() )
1103  {
1104  extGIDList.push_back( IndexPair( GIDs[gid_index], 1 ) );
1105  testIndexMap[GIDs[gid_index]] = 1;
1106  }
1107  }
1108 
1109  testIndexMap.clear ();
1110 
1111  // Copy out internal gids:
1112  intGIDList.clear ();
1113  for (; gid_index < intSize + extSize; ++gid_index)
1114  {
1115  if ( testIndexMap.find(GIDs[gid_index]) == testIndexMap.end() )
1116  {
1117  intGIDList.push_back( IndexPair( GIDs[gid_index], 1 ) );
1118  testIndexMap[GIDs[gid_index]] = 1;
1119  }
1120  }
1121 
1122  testIndexMap.clear ();
1123 
1124  // Copy out the exp var gid's, if they exist. These will
1125  // only exist in devices which depend on expressions, like the Bsrc.
1126  expVarGIDs.clear ();
1127  for (; gid_index < intSize + extSize + expSize; ++gid_index)
1128  {
1129  if ( testIndexMap.find(GIDs[gid_index]) == testIndexMap.end() )
1130  {
1131  expVarGIDs.push_back( GIDs[gid_index] );
1132  testIndexMap[GIDs[gid_index]] = 1;
1133  }
1134  }
1135  }
1136 
1137  // Now copy the exp var GIDs into the extVarGID's.
1138  // add the contents of expVarGIDs to the extGIDListRef.
1139  // This is done because the numerical jacobian treats expression
1140  // GIDs the same as external (nodal) GIDs.
1141  int expS = expVarGIDs.size();
1142  for (int i = 0; i < expS; ++i)
1143  {
1144  extGIDList.push_back( IndexPair( expVarGIDs[i], 1 ) );
1145  }
1146 
1147  testIndexMap.clear();
1148 
1149  // do the index pairs for the jacobian matrix
1150  indexPairList.clear ();
1151  for (int i = 0; i < jacGIDs.size () ; ++i )
1152  {
1153  if ( testIndexMap.find(GIDs[i]) == testIndexMap.end() )
1154  {
1155  testIndexMap[GIDs[i]] = 1;
1156 
1157  std::map<int,int> testJMap;
1158  testJMap.clear ();
1159  int length = jacGIDs[i].size();
1160  for( int j = 0; j < length; ++j )
1161  {
1162  if ( testJMap.find(jacGIDs[i][j]) == testJMap.end () )
1163  {
1164  indexPairList.push_back( IndexPair( GIDs[i], jacGIDs[i][j] ) );
1165  testJMap[jacGIDs[i][j]] = 1;
1166  }
1167  }
1168  }
1169  }
1170 
1171  if (DEBUG_DEVICE && isActive(Diag::DEVICE_PARAMETERS) && getSolverState().debugTimeFlag)
1172  {
1173  Xyce::dout() << " Complete GIDs :" << std::endl;
1174  for (std::vector<int>::const_iterator it = GIDs.begin(), end = GIDs.end(); it != end; ++it)
1175  Xyce::dout() << "\tgid=" << *it << std::endl;
1176 
1177  Xyce::dout() << std::endl;
1178 
1179  Xyce::dout() << " intGIDList :" << std::endl;
1180  for (IndexPairVector::const_iterator it = intGIDList.begin(), end = intGIDList.end(); it != end; ++it)
1181  Xyce::dout() << "\tgid=" << (*it).row << std::endl;
1182 
1183  Xyce::dout() << std::endl;
1184 
1185  Xyce::dout() << " extGIDList :" << std::endl;
1186  for (IndexPairVector::const_iterator it = extGIDList.begin(), end = extGIDList.end(); it != end; ++it)
1187  Xyce::dout() << "\tgid=" << (*it).row << std::endl;
1188 
1189  Xyce::dout() << std::endl;
1190 
1191 
1192  Xyce::dout() << " indexPairList :" << std::endl;
1193  for (IndexPairVector::const_iterator it = indexPairList.begin(), end = indexPairList.end(); it != end; ++it)
1194  Xyce::dout() << " row=" << (*it).row << " col=" << (*it).col << std::endl;
1195 
1196  Xyce::dout() << std::endl << std::endl;
1197  }
1198  }
1199 }
1200 
1201 //-----------------------------------------------------------------------------
1202 // Function : DeviceInstance::updateTemperature
1203 // Purpose :
1204 // Special Notes :
1205 // Scope : public
1206 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1207 // Creation Date : 11/30/00
1208 //-----------------------------------------------------------------------------
1209 bool DeviceInstance::updateTemperature(const double & temp_tmp)
1210 {
1211  return true;
1212 }
1213 
1214 //-----------------------------------------------------------------------------
1215 // Function : DeviceInstance::processParams
1216 // Purpose :
1217 // Special Notes :
1218 // Scope : public
1219 // Creator : Eric Keiter, SNL, Parallel Computational Sciences
1220 // Creation Date : 06/03/02
1221 //-----------------------------------------------------------------------------
1223 {
1224  Report::DevelFatal0().in("DeviceInstance::processParams")
1225  << "DeviceInstance::processParams() must be implemented for device " << getName();
1226 
1227  return true;
1228 }
1229 
1230 //-----------------------------------------------------------------------------
1231 // Function : DeviceInstance::setInternalState
1232 // Purpose :
1233 // Special Notes :
1234 // Scope : public
1235 // Creator : Robert J Hoekstra, SNL, Parallel Computational Sciences
1236 // Creation Date : 09/02/01
1237 //-----------------------------------------------------------------------------
1239  const DeviceState & state )
1240 {
1241  Report::DevelFatal().in("DeviceInstance::setInternalState") << "does not exist for this device " << getName();
1242 
1243  return false;
1244 }
1245 
1246 std::ostream &
1247 DeviceInstance::printName(std::ostream &os) const
1248 {
1249  return os << "instance " << name_.getEncodedName();
1250 }
1251 
1252 } // namespace Device
1253 } // namespace Xyce
const InstanceName & getName() const
virtual void registerGIDData(const std::vector< int > &counts, const IdVector &GIDs, const JacobianStamp &jacGIDs)
const DeviceOptions & deviceOptions_
std::vector< double > & vals
Pure virtual class to augment a linear system.
void outputJacMaps(const std::vector< int > &jacMap, const JacobianStamp &jacMap2)
const std::string & getEncodedName() const
Return the instance name encoded as: [s:]*xname [s:]*Ytype!name [s:]*Utype!name!count.
virtual bool enablePDEContinuation(int &max_PDE_continuation_steps)
virtual void registerDepSolnGIDs(const std::vector< IdVector > &varList)
void jacStampMap_fixOrder(const JacobianStamp &stamp_parent, JacobianStamp &map2_parent, JacobianStamp &stamp, JacobianStamp &map2)
virtual void registerJacLIDs(const JacobianStamp &jacLIDVec)
virtual bool setInternalState(const DeviceState &state)
virtual bool testDAEMatrices(const std::vector< const std::string * > &nameVec)
virtual const std::vector< std::string > & getDepStoreVars()
virtual void registerDepStateGIDs(const std::vector< IdVector > &varList)
std::vector< int > IdVector
Definition: N_DEV_fwd.h:186
The FactoryBlock contains parameters needed by the device, instance and model creation functions...
virtual void registerDepSolnLIDs(const std::vector< IdVector > &depSolnLIDVecRef)
virtual const std::vector< std::string > & getDepLeadCurrentVars()
const DeviceOptions & getDeviceOptions() const
bool testDAEMatrices(DeviceInstance &instance, const std::vector< const std::string * > &nameVec)
virtual void registerDepLeadCurrentGIDs(const std::vector< IdVector > &varList)
std::vector< std::vector< int > > JacobianStamp
Definition: N_DEV_fwd.h:185
virtual bool updateTemperature(const double &temp_tmp)
Class ParametricData manages the configuration information and the parameter binding map...
Definition: N_DEV_Pars.h:1303
bool trivialStampLoader(Linear::Matrix *matPtr)
Linear::Matrix * dFdxMatrixPtr
const SolverState & solverState_
void outputJacStamp(const JacobianStamp &jac)
virtual void setPDEContinuationBeta(double beta)
virtual const std::vector< std::string > & getDepStateVars()
IdVector devLIDs
devLIDs is a combined LID vector, containing int, ext, and expVar ID's.
void jacStampMap(const JacobianStamp &stamp_parent, IdVector &map_parent, JacobianStamp &map2_parent, JacobianStamp &stamp, IdVector &map, JacobianStamp &map2, int from, int to, int original_size)
virtual void registerDepStoreGIDs(const std::vector< IdVector > &varList)
const SolverState & getSolverState() const
virtual void setPDEContinuationAlpha(double alpha)
bool zeroMatrixDiagonal(Linear::Matrix *matPtr)
virtual std::ostream & printName(std::ostream &os) const
InstanceBlock represent a device instance line from the netlist.
std::vector< std::string > expVarNames
virtual const std::vector< std::string > & getDepSolnVars()