Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
N_DEV_ROM.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_ROM.C,v $
27 //
28 // Purpose :
29 //
30 // Special Notes :
31 //
32 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
33 //
34 // Creation Date : 12/11/09
35 //
36 // Revision Information:
37 // ---------------------
38 //
39 // Revision Number: $Revision: 1.62.2.2 $
40 //
41 // Revision Date : $Date: 2014/03/06 23:33:43 $
42 //
43 // Current Owner : $Author: tvrusso $
44 //-------------------------------------------------------------------------
45 
46 #include <Xyce_config.h>
47 
48 
49 // ---------- Standard Includes ----------
50 #include <N_UTL_Misc.h>
51 
52 #include <algorithm>
53 #include <cmath>
54 
55 // ---------- Xyce Includes ----------
56 #include <N_DEV_Const.h>
57 #include <N_DEV_DeviceOptions.h>
58 #include <N_DEV_DeviceMaster.h>
59 #include <N_DEV_ExternData.h>
60 #include <N_DEV_MatrixLoadData.h>
61 #include <N_DEV_ROM.h>
62 #include <N_DEV_SolverState.h>
63 #include <N_DEV_Message.h>
64 #include <N_ERH_ErrorMgr.h>
65 
66 #include <N_LAS_Vector.h>
67 #include <N_LAS_Matrix.h>
68 #include <N_LAS_Util.h>
69 
70 #include <N_UTL_Expression.h>
71 #include <N_IO_mmio.h>
72 
73 #include <Teuchos_BLAS.hpp>
74 #include <Teuchos_Utils.hpp>
75 #include <Teuchos_LAPACK.hpp>
76 
77 // Keep redundant (assuming Trilinos and Xyce are configured in the same environment) definitions from whining
78 #undef HAVE_CMATH
79 #undef HAVE_CSTDIO
80 #undef HAVE_CSTDLIB
81 #undef HAVE_INTTYPES_H
82 #undef HAVE_IOSTREAM
83 #undef HAVE_STDINT_H
84 #include <Trilinos_Util.h>
85 
86 namespace Xyce {
87 namespace Device {
88 
89 
90 namespace ROM {
91 
92 
94 {
95 p.addPar("BASE_FILENAME", std::string("rom_input"), &ROM::Instance::baseFileName);
96  p.addPar("MASK_VARS", false, &ROM::Instance::maskROMVars);
97  p.addPar("USE_PORT_DESCRIPTION", 0, &ROM::Instance::usePortDesc);
98 }
99 
101 {}
102 
103 
104 // Class Instance
105 //-----------------------------------------------------------------------------
106 // Function : Instance::processParams
107 // Purpose :
108 // Special Notes :
109 // Scope : public
110 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
111 // Creation Date : 12/11/09
112 //-----------------------------------------------------------------------------
114 {
115  return true;
116 }
117 
118 //-----------------------------------------------------------------------------
119 // Function : Instance::updateTemperature
120 // Purpose :
121 // Special Notes :
122 // Scope : public
123 // Creator : Tom Russo, Component Information and Models
124 // Creation Date : 12/11/09
125 //-----------------------------------------------------------------------------
126 bool Instance::updateTemperature ( const double & temp_tmp)
127 {
128  return true;
129 }
130 
131 //-----------------------------------------------------------------------------
132 // Function : Instance::Instance
133 // Purpose : instance block constructor
134 // Special Notes :
135 // Scope : public
136 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
137 // Creation Date : 12/11/09
138 //-----------------------------------------------------------------------------
140  const Configuration & configuration,
141  const InstanceBlock & IB,
142  Model & ROMiter,
143  const FactoryBlock & factory_block)
144  : DeviceInstance(IB, configuration.getInstanceParameters(), factory_block),
145  model_(ROMiter),
146  isCSparse(false),
147  isGSparse(false),
148  maskROMVars(false),
149  numROMVars(0),
150  baseFileName(""),
151  dt(0),
152  dt_last(0),
153  alph(0),
154  alph_last(0),
155  coef(0),
156  coefLast(0),
157  currentOrder(0),
158  usedOrder(0),
159  lastTimeStepNumber(0)
160 {
161  numExtVars = IB.numExtVars; // we have as many as were specified on the
162  // instance line
163 
164  // Set params to constant default values:
165  setDefaultParams ();
166 
167  // Set params according to instance line and constant defaults from metadata:
168  setParams (IB.params);
169 
170  // Read in reduced-order model.
171  if (given("BASE_FILENAME"))
172  {
173  FILE *c_file, *g_file, *b_file, *l_file;
174  Xyce::IO::MMIO::MM_typecode mat_code;
175  int M=0, N=0, nz=0;
176  std::string cfile = Instance::baseFileName + ".Chat";
177  std::string gfile = Instance::baseFileName + ".Ghat";
178  std::string bfile = Instance::baseFileName + ".Bhat";
179  std::string lfile = Instance::baseFileName + ".Lhat";
180  c_file = fopen(cfile.c_str(), "r");
181  g_file = fopen(gfile.c_str(), "r");
182  b_file = fopen(bfile.c_str(), "r");
183  l_file = fopen(lfile.c_str(), "r");
184  if (c_file == NULL || g_file == NULL || b_file == NULL || l_file == NULL)
185  {
186  UserFatal0(*this) << "Cannot open one of the ROM files: " << cfile << "," << gfile << "," << bfile << "," << lfile;
187  }
188 
189  // Get the input-output numbers from the projected B matrix
190  Xyce::IO::MMIO::mm_read_banner( b_file, &mat_code );
191  Xyce::IO::MMIO::mm_read_mtx_array_size( b_file, &M, &N );
192 
193  // Set number of internal variables to dimension of reduced-order model
195  {
196  numIntVars= 0;
197  numROMVars = 0;
198  numStateVars = M+N;
199  }
200  else
201  {
202  numIntVars = M+N; // Number of ROM variables + current variables for ports
203  numROMVars = M;
204  numStateVars = 0;
205  }
206 
207  numExtVars = N;
208 
209  // Read in B and L matrices.
210  // NOTE: B and L are assumed to be dense arrays at this time, so read them in.
211  Bhat.resize( M*N );
212  Lhat.resize( M*N );
213 
214  // NOTE: The banners and array sizes need to be read in
215  // before the rest of the file can be read.
216  int tmpM=0, tmpN=0;
217  Xyce::IO::MMIO::mm_read_banner( l_file, &mat_code ); // Already read b_file banner
218  Xyce::IO::MMIO::mm_read_mtx_array_size( l_file, &tmpM, &tmpN ); // Already read b_file array size
219 
220  // Read in Bhat and Lhat multivectors
221  for (int i=0; i<M*N; i++)
222  {
223  fscanf(b_file, "%lg\n", &Bhat[i]);
224  fscanf(l_file, "%lg\n", &Lhat[i]);
225  }
226 
227  // Read in C matrix.
228  // NOTE: This matrix may have been sparsified or stored in a symmetric format
229  Xyce::IO::MMIO::mm_read_banner( c_file, &mat_code );
230  isCSparse = mm_is_sparse(mat_code);
231 
232  // If the input matrix C is dense, read in the dense data
233  if (!isCSparse)
234  {
235  // Read in array size.
236  Xyce::IO::MMIO::mm_read_mtx_array_size( c_file, &tmpM, &tmpN );
237  // TODO: Add check of tmpM and tmpN
238 
239  Chat.resize( M*M );
240  if (mm_is_general(mat_code))
241  {
242  // Read in Chat matrix, stored column-wise
243  for (int i=0; i<M*M; i++)
244  {
245  fscanf(c_file, "%lg\n", &Chat[i]);
246  }
247  }
248  else if (mm_is_symmetric(mat_code) || mm_is_skew(mat_code))
249  {
250  int arraySize = M*(M+1)/2; // Only one triangle is stored
251  std::vector<double> Chat_tmp( arraySize ); // Only one triangle is stored
252  // Read in Chat matrix, stored column-wise
253  for (int i=0; i<arraySize; i++)
254  {
255  fscanf(c_file, "%lg\n", &Chat_tmp[i]);
256  }
257  // Copy Chat matrix into full dense matrix
258  for (int j=0; j<M; j++)
259  {
260  for (int i=j; i<M; i++)
261  {
262  double val = Chat_tmp[j*M - j*(j-1)/2 + i - j];
263  Chat[j*M+i] = val;
264  if (i!=j)
265  {
266  if (mm_is_symmetric(mat_code))
267  Chat[i*M+j] = val; // Symmetric
268  else
269  Chat[i*M+j] = -val; // Skew-symmetric
270  }
271  }
272  }
273  }
274  else
275  {
276  UserFatal0(*this) << "Do not recognize the Matrix Market format for Chat (matrix is not general or symmetric)";
277  }
278  }
279  else
280  {
281  int nnz=0;
282  Xyce::IO::MMIO::mm_read_mtx_crd_size( c_file, &tmpM, &tmpN, &nnz );
283  if (nnz==0)
284  {
285  UserFatal0(*this) << "Chat has zero entries according to the Matrix Market file " << cfile;
286  }
287 
288  // Temporary storage for Chat, to read in coordinate format
289  std::vector<double> Chat_tmp( nnz );
290  std::vector<int> rowIdx( nnz ), colIdx( nnz );
291 
292  if (nnz > 0)
293  Xyce::IO::MMIO::mm_read_mtx_crd_data( c_file, tmpM, tmpN, nnz, &rowIdx[0], &colIdx[0], &Chat_tmp[0], mat_code );
294 
295  // Reduce the row and column indices to 0-based indexing and add entries if the matrix is (skew) symmetric.
296  for (int i=0; i<nnz; ++i)
297  {
298  rowIdx[i]--;
299  colIdx[i]--;
300 
301  // If matrices are symmetric or skew symmetric, add entries to the coordinate storage format.
302  if (mm_is_symmetric(mat_code) || mm_is_skew(mat_code))
303  {
304  if (rowIdx[i]!=colIdx[i])
305  {
306  if (mm_is_symmetric(mat_code))
307  {
308  rowIdx.push_back(colIdx[i]);
309  colIdx.push_back(rowIdx[i]);
310  Chat_tmp.push_back(Chat_tmp[i]); // Symmetric
311  }
312  else
313  {
314  rowIdx.push_back(colIdx[i]);
315  colIdx.push_back(rowIdx[i]);
316  Chat_tmp.push_back(-Chat_tmp[i]); // Skew-symmetric
317  }
318  }
319  }
320  }
321 
322  // Use nnz2, the number of nonzeros for the symmetrized matrix, to compute the new CSR format.
323  int nnz2 = rowIdx.size();
324 
325  // Allocate storage for Chat in CSR format
326  Chat.resize( nnz2 );
327  Chat_rowPtr.resize( tmpM+1 );
328  Chat_colIdx.resize( nnz2 );
329 
330  // Convert coordinate (Matrix Market) storage to CSR format
331  if (nnz2 > 0)
332  Trilinos_Util_coocsr( tmpM, nnz2, &Chat_tmp[0], &rowIdx[0], &colIdx[0], &Chat[0], &Chat_colIdx[0], &Chat_rowPtr[0] );
333  }
334 
335  // Read in G matrix.
336  // NOTE: This matrix may have been sparsified or stored in a symmetric format
337  Xyce::IO::MMIO::mm_read_banner( g_file, &mat_code );
338  isGSparse = mm_is_sparse(mat_code);
339 
340  // If the input matrix G is dense, read in the dense data
341  if (!isGSparse)
342  {
343  // Read in array size.
344  Xyce::IO::MMIO::mm_read_mtx_array_size( g_file, &tmpM, &tmpN );
345  // TODO: Add check of tmpM and tmpN
346 
347  Ghat.resize( M*M );
348  if (mm_is_general(mat_code))
349  {
350  // Read in Ghat matrix, stored column-wise
351  for (int i=0; i<M*M; i++)
352  {
353  fscanf(g_file, "%lg\n", &Ghat[i]);
354  }
355  }
356  else if (mm_is_symmetric(mat_code) || mm_is_skew(mat_code))
357  {
358  int arraySize = M*(M+1)/2;
359  std::vector<double> Ghat_tmp( arraySize ); // Only one triangle is stored
360  // Read in Ghat matrix, stored column-wise
361  for (int i=0; i<arraySize; i++)
362  {
363  fscanf(g_file, "%lg\n", &Ghat_tmp[i]);
364  }
365  // Copy Ghat matrix into full dense matrix
366  for (int j=0; j<M; j++)
367  {
368  for (int i=j; i<M; i++)
369  {
370  double val = Ghat_tmp[j*M - j*(j-1)/2 + i - j];
371  Ghat[j*M+i] = val;
372  if (i!=j)
373  {
374  if (mm_is_symmetric(mat_code))
375  Ghat[i*M+j] = val; // Symmetric
376  else
377  Ghat[i*M+j] = -val; // Skew-symmetric
378  }
379  }
380  }
381  }
382  else
383  {
384  UserFatal0(*this) << "Do not recognize the Matrix Market format for Ghat (matrix is not general or symmetric)";
385  }
386  }
387  else
388  {
389  int nnz=0;
390  Xyce::IO::MMIO::mm_read_mtx_crd_size( g_file, &tmpM, &tmpN, &nnz );
391  if (nnz==0)
392  {
393  UserFatal0(*this) << "Ghat has zero entries according to the Matrix Market file " << gfile;
394  }
395 
396  // Temporary storage for Ghat, to read in coordinate format
397  std::vector<double> Ghat_tmp( nnz );
398  std::vector<int> rowIdx( nnz ), colIdx( nnz );
399 
400  if (nnz > 0)
401  Xyce::IO::MMIO::mm_read_mtx_crd_data( g_file, tmpM, tmpN, nnz, &rowIdx[0], &colIdx[0], &Ghat_tmp[0], mat_code );
402 
403  // Reduce the row and column indices to 0-based indexing
404  for (int i=0; i<nnz; ++i)
405  {
406  rowIdx[i]--;
407  colIdx[i]--;
408 
409  // If matrices are symmetric or skew symmetric, add entries to the coordinate storage format.
410  if (mm_is_symmetric(mat_code) || mm_is_skew(mat_code))
411  {
412  if (rowIdx[i]!=colIdx[i])
413  {
414  if (mm_is_symmetric(mat_code))
415  {
416  rowIdx.push_back(colIdx[i]);
417  colIdx.push_back(rowIdx[i]);
418  Ghat_tmp.push_back(Ghat_tmp[i]); // Symmetric
419  }
420  else
421  {
422  rowIdx.push_back(colIdx[i]);
423  colIdx.push_back(rowIdx[i]);
424  Ghat_tmp.push_back(-Ghat_tmp[i]); // Skew-symmetric
425  }
426  }
427  }
428  }
429 
430  // Use nnz2, the number of nonzeros for the symmetrized matrix, to compute the new CSR format.
431  int nnz2 = rowIdx.size();
432 
433  // Allocate storage for Ghat in CSR format
434  Ghat.resize( nnz2 );
435  Ghat_rowPtr.resize( tmpM+1 );
436  Ghat_colIdx.resize( nnz2 );
437 
438  // Convert coordinate (Matrix Market) storage to CSR format
439  if (nnz2 > 0)
440  Trilinos_Util_coocsr( tmpM, nnz2, &Ghat_tmp[0], &rowIdx[0], &colIdx[0], &Ghat[0], &Ghat_colIdx[0], &Ghat_rowPtr[0] );
441  }
442 
443  // Create a union map for Chat and Ghat if both are sparse, otherwise the union is a dense block.
444  if (isCSparse && isGSparse)
445  {
446  CG_rowPtr.resize( M+1 );
447  CG_colIdx.resize( Chat_colIdx.size() + Ghat_colIdx.size() ); // Maximum number of nonzeros in the union
448 
449  std::vector<int>::iterator it;
450  std::vector<int>::iterator itCG = CG_colIdx.begin();
451  std::vector<int>::iterator itChat = Chat_colIdx.begin();
452  std::vector<int>::iterator itGhat = Ghat_colIdx.begin();
453  CG_rowPtr[0] = 0;
454  for (int i=0; i<M; ++i)
455  {
456  // Get the number of nonzero entries for this row
457  int numEntriesChat = Chat_rowPtr[i+1] - Chat_rowPtr[i];
458  int numEntriesGhat = Ghat_rowPtr[i+1] - Ghat_rowPtr[i];
459  // Compute the union of the entries
460  it = set_union( itChat, itChat + numEntriesChat, itGhat, itGhat + numEntriesGhat, itCG );
461  CG_rowPtr[i+1] = CG_rowPtr[i] + (int)(it - itCG);
462  // Check if we need to sort the entries HERE!!!!
463 
464  // Increment the iterators
465  itCG = it;
466  itChat += numEntriesChat;
467  itGhat += numEntriesGhat;
468  }
469  }
470 
471  // Allocate memory for projected matrices
472  Qhat.resize( M );
473  Fhat.resize( M+N );
474  i_ip.resize( N );
475 
477  {
478  Jstamp.resize(N*N);
479  Fstamp.resize(N);
480  G2.resize((M+N)*(M+N));
481  C2.resize((M+N)*(M+N));
482  A2.resize((M+N)*(M+N));
483  A2last.resize((M+N)*(M+N));
484  G2p.resize((M+N)*N);
485  Gp2.resize((M+N)*N);
486  A2sol.resize((M+N)*N);
487 
488  ipiv_A2.resize(M+N);
489  }
490 
491  fclose(c_file);
492  fclose(g_file);
493  fclose(b_file);
494  fclose(l_file);
495 
497  {
498  if (!isGSparse)
499  {
500  // Construct constant matrices for two-level stamp
501  // G2 = [eye(N),-Lhat'; zeros(M,N), Ghat];
502  for(int iy=0; iy<M; iy++) // add Ghat term
503  {
504  for(int ix=0; ix<M; ix++)
505  G2[((N+M+1)*N)+ix+(M+N)*iy] = Ghat[ix+iy*M];
506  }
507  }
508  else
509  {
510  for (int ix=0; ix<M; ix++)
511  {
512  for (int j=Ghat_rowPtr[ix]; j<Ghat_rowPtr[ix+1]; ++j)
513  G2[((N+M+1)*N)+ix+(M+N)*Ghat_colIdx[j]] = Ghat[j];
514  }
515  }
516 
517  for(int ix=0; ix<N; ix++) // add eye(N) term
518  G2[ix+(M+N)*ix] = 1;
519  for(int ix=0; ix<M; ix++) // add Lhat' term
520  {
521  for(int iy=0; iy<N; iy++)
522  G2[((M+N)*N)+iy+(M+N)*ix] = -Lhat[ix+iy*M]; // L is transposed
523  }
524  // C2 = [zeros(N),zeros(N,M); zeros(M,N), Chat];
525  if (!isCSparse)
526  {
527  for(int iy=0; iy<M; iy++) // add Chat term
528  {
529  for(int ix=0; ix<M; ix++)
530  C2[((N+M+1)*N)+ix+(M+N)*iy] = Chat[ix+iy*M];
531  }
532  }
533  else
534  {
535  for (int ix=0; ix<M; ix++)
536  {
537  for (int j=Chat_rowPtr[ix]; j<Chat_rowPtr[ix+1]; ++j)
538  C2[((N+M+1)*N)+ix+(M+N)*Chat_colIdx[j]] = Chat[j];
539  }
540  }
541 
542  // G2p = -[zeros(N); Bhat];
543  for(int iy=0; iy<N; iy++) // add Bhat term
544  {
545  for(int ix=0; ix<M; ix++)
546  G2p[N+ix+(M+N)*iy] = -Bhat[ix+iy*M];
547  }
548 
549  // Gp2 = [eye(N), zeros(M,N)];
550  for(int iy=0; iy<N; iy++) // add eye(N) term
551  {
552  Gp2[iy+(N)*iy] = 1;
553  }
554 
555  // Construct jacStamp
556  if( jacStamp.empty() )
557  {
558  jacStamp.resize(numExtVars);
559 
560  // Put in external variables (node voltages)
561  for (int i=0; i<numExtVars; i++)
562  {
563  jacStamp[i].resize(numExtVars);
564  for(int j=0; j<numExtVars; j++)
565  jacStamp[i][j] = j;
566  }
567  }
568  }
569  else
570  {
571  // Create Jacobian stamp for direct stamping of ROM into full system
572  //
573  // [ Stamps for 0 0 ] [ x_NL ] [ v_NL ]
574  // [ f(x_NL,u_p) I_N 0 ] [ u_p ] = [ v_p ] (a)
575  // [ 0 0 I_N -Lhat^T ] [ i_p ] [ 0 ] (b)
576  // [ 0 -Bhat 0 (Ghat + Chat d/dt) ] [xhat_q] [ 0 ] (c)
577  //
578  if( jacStamp.empty() )
579  {
580  // Resize Jacobian stamp to size of reduced system + 2 x #ports
582 
583  // Equations (a): Put in external variables (port voltages)
584  for (int i=0; i<numExtVars; i++)
585  {
586  jacStamp[i].resize(1);
587  jacStamp[i][0] = numExtVars+i;
588  }
589 
590  // Equations (b): Put in internal variables (size of reduced model + port currents)
591  for (int i=numExtVars; i<2*numExtVars; i++)
592  {
593  jacStamp[i].resize(numROMVars+1);
594  jacStamp[i][0] = i;
595  for (int j=0; j<numROMVars; j++)
596  jacStamp[i][j+1] = 2*numExtVars+j;
597  }
598 
599  // Equations (c): Put in projected system
600  for (int i=2*numExtVars; i<numIntVars+numExtVars; i++)
601  {
602  int numEntries = numIntVars;
603  if (isCSparse && isGSparse)
604  numEntries = numExtVars+(CG_rowPtr[i-2*numExtVars+1]-CG_rowPtr[i-2*numExtVars]);
605  jacStamp[i].resize( numEntries );
606 
607  for (int j=0; j<numExtVars; j++)
608  jacStamp[i][j] = j;
609 
610  // Insert entries for (Ghat + Chat d/dt)
611  if (isCSparse && isGSparse)
612  {
613  for (int j=numExtVars; j<numEntries; j++)
614  jacStamp[i][j] = 2*numExtVars + CG_colIdx[CG_rowPtr[i-2*numExtVars] + j - numExtVars];
615  }
616  else
617  {
618  for (int j=numExtVars; j<numEntries; j++)
619  jacStamp[i][j] = numExtVars + j;
620  }
621  }
622  }
623  }
624  }
625 
626  // Calculate any parameters specified as expressions:
627 
629 
630  // calculate dependent (ie computed) params:
631 
632  processParams ();
633 }
634 
635 //-----------------------------------------------------------------------------
636 // Function : Instance::~Instance
637 // Purpose : destructor
638 // Special Notes :
639 // Scope : public
640 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
641 // Creation Date : 3/16/00
642 //-----------------------------------------------------------------------------
644 {
645 }
646 
647 // Additional Declarations
648 
649 //-----------------------------------------------------------------------------
650 // Function : Instance::registerLIDs
651 // Purpose :
652 // Special Notes :
653 // Scope : public
654 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
655 // Creation Date : 6/20/02
656 //-----------------------------------------------------------------------------
657 void Instance::registerLIDs( const std::vector<int> & intLIDVecRef,
658  const std::vector<int> & extLIDVecRef)
659 {
660  AssertLIDs(intLIDVecRef.size() == numIntVars);
661  AssertLIDs(extLIDVecRef.size() == numExtVars);
662 
663  // Copy over the local ID lists:
664  intLIDVec = intLIDVecRef;
665  extLIDVec = extLIDVecRef;
666 
667  // Now use these lists to obtain the indices into the linear algebra
668  // entities. This assumes an order. For the matrix indices, first do the
669  // rows.
670 
671  // Obtain indices for internal variables
672  li_ROM.resize(numROMVars);
673  if(usePortDesc==0)
674  {
675  for (int i=0; i<numROMVars; i++)
676  li_ROM[i] = intLIDVec[i+numExtVars];
677  }
678 #ifdef Xyce_DEBUG_DEVICE
679  if (getDeviceOptions().debugLevel > 0 )
680  {
681  Xyce::dout() << section_divider << std::endl;
682 
683  Xyce::dout() << "::registerLIDs:\n";
684  Xyce::dout() << " name = " << getName() << std::endl;
685 
686  Xyce::dout() << "\nsolution indices:\n";
687  for (int i=0; i<numExtVars; ++i)
688  Xyce::dout() << " li_up[" << i << "] = " << extLIDVec[i] << std::endl;
689  if (usePortDesc==0)
690  {
691  for (int i=0; i<numExtVars; ++i)
692  Xyce::dout() << " li_ip[" << i << "] = " << intLIDVec[i] << std::endl;
693  }
694  for (int i=0; i<numROMVars; i++)
695  Xyce::dout() << " li_ROM[" << i << "] = " << li_ROM[i] << std::endl;
696 
697  Xyce::dout() << section_divider << std::endl;
698  }
699 #endif
700 
701 }
702 
703 //-----------------------------------------------------------------------------
704 // Function : Instance::registerStateLIDs
705 // Purpose :
706 // Special Notes :
707 // Scope : public
708 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
709 // Creation Date : 6/20/02
710 //-----------------------------------------------------------------------------
711 void Instance::registerStateLIDs( const std::vector<int> & staLIDVecRef)
712 {
713  AssertLIDs(staLIDVecRef.size() == numStateVars);
714 
715  // Copy over the global ID lists:
716  staLIDVec = staLIDVecRef;
717 
718  li_state.resize(numStateVars, 0);
719  for (int ix=0; ix<numStateVars; ix++) {
720  li_state[ix] = staLIDVec[ix];
721  }
722 }
723 
724 //-----------------------------------------------------------------------------
725 // Function : Instance::getIntNameMap
726 // Purpose :
727 // Special Notes :
728 // Scope : public
729 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
730 // Creation Date : 05/13/05
731 //-----------------------------------------------------------------------------
732 std::map<int,std::string> & Instance::getIntNameMap ()
733 {
734  // set up the internal name map, if it hasn't been already.
735  if (intNameMap.empty ())
736  {
737  std::string tmpstr;
738  if (numIntVars > 0) // Then add the current variables at the ports
739  {
740  for (int i=0; i<numExtVars; i++)
741  {
742  tmpstr = getName()+"_ip_Node"+Teuchos::Utils::toString(i+1);
743  spiceInternalName (tmpstr);
744  intNameMap[intLIDVec[i]] = tmpstr;
745  }
746  }
747  for (int i=0; i<numROMVars; i++)
748  {
749  tmpstr = getName()+"_ROM_Node"+Teuchos::Utils::toString(i+1);
750  spiceInternalName (tmpstr);
751  intNameMap[li_ROM[i]] = tmpstr;
752  }
753  }
754 
755  return intNameMap;
756 }
757 
758 
759 //-----------------------------------------------------------------------------
760 // Function : Instance::jacobianStamp
761 // Purpose :
762 // Special Notes :
763 // Scope : public
764 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
765 // Creation Date : 08/27/02
766 //-----------------------------------------------------------------------------
767 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
768 {
769  return jacStamp;
770 }
771 
772 //-----------------------------------------------------------------------------
773 // Function : Instance::registerJacLIDs
774 // Purpose :
775 // Special Notes :
776 // Scope : public
777 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
778 // Creation Date : 08/27/02
779 //-----------------------------------------------------------------------------
780 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
781 {
782 
783  DeviceInstance::registerJacLIDs( jacLIDVec );
784 
785  if(usePortDesc>0)
786  {
787  AEqu_NodeOffset.resize(numExtVars);
788  for (int i=0; i<numExtVars; i++)
789  {
790  AEqu_NodeOffset[i].resize(numExtVars);
791  for (int j=0; j<numExtVars; j++)
792  {
793  AEqu_NodeOffset[i][j] = jacLIDVec[i][j];
794  }
795  }
796  }
797  else
798  {
801  for (int i=0; i<numExtVars; i++)
802  {
803  AEqu_up_NodeOffset[i] = jacLIDVec[i][0];
804  AEqu_ip_NodeOffset[i] = jacLIDVec[numExtVars+i][0];
805  }
806 
807  // Get the offsets for -L^T
809  for (int i=0; i<numROMVars; i++)
810  {
811  ROMEqu_Lt_NodeOffset[i] = jacLIDVec[numExtVars][i+1];
812  }
813 
814  // Get the offsets for -B
815  ROMEqu_B_NodeOffset.resize(numExtVars*numROMVars);
816  for (int i=0; i<numROMVars; i++)
817  {
818  for (int j=0; j<numExtVars; j++)
819  ROMEqu_B_NodeOffset[i*numExtVars+j] = jacLIDVec[2*numExtVars+i][j];
820  }
821 
822  // Get the offsets for C d/dt
823  // If the matrix is sparse, then an offset will be stored for each nonzero.
824  if (isCSparse)
825  {
826  ROMEqu_C_NodeOffset.resize(Chat_rowPtr[numROMVars]);
827  for (int i=0; i<numROMVars; i++)
828  {
829  int nnz = CG_rowPtr[i+1]-CG_rowPtr[i];
830  int CrowPtr = Chat_rowPtr[i], Cnnz = Chat_rowPtr[i+1]-Chat_rowPtr[i];
831  for (int j=0, Cidx=0; j<nnz && Cidx<Cnnz; j++)
832  {
833  int colIdx = CG_colIdx[CG_rowPtr[i]+j];
834  if (colIdx == Chat_colIdx[CrowPtr])
835  {
836  ROMEqu_C_NodeOffset[CrowPtr++] = jacLIDVec[2*numExtVars+i][numExtVars+j];
837  Cidx++;
838  }
839  }
840  }
841  }
842 
843  // Get the offsets for G
844  // If the matrix is sparse, then an offset will be stored for each nonzero.
845  if (isGSparse)
846  {
847  ROMEqu_G_NodeOffset.resize(Ghat_rowPtr[numROMVars]);
848  for (int i=0; i<numROMVars; i++)
849  {
850  int nnz = CG_rowPtr[i+1]-CG_rowPtr[i];
851  int GrowPtr = Ghat_rowPtr[i], Gnnz = Ghat_rowPtr[i+1]-Ghat_rowPtr[i];
852  for (int j=0, Gidx=0; j<nnz && Gidx<Gnnz; j++)
853  {
854  int colIdx = CG_colIdx[CG_rowPtr[i]+j];
855  if (colIdx == Ghat_colIdx[GrowPtr])
856  {
857  ROMEqu_G_NodeOffset[GrowPtr++] = jacLIDVec[2*numExtVars+i][numExtVars+j];
858  Gidx++;
859  }
860  }
861  }
862  }
863 
864  // If either C or G is dense, we need these node offsets, which assume the storage is contiguous.
865  if (!isCSparse || !isGSparse)
866  {
867  ROMEqu_GpC_NodeOffset.resize(numROMVars);
868  for (int i=0; i<numROMVars; i++)
869  {
870  ROMEqu_GpC_NodeOffset[i] = jacLIDVec[2*numExtVars][numExtVars+i];
871  }
872  }
873 
874 #ifdef Xyce_DEBUG_DEVICE
875  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
876  {
877  Xyce::dout() << Xyce::section_divider << std::endl;
878  Xyce::dout() << "Instance::registerJacLIDs\n";
879  if (usePortDesc==0)
880  {
881  Xyce::dout() << " AEqu_up_NodeOffset: ";
882  for (int i=0; i<numExtVars; i++)
883  Xyce::dout() << AEqu_up_NodeOffset[i] << " ";
884  Xyce::dout() << std::endl;
885  Xyce::dout() << " AEqu_ip_NodeOffset: ";
886  for (int i=0; i<numExtVars; i++)
887  Xyce::dout() << AEqu_ip_NodeOffset[i] << " ";
888  Xyce::dout() << std::endl;
889  Xyce::dout() << " AROMEqu_Lt_NodeOffset: ";
890  for (int i=0; i<numROMVars; i++)
891  Xyce::dout() << ROMEqu_Lt_NodeOffset[i] << " ";
892  Xyce::dout() << std::endl;
893  Xyce::dout() << " AROMEqu_B_NodeOffset: " << std::endl;
894  for (int i=0; i<numROMVars; i++)
895  {
896  for (int j=0; j<numExtVars; j++)
897  Xyce::dout() << ROMEqu_B_NodeOffset[i*numExtVars+j] << " ";
898  Xyce::dout() << std::endl;
899  }
900  Xyce::dout() << " AROMEqu_GpC_NodeOffset: ";
901  for (int i=0; i<numROMVars; i++)
902  Xyce::dout() << ROMEqu_GpC_NodeOffset[i] << " ";
903  Xyce::dout() << std::endl;
904  }
905  Xyce::dout() << Xyce::section_divider << std::endl;
906  }
907 #endif
908  }
909 }
910 
911 //-----------------------------------------------------------------------------
912 // Function : Instance::setupPointers
913 // Purpose :
914 // Special Notes :
915 // Scope : public
916 // Creator : Heidi Thornquist, SNL
917 // Creation Date : 11/30/08
918 //-----------------------------------------------------------------------------
920 {
921 
922 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
923  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
924  N_LAS_Matrix & dQdx = *(extData.dQdxMatrixPtr);
925 
926  // Get pointers for KCL equations and Ghat, Lhat, and Bhat
927  if(usePortDesc==0)
928  {
929  fEqu_up_NodePtr.resize(numExtVars);
930  for (int i=0; i<numExtVars; ++i)
931  {
932  fEqu_up_NodePtr[i] = &(dFdx[extLIDVec[i]][AEqu_up_NodeOffset[i]]);
933  }
934 
935  fEqu_ip_NodePtr.resize(numExtVars);
936  for (int i=0; i<numExtVars; ++i)
937  {
938  fEqu_ip_NodePtr[i] = &(dFdx[intLIDVec[i]][AEqu_ip_NodeOffset[i]]);
939  }
940 
941  // Get pointers for Ghat (assuming contiguous), only if Ghat is not sparse.
942  if (isGSparse)
943  {
945  for (int i=0; i<numROMVars; ++i)
946  {
947  for (int j=Ghat_rowPtr[i]; j<Ghat_rowPtr[i+1]; j++)
948  {
950  }
951  }
952  }
953  else
954  {
956  for (int i=0; i<numROMVars; ++i)
957  {
959  }
960  }
961 
962  // Lhat (assuming contiguous)
963  fROMEqu_Lhat_VarsPtrs.resize(numExtVars);
964  for (int i=0; i<numExtVars; ++i)
965  {
967  }
968 
969  // Bhat (these are not guaranteed to be contiguous)
970  fROMEqu_Bhat_VarsPtrs.resize(numExtVars*numROMVars);
971  for (int i=0; i<numROMVars; ++i)
972  {
973  for (int j=0; j<numExtVars; ++j)
974  {
975  fROMEqu_Bhat_VarsPtrs[numExtVars*i+j]=&(dFdx[li_ROM[i]][ROMEqu_B_NodeOffset[i*numExtVars+j]]);
976  }
977  }
978 
979  // Get pointers for Chat (assuming contiguous), only if Chat is not sparse.
980  if (isCSparse)
981  {
982  qROMEqu_Chat_VarsPtrs.resize(Chat_rowPtr[numROMVars]);
983  for (int i=0; i<numROMVars; ++i)
984  {
985  for (int j=Chat_rowPtr[i]; j<Chat_rowPtr[i+1]; j++)
986  {
988  }
989  }
990  }
991  else
992  {
993  qROMEqu_Chat_VarsPtrs.resize(numROMVars);
994  for (int i=0; i<numROMVars; ++i)
996  }
997  }
998 #endif
999 }
1000 
1001 //-----------------------------------------------------------------------------
1002 // Function : Instance::updatePrimaryState
1003 // Purpose :
1004 // Special Notes :
1005 // Scope : public
1006 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1007 // Creation Date : 01/29/01
1008 //-----------------------------------------------------------------------------
1010 {
1011  double * solVec = extData.nextSolVectorRawPtr;
1012  double * staVec = extData.nextStaVectorRawPtr;
1013  std::vector<double> v_up(numExtVars);
1014  for (int i=0; i<numExtVars; ++i)
1015  {
1016  v_up[i] = solVec[extLIDVec[i]];
1017  Fhat[i] = solVec[intLIDVec[i]];
1018  i_ip[i] = solVec[intLIDVec[i]];
1019  }
1020  double * xhat = &solVec[li_ROM[0]];
1021 
1022  Teuchos::BLAS<int, double> blas;
1023 
1024  // Compute Fhat[0:numExtVars-1] = i_ip - Lhat'*xhat
1025  blas.GEMV( Teuchos::TRANS, numROMVars, numExtVars, -1.0, &Lhat[0], numROMVars, xhat, 1, 1.0, &Fhat[0], 1 );
1026 
1027  // Compute Fhat[numExtVars:numIntVars] = Ghat*xhat - Bhat*v_up
1028  if (isGSparse)
1029  N_LAS_Util::crsAxpy( numROMVars, 1.0, &Ghat[0], &Ghat_rowPtr[0], &Ghat_colIdx[0], xhat, 0.0, &Fhat[numExtVars] );
1030  else
1031  blas.GEMV( Teuchos::NO_TRANS, numROMVars, numROMVars, 1.0, &Ghat[0], numROMVars, xhat, 1, 0.0, &Fhat[numExtVars], 1 );
1032  blas.GEMV( Teuchos::NO_TRANS, numROMVars, numExtVars, -1.0, &Bhat[0], numROMVars, &v_up[0], 1, 1.0, &Fhat[numExtVars], 1 );
1033 
1034  // Compute Qhat = Chat * xhat
1035  if (isCSparse)
1036  N_LAS_Util::crsAxpy( numROMVars, 1.0, &Chat[0], &Chat_rowPtr[0], &Chat_colIdx[0], xhat, 0.0, &Qhat[0] );
1037  else
1038  blas.GEMV( Teuchos::NO_TRANS, numROMVars, numROMVars, 1.0, &Chat[0], numROMVars, xhat, 1, 0.0, &Qhat[0], 1 );
1039 
1040 #ifdef Xyce_DEBUG_DEVICE
1041  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1042  {
1043  Xyce::dout() << " ----------------------------------" << std::endl;
1044  Xyce::dout() << "Instance::updatePrimaryState:" << std::endl;
1045  }
1046 #endif
1047 
1048  return true;
1049 }
1050 
1051 //-----------------------------------------------------------------------------
1052 // Function : Instance::loadDeviceMask
1053 //
1054 // Purpose : Loads the zero elements of the device mask
1055 //
1056 // Special Notes : elements of the error vector associated with zero
1057 // elements of the mask will not be included in weighted
1058 // norms by the time integrator.
1059 //
1060 // Scope : public
1061 // Creator : Keith Santarelli, SNL, Electrical and Microsystems Modeling
1062 // Creation Date : 03/12/08
1063 //-----------------------------------------------------------------------------
1065 {
1066  if (maskROMVars)
1067  {
1068  N_LAS_Vector * maskVectorPtr = extData.deviceMaskVectorPtr;
1069 
1070  for (int i=0; i<numROMVars; i++)
1071  {
1072  (*maskVectorPtr)[li_ROM[i]] = 0.0;
1073  }
1074  }
1075  return (true);
1076 }
1077 
1078 //-----------------------------------------------------------------------------
1079 // Function : Instance::loadDAEQVector
1080 //
1081 // Purpose : Loads the Q-vector contributions for a single
1082 // ROM instance.
1083 //
1084 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1085 // which the system of equations is represented as:
1086 //
1087 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1088 //
1089 // Scope : public
1090 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1091 // Creation Date : 01/24/03
1092 //-----------------------------------------------------------------------------
1094 {
1095  double * qVec = extData.daeQVectorRawPtr;
1096  for (int i=0; i<numROMVars; i++)
1097  {
1098  qVec[li_ROM[i]] += Qhat[i];
1099  }
1100  return true;
1101 }
1102 
1103 //-----------------------------------------------------------------------------
1104 // Function : Instance::loadDAEFVector
1105 //
1106 // Purpose : Loads the F-vector contributions for a single
1107 // ROM instance.
1108 //
1109 // Special Notes :
1110 //
1111 // Scope : public
1112 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1113 // Creation Date : 01/24/03
1114 //-----------------------------------------------------------------------------
1116 {
1117  double * fVec = extData.daeFVectorRawPtr;
1118 
1119  // Load F vector
1120  for (int i=0; i<numExtVars; ++i)
1121  {
1122  fVec[extLIDVec[i]] += i_ip[i];
1123  fVec[intLIDVec[i]] += Fhat[i];
1124  }
1125  for (int i=0; i<numROMVars; i++)
1126  {
1127  fVec[li_ROM[i]] += Fhat[numExtVars+i];
1128  }
1129 
1130  return true;
1131 }
1132 
1133 //-----------------------------------------------------------------------------
1134 // Function : Instance::loadDAEdQdx
1135 //
1136 // Purpose : Loads the dQdx-matrix contributions for a single
1137 // ROM instance.
1138 //
1139 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1140 // which the system of equations is represented as:
1141 //
1142 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1143 //
1144 // Scope : public
1145 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1146 // Creation Date : 03/05/04
1147 //-----------------------------------------------------------------------------
1149 {
1150  N_LAS_Matrix & dQdx = *(extData.dQdxMatrixPtr);
1151 
1152  // Load Chat portion of dQ/dx
1153  for (int i=0; i<numROMVars; i++)
1154  {
1155  if (isCSparse)
1156  {
1157  for (int j=Chat_rowPtr[i]; j<Chat_rowPtr[i+1]; j++)
1158  {
1159 
1160  dQdx[li_ROM[i]][ROMEqu_C_NodeOffset[j]] += Chat[j];
1161  }
1162  }
1163  else
1164  {
1165  for (int j=0; j<numROMVars; j++)
1166  {
1167 
1168  dQdx[li_ROM[i]][ROMEqu_GpC_NodeOffset[j]] += Chat[j*numROMVars + i];
1169  }
1170  }
1171  }
1172  return true;
1173 }
1174 
1175 //-----------------------------------------------------------------------------
1176 // Function : Instance::loadDAEdFdx ()
1177 //
1178 // Purpose : Loads the F-vector contributions for a single
1179 // ROM instance.
1180 //
1181 // Special Notes :
1182 //
1183 // Scope : public
1184 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1185 // Creation Date : 03/05/04
1186 //-----------------------------------------------------------------------------
1188 {
1189  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
1190 
1191  for (int i=0; i<numExtVars; ++i)
1192  {
1193 
1194  dFdx[extLIDVec[i]][AEqu_up_NodeOffset[i]] += 1.0;
1195 
1196  dFdx[intLIDVec[i]][AEqu_ip_NodeOffset[i]] += 1.0;
1197  }
1198 
1199  // Load -Lhat portion of dF/dx
1200  for (int j=0; j<numROMVars; j++)
1201  {
1202  for (int i=0; i<numExtVars; i++)
1203  {
1204 
1205  dFdx[intLIDVec[i]][ROMEqu_Lt_NodeOffset[j]] -= Lhat[j];
1206  }
1207  }
1208 
1209  // Load -Bhat portion of dF/dx
1210  for (int i=0; i<numROMVars; i++)
1211  {
1212  for (int j=0; j<numExtVars; j++)
1213  {
1214 
1215  dFdx[li_ROM[i]][ROMEqu_B_NodeOffset[i*numExtVars+j]] -= Bhat[j*numROMVars + i];
1216  }
1217  }
1218 
1219  // Load Ghat portion of dF/dx
1220  for (int i=0; i<numROMVars; i++)
1221  {
1222  if (isGSparse)
1223  {
1224  for (int j=Ghat_rowPtr[i]; j<Ghat_rowPtr[i+1]; j++)
1225  {
1226 
1227  dFdx[li_ROM[i]][ROMEqu_G_NodeOffset[j]] += Ghat[j];
1228  }
1229  }
1230  else
1231  {
1232  for (int j=0; j<numROMVars; j++)
1233  {
1234 
1235  dFdx[li_ROM[i]][ROMEqu_GpC_NodeOffset[j]] += Ghat[j*numROMVars + i];
1236  }
1237  }
1238  }
1239  return true;
1240 }
1241 
1242 //-----------------------------------------------------------------------------
1243 // Function : Instance::setIC
1244 // Purpose :
1245 // Special Notes :
1246 // Scope : public
1247 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
1248 // Creation Date : 01/10/02
1249 //-----------------------------------------------------------------------------
1251 {
1252  return true;
1253 }
1254 
1255 //-----------------------------------------------------------------------------
1256 // Function : Instance::varTypes
1257 // Purpose :
1258 // Special Notes :
1259 // Scope : public
1260 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
1261 // Creation Date : 02/17/04
1262 //-----------------------------------------------------------------------------
1263 void Instance::varTypes( std::vector<char> & varTypeVec )
1264 {
1265 }
1266 
1267 
1268 // Class Model
1269 
1270 //-----------------------------------------------------------------------------
1271 // Function : Model::processParams
1272 // Purpose :
1273 // Special Notes :
1274 // Scope : public
1275 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1276 // Creation Date : 6/03/02
1277 //-----------------------------------------------------------------------------
1279 {
1280  return true;
1281 }
1282 
1283 //----------------------------------------------------------------------------
1284 // Function : Model::processInstanceParams
1285 // Purpose :
1286 // Special Notes :
1287 // Scope : public
1288 // Creator : Dave Shirely, PSSI
1289 // Creation Date : 03/23/06
1290 //----------------------------------------------------------------------------
1292 {
1293  std::vector<Instance*>::iterator iter;
1294  std::vector<Instance*>::iterator first = instanceContainer.begin();
1295  std::vector<Instance*>::iterator last = instanceContainer.end();
1296 
1297  for (iter=first; iter!=last; ++iter)
1298  {
1299  (*iter)->processParams();
1300  }
1301 
1302  return true;
1303 }
1304 
1305 //-----------------------------------------------------------------------------
1306 // Function : Model::Model
1307 // Purpose : block constructor
1308 // Special Notes :
1309 // Scope : public
1310 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1311 // Creation Date : 5/17/00
1312 //-----------------------------------------------------------------------------
1313 
1315  const Configuration & configuration,
1316  const ModelBlock & MB,
1317  const FactoryBlock & factory_block)
1318  : DeviceModel(MB, configuration.getModelParameters(), factory_block)
1319 {
1320 
1321  // Set params to constant default values:
1322  setDefaultParams ();
1323 
1324  // Set params according to .model line and constant defaults from metadata:
1325  setModParams (MB.params);
1326 
1327  // Calculate any parameters specified as expressions:
1329 
1330  // calculate dependent (ie computed) params and check for errors:
1331  processParams ();
1332 }
1333 
1334 //-----------------------------------------------------------------------------
1335 // Function : Model::Model
1336 // Purpose : destructor
1337 // Special Notes :
1338 // Scope : public
1339 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1340 // Creation Date : 3/16/00
1341 //-----------------------------------------------------------------------------
1342 
1344 {
1345  std::vector<Instance*>::iterator iter;
1346  std::vector<Instance*>::iterator first = instanceContainer.begin();
1347  std::vector<Instance*>::iterator last = instanceContainer.end();
1348 
1349  for (iter=first; iter!=last; ++iter)
1350  {
1351  delete (*iter);
1352  }
1353 
1354 }
1355 
1356 //-----------------------------------------------------------------------------
1357 // Function : Model::printOutInstances
1358 // Purpose : debugging tool.
1359 // Special Notes :
1360 // Scope : public
1361 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1362 // Creation Date : 4/03/00
1363 //-----------------------------------------------------------------------------
1364 
1365 std::ostream &Model::printOutInstances(std::ostream &os) const
1366 {
1367  std::vector<Instance*>::const_iterator iter;
1368  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
1369  std::vector<Instance*>::const_iterator last = instanceContainer.end();
1370 
1371  int i,isize;
1372 
1373  isize = instanceContainer.size();
1374  os << std::endl;
1375  os << "Number of ROM instances: " << isize << std::endl;
1376  os << " name\t\tmodelName\tParameters" << std::endl;
1377 
1378  for (i = 0, iter = first; iter != last; ++iter, ++i)
1379  {
1380  os << " " << i << ": " << (*iter)->getName() << "\t";
1381  os << getName();
1382  os << std::endl;
1383  }
1384 
1385  os << std::endl;
1386 
1387  return os;
1388 }
1389 
1390 //-----------------------------------------------------------------------------
1391 // Function : Model::forEachInstance
1392 // Purpose :
1393 // Special Notes :
1394 // Scope : public
1395 // Creator : David Baur
1396 // Creation Date : 2/4/2014
1397 //-----------------------------------------------------------------------------
1398 /// Apply a device instance "op" to all instances associated with this
1399 /// model
1400 ///
1401 /// @param[in] op Operator to apply to all instances.
1402 ///
1403 ///
1404 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
1405 {
1406  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1407  op(*it);
1408 }
1409 
1410 
1411 // ROM Master functions:
1412 
1413 //-----------------------------------------------------------------------------
1414 // Function : Master::updateState
1415 // Purpose :
1416 // Special Notes :
1417 // Scope : public
1418 // Creator : Heidi Thornquist, SNL
1419 // Creation Date : 11/26/08
1420 //-----------------------------------------------------------------------------
1421 bool Master::updateState (double * solVec, double * staVec, double * stoVec)
1422 {
1423 #ifdef Xyce_DEBUG_DEVICE
1424  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1425  {
1426  Xyce::dout() << " ----------------------------------" << std::endl;
1427  Xyce::dout() << " Master::updateState: " << std::endl;
1428  }
1429 #endif
1430 
1431 #ifdef _OMP
1432 #pragma omp parallel for
1433 #endif
1434  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1435  {
1436  Instance & ci = *(*it);
1437 
1438  Teuchos::BLAS<int, double> blas;
1439  if (ci.usePortDesc>0) // TWO-LEVEL DEVICE STAMPS
1440  {
1441  const char test = 'N';
1442  int MN = ci.numStateVars;
1443  int N = ci.numExtVars;
1444  int M = MN-N;
1445 
1446  // Check if this is the first device call after a successful timestep
1447  int sameTimeStep=0;
1449  if (ci.lastTimeStepNumber==ci.getSolverState().timeStepNumber) {sameTimeStep=1;}
1450 
1451  //********************************************************************
1452  // Set up the coefficients for discretization for the INNER solve
1453  //********************************************************************
1454  if (ci.usePortDesc==1) {// DYNAMIC ORDER SELECTION
1455  if (sameTimeStep==0) {ci.coefLast = ci.coef;}
1456  ci.coef = (1/ci.getSolverState().currentOrder);
1457  if (ci.getSolverState().currentOrder==0) { ci.coef=1; } // Force BE
1458  if (ci.getSolverState().usedOrder==0) { ci.coefLast = 1; } // Force BE
1459  }
1460  else if (ci.usePortDesc==2) { // BACKWARD EULER
1461  ci.coef=1;
1462  ci.coefLast = 1;
1463  }
1464  else if (ci.usePortDesc==3) { // TRAP
1465  ci.coef=0.5;
1466  ci.coefLast = 0.5;
1467  }
1468  else
1469  Xyce::dout() << "Bad 'USE_PORT_DESCRIPTION' flag" << std::endl;
1470 
1471 
1472  // Get alph=1/dt for current and last time steps
1473  if (sameTimeStep==0) {ci.alph_last = ci.alph;}
1474  ci.alph=1/ci.getSolverState().currTimeStep;
1475  if (ci.getSolverState().dcopFlag==1) { ci.alph=0.0; ci.alph_last=0.0; }
1476  if (ci.getSolverState().timeStepNumber==0) { ci.alph_last=0.0; }
1477 
1478 
1479  //********************************************************************
1480  // Load port and internal state variables
1481  //********************************************************************
1482  std::vector<double> lastStaVec, currStaVec, nextStaVec; // Internal states
1483  lastStaVec.resize(M+N,0);
1484  currStaVec.resize(M+N,0);
1485  nextStaVec.resize(M+N,0);
1486  //for(int ix=0; ix<(M+N); ++ix) { lastStaVec[ix] = (*ci.extData.lastStaVectorPtr)[ix]; } // WRONG
1487  for(int ix=0; ix<(M+N); ++ix) { lastStaVec[ix] = (*ci.extData.lastStaVectorPtr)[ ci.li_state[ix] ]; }
1488  std::vector<double> lastPortVec, currPortVec, nextPortVec; // Port voltages
1489  lastPortVec.resize(N,0);
1490  currPortVec.resize(N,0);
1491  nextPortVec.resize(N,0);
1492  for(int ix=0; ix<N; ++ix)
1493  {
1494  lastPortVec[ix] = (*ci.extData.lastSolVectorPtr)[ci.extLIDVec[ix]];
1495  currPortVec[ix] = (*ci.extData.currSolVectorPtr)[ci.extLIDVec[ix]];
1496  nextPortVec[ix] = solVec[ci.extLIDVec[ix]];
1497  }
1498 
1499  /*
1500  std::vector<int> lidState = set this up in registerStateLIDs
1501  localState[ix] = ci.extradata.currState[ ci.lidState[ix] ];
1502  ci.extData.currState[ ci.lidState[ix] ] = localState[ix];
1503  */
1504 
1505  // Begin math stuff
1506  Teuchos::LAPACK<int,double> lapack;
1507  std::vector<int> ipiv_A2last (M+N, 0);
1508  int info_A2, info_A2last, info2_A2, info2_A2last;
1509 
1510 
1511  //****************************************************************
1512  // Compute, or load, old internal state (currStaVec) [INNER SOLVE]
1513  // x2[t] = A2\(-coef*G2p*xp[t] - (1-coef)*G2p*xp[t-1] - [(1-coef)*G2-C2/dt]*x2[t-1])
1514  //******************************************************
1515  int updateCurrStaVec=0;
1516  // if (ci.getSolverState().newtonIter==0) { updateCurrStaVec=1; }
1517  if (sameTimeStep==0) {updateCurrStaVec=1; }
1518  if (updateCurrStaVec==1) { // compute new `last' state
1519  blas.GEMV( Teuchos::NO_TRANS,N+M,N+M,-(1-ci.coefLast),&ci.G2[0],M+N,&lastStaVec[0],1,0.0,&currStaVec[0],1 ); // -(1-coefLast)*G2*lastStaVec
1520  blas.GEMV( Teuchos::NO_TRANS,N+M,N+M,ci.alph_last,&ci.C2[0],M+N,&lastStaVec[0],1,1.0,&currStaVec[0],1 ); // C2/dtlast*lastStaVec
1521  blas.GEMV( Teuchos::NO_TRANS,N+M,N,-ci.coefLast,&ci.G2p[0],N+M,&currPortVec[0],1, 1.0,&currStaVec[0],1 ); // -coefLast*G2p*currPortVec
1522  blas.GEMV( Teuchos::NO_TRANS,N+M,N,-(1-ci.coefLast),&ci.G2p[0],N+M,&lastPortVec[0],1,1.0,&currStaVec[0],1 ); // -(1-coefLast)*G2p*lastPortVec
1523  int useOldA2=1;
1524  if (ci.getSolverState().timeStepNumber<2) { useOldA2=0; }
1525  if (ci.lastTimeStepNumber==ci.getSolverState().timeStepNumber) { useOldA2=0; }
1526  if (useOldA2==1) // use [previously factored] A2 as A2last
1527  lapack.GETRS(test, M+N, 1, &ci.A2[0], M+N, &ci.ipiv_A2[0], &currStaVec[0], M+N, &info2_A2); // A2\(xtmp)
1528  else { // compute new A2last
1529  for(int ix=0; ix<(M+N)*(M+N); ix++) { ci.A2last[ix]= (ci.alph_last*ci.C2[ix]) + (ci.coefLast*ci.G2[ix]); } // A2 using previous dt
1530  lapack.GETRF( M+N, M+N, &ci.A2last[0], M+N, &ipiv_A2last[0], &info_A2last); // factor A2last
1531  lapack.GETRS(test, M+N, 1, &ci.A2last[0], M+N, &ipiv_A2last[0], &currStaVec[0], M+N, &info2_A2last); // A2last\(xtmp)
1532  }
1533  for(int ix=0; ix<(M+N); ++ix) { (*ci.extData.currStaVectorPtr)[ ci.li_state[ix] ] = currStaVec[ix]; } // Store answer
1534  }
1535  else
1536  { // Load currStaVec
1537  for(int ix=0; ix<(M+N); ++ix) { currStaVec[ix] = (*ci.extData.currStaVectorPtr)[ ci.li_state[ix] ]; }
1538  }
1539 
1540 
1541  //**************************************************
1542  // construct A2 and Jacobian (Jstamp), if necessary
1543  // Jstamp = -Gp2*(A2\(coef*G2p)) = -Gp2 * A2sol
1544  //**************************************************
1545  int updateA2 = 1;
1546  if (ci.getSolverState().timeStepNumber>2){
1547  if (ci.getSolverState().newtonIter>0) { updateA2=0; }
1548  if (ci.alph==ci.alph_last) { if (ci.coef==ci.coefLast) { updateA2=0; }}}
1549  if (updateA2==1) {
1550  for(int ix=0; ix<(M+N)*(M+N); ix++) { ci.A2[ix]= (ci.alph*ci.C2[ix]) + (ci.coef*ci.G2[ix]); } // A2 = 1/dt*C2 + coef*G2;
1551  lapack.GETRF( M+N, M+N, &ci.A2[0], M+N, &ci.ipiv_A2[0], &info_A2); // Factor A2
1552  for(int ix=0; ix<(M+N)*N; ix++) { ci.A2sol[ix] = ci.coef * ci.G2p[ix]; } // copy to RHS vector
1553  lapack.GETRS(test, M+N, N, &ci.A2[0], M+N, &ci.ipiv_A2[0], &ci.A2sol[0], M+N, &info2_A2);
1554  blas.GEMM(Teuchos::NO_TRANS, Teuchos::NO_TRANS, N, N, M+N, -1.0,&ci.Gp2[0],N,&ci.A2sol[0],M+N,0.0,&ci.Jstamp[0], N);
1555  }
1556 
1557 
1558  //************************************************
1559  // Compute and save new internal state (nextStaVec)
1560  // x2[t] = A2\(-coef*G2p*xp[t] - (1-coef)*G2p*xp[t-1] - [(1-coef)*G2-C2/dt]*x2[t-1])
1561  //************************************************
1562  blas.GEMV( Teuchos::NO_TRANS,N+M,N+M,-(1-ci.coef),&ci.G2[0],M+N,&currStaVec[0],1,0.0,&nextStaVec[0],1 ); // -(1-coef)*G2*currStaVec
1563  blas.GEMV( Teuchos::NO_TRANS,N+M,N+M,ci.alph,&ci.C2[0],M+N,&currStaVec[0],1,1.0,&nextStaVec[0],1 ); // C2/dt*currStaVec
1564  blas.GEMV( Teuchos::NO_TRANS,N+M,N,-ci.coef,&ci.G2p[0],N+M,&nextPortVec[0],1, 1.0,&nextStaVec[0],1 ); // -coef*G2p*nextPortVec
1565  blas.GEMV( Teuchos::NO_TRANS,N+M,N,-(1-ci.coef),&ci.G2p[0],N+M,&currPortVec[0],1,1.0,&nextStaVec[0],1 ); // -(1-coef)*G2p*currPortVec
1566  lapack.GETRS(test, M+N, 1, &ci.A2[0], M+N, &ci.ipiv_A2[0], &nextStaVec[0], M+N, &info2_A2); // A2\(prev)
1567  // for(int ix=0; ix<(M+N); ++ix) { (*ci.extData.nextStaVectorPtr)[ix] = nextStaVec[ix]; } // save internal state
1568  for(int ix=0; ix<(M+N); ++ix) { (*ci.extData.nextStaVectorPtr)[ ci.li_state[ix] ] = nextStaVec[ix]; } // save internal state
1569 
1570 
1571  //********************************************************
1572  // Compute residual stamp (Fstamp) using new internal state
1573  // Fstamp = Gp2 * nextStaVec
1574  //********************************************************
1575  blas.GEMV( Teuchos::NO_TRANS,N,N+M,1.0,&ci.Gp2[0],N,&nextStaVec[0],1,0.0,&ci.Fstamp[0],1 ); // Gp2*nextStaVec
1576 
1577 
1578  } // END 2-LEVEL STAMP
1579 
1580  //-------------------------------------------------------------------------
1581  //-------------------------------------------------------------------------
1582  //-------------------------------------------------------------------------
1583 
1584  if(ci.usePortDesc==0) // REGULAR DEVICE STAMPS
1585  {
1586  int N = ci.numExtVars;
1587  std::vector<double> v_up(N);
1588  for (int i=0; i<N; ++i)
1589  {
1590  v_up[i] = solVec[ci.extLIDVec[i]];
1591  ci.i_ip[i] = solVec[ci.intLIDVec[i]];
1592  ci.Fhat[i] = solVec[ci.intLIDVec[i]];
1593  }
1594  double * xhat = &solVec[ci.li_ROM[0]];
1595 
1596  // Compute Fhat[0:numExtVars-1] = i_ip - Lhat'*xhat
1597  blas.GEMV( Teuchos::TRANS, ci.numROMVars, ci.numExtVars, -1.0, &ci.Lhat[0], ci.numROMVars, xhat, 1, 1.0, &ci.Fhat[0], 1 );
1598 
1599  // Xyce::dout() << "Fhat (should just change first two elements): " << std::endl;
1600  // for (int i=0; i<ci.numIntVars; i++)
1601  // Xyce::dout() << "Fhat [" << i << "] = " << ci.Fhat[i] << std::endl;
1602 
1603  // Compute Fhat[numExtVars:numIntVars] = Ghat*xhat - Bhat*v_up
1604  if (ci.isGSparse)
1605  N_LAS_Util::crsAxpy( ci.numROMVars, 1.0, &ci.Ghat[0], &ci.Ghat_rowPtr[0], &ci.Ghat_colIdx[0], xhat, 0.0, &ci.Fhat[ci.numExtVars] );
1606  else
1607  blas.GEMV( Teuchos::NO_TRANS, ci.numROMVars, ci.numROMVars, 1.0, &ci.Ghat[0], ci.numROMVars, xhat, 1, 0.0, &ci.Fhat[ci.numExtVars], 1 );
1608  blas.GEMV( Teuchos::NO_TRANS, ci.numROMVars, ci.numExtVars, -1.0, &ci.Bhat[0], ci.numROMVars, &v_up[0], 1, 1.0, &ci.Fhat[ci.numExtVars], 1 );
1609 
1610  // Xyce::dout() << "Fhat (should just change last elements representing ROM): " << std::endl;
1611  // for (int i=0; i<ci.numIntVars; i++)
1612  // Xyce::dout() << "Fhat [" << i << "] = " << ci.Fhat[i] << std::endl;
1613 
1614  // Compute Qhat = Chat * xhat
1615  if (ci.isCSparse)
1616  N_LAS_Util::crsAxpy( ci.numROMVars, 1.0, &ci.Chat[0], &ci.Chat_rowPtr[0], &ci.Chat_colIdx[0], xhat, 0.0, &ci.Qhat[0] );
1617  else
1618  blas.GEMV( Teuchos::NO_TRANS, ci.numROMVars, ci.numROMVars, 1.0, &ci.Chat[0], ci.numROMVars, xhat, 1, 0.0, &ci.Qhat[0], 1 );
1619 
1620  // Xyce::dout() << "Qhat (should change all elements): " << std::endl;
1621  // for (int i=0; i<ci.numROMVars; i++)
1622  // Xyce::dout() << "Qhat [" << i << "] = " << ci.Qhat[i] << std::endl;
1623  }
1624  }
1625 
1626  return true;
1627 }
1628 
1629 
1630 
1631 //-----------------------------------------------------------------------------
1632 // Function : Master::printMatrix
1633 // Purpose :
1634 // Special Notes : For debugging 2-level device stamp
1635 // Scope : public
1636 // Creator : Brad Bond, SNL
1637 // Creation Date : 2011-03-11
1638 //-----------------------------------------------------------------------------
1639 void Master::printMatrix ( std::string vname, double * Matrix, int Nrows, int Ncols )
1640 {
1641  Xyce::dout() << std::endl << vname << ": " << std::endl;
1642  for(int ix=0; ix < Nrows; ix++)
1643  {
1644  for(int iy=0; iy < Ncols; iy++)
1645  {
1646  Xyce::dout() << Matrix[iy*Nrows+ix] << " ";
1647  }
1648  Xyce::dout() << std::endl;
1649  }
1650 }
1651 
1652 //-----------------------------------------------------------------------------
1653 // Function : Master::loadDAEVectors
1654 // Purpose :
1655 // Special Notes :
1656 // Scope : public
1657 // Creator : Heidi Thornquist, SNL
1658 // Creation Date : 11/26/08
1659 //-----------------------------------------------------------------------------
1660 bool Master::loadDAEVectors (double * solVec, double * fVec, double *qVec, double * storeLeadF, double * storeLeadQ)
1661 {
1662 #ifdef Xyce_DEBUG_DEVICE
1663  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1664  {
1665  Xyce::dout() << " ----------------------------------" << std::endl;
1666  Xyce::dout() << " Master::loadDAEVectors: " << std::endl;
1667  }
1668 #endif
1669 
1670  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1671  {
1672  Instance & ci = *(*it);
1673  if(ci.usePortDesc==0)
1674  {
1675  // Load F vector
1676  for (int i=0; i<ci.numExtVars; ++i)
1677  {
1678  fVec[ci.extLIDVec[i]] += ci.i_ip[i];
1679  fVec[ci.intLIDVec[i]] += ci.Fhat[i];
1680  }
1681 
1682  // Load ROM part of F and Q vector
1683 #ifdef _OMP
1684 #pragma omp parallel for
1685 #endif
1686  for (int i=0; i<ci.numROMVars; i++)
1687  {
1688  // F vector
1689 
1690  fVec[ci.li_ROM[i]] += ci.Fhat[ci.numExtVars+i];
1691  // Q vector
1692 
1693  qVec[ci.li_ROM[i]] += ci.Qhat[i];
1694  }
1695  }
1696 
1697  // TWO-LEVEL STAMP
1698  else
1699  {
1700  for (int i=0; i<ci.numExtVars; ++i)
1701  {
1702  fVec[ci.extLIDVec[i]] += ci.Fstamp[i];
1703  }
1704  }
1705  }
1706  return true;
1707 }
1708 
1709 //-----------------------------------------------------------------------------
1710 // Function : Master::loadDAEMatrices
1711 // Purpose :
1712 // Special Notes :
1713 // Scope : public
1714 // Creator : Heidi Thornquist, SNL
1715 // Creation Date : 11/26/08
1716 //-----------------------------------------------------------------------------
1717 bool Master::loadDAEMatrices (N_LAS_Matrix & dFdx, N_LAS_Matrix & dQdx)
1718 {
1719 #ifdef Xyce_DEBUG_DEVICE
1720  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1721  {
1722  Xyce::dout() << " ----------------------------------" << std::endl;
1723  Xyce::dout() << " Master::loadDAEMatrices: " << std::endl;
1724  }
1725 #endif
1726 
1727  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1728  {
1729  Instance & ci = *(*it);
1730 
1731  if(ci.usePortDesc==0)
1732  {
1733 
1734 #ifdef Xyce_DEBUG_DEVICE
1736  {
1737  Xyce::dout() << " loads for ROM " << ci.getName() << std::endl;
1738  }
1739 #endif
1740 
1741 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
1742  // Load dF/dx
1743  for (int i=0; i<ci.numExtVars; ++i)
1744  {
1745 
1746  *(ci.fEqu_up_NodePtr[i]) += 1.0;
1747 
1748  *(ci.fEqu_ip_NodePtr[i]) += 1.0;
1749  }
1750 
1751  // Load -Lhat portion of dF/dx
1752 #ifdef _OMP
1753 #pragma omp parallel for
1754 #endif
1755  for (int i=0; i<ci.numExtVars; i++)
1756  {
1757  double * LhatPtr = ci.fROMEqu_Lhat_VarsPtrs[i];
1758 #ifdef _OMP
1759 #pragma omp parallel for
1760 #endif
1761  for (int j=0; j<ci.numROMVars; j++)
1762  {
1763 
1764  LhatPtr[j] -= ci.Lhat[i*ci.numROMVars + j];
1765  }
1766  }
1767 
1768  // Load -Bhat portion of dF/dx
1769 #ifdef _OMP
1770 #pragma omp parallel for
1771 #endif
1772  for (int i=0; i<ci.numROMVars; i++)
1773  {
1774 #ifdef _OMP
1775 #pragma omp parallel for
1776 #endif
1777  for (int j=0; j<ci.numExtVars; j++)
1778  {
1779 
1780  *(ci.fROMEqu_Bhat_VarsPtrs[2*i+j]) -= ci.Bhat[j*ci.numROMVars + i];
1781  }
1782  }
1783 
1784  // Load Ghat portion of dF/dx
1785  if (ci.isGSparse)
1786  {
1787 #ifdef _OMP
1788 #pragma omp parallel for
1789 #endif
1790  int nnz = ci.Ghat_rowPtr[ci.numROMVars];
1791  for (int i=0; i<nnz; ++i)
1792  *(ci.fROMEqu_Ghat_VarsPtrs[i]) += ci.Ghat[i];
1793  }
1794  else
1795  {
1796 #ifdef _OMP
1797 #pragma omp parallel for
1798 #endif
1799  for (int i=0; i<ci.numROMVars; i++)
1800  {
1801  double * GhatPtr = ci.fROMEqu_Ghat_VarsPtrs[i];
1802 #ifdef _OMP
1803 #pragma omp parallel for
1804 #endif
1805  for (int j=0; j<ci.numROMVars; j++)
1806  {
1807 
1808  GhatPtr[j] += ci.Ghat[j*ci.numROMVars + i];
1809  }
1810  }
1811  }
1812 
1813  // Load dQ/dx
1814  // Load Chat portion of dQ/dx
1815  if (ci.isCSparse)
1816  {
1817 #ifdef _OMP
1818 #pragma omp parallel for
1819 #endif
1820  int nnz=ci.Chat_rowPtr[ci.numROMVars];
1821  for(int i=0; i<nnz; i++)
1822  *(ci.qROMEqu_Chat_VarsPtrs[i]) += ci.Chat[i];
1823  }
1824  else
1825  {
1826 #ifdef _OMP
1827 #pragma omp parallel for
1828 #endif
1829  for (int i=0; i<ci.numROMVars; i++)
1830  {
1831  double * ChatPtr = ci.qROMEqu_Chat_VarsPtrs[i];
1832 #ifdef _OMP
1833 #pragma omp parallel for
1834 #endif
1835  for (int j=0; j<ci.numROMVars; j++)
1836  {
1837 
1838  ChatPtr[j] += ci.Chat[j*ci.numROMVars + i];
1839  }
1840  }
1841  }
1842 
1843 #else
1844 
1845 #ifdef _OMP
1846 #pragma omp parallel for
1847 #endif
1848  for (int i=0; i<ci.numExtVars; i++)
1849  {
1850 
1851  dFdx[ci.extLIDVec[i]][ci.AEqu_up_NodeOffset[i]] += 1.0;
1852 
1853  dFdx[ci.intLIDVec[i]][ci.AEqu_ip_NodeOffset[i]] += 1.0;
1854  }
1855 
1856 #ifdef _OMP
1857 #pragma omp parallel for
1858 #endif
1859  // Load -Lhat portion of dF/dx
1860  for (int j=0; j<ci.numROMVars; j++)
1861  {
1862 #ifdef _OMP
1863 #pragma omp parallel for
1864 #endif
1865  for (int i=0; i<ci.numExtVars; i++)
1866  {
1867 
1868  dFdx[ci.intLIDVec[i]][ci.ROMEqu_Lt_NodeOffset[j]] -= ci.Lhat[i*ci.numROMVars + j];
1869  }
1870  }
1871 
1872  // Load -Bhat portion of dF/dx
1873 #ifdef _OMP
1874 #pragma omp parallel for
1875 #endif
1876  for (int i=0; i<ci.numROMVars; i++)
1877  {
1878 #ifdef _OMP
1879 #pragma omp parallel for
1880 #endif
1881  for (int j=0; j<ci.numExtVars; j++)
1882  {
1883 
1884  dFdx[ci.li_ROM[i]][ci.ROMEqu_B_NodeOffset[i*ci.numExtVars+j]] -= ci.Bhat[j*ci.numROMVars + i];
1885  }
1886  }
1887 
1888  // Load Ghat portion of dF/dx
1889  if (ci.isGSparse)
1890  {
1891  for (int j=ci.Ghat_rowPtr[i]; j<ci.Ghat_rowPtr[i+1]; j++)
1892  {
1893 
1894  dFdx[ci.li_ROM[i]][ci.ROMEqu_G_NodeOffset[j]] += ci.Ghat[j];
1895  }
1896  }
1897  else
1898  {
1899 #ifdef _OMP
1900 #pragma omp parallel for
1901 #endif
1902  for (int i=0; i<ci.numROMVars; i++)
1903  {
1904 #ifdef _OMP
1905 #pragma omp parallel for
1906 #endif
1907  for (int j=0; j<ci.numROMVars; j++)
1908  {
1909 
1910  dFdx[ci.li_ROM[i]][ci.ROMEqu_GpC_NodeOffset[j]] += ci.Ghat[j*ci.numROMVars + i];
1911  }
1912  }
1913  }
1914 
1915  // Load Chat portion of dQ/dx
1916  if (ci.isCSparse)
1917  {
1918  for (int j=ci.Chat_rowPtr[i]; j<ci.Chat_rowPtr[i+1]; j++)
1919  {
1920 
1921  dQdx[ci.li_ROM[i]][ci.ROMEqu_C_NodeOffset[j]] += ci.Chat[j];
1922  }
1923  }
1924  else
1925  {
1926 #ifdef _OMP
1927 #pragma omp parallel for
1928 #endif
1929  for (int i=0; i<ci.numROMVars; i++)
1930  {
1931 #ifdef _OMP
1932 #pragma omp parallel for
1933 #endif
1934  for (int j=0; j<ci.numROMVars; j++)
1935  {
1936 
1937  dQdx[ci.li_ROM[i]][ci.ROMEqu_GpC_NodeOffset[j]] += ci.Chat[j*ci.numROMVars + i];
1938  }
1939  }
1940  }
1941 #endif
1942  }
1943  else
1944  {
1945  for (int i=0; i<ci.numExtVars; i++)
1946  {
1947  for (int j=0; j<ci.numExtVars; j++)
1948  {
1949  dFdx[ci.extLIDVec[i]][ci.AEqu_NodeOffset[i][j]] += ci.Jstamp[i*ci.numExtVars + j];
1950  }
1951  }
1952  }
1953  }
1954  return true;
1955 }
1956 
1957 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
1958 {
1959 
1960  return new Master(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
1961 }
1962 
1964 {
1966  .registerDevice("rom", 1)
1967  .registerModelType("rom", 1);
1968 }
1969 
1970 } // namespace ROM
1971 } // namespace Device
1972 } // namespace Xyce