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.65 $
40 //
41 // Revision Date : $Date: 2014/05/22 17:40:30 $
42 //
43 // Current Owner : $Author: erkeite $
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  if (numIntVars > 0) // Then add the current variables at the ports
738  {
739  for (int i=0; i<numExtVars; i++)
740  {
741  intNameMap[intLIDVec[i]] = spiceInternalName(getName(), "ip_Node"+Teuchos::Utils::toString(i+1));
742  }
743  }
744  for (int i=0; i<numROMVars; i++)
745  {
746  intNameMap[li_ROM[i]] = spiceInternalName(getName(), "ROM_Node"+Teuchos::Utils::toString(i+1));
747  }
748  }
749 
750  return intNameMap;
751 }
752 
753 
754 //-----------------------------------------------------------------------------
755 // Function : Instance::jacobianStamp
756 // Purpose :
757 // Special Notes :
758 // Scope : public
759 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
760 // Creation Date : 08/27/02
761 //-----------------------------------------------------------------------------
762 const std::vector< std::vector<int> > & Instance::jacobianStamp() const
763 {
764  return jacStamp;
765 }
766 
767 //-----------------------------------------------------------------------------
768 // Function : Instance::registerJacLIDs
769 // Purpose :
770 // Special Notes :
771 // Scope : public
772 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
773 // Creation Date : 08/27/02
774 //-----------------------------------------------------------------------------
775 void Instance::registerJacLIDs( const std::vector< std::vector<int> > & jacLIDVec )
776 {
777 
778  DeviceInstance::registerJacLIDs( jacLIDVec );
779 
780  if(usePortDesc>0)
781  {
782  AEqu_NodeOffset.resize(numExtVars);
783  for (int i=0; i<numExtVars; i++)
784  {
785  AEqu_NodeOffset[i].resize(numExtVars);
786  for (int j=0; j<numExtVars; j++)
787  {
788  AEqu_NodeOffset[i][j] = jacLIDVec[i][j];
789  }
790  }
791  }
792  else
793  {
796  for (int i=0; i<numExtVars; i++)
797  {
798  AEqu_up_NodeOffset[i] = jacLIDVec[i][0];
799  AEqu_ip_NodeOffset[i] = jacLIDVec[numExtVars+i][0];
800  }
801 
802  // Get the offsets for -L^T
804  for (int i=0; i<numROMVars; i++)
805  {
806  ROMEqu_Lt_NodeOffset[i] = jacLIDVec[numExtVars][i+1];
807  }
808 
809  // Get the offsets for -B
810  ROMEqu_B_NodeOffset.resize(numExtVars*numROMVars);
811  for (int i=0; i<numROMVars; i++)
812  {
813  for (int j=0; j<numExtVars; j++)
814  ROMEqu_B_NodeOffset[i*numExtVars+j] = jacLIDVec[2*numExtVars+i][j];
815  }
816 
817  // Get the offsets for C d/dt
818  // If the matrix is sparse, then an offset will be stored for each nonzero.
819  if (isCSparse)
820  {
821  ROMEqu_C_NodeOffset.resize(Chat_rowPtr[numROMVars]);
822  for (int i=0; i<numROMVars; i++)
823  {
824  int nnz = CG_rowPtr[i+1]-CG_rowPtr[i];
825  int CrowPtr = Chat_rowPtr[i], Cnnz = Chat_rowPtr[i+1]-Chat_rowPtr[i];
826  for (int j=0, Cidx=0; j<nnz && Cidx<Cnnz; j++)
827  {
828  int colIdx = CG_colIdx[CG_rowPtr[i]+j];
829  if (colIdx == Chat_colIdx[CrowPtr])
830  {
831  ROMEqu_C_NodeOffset[CrowPtr++] = jacLIDVec[2*numExtVars+i][numExtVars+j];
832  Cidx++;
833  }
834  }
835  }
836  }
837 
838  // Get the offsets for G
839  // If the matrix is sparse, then an offset will be stored for each nonzero.
840  if (isGSparse)
841  {
842  ROMEqu_G_NodeOffset.resize(Ghat_rowPtr[numROMVars]);
843  for (int i=0; i<numROMVars; i++)
844  {
845  int nnz = CG_rowPtr[i+1]-CG_rowPtr[i];
846  int GrowPtr = Ghat_rowPtr[i], Gnnz = Ghat_rowPtr[i+1]-Ghat_rowPtr[i];
847  for (int j=0, Gidx=0; j<nnz && Gidx<Gnnz; j++)
848  {
849  int colIdx = CG_colIdx[CG_rowPtr[i]+j];
850  if (colIdx == Ghat_colIdx[GrowPtr])
851  {
852  ROMEqu_G_NodeOffset[GrowPtr++] = jacLIDVec[2*numExtVars+i][numExtVars+j];
853  Gidx++;
854  }
855  }
856  }
857  }
858 
859  // If either C or G is dense, we need these node offsets, which assume the storage is contiguous.
860  if (!isCSparse || !isGSparse)
861  {
862  ROMEqu_GpC_NodeOffset.resize(numROMVars);
863  for (int i=0; i<numROMVars; i++)
864  {
865  ROMEqu_GpC_NodeOffset[i] = jacLIDVec[2*numExtVars][numExtVars+i];
866  }
867  }
868 
869 #ifdef Xyce_DEBUG_DEVICE
870  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
871  {
872  Xyce::dout() << Xyce::section_divider << std::endl;
873  Xyce::dout() << "Instance::registerJacLIDs\n";
874  if (usePortDesc==0)
875  {
876  Xyce::dout() << " AEqu_up_NodeOffset: ";
877  for (int i=0; i<numExtVars; i++)
878  Xyce::dout() << AEqu_up_NodeOffset[i] << " ";
879  Xyce::dout() << std::endl;
880  Xyce::dout() << " AEqu_ip_NodeOffset: ";
881  for (int i=0; i<numExtVars; i++)
882  Xyce::dout() << AEqu_ip_NodeOffset[i] << " ";
883  Xyce::dout() << std::endl;
884  Xyce::dout() << " AROMEqu_Lt_NodeOffset: ";
885  for (int i=0; i<numROMVars; i++)
886  Xyce::dout() << ROMEqu_Lt_NodeOffset[i] << " ";
887  Xyce::dout() << std::endl;
888  Xyce::dout() << " AROMEqu_B_NodeOffset: " << std::endl;
889  for (int i=0; i<numROMVars; i++)
890  {
891  for (int j=0; j<numExtVars; j++)
892  Xyce::dout() << ROMEqu_B_NodeOffset[i*numExtVars+j] << " ";
893  Xyce::dout() << std::endl;
894  }
895  Xyce::dout() << " AROMEqu_GpC_NodeOffset: ";
896  for (int i=0; i<numROMVars; i++)
897  Xyce::dout() << ROMEqu_GpC_NodeOffset[i] << " ";
898  Xyce::dout() << std::endl;
899  }
900  Xyce::dout() << Xyce::section_divider << std::endl;
901  }
902 #endif
903  }
904 }
905 
906 //-----------------------------------------------------------------------------
907 // Function : Instance::setupPointers
908 // Purpose :
909 // Special Notes :
910 // Scope : public
911 // Creator : Heidi Thornquist, SNL
912 // Creation Date : 11/30/08
913 //-----------------------------------------------------------------------------
915 {
916 
917 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
918  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
919  N_LAS_Matrix & dQdx = *(extData.dQdxMatrixPtr);
920 
921  // Get pointers for KCL equations and Ghat, Lhat, and Bhat
922  if(usePortDesc==0)
923  {
924  fEqu_up_NodePtr.resize(numExtVars);
925  for (int i=0; i<numExtVars; ++i)
926  {
927  fEqu_up_NodePtr[i] = &(dFdx[extLIDVec[i]][AEqu_up_NodeOffset[i]]);
928  }
929 
930  fEqu_ip_NodePtr.resize(numExtVars);
931  for (int i=0; i<numExtVars; ++i)
932  {
933  fEqu_ip_NodePtr[i] = &(dFdx[intLIDVec[i]][AEqu_ip_NodeOffset[i]]);
934  }
935 
936  // Get pointers for Ghat (assuming contiguous), only if Ghat is not sparse.
937  if (isGSparse)
938  {
940  for (int i=0; i<numROMVars; ++i)
941  {
942  for (int j=Ghat_rowPtr[i]; j<Ghat_rowPtr[i+1]; j++)
943  {
945  }
946  }
947  }
948  else
949  {
951  for (int i=0; i<numROMVars; ++i)
952  {
954  }
955  }
956 
957  // Lhat (assuming contiguous)
958  fROMEqu_Lhat_VarsPtrs.resize(numExtVars);
959  for (int i=0; i<numExtVars; ++i)
960  {
962  }
963 
964  // Bhat (these are not guaranteed to be contiguous)
965  fROMEqu_Bhat_VarsPtrs.resize(numExtVars*numROMVars);
966  for (int i=0; i<numROMVars; ++i)
967  {
968  for (int j=0; j<numExtVars; ++j)
969  {
970  fROMEqu_Bhat_VarsPtrs[numExtVars*i+j]=&(dFdx[li_ROM[i]][ROMEqu_B_NodeOffset[i*numExtVars+j]]);
971  }
972  }
973 
974  // Get pointers for Chat (assuming contiguous), only if Chat is not sparse.
975  if (isCSparse)
976  {
977  qROMEqu_Chat_VarsPtrs.resize(Chat_rowPtr[numROMVars]);
978  for (int i=0; i<numROMVars; ++i)
979  {
980  for (int j=Chat_rowPtr[i]; j<Chat_rowPtr[i+1]; j++)
981  {
983  }
984  }
985  }
986  else
987  {
988  qROMEqu_Chat_VarsPtrs.resize(numROMVars);
989  for (int i=0; i<numROMVars; ++i)
991  }
992  }
993 #endif
994 }
995 
996 //-----------------------------------------------------------------------------
997 // Function : Instance::updatePrimaryState
998 // Purpose :
999 // Special Notes :
1000 // Scope : public
1001 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1002 // Creation Date : 01/29/01
1003 //-----------------------------------------------------------------------------
1005 {
1006  double * solVec = extData.nextSolVectorRawPtr;
1007  double * staVec = extData.nextStaVectorRawPtr;
1008  std::vector<double> v_up(numExtVars);
1009  for (int i=0; i<numExtVars; ++i)
1010  {
1011  v_up[i] = solVec[extLIDVec[i]];
1012  Fhat[i] = solVec[intLIDVec[i]];
1013  i_ip[i] = solVec[intLIDVec[i]];
1014  }
1015  double * xhat = &solVec[li_ROM[0]];
1016 
1017  Teuchos::BLAS<int, double> blas;
1018 
1019  // Compute Fhat[0:numExtVars-1] = i_ip - Lhat'*xhat
1020  blas.GEMV( Teuchos::TRANS, numROMVars, numExtVars, -1.0, &Lhat[0], numROMVars, xhat, 1, 1.0, &Fhat[0], 1 );
1021 
1022  // Compute Fhat[numExtVars:numIntVars] = Ghat*xhat - Bhat*v_up
1023  if (isGSparse)
1024  N_LAS_Util::crsAxpy( numROMVars, 1.0, &Ghat[0], &Ghat_rowPtr[0], &Ghat_colIdx[0], xhat, 0.0, &Fhat[numExtVars] );
1025  else
1026  blas.GEMV( Teuchos::NO_TRANS, numROMVars, numROMVars, 1.0, &Ghat[0], numROMVars, xhat, 1, 0.0, &Fhat[numExtVars], 1 );
1027  blas.GEMV( Teuchos::NO_TRANS, numROMVars, numExtVars, -1.0, &Bhat[0], numROMVars, &v_up[0], 1, 1.0, &Fhat[numExtVars], 1 );
1028 
1029  // Compute Qhat = Chat * xhat
1030  if (isCSparse)
1031  N_LAS_Util::crsAxpy( numROMVars, 1.0, &Chat[0], &Chat_rowPtr[0], &Chat_colIdx[0], xhat, 0.0, &Qhat[0] );
1032  else
1033  blas.GEMV( Teuchos::NO_TRANS, numROMVars, numROMVars, 1.0, &Chat[0], numROMVars, xhat, 1, 0.0, &Qhat[0], 1 );
1034 
1035 #ifdef Xyce_DEBUG_DEVICE
1036  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1037  {
1038  Xyce::dout() << " ----------------------------------" << std::endl;
1039  Xyce::dout() << "Instance::updatePrimaryState:" << std::endl;
1040  }
1041 #endif
1042 
1043  return true;
1044 }
1045 
1046 //-----------------------------------------------------------------------------
1047 // Function : Instance::loadDeviceMask
1048 //
1049 // Purpose : Loads the zero elements of the device mask
1050 //
1051 // Special Notes : elements of the error vector associated with zero
1052 // elements of the mask will not be included in weighted
1053 // norms by the time integrator.
1054 //
1055 // Scope : public
1056 // Creator : Keith Santarelli, SNL, Electrical and Microsystems Modeling
1057 // Creation Date : 03/12/08
1058 //-----------------------------------------------------------------------------
1060 {
1061  if (maskROMVars)
1062  {
1063  N_LAS_Vector * maskVectorPtr = extData.deviceMaskVectorPtr;
1064 
1065  for (int i=0; i<numROMVars; i++)
1066  {
1067  (*maskVectorPtr)[li_ROM[i]] = 0.0;
1068  }
1069  }
1070  return (true);
1071 }
1072 
1073 //-----------------------------------------------------------------------------
1074 // Function : Instance::loadDAEQVector
1075 //
1076 // Purpose : Loads the Q-vector contributions for a single
1077 // ROM instance.
1078 //
1079 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1080 // which the system of equations is represented as:
1081 //
1082 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1083 //
1084 // Scope : public
1085 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1086 // Creation Date : 01/24/03
1087 //-----------------------------------------------------------------------------
1089 {
1090  double * qVec = extData.daeQVectorRawPtr;
1091  for (int i=0; i<numROMVars; i++)
1092  {
1093  qVec[li_ROM[i]] += Qhat[i];
1094  }
1095  return true;
1096 }
1097 
1098 //-----------------------------------------------------------------------------
1099 // Function : Instance::loadDAEFVector
1100 //
1101 // Purpose : Loads the F-vector contributions for a single
1102 // ROM instance.
1103 //
1104 // Special Notes :
1105 //
1106 // Scope : public
1107 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1108 // Creation Date : 01/24/03
1109 //-----------------------------------------------------------------------------
1111 {
1112  double * fVec = extData.daeFVectorRawPtr;
1113 
1114  // Load F vector
1115  for (int i=0; i<numExtVars; ++i)
1116  {
1117  fVec[extLIDVec[i]] += i_ip[i];
1118  fVec[intLIDVec[i]] += Fhat[i];
1119  }
1120  for (int i=0; i<numROMVars; i++)
1121  {
1122  fVec[li_ROM[i]] += Fhat[numExtVars+i];
1123  }
1124 
1125  return true;
1126 }
1127 
1128 //-----------------------------------------------------------------------------
1129 // Function : Instance::loadDAEdQdx
1130 //
1131 // Purpose : Loads the dQdx-matrix contributions for a single
1132 // ROM instance.
1133 //
1134 // Special Notes : The "Q" vector is part of a standard DAE formalism in
1135 // which the system of equations is represented as:
1136 //
1137 // f(x) = dQ(x)/dt + F(x) - B(t) = 0
1138 //
1139 // Scope : public
1140 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1141 // Creation Date : 03/05/04
1142 //-----------------------------------------------------------------------------
1144 {
1145  N_LAS_Matrix & dQdx = *(extData.dQdxMatrixPtr);
1146 
1147  // Load Chat portion of dQ/dx
1148  for (int i=0; i<numROMVars; i++)
1149  {
1150  if (isCSparse)
1151  {
1152  for (int j=Chat_rowPtr[i]; j<Chat_rowPtr[i+1]; j++)
1153  {
1154 
1155  dQdx[li_ROM[i]][ROMEqu_C_NodeOffset[j]] += Chat[j];
1156  }
1157  }
1158  else
1159  {
1160  for (int j=0; j<numROMVars; j++)
1161  {
1162 
1163  dQdx[li_ROM[i]][ROMEqu_GpC_NodeOffset[j]] += Chat[j*numROMVars + i];
1164  }
1165  }
1166  }
1167  return true;
1168 }
1169 
1170 //-----------------------------------------------------------------------------
1171 // Function : Instance::loadDAEdFdx ()
1172 //
1173 // Purpose : Loads the F-vector contributions for a single
1174 // ROM instance.
1175 //
1176 // Special Notes :
1177 //
1178 // Scope : public
1179 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1180 // Creation Date : 03/05/04
1181 //-----------------------------------------------------------------------------
1183 {
1184  N_LAS_Matrix & dFdx = *(extData.dFdxMatrixPtr);
1185 
1186  for (int i=0; i<numExtVars; ++i)
1187  {
1188 
1189  dFdx[extLIDVec[i]][AEqu_up_NodeOffset[i]] += 1.0;
1190 
1191  dFdx[intLIDVec[i]][AEqu_ip_NodeOffset[i]] += 1.0;
1192  }
1193 
1194  // Load -Lhat portion of dF/dx
1195  for (int j=0; j<numROMVars; j++)
1196  {
1197  for (int i=0; i<numExtVars; i++)
1198  {
1199 
1200  dFdx[intLIDVec[i]][ROMEqu_Lt_NodeOffset[j]] -= Lhat[j];
1201  }
1202  }
1203 
1204  // Load -Bhat portion of dF/dx
1205  for (int i=0; i<numROMVars; i++)
1206  {
1207  for (int j=0; j<numExtVars; j++)
1208  {
1209 
1210  dFdx[li_ROM[i]][ROMEqu_B_NodeOffset[i*numExtVars+j]] -= Bhat[j*numROMVars + i];
1211  }
1212  }
1213 
1214  // Load Ghat portion of dF/dx
1215  for (int i=0; i<numROMVars; i++)
1216  {
1217  if (isGSparse)
1218  {
1219  for (int j=Ghat_rowPtr[i]; j<Ghat_rowPtr[i+1]; j++)
1220  {
1221 
1222  dFdx[li_ROM[i]][ROMEqu_G_NodeOffset[j]] += Ghat[j];
1223  }
1224  }
1225  else
1226  {
1227  for (int j=0; j<numROMVars; j++)
1228  {
1229 
1230  dFdx[li_ROM[i]][ROMEqu_GpC_NodeOffset[j]] += Ghat[j*numROMVars + i];
1231  }
1232  }
1233  }
1234  return true;
1235 }
1236 
1237 //-----------------------------------------------------------------------------
1238 // Function : Instance::setIC
1239 // Purpose :
1240 // Special Notes :
1241 // Scope : public
1242 // Creator : Eric R. Keiter, SNL, Parallel Computational Sciences
1243 // Creation Date : 01/10/02
1244 //-----------------------------------------------------------------------------
1246 {
1247  return true;
1248 }
1249 
1250 //-----------------------------------------------------------------------------
1251 // Function : Instance::varTypes
1252 // Purpose :
1253 // Special Notes :
1254 // Scope : public
1255 // Creator : Robert Hoekstra, SNL, Parallel Computational Sciences
1256 // Creation Date : 02/17/04
1257 //-----------------------------------------------------------------------------
1258 void Instance::varTypes( std::vector<char> & varTypeVec )
1259 {
1260 }
1261 
1262 
1263 // Class Model
1264 
1265 //-----------------------------------------------------------------------------
1266 // Function : Model::processParams
1267 // Purpose :
1268 // Special Notes :
1269 // Scope : public
1270 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1271 // Creation Date : 6/03/02
1272 //-----------------------------------------------------------------------------
1274 {
1275  return true;
1276 }
1277 
1278 //----------------------------------------------------------------------------
1279 // Function : Model::processInstanceParams
1280 // Purpose :
1281 // Special Notes :
1282 // Scope : public
1283 // Creator : Dave Shirely, PSSI
1284 // Creation Date : 03/23/06
1285 //----------------------------------------------------------------------------
1287 {
1288  std::vector<Instance*>::iterator iter;
1289  std::vector<Instance*>::iterator first = instanceContainer.begin();
1290  std::vector<Instance*>::iterator last = instanceContainer.end();
1291 
1292  for (iter=first; iter!=last; ++iter)
1293  {
1294  (*iter)->processParams();
1295  }
1296 
1297  return true;
1298 }
1299 
1300 //-----------------------------------------------------------------------------
1301 // Function : Model::Model
1302 // Purpose : block constructor
1303 // Special Notes :
1304 // Scope : public
1305 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1306 // Creation Date : 5/17/00
1307 //-----------------------------------------------------------------------------
1308 
1310  const Configuration & configuration,
1311  const ModelBlock & MB,
1312  const FactoryBlock & factory_block)
1313  : DeviceModel(MB, configuration.getModelParameters(), factory_block)
1314 {
1315 
1316  // Set params to constant default values:
1317  setDefaultParams ();
1318 
1319  // Set params according to .model line and constant defaults from metadata:
1320  setModParams (MB.params);
1321 
1322  // Calculate any parameters specified as expressions:
1324 
1325  // calculate dependent (ie computed) params and check for errors:
1326  processParams ();
1327 }
1328 
1329 //-----------------------------------------------------------------------------
1330 // Function : Model::Model
1331 // Purpose : destructor
1332 // Special Notes :
1333 // Scope : public
1334 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1335 // Creation Date : 3/16/00
1336 //-----------------------------------------------------------------------------
1337 
1339 {
1340  std::vector<Instance*>::iterator iter;
1341  std::vector<Instance*>::iterator first = instanceContainer.begin();
1342  std::vector<Instance*>::iterator last = instanceContainer.end();
1343 
1344  for (iter=first; iter!=last; ++iter)
1345  {
1346  delete (*iter);
1347  }
1348 
1349 }
1350 
1351 //-----------------------------------------------------------------------------
1352 // Function : Model::printOutInstances
1353 // Purpose : debugging tool.
1354 // Special Notes :
1355 // Scope : public
1356 // Creator : Heidi Thornquist, SNL, Parallel Computational Sciences
1357 // Creation Date : 4/03/00
1358 //-----------------------------------------------------------------------------
1359 
1360 std::ostream &Model::printOutInstances(std::ostream &os) const
1361 {
1362  std::vector<Instance*>::const_iterator iter;
1363  std::vector<Instance*>::const_iterator first = instanceContainer.begin();
1364  std::vector<Instance*>::const_iterator last = instanceContainer.end();
1365 
1366  int i,isize;
1367 
1368  isize = instanceContainer.size();
1369  os << std::endl;
1370  os << "Number of ROM instances: " << isize << std::endl;
1371  os << " name\t\tmodelName\tParameters" << std::endl;
1372 
1373  for (i = 0, iter = first; iter != last; ++iter, ++i)
1374  {
1375  os << " " << i << ": " << (*iter)->getName() << "\t";
1376  os << getName();
1377  os << std::endl;
1378  }
1379 
1380  os << std::endl;
1381 
1382  return os;
1383 }
1384 
1385 //-----------------------------------------------------------------------------
1386 // Function : Model::forEachInstance
1387 // Purpose :
1388 // Special Notes :
1389 // Scope : public
1390 // Creator : David Baur
1391 // Creation Date : 2/4/2014
1392 //-----------------------------------------------------------------------------
1393 /// Apply a device instance "op" to all instances associated with this
1394 /// model
1395 ///
1396 /// @param[in] op Operator to apply to all instances.
1397 ///
1398 ///
1399 void Model::forEachInstance(DeviceInstanceOp &op) const /* override */
1400 {
1401  for (std::vector<Instance *>::const_iterator it = instanceContainer.begin(); it != instanceContainer.end(); ++it)
1402  op(*it);
1403 }
1404 
1405 
1406 // ROM Master functions:
1407 
1408 //-----------------------------------------------------------------------------
1409 // Function : Master::updateState
1410 // Purpose :
1411 // Special Notes :
1412 // Scope : public
1413 // Creator : Heidi Thornquist, SNL
1414 // Creation Date : 11/26/08
1415 //-----------------------------------------------------------------------------
1416 bool Master::updateState (double * solVec, double * staVec, double * stoVec)
1417 {
1418 #ifdef Xyce_DEBUG_DEVICE
1419  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1420  {
1421  Xyce::dout() << " ----------------------------------" << std::endl;
1422  Xyce::dout() << " Master::updateState: " << std::endl;
1423  }
1424 #endif
1425 
1426 #ifdef _OMP
1427 #pragma omp parallel for
1428 #endif
1429  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1430  {
1431  Instance & ci = *(*it);
1432 
1433  Teuchos::BLAS<int, double> blas;
1434  if (ci.usePortDesc>0) // TWO-LEVEL DEVICE STAMPS
1435  {
1436  const char test = 'N';
1437  int MN = ci.numStateVars;
1438  int N = ci.numExtVars;
1439  int M = MN-N;
1440 
1441  // Check if this is the first device call after a successful timestep
1442  int sameTimeStep=0;
1444  if (ci.lastTimeStepNumber==ci.getSolverState().timeStepNumber) {sameTimeStep=1;}
1445 
1446  //********************************************************************
1447  // Set up the coefficients for discretization for the INNER solve
1448  //********************************************************************
1449  if (ci.usePortDesc==1) {// DYNAMIC ORDER SELECTION
1450  if (sameTimeStep==0) {ci.coefLast = ci.coef;}
1451  ci.coef = (1/ci.getSolverState().currentOrder);
1452  if (ci.getSolverState().currentOrder==0) { ci.coef=1; } // Force BE
1453  if (ci.getSolverState().usedOrder==0) { ci.coefLast = 1; } // Force BE
1454  }
1455  else if (ci.usePortDesc==2) { // BACKWARD EULER
1456  ci.coef=1;
1457  ci.coefLast = 1;
1458  }
1459  else if (ci.usePortDesc==3) { // TRAP
1460  ci.coef=0.5;
1461  ci.coefLast = 0.5;
1462  }
1463  else
1464  Xyce::dout() << "Bad 'USE_PORT_DESCRIPTION' flag" << std::endl;
1465 
1466 
1467  // Get alph=1/dt for current and last time steps
1468  if (sameTimeStep==0) {ci.alph_last = ci.alph;}
1469  ci.alph=1/ci.getSolverState().currTimeStep;
1470  if (ci.getSolverState().dcopFlag==1) { ci.alph=0.0; ci.alph_last=0.0; }
1471  if (ci.getSolverState().timeStepNumber==0) { ci.alph_last=0.0; }
1472 
1473 
1474  //********************************************************************
1475  // Load port and internal state variables
1476  //********************************************************************
1477  std::vector<double> lastStaVec, currStaVec, nextStaVec; // Internal states
1478  lastStaVec.resize(M+N,0);
1479  currStaVec.resize(M+N,0);
1480  nextStaVec.resize(M+N,0);
1481  //for(int ix=0; ix<(M+N); ++ix) { lastStaVec[ix] = (*ci.extData.lastStaVectorPtr)[ix]; } // WRONG
1482  for(int ix=0; ix<(M+N); ++ix) { lastStaVec[ix] = (*ci.extData.lastStaVectorPtr)[ ci.li_state[ix] ]; }
1483  std::vector<double> lastPortVec, currPortVec, nextPortVec; // Port voltages
1484  lastPortVec.resize(N,0);
1485  currPortVec.resize(N,0);
1486  nextPortVec.resize(N,0);
1487  for(int ix=0; ix<N; ++ix)
1488  {
1489  lastPortVec[ix] = (*ci.extData.lastSolVectorPtr)[ci.extLIDVec[ix]];
1490  currPortVec[ix] = (*ci.extData.currSolVectorPtr)[ci.extLIDVec[ix]];
1491  nextPortVec[ix] = solVec[ci.extLIDVec[ix]];
1492  }
1493 
1494  /*
1495  std::vector<int> lidState = set this up in registerStateLIDs
1496  localState[ix] = ci.extradata.currState[ ci.lidState[ix] ];
1497  ci.extData.currState[ ci.lidState[ix] ] = localState[ix];
1498  */
1499 
1500  // Begin math stuff
1501  Teuchos::LAPACK<int,double> lapack;
1502  std::vector<int> ipiv_A2last (M+N, 0);
1503  int info_A2, info_A2last, info2_A2, info2_A2last;
1504 
1505 
1506  //****************************************************************
1507  // Compute, or load, old internal state (currStaVec) [INNER SOLVE]
1508  // x2[t] = A2\(-coef*G2p*xp[t] - (1-coef)*G2p*xp[t-1] - [(1-coef)*G2-C2/dt]*x2[t-1])
1509  //******************************************************
1510  int updateCurrStaVec=0;
1511  // if (ci.getSolverState().newtonIter==0) { updateCurrStaVec=1; }
1512  if (sameTimeStep==0) {updateCurrStaVec=1; }
1513  if (updateCurrStaVec==1) { // compute new `last' state
1514  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
1515  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
1516  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
1517  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
1518  int useOldA2=1;
1519  if (ci.getSolverState().timeStepNumber<2) { useOldA2=0; }
1520  if (ci.lastTimeStepNumber==ci.getSolverState().timeStepNumber) { useOldA2=0; }
1521  if (useOldA2==1) // use [previously factored] A2 as A2last
1522  lapack.GETRS(test, M+N, 1, &ci.A2[0], M+N, &ci.ipiv_A2[0], &currStaVec[0], M+N, &info2_A2); // A2\(xtmp)
1523  else { // compute new A2last
1524  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
1525  lapack.GETRF( M+N, M+N, &ci.A2last[0], M+N, &ipiv_A2last[0], &info_A2last); // factor A2last
1526  lapack.GETRS(test, M+N, 1, &ci.A2last[0], M+N, &ipiv_A2last[0], &currStaVec[0], M+N, &info2_A2last); // A2last\(xtmp)
1527  }
1528  for(int ix=0; ix<(M+N); ++ix) { (*ci.extData.currStaVectorPtr)[ ci.li_state[ix] ] = currStaVec[ix]; } // Store answer
1529  }
1530  else
1531  { // Load currStaVec
1532  for(int ix=0; ix<(M+N); ++ix) { currStaVec[ix] = (*ci.extData.currStaVectorPtr)[ ci.li_state[ix] ]; }
1533  }
1534 
1535 
1536  //**************************************************
1537  // construct A2 and Jacobian (Jstamp), if necessary
1538  // Jstamp = -Gp2*(A2\(coef*G2p)) = -Gp2 * A2sol
1539  //**************************************************
1540  int updateA2 = 1;
1541  if (ci.getSolverState().timeStepNumber>2){
1542  if (ci.getSolverState().newtonIter>0) { updateA2=0; }
1543  if (ci.alph==ci.alph_last) { if (ci.coef==ci.coefLast) { updateA2=0; }}}
1544  if (updateA2==1) {
1545  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;
1546  lapack.GETRF( M+N, M+N, &ci.A2[0], M+N, &ci.ipiv_A2[0], &info_A2); // Factor A2
1547  for(int ix=0; ix<(M+N)*N; ix++) { ci.A2sol[ix] = ci.coef * ci.G2p[ix]; } // copy to RHS vector
1548  lapack.GETRS(test, M+N, N, &ci.A2[0], M+N, &ci.ipiv_A2[0], &ci.A2sol[0], M+N, &info2_A2);
1549  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);
1550  }
1551 
1552 
1553  //************************************************
1554  // Compute and save new internal state (nextStaVec)
1555  // x2[t] = A2\(-coef*G2p*xp[t] - (1-coef)*G2p*xp[t-1] - [(1-coef)*G2-C2/dt]*x2[t-1])
1556  //************************************************
1557  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
1558  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
1559  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
1560  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
1561  lapack.GETRS(test, M+N, 1, &ci.A2[0], M+N, &ci.ipiv_A2[0], &nextStaVec[0], M+N, &info2_A2); // A2\(prev)
1562  // for(int ix=0; ix<(M+N); ++ix) { (*ci.extData.nextStaVectorPtr)[ix] = nextStaVec[ix]; } // save internal state
1563  for(int ix=0; ix<(M+N); ++ix) { (*ci.extData.nextStaVectorPtr)[ ci.li_state[ix] ] = nextStaVec[ix]; } // save internal state
1564 
1565 
1566  //********************************************************
1567  // Compute residual stamp (Fstamp) using new internal state
1568  // Fstamp = Gp2 * nextStaVec
1569  //********************************************************
1570  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
1571 
1572 
1573  } // END 2-LEVEL STAMP
1574 
1575  //-------------------------------------------------------------------------
1576  //-------------------------------------------------------------------------
1577  //-------------------------------------------------------------------------
1578 
1579  if(ci.usePortDesc==0) // REGULAR DEVICE STAMPS
1580  {
1581  int N = ci.numExtVars;
1582  std::vector<double> v_up(N);
1583  for (int i=0; i<N; ++i)
1584  {
1585  v_up[i] = solVec[ci.extLIDVec[i]];
1586  ci.i_ip[i] = solVec[ci.intLIDVec[i]];
1587  ci.Fhat[i] = solVec[ci.intLIDVec[i]];
1588  }
1589  double * xhat = &solVec[ci.li_ROM[0]];
1590 
1591  // Compute Fhat[0:numExtVars-1] = i_ip - Lhat'*xhat
1592  blas.GEMV( Teuchos::TRANS, ci.numROMVars, ci.numExtVars, -1.0, &ci.Lhat[0], ci.numROMVars, xhat, 1, 1.0, &ci.Fhat[0], 1 );
1593 
1594  // Xyce::dout() << "Fhat (should just change first two elements): " << std::endl;
1595  // for (int i=0; i<ci.numIntVars; i++)
1596  // Xyce::dout() << "Fhat [" << i << "] = " << ci.Fhat[i] << std::endl;
1597 
1598  // Compute Fhat[numExtVars:numIntVars] = Ghat*xhat - Bhat*v_up
1599  if (ci.isGSparse)
1600  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] );
1601  else
1602  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 );
1603  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 );
1604 
1605  // Xyce::dout() << "Fhat (should just change last elements representing ROM): " << std::endl;
1606  // for (int i=0; i<ci.numIntVars; i++)
1607  // Xyce::dout() << "Fhat [" << i << "] = " << ci.Fhat[i] << std::endl;
1608 
1609  // Compute Qhat = Chat * xhat
1610  if (ci.isCSparse)
1611  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] );
1612  else
1613  blas.GEMV( Teuchos::NO_TRANS, ci.numROMVars, ci.numROMVars, 1.0, &ci.Chat[0], ci.numROMVars, xhat, 1, 0.0, &ci.Qhat[0], 1 );
1614 
1615  // Xyce::dout() << "Qhat (should change all elements): " << std::endl;
1616  // for (int i=0; i<ci.numROMVars; i++)
1617  // Xyce::dout() << "Qhat [" << i << "] = " << ci.Qhat[i] << std::endl;
1618  }
1619  }
1620 
1621  return true;
1622 }
1623 
1624 
1625 
1626 //-----------------------------------------------------------------------------
1627 // Function : Master::printMatrix
1628 // Purpose :
1629 // Special Notes : For debugging 2-level device stamp
1630 // Scope : public
1631 // Creator : Brad Bond, SNL
1632 // Creation Date : 2011-03-11
1633 //-----------------------------------------------------------------------------
1634 void Master::printMatrix ( std::string vname, double * Matrix, int Nrows, int Ncols )
1635 {
1636  Xyce::dout() << std::endl << vname << ": " << std::endl;
1637  for(int ix=0; ix < Nrows; ix++)
1638  {
1639  for(int iy=0; iy < Ncols; iy++)
1640  {
1641  Xyce::dout() << Matrix[iy*Nrows+ix] << " ";
1642  }
1643  Xyce::dout() << std::endl;
1644  }
1645 }
1646 
1647 //-----------------------------------------------------------------------------
1648 // Function : Master::loadDAEVectors
1649 // Purpose :
1650 // Special Notes :
1651 // Scope : public
1652 // Creator : Heidi Thornquist, SNL
1653 // Creation Date : 11/26/08
1654 //-----------------------------------------------------------------------------
1655 bool Master::loadDAEVectors (double * solVec, double * fVec, double *qVec, double * bVec, double * storeLeadF, double * storeLeadQ)
1656 {
1657 #ifdef Xyce_DEBUG_DEVICE
1658  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1659  {
1660  Xyce::dout() << " ----------------------------------" << std::endl;
1661  Xyce::dout() << " Master::loadDAEVectors: " << std::endl;
1662  }
1663 #endif
1664 
1665  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1666  {
1667  Instance & ci = *(*it);
1668  if(ci.usePortDesc==0)
1669  {
1670  // Load F vector
1671  for (int i=0; i<ci.numExtVars; ++i)
1672  {
1673  fVec[ci.extLIDVec[i]] += ci.i_ip[i];
1674  fVec[ci.intLIDVec[i]] += ci.Fhat[i];
1675  }
1676 
1677  // Load ROM part of F and Q vector
1678 #ifdef _OMP
1679 #pragma omp parallel for
1680 #endif
1681  for (int i=0; i<ci.numROMVars; i++)
1682  {
1683  // F vector
1684 
1685  fVec[ci.li_ROM[i]] += ci.Fhat[ci.numExtVars+i];
1686  // Q vector
1687 
1688  qVec[ci.li_ROM[i]] += ci.Qhat[i];
1689  }
1690  }
1691 
1692  // TWO-LEVEL STAMP
1693  else
1694  {
1695  for (int i=0; i<ci.numExtVars; ++i)
1696  {
1697  fVec[ci.extLIDVec[i]] += ci.Fstamp[i];
1698  }
1699  }
1700  }
1701  return true;
1702 }
1703 
1704 //-----------------------------------------------------------------------------
1705 // Function : Master::loadDAEMatrices
1706 // Purpose :
1707 // Special Notes :
1708 // Scope : public
1709 // Creator : Heidi Thornquist, SNL
1710 // Creation Date : 11/26/08
1711 //-----------------------------------------------------------------------------
1712 bool Master::loadDAEMatrices (N_LAS_Matrix & dFdx, N_LAS_Matrix & dQdx)
1713 {
1714 #ifdef Xyce_DEBUG_DEVICE
1715  if (getDeviceOptions().debugLevel > 0 && getSolverState().debugTimeFlag)
1716  {
1717  Xyce::dout() << " ----------------------------------" << std::endl;
1718  Xyce::dout() << " Master::loadDAEMatrices: " << std::endl;
1719  }
1720 #endif
1721 
1722  for (InstanceVector::const_iterator it = getInstanceBegin(); it != getInstanceEnd(); ++it)
1723  {
1724  Instance & ci = *(*it);
1725 
1726  if(ci.usePortDesc==0)
1727  {
1728 
1729 #ifdef Xyce_DEBUG_DEVICE
1731  {
1732  Xyce::dout() << " loads for ROM " << ci.getName() << std::endl;
1733  }
1734 #endif
1735 
1736 #ifndef Xyce_NONPOINTER_MATRIX_LOAD
1737  // Load dF/dx
1738  for (int i=0; i<ci.numExtVars; ++i)
1739  {
1740 
1741  *(ci.fEqu_up_NodePtr[i]) += 1.0;
1742 
1743  *(ci.fEqu_ip_NodePtr[i]) += 1.0;
1744  }
1745 
1746  // Load -Lhat portion of dF/dx
1747 #ifdef _OMP
1748 #pragma omp parallel for
1749 #endif
1750  for (int i=0; i<ci.numExtVars; i++)
1751  {
1752  double * LhatPtr = ci.fROMEqu_Lhat_VarsPtrs[i];
1753 #ifdef _OMP
1754 #pragma omp parallel for
1755 #endif
1756  for (int j=0; j<ci.numROMVars; j++)
1757  {
1758 
1759  LhatPtr[j] -= ci.Lhat[i*ci.numROMVars + j];
1760  }
1761  }
1762 
1763  // Load -Bhat portion of dF/dx
1764 #ifdef _OMP
1765 #pragma omp parallel for
1766 #endif
1767  for (int i=0; i<ci.numROMVars; i++)
1768  {
1769 #ifdef _OMP
1770 #pragma omp parallel for
1771 #endif
1772  for (int j=0; j<ci.numExtVars; j++)
1773  {
1774 
1775  *(ci.fROMEqu_Bhat_VarsPtrs[2*i+j]) -= ci.Bhat[j*ci.numROMVars + i];
1776  }
1777  }
1778 
1779  // Load Ghat portion of dF/dx
1780  if (ci.isGSparse)
1781  {
1782 #ifdef _OMP
1783 #pragma omp parallel for
1784 #endif
1785  int nnz = ci.Ghat_rowPtr[ci.numROMVars];
1786  for (int i=0; i<nnz; ++i)
1787  *(ci.fROMEqu_Ghat_VarsPtrs[i]) += ci.Ghat[i];
1788  }
1789  else
1790  {
1791 #ifdef _OMP
1792 #pragma omp parallel for
1793 #endif
1794  for (int i=0; i<ci.numROMVars; i++)
1795  {
1796  double * GhatPtr = ci.fROMEqu_Ghat_VarsPtrs[i];
1797 #ifdef _OMP
1798 #pragma omp parallel for
1799 #endif
1800  for (int j=0; j<ci.numROMVars; j++)
1801  {
1802 
1803  GhatPtr[j] += ci.Ghat[j*ci.numROMVars + i];
1804  }
1805  }
1806  }
1807 
1808  // Load dQ/dx
1809  // Load Chat portion of dQ/dx
1810  if (ci.isCSparse)
1811  {
1812 #ifdef _OMP
1813 #pragma omp parallel for
1814 #endif
1815  int nnz=ci.Chat_rowPtr[ci.numROMVars];
1816  for(int i=0; i<nnz; i++)
1817  *(ci.qROMEqu_Chat_VarsPtrs[i]) += ci.Chat[i];
1818  }
1819  else
1820  {
1821 #ifdef _OMP
1822 #pragma omp parallel for
1823 #endif
1824  for (int i=0; i<ci.numROMVars; i++)
1825  {
1826  double * ChatPtr = ci.qROMEqu_Chat_VarsPtrs[i];
1827 #ifdef _OMP
1828 #pragma omp parallel for
1829 #endif
1830  for (int j=0; j<ci.numROMVars; j++)
1831  {
1832 
1833  ChatPtr[j] += ci.Chat[j*ci.numROMVars + i];
1834  }
1835  }
1836  }
1837 
1838 #else
1839 
1840 #ifdef _OMP
1841 #pragma omp parallel for
1842 #endif
1843  for (int i=0; i<ci.numExtVars; i++)
1844  {
1845 
1846  dFdx[ci.extLIDVec[i]][ci.AEqu_up_NodeOffset[i]] += 1.0;
1847 
1848  dFdx[ci.intLIDVec[i]][ci.AEqu_ip_NodeOffset[i]] += 1.0;
1849  }
1850 
1851 #ifdef _OMP
1852 #pragma omp parallel for
1853 #endif
1854  // Load -Lhat portion of dF/dx
1855  for (int j=0; j<ci.numROMVars; j++)
1856  {
1857 #ifdef _OMP
1858 #pragma omp parallel for
1859 #endif
1860  for (int i=0; i<ci.numExtVars; i++)
1861  {
1862 
1863  dFdx[ci.intLIDVec[i]][ci.ROMEqu_Lt_NodeOffset[j]] -= ci.Lhat[i*ci.numROMVars + j];
1864  }
1865  }
1866 
1867  // Load -Bhat portion of dF/dx
1868 #ifdef _OMP
1869 #pragma omp parallel for
1870 #endif
1871  for (int i=0; i<ci.numROMVars; i++)
1872  {
1873 #ifdef _OMP
1874 #pragma omp parallel for
1875 #endif
1876  for (int j=0; j<ci.numExtVars; j++)
1877  {
1878 
1879  dFdx[ci.li_ROM[i]][ci.ROMEqu_B_NodeOffset[i*ci.numExtVars+j]] -= ci.Bhat[j*ci.numROMVars + i];
1880  }
1881  }
1882 
1883  // Load Ghat portion of dF/dx
1884  if (ci.isGSparse)
1885  {
1886  for (int j=ci.Ghat_rowPtr[i]; j<ci.Ghat_rowPtr[i+1]; j++)
1887  {
1888 
1889  dFdx[ci.li_ROM[i]][ci.ROMEqu_G_NodeOffset[j]] += ci.Ghat[j];
1890  }
1891  }
1892  else
1893  {
1894 #ifdef _OMP
1895 #pragma omp parallel for
1896 #endif
1897  for (int i=0; i<ci.numROMVars; i++)
1898  {
1899 #ifdef _OMP
1900 #pragma omp parallel for
1901 #endif
1902  for (int j=0; j<ci.numROMVars; j++)
1903  {
1904 
1905  dFdx[ci.li_ROM[i]][ci.ROMEqu_GpC_NodeOffset[j]] += ci.Ghat[j*ci.numROMVars + i];
1906  }
1907  }
1908  }
1909 
1910  // Load Chat portion of dQ/dx
1911  if (ci.isCSparse)
1912  {
1913  for (int j=ci.Chat_rowPtr[i]; j<ci.Chat_rowPtr[i+1]; j++)
1914  {
1915 
1916  dQdx[ci.li_ROM[i]][ci.ROMEqu_C_NodeOffset[j]] += ci.Chat[j];
1917  }
1918  }
1919  else
1920  {
1921 #ifdef _OMP
1922 #pragma omp parallel for
1923 #endif
1924  for (int i=0; i<ci.numROMVars; i++)
1925  {
1926 #ifdef _OMP
1927 #pragma omp parallel for
1928 #endif
1929  for (int j=0; j<ci.numROMVars; j++)
1930  {
1931 
1932  dQdx[ci.li_ROM[i]][ci.ROMEqu_GpC_NodeOffset[j]] += ci.Chat[j*ci.numROMVars + i];
1933  }
1934  }
1935  }
1936 #endif
1937  }
1938  else
1939  {
1940  for (int i=0; i<ci.numExtVars; i++)
1941  {
1942  for (int j=0; j<ci.numExtVars; j++)
1943  {
1944  dFdx[ci.extLIDVec[i]][ci.AEqu_NodeOffset[i][j]] += ci.Jstamp[i*ci.numExtVars + j];
1945  }
1946  }
1947  }
1948  }
1949  return true;
1950 }
1951 
1952 Device *Traits::factory(const Configuration &configuration, const FactoryBlock &factory_block)
1953 {
1954 
1955  return new Master(configuration, factory_block, factory_block.solverState_, factory_block.deviceOptions_);
1956 }
1957 
1959 {
1961  .registerDevice("rom", 1)
1962  .registerModelType("rom", 1);
1963 }
1964 
1965 } // namespace ROM
1966 } // namespace Device
1967 } // namespace Xyce