Xyce  6.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
N_ANP_MOR.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_ANP_MOR.C,v $
27 // Purpose : MOR analysis functions.
28 // Special Notes :
29 // Creator : Ting Mei
30 // Creation Date : 7/11
31 //
32 // Revision Information:
33 // ---------------------
34 // Revision Number: $Revision: 1.37.2.1 $
35 // Revision Date : $Date: 2014/03/04 23:50:53 $
36 // Current Owner : $Author: tvrusso $
37 //-----------------------------------------------------------------------------
38 
39 #include <Xyce_config.h>
40 
41 
42 // ---------- Standard Includes ----------
43 #include <iomanip>
44 
45 
46 // ---------- Xyce Includes ----------
47 #include <N_ANP_AnalysisManager.h>
48 #include <N_TIA_Assembler.h>
49 #include <N_LOA_Loader.h>
50 #include <N_LAS_Matrix.h>
51 #include <N_LAS_System.h>
52 #include <N_IO_CmdParse.h>
53 #include <N_TIA_StepErrorControl.h>
54 #include <N_UTL_Timer.h>
55 #include <N_UTL_ExpressionData.h>
56 #include <N_NLS_ReturnCodes.h>
57 
58 #include <N_UTL_Misc.h>
59 #include <N_LAS_MultiVector.h>
60 #include <N_LAS_BlockMatrix.h>
61 #include <N_LAS_BlockVector.h>
62 #include <N_LAS_BlockSystemHelpers.h>
63 
64 #include <N_ANP_MOR.h>
65 #include <N_ANP_Report.h>
66 #include <N_LAS_MOROperators.h>
67 
68 #include <N_PDS_ParMap.h>
69 #include <N_PDS_Comm.h>
70 
71 #ifdef Xyce_PARALLEL_MPI
72 #include <N_PDS_ParComm.h>
73 #include <mpi.h>
74 #else
75 #include <N_PDS_SerialComm.h>
76 #endif
77 
78 // ---------- Other Includes ----------
79 
80 #include <Epetra_CrsMatrix.h>
81 #include <Epetra_Operator.h>
82 #include <Epetra_CrsGraph.h>
83 #include <Epetra_MultiVector.h>
84 #include <Epetra_LinearProblem.h>
85 #include <Amesos.h>
86 
87 #ifdef Xyce_BELOS
88 #include <BelosLinearProblem.hpp>
89 #include <BelosBlockGmresIter.hpp>
90 #include <BelosDGKSOrthoManager.hpp>
91 #include <BelosStatusTestMaxIters.hpp>
92 #include <BelosOutputManager.hpp>
93 #include <BelosEpetraAdapter.hpp>
94 #endif
95 
96 #include <Teuchos_SerialDenseMatrix.hpp>
97 #include <Teuchos_ScalarTraits.hpp>
98 #include <Teuchos_LAPACK.hpp>
99 #include <Teuchos_BLAS.hpp>
100 
101 namespace Xyce {
102 namespace Analysis {
103 
104 //-----------------------------------------------------------------------------
105 // Function : MOR::MOR( AnalysisManager * )
106 // Purpose : constructor
107 // Special Notes :
108 // Scope : public
109 // Creator : Ting Mei
110 // Creation Date : 5/11
111 //-----------------------------------------------------------------------------
112 MOR::MOR( AnalysisManager * anaManagerPtr ) :
113  AnalysisBase(anaManagerPtr),
114  dcopFlag_(true),
115  morEvalSize_(0),
116  numPorts_(0),
117  stepMult_(0.0),
118  fStep_(0.0),
119  currentFreq_(0.0),
120  s0_(0.0)
121 {
122 }
123 
124 //-----------------------------------------------------------------------------
125 // Function : MOR::~MOR()
126 // Purpose : destructor
127 // Special Notes :
128 // Scope : public
129 // Creator : Ting Mei
130 // Creation Date : 5/11
131 //-----------------------------------------------------------------------------
133 {
134 }
135 
136 //-----------------------------------------------------------------------------
137 // Function : MOR::setAnalysisParams
138 // Purpose :
139 // Special Notes : These are from the .MOR statement.
140 // Scope : public
141 // Creator : Ting Mei, SNL
142 // Creation Date : 6/11
143 //-----------------------------------------------------------------------------
144 bool MOR::setAnalysisParams(const N_UTL_OptionBlock & paramsBlock)
145 {
146  std::list<N_UTL_Param>::const_iterator it_tp;
147  std::list<N_UTL_Param>::const_iterator first = paramsBlock.getParams().begin();
148  std::list<N_UTL_Param>::const_iterator last = paramsBlock.getParams().end();
149  for (it_tp = first; it_tp != last; ++it_tp)
150  {
151  if (it_tp->uTag() == "SIZE")
152  {
153  tiaParams.ROMsize = it_tp->getImmutableValue<int>();
154  }
155  else if (it_tp->uTag() == "PORTLIST")
156  {
157  portList_ = it_tp->getValue<std::vector<std::string> >();
158  }
159  }
160 
161 // tiaParams.debugLevel = 1;
162 #ifdef Xyce_DEBUG_ANALYSIS
163  if (tiaParams.debugLevel > 0)
164  {
165  dout() << std::endl
166  << section_divider << std::endl
167  <<" MOR simulation parameters" << std::endl
168  << " size = " << tiaParams.ROMsize << std::endl;
169  }
170 #endif
171 
172  return true;
173 }
174 
175 //-----------------------------------------------------------------------------
176 // Function : MOR::run()
177 // Purpose :
178 // Special Notes :
179 // Scope : public
180 // Creator : Ting Mei, SNL
181 // Creation Date : 5/11
182 //-----------------------------------------------------------------------------
183 bool MOR::run()
184 {
185  bool bsuccess = true;
186 
187  bsuccess = bsuccess & init();
188  bsuccess = bsuccess & reduceSystem();
189 
191  {
192  // Evaluate original system
193  bsuccess = bsuccess & evalOrigTransferFunction();
194  }
195 
196  // Reset the output adapter, just in case the reduced system needs to output
197  // its transfer functions.
198  outputMgrAdapterRCPtr_->resetOutputMORTF();
199 
201  {
202  // Evaluate reduced system
203  bsuccess = bsuccess & evalRedTransferFunction();
204  }
205 
206  // if processing the loop failed,
207  // then skip finish step
208  if( bsuccess )
209  {
210  bsuccess = bsuccess & finish();
211  }
212 
213  return bsuccess;
214 }
215 
216 //-----------------------------------------------------------------------------
217 // Function : MOR::init()
218 // Purpose :
219 // Special Notes :
220 // Scope : public
221 // Creator : Ting Mei, SNL
222 // Creation Date : 5/11
223 //-----------------------------------------------------------------------------
224 bool MOR::init()
225 {
226  bool bsuccess = true;
227 
228  // Compute expansion point in transformed space.
229  s0_ = 2.0 * M_PI * tiaParams.morExpPoint;
230 
232  {
234  }
235 
236  if(dcopFlag_)
237  {
238  anaManagerRCPtr_->currentMode_ = 0;
239  }
240 
241  // Get set to do the operating point.
243  wimRCPtr_->createTimeIntegMethod(integrationMethod_);
244 
245  stepNumber = 0;
246  doubleDCOPFlag_ = loaderRCPtr_->getDoubleDCOPFlag ();
248 
249  // set initial guess, if there is one to be set.
250  // this setInitialGuess call is to up an initial guess in the
251  // devices that have them (usually PDE devices). This is different than
252  // the "intializeProblem" call, which sets IC's. (initial conditions are
253  // different than initial guesses.
254  loaderRCPtr_->setInitialGuess (anaManagerRCPtr_->getTIADataStore()->nextSolutionPtr);
255 
256  // If available, set initial solution
257  inputOPFlag_ =
258  outputMgrAdapterRCPtr_->setupInitialConditions( *(anaManagerRCPtr_->getTIADataStore()->nextSolutionPtr),
259  *(anaManagerRCPtr_->getTIADataStore()->flagSolutionPtr));
260 
261  // Set a constant history for operating point calculation
262  anaManagerRCPtr_->getTIADataStore()->setConstantHistory();
263  anaManagerRCPtr_->getTIADataStore()->computeDividedDifferences();
264  wimRCPtr_->obtainCorrectorDeriv();
265 
266  // solving for DC op
267  handlePredictor();
268  loaderRCPtr_->updateSources();
269  secRCPtr_->newtonConvergenceStatus = nlsMgrRCPtr_->solve();
270  anaManagerRCPtr_->getTIADataStore()->stepLinearCombo ();
272  secRCPtr_->evaluateStepError ();
273 
274  if ( secRCPtr_->newtonConvergenceStatus <= 0)
275  {
276  std::string msg=
277  "Solving for DC operating point failed! Cannot continue MOR analysis.";
278  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
279  }
280 
281  // Create B matrix stamp
282  std::vector<int> tempVec;
283  loaderRCPtr_->getBMatrixEntriesforMOR(tempVec, bMatPosEntriesVec_);
284 
285  // Create inductor matrix stamp
286 // loaderRCPtr_->getInductorsEntriesforMOR(inductorEntriesVec_);
287 
288  // Determine how many global ports their are performing a sumAll()
289  int hsize = tempVec.size();
290  N_PDS_Comm * pdsComm = (lasSystemRCPtr_->getPDSManager())->getPDSComm();
291  pdsComm->sumAll( &hsize, &numPorts_, 1 );
292 
293  // Check that the listed ports on the .mor line are the same number as the B matrix entries.
294  if ( numPorts_ != (int)portList_.size() )
295  {
296  std::string msg=
297  "Number of specified ports in .MOR line is inconsistent with number of voltage sources.";
298  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
299  }
300 
301  // Getting the GIDs for the port list in the order specified in the .MOR line
302  // This is used to permute the bMatEntriesVec_ in the order specified by the user.
303  std::vector<int> gidPosEntries( hsize );
304  for (int i=0; i<hsize; ++i)
305  {
306  std::list<int> svGIDList1, dummyList;
307  char type1;
308  anaManagerRCPtr_->topoMgrPtr->getNodeSVarGIDs(NodeID(portList_[i],_VNODE), svGIDList1, dummyList, type1);
309 
310  // Grab the GID for this port.
311  gidPosEntries[i] = svGIDList1.front();
312  }
313 
314  // Use the base map to get the global IDs
315  // Get the parallel maps for the original system
316  RCP<N_PDS_Manager> pdsMgrPtr_ = rcp(lasSystemRCPtr_->getPDSManager(), false);
317  RCP<N_PDS_ParMap> BaseMap_ = rcp(pdsMgrPtr_->getParallelMap( "SOLUTION" ), false);
318 
319  // Find the voltage source corresponding to each port and place the LID in the bMatEntriesVec_.
320  bMatEntriesVec_.resize( hsize );
321  for (int i=0; i<hsize; ++i)
322  {
323  int gid = gidPosEntries[i];
324  bool found = false;
325  for (int j=0; j<hsize; ++j)
326  {
327  if (gid == BaseMap_->localToGlobalIndex(bMatPosEntriesVec_[j]))
328  {
329  bMatEntriesVec_[i] = tempVec[j];
330  found = true;
331  break;
332  }
333  }
334  if (found == false)
335  { std::string msg=
336  "Did not find voltage source corresponding to port.";
337  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
338  }
339  }
340 
342  {
343  // Resize transfer function matrices
344  origH_.shape(numPorts_, numPorts_);
345  }
347  {
348  // Resize transfer function matrices
349  redH_.shape(numPorts_, numPorts_);
350  }
351 
352  // Create C and G matrices from DCOP solution
353  anaManagerRCPtr_->getTIADataStore()->daeQVectorPtr->putScalar(0.0);
354  anaManagerRCPtr_->getTIADataStore()->daeFVectorPtr->putScalar(0.0);
355 
356  anaManagerRCPtr_->getTIADataStore()->dFdxdVpVectorPtr->putScalar(0.0);
357  anaManagerRCPtr_->getTIADataStore()->dQdxdVpVectorPtr->putScalar(0.0);
358  anaManagerRCPtr_->getTIADataStore()->dQdxMatrixPtr->put(0.0);
359  anaManagerRCPtr_->getTIADataStore()->dFdxMatrixPtr->put(0.0);
360 
361  loaderRCPtr_->updateState
362  ((anaManagerRCPtr_->getTIADataStore()->nextSolutionPtr),
363  (anaManagerRCPtr_->getTIADataStore()->currSolutionPtr),
364  (anaManagerRCPtr_->getTIADataStore()->lastSolutionPtr),
365  (anaManagerRCPtr_->getTIADataStore()->nextStatePtr),
366  (anaManagerRCPtr_->getTIADataStore()->currStatePtr),
367  (anaManagerRCPtr_->getTIADataStore()->lastStatePtr),
368  (anaManagerRCPtr_->getTIADataStore()->nextStorePtr),
369  (anaManagerRCPtr_->getTIADataStore()->currStorePtr),
370  (anaManagerRCPtr_->getTIADataStore()->lastStorePtr)
371  );
372 
373  loaderRCPtr_->loadDAEVectors
374  ((anaManagerRCPtr_->getTIADataStore()->nextSolutionPtr),
375  (anaManagerRCPtr_->getTIADataStore()->currSolutionPtr),
376  (anaManagerRCPtr_->getTIADataStore()->lastSolutionPtr),
377  (anaManagerRCPtr_->getTIADataStore()->nextStatePtr),
378  (anaManagerRCPtr_->getTIADataStore()->currStatePtr),
379  (anaManagerRCPtr_->getTIADataStore()->lastStatePtr),
380  (anaManagerRCPtr_->getTIADataStore()->nextStateDerivPtr),
381  (anaManagerRCPtr_->getTIADataStore()->nextStorePtr),
382  (anaManagerRCPtr_->getTIADataStore()->currStorePtr),
383  (anaManagerRCPtr_->getTIADataStore()->lastStorePtr),
384  (anaManagerRCPtr_->getTIADataStore()->nextStoreLeadCurrQCompPtr),
385  (anaManagerRCPtr_->getTIADataStore()->daeQVectorPtr),
386  (anaManagerRCPtr_->getTIADataStore()->daeFVectorPtr),
387  (anaManagerRCPtr_->getTIADataStore()->dFdxdVpVectorPtr),
388  (anaManagerRCPtr_->getTIADataStore()->dQdxdVpVectorPtr) );
389 
390  loaderRCPtr_->loadDAEMatrices(anaManagerRCPtr_->getTIADataStore()->nextSolutionPtr,
391  anaManagerRCPtr_->getTIADataStore()->nextStatePtr, anaManagerRCPtr_->getTIADataStore()->nextStateDerivPtr,
392  anaManagerRCPtr_->getTIADataStore()->nextStorePtr,
393  anaManagerRCPtr_->getTIADataStore()->dQdxMatrixPtr, anaManagerRCPtr_->getTIADataStore()->dFdxMatrixPtr);
394 
395  CPtr_ = rcp(anaManagerRCPtr_->getTIADataStore()->dQdxMatrixPtr, false);
396  GPtr_ = rcp(anaManagerRCPtr_->getTIADataStore()->dFdxMatrixPtr, false);
397 
398 
399  /// Xyce::dout() << "Branch nodes: " << std::endl;
400  /// for (unsigned int i=0; i < bMatEntriesVec_.size(); ++i)
401  /// {
402  /// Xyce::dout() << "Node " << i << " : " << bMatEntriesVec_[i] << std::endl;
403  /// }
404 
405  /// Xyce::dout() << "Printing GPtr: " << std::endl;
406  /// GPtr_->printPetraObject();
407  /// Xyce::dout() << "Printing CPtr: " << std::endl;
408  /// CPtr_->printPetraObject();
409 
410 
411  // Storage for row extraction
412  int length=1, numEntries=0;
413  std::vector<int> colIndices(length);
414  std::vector<double> coeffs(length);
415 
416  for (unsigned int i=0; i < bMatEntriesVec_.size(); ++i)
417  {
418  // Get the number of non-zero entries in this row.
419  numEntries = GPtr_->getLocalRowLength( bMatEntriesVec_[i] );
420  if ( numEntries != 1 )
421  {
422  std::string msg=
423  "Supposed voltage source row has too many entries! Cannot continue MOR analysis.";
424  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
425  }
426 
427  // Extract out rows of G based on indices in bMatEntriesVec_.
428  GPtr_->getLocalRowCopy(bMatEntriesVec_[i], length, numEntries, &coeffs[0], &colIndices[0]);
429 
430  // If the coefficient for this voltage source is positive, make it negative.
431  if ( coeffs[0] > 0.0 )
432  {
433  coeffs[0] *= -1.0;
434  GPtr_->putLocalRow(bMatEntriesVec_[i], length, &coeffs[0], &colIndices[0]);
435  }
436  }
437 
438 
439  /// Xyce::dout() << "Printing GPtr (after scaling): " << std::endl;
440  /// GPtr_->printPetraObject();
441 
442  return bsuccess;
443 }
444 
445 //-----------------------------------------------------------------------------
446 // Function : MOR::reduceSystem()
447 // Purpose :
448 // Special Notes :
449 // Scope : public
450 // Creator : Heidi Thornquist, SNL
451 // Creation Date : 6/4/2012
452 //-----------------------------------------------------------------------------
454 {
455  // At this time, the reduceSystem() method will compute the reduced-order system using
456  // multi-port PRIMA. This method should allow the user multiple algorithms, defined by
457  // the tiaParams.morMethod option, which would be best implemented using a factory design.
458 
459  bool bsuccess = true;
460 
461  // Get the parallel maps for the original system
462  RCP<N_PDS_Manager> pdsMgrPtr_;
463  pdsMgrPtr_ = rcp(lasSystemRCPtr_->getPDSManager(), false);
464 
465  RCP<N_PDS_ParMap> BaseMap_;
466  BaseMap_ = rcp(pdsMgrPtr_->getParallelMap( "SOLUTION" ), false);
467  //BaseMap_->petraMap()->Print(Xyce::dout());
468 
469  // Create matrix for (G + s0 * C)
470  if (s0_ != 0.0)
471  {
472  sCpG_MatrixPtr_ = rcp( new N_LAS_Matrix( &CPtr_->epetraObj(), false ) );
473  sCpG_MatrixPtr_->scale( s0_ );
474  sCpG_MatrixPtr_->add( *GPtr_ );
475  }
476  else
477  {
478  sCpG_MatrixPtr_ = rcp( new N_LAS_Matrix( &GPtr_->epetraObj(), false ) );
479  }
480 
481  // Create multivector for B and R
482  RPtr_ = rcp( new N_LAS_MultiVector( *BaseMap_, numPorts_ ) );
483  RPtr_->putScalar( 0.0 );
484  BPtr_ = rcp( new N_LAS_MultiVector( *BaseMap_, numPorts_ ) );
485  for (unsigned int j=0; j < bMatEntriesVec_.size(); ++j)
486  {
487  BPtr_->setElementByGlobalIndex( BaseMap_->localToGlobalIndex(bMatEntriesVec_[j]), -1.0, j );
488  }
489 
490  /// Xyce::dout() << "Printing out BPtr" << std::endl;
491  /// BPtr_->epetraObj().Print(Xyce::dout());
492 
493  /// Xyce::dout() << "Printing out sCpG" << std::endl;
494  /// (sCpG_MatrixPtr_->epetraObj()).Print(Xyce::dout());
495 
496  // Create linear problem for (G + s0 * C)
497  origProblem_ = rcp(new Epetra_LinearProblem(&sCpG_MatrixPtr_->epetraObj(), &RPtr_->epetraObj(), &BPtr_->epetraObj() ) );
498 
499  // Create solver object for this linear problem, which will be used to generate the projection basis
500  Amesos amesosFactory;
501  origSolver_ = rcp( amesosFactory.Create( "Klu", *origProblem_ ) );
502 
503  // Solve for R = inv(G + s0*C)*B
504  // Perform symbolic factorization.
505  int linearStatus = origSolver_->SymbolicFactorization();
506  if (linearStatus != 0)
507  {
508  Xyce::dout() << "Amesos symbolic factorization exited with error: " << linearStatus << std::endl;
509  bsuccess = false;
510  }
511 
512  // Perform numeric factorization
513  linearStatus = origSolver_->NumericFactorization();
514  if (linearStatus != 0)
515  {
516  Xyce::dout() << "Amesos numeric factorization exited with error: " << linearStatus << std::endl;
517  bsuccess = false;
518  }
519 
520  // Perform solve for R = inv(G + s0*C)*B
521  linearStatus = origSolver_->Solve();
522  if (linearStatus != 0)
523  {
524  Xyce::dout() << "Amesos solve exited with error: " << linearStatus << std::endl;
525  bsuccess = false;
526  }
527 
528  /// Xyce::dout() << "Printing out R" << std::endl;
529  /// (RPtr_->epetraObj()).Print(Xyce::dout());
530 
531  // Create an Epetra_Operator object to apply the operator inv(G + s0*C)*C
532  RCP<Epetra_Operator> COpPtr_ = rcp( &CPtr_->epetraObj(), false );
533  RCP<N_LAS_AmesosGenOp> AOp = rcp( new N_LAS_AmesosGenOp( origSolver_, COpPtr_ ) );
534 
535  // Check to see if the requested size of the ROM is valid.
536  // An orthogonal basis cannot be generated that is larger than the dimension of the original system
537  int kblock = 0;
538  if (tiaParams.ROMsize > RPtr_->globalLength())
539  {
540  kblock = (int)(RPtr_->globalLength() / numPorts_);
541  UserWarning(*this) << "Requested reduced-order model dimension is larger than original system dimension, resizing to original system dimension";
542  }
543  else
544  {
545  kblock = (int)(tiaParams.ROMsize / numPorts_);
546  }
547  int k = kblock * numPorts_;
548 
549  // Resize the projection matrices
550  redG_.shape(k, k);
551  redC_.shape(k, k);
552  redB_.shape(k, numPorts_);
553  redL_.shape(k, numPorts_);
554 
555 #ifdef Xyce_BELOS
556  // ---------------------------------------------------------------------
557  // Now use Belos to compute the basis vectors for K_k(inv(G + s0*C)*C, R)
558  // ---------------------------------------------------------------------
559 
560  // Helpful typedefs for the templates
561  typedef double ST;
562  typedef Epetra_MultiVector MV;
563  typedef Epetra_Operator OP;
564  typedef Belos::MultiVecTraits<ST,MV> MVT;
565 
566  // Output manager.
567  Belos::OutputManager<ST> printer;
568 
569  // Status test.
570  Belos::StatusTestMaxIters<ST, MV, OP> maxIterTest( kblock );
571 
572  // Orthogonalization manager.
573  Belos::DGKSOrthoManager<ST, MV, OP> orthoMgr;
574 
575  // Linear Problem.
576  // Reuse RPtr_. We need the basis vectors for K(inv(G + s0*C)*C, R)
577  N_LAS_MultiVector temp( *BaseMap_, numPorts_ );
578  Belos::LinearProblem<ST, MV, OP > problem( AOp,
579  rcp( &temp.epetraObj(), false ),
580  rcp( &RPtr_->epetraObj(), false ));
581  problem.setProblem();
582 
583  // Create parameter list.
584  Teuchos::ParameterList params;
585  params.set("Num Blocks", kblock);
586  params.set("Block Size", numPorts_ );
587 
588  // Create Krylov subspace iteration from Belos
589  Belos::BlockGmresIter<ST, MV, OP> krylovIter( rcp( &problem, false ),
590  rcp( &printer, false ),
591  rcp( &maxIterTest, false ),
592  rcp( &orthoMgr, false ),
593  params );
594 
595  // Get a matrix to hold the orthonormalization coefficients.
596  RCP<Teuchos::SerialDenseMatrix<int,ST> > z
597  = rcp( new Teuchos::SerialDenseMatrix<int,ST>( numPorts_, numPorts_ ) );
598 
599  // Orthonormalize the Krylov kernel vectors V
600  RCP<MV> V = rcp( new Epetra_MultiVector( RPtr_->epetraObj() ) );
601  orthoMgr.normalize( *V, z );
602 
603  // Set the new state and initialize the solver to use R as the kernel vectors.
604  Belos::GmresIterationState<ST,MV> initState;
605  initState.V = V;
606  initState.z = z;
607  initState.curDim = 0;
608  krylovIter.initializeGmres(initState);
609 
610  // Have the solver iterate until the basis size is computed
611  try {
612  krylovIter.iterate();
613  }
614  catch (const Belos::GmresIterationOrthoFailure &e) {
615  // This might happen if the basis size is the same as the operator's dimension.
616  }
617  catch (const std::exception &e) {
618  bsuccess = false; // Anything else is a failure.
619  }
620 
621  // Get the basis vectors back from the iteration object
622  Belos::GmresIterationState<ST,MV> newState = krylovIter.getState();
623 
624  // Create a view into the first k vectors of newState.V
625  std::vector<int> indices( k );
626  for (int i=0; i<k; ++i) { indices[i] = i; }
627  V = rcp( new Epetra_MultiVector( View, *newState.V, &indices[0], k ) );
628 
629  RCP<MV> W = rcp( new Epetra_MultiVector( V->Map(), k ) );
630  W = V;
631 // Xyce::dout() << "Printing out V" << std::endl;
632 // V->Print(Xyce::dout());
633 // Xyce::dout() << "Printing out W" << std::endl;
634 // W->Print(Xyce::dout());
635 
636  // ---------------------------------------------------------------------
637  // Sparsify the reduced system, if requested.
638  // ---------------------------------------------------------------------
640  {
641 
642  N_LAS_MultiVector xyceV( &*V, false );
643  N_LAS_MultiVector temp2( *BaseMap_, k );
644 
645  // G * V
646  GPtr_->matvec( false, xyceV, temp2 );
647  // V' * G * V
648  MVT::MvTransMv( 1.0, xyceV.epetraObj(), temp2.epetraObj(), redG_ );
649  //redG_.print( Xyce::dout() );
650 
651  // C * V
652  CPtr_->matvec( false, xyceV, temp2 );
653  // V' * C * V
654  MVT::MvTransMv( 1.0, xyceV.epetraObj(), temp2.epetraObj(), redC_ );
655  //redC_.print( Xyce::dout() );
656 
657  // V' * B
658  MVT::MvTransMv( 1.0, xyceV.epetraObj(), BPtr_->epetraObj(), redB_ );
659  //redB_.print( Xyce::dout() );
660 
661  bsuccess = bsuccess & sparsifyRedSystem_();
662  }
663 
664  // -----------------------------------------------------------------------------
665  // Scale the basis vectors, if requested, before computing the projected system
666  // -----------------------------------------------------------------------------
667 
668  // Create the scaling vector.
669  Teuchos::SerialDenseMatrix<int,ST> Xhatscale( k, 1 );
670 
671  int scaleType = tiaParams.morScaleType;
672 
673  if ( scaleType == 1 )
674  {
675  for (int i=0; i<k; ++i)
676  {
677  Xhatscale( i, 0 ) = tiaParams.morScaleFactor;
678  }
679  }
680 
681 // if ( scaleType == 2 )
682 // {
683 
684 // }
685 
686 if ( scaleType == 2 || scaleType == 3 || scaleType ==4)
687  {
688  Epetra_MultiVector Xmag( V->Map(), 1 );
689 
690  if ( scaleType == 2 )
691  Xmag.PutScalar( tiaParams.morScaleFactor );
692 
693  if ( scaleType == 4)
694  Xmag.PutScalar(1.0);
695 
696  MVT::MvTransMv( 1.0, *V, Xmag, Xhatscale );
697 
698 // Xhatscale.print(Xyce::dout());
699  for (int i=0; i<k; ++i)
700  {
701 
702  if ( scaleType == 2 )
703  {
704  if ( fabs(Xhatscale( i, 0 )) > tiaParams.morScaleFactor)
705  {
706  Xhatscale( i, 0 ) = tiaParams.morScaleFactor / fabs( Xhatscale( i, 0 ) );
707  }
708  else
709  {
710  Xhatscale( i, 0 ) = tiaParams.morScaleFactor1 / fabs( Xhatscale( i, 0 ) );
711  }
712  }
713 
714  if ( scaleType == 3 )
715  Xhatscale( i, 0 ) = tiaParams.morScaleFactor * fabs( Xhatscale( i, 0 ) );
716 
717  if ( scaleType == 4 )
718  {
719  if ( fabs(Xhatscale( i, 0 )) > 1.0 )
720  {
721  Xhatscale( i, 0 ) = tiaParams.morScaleFactor / fabs( Xhatscale( i, 0 ) );
722  }
723  else
724  {
725  Xhatscale( i, 0 ) = tiaParams.morScaleFactor1 / fabs( Xhatscale( i, 0 ) );
726  }
727  }
728 
729 
730  }
731  }
732 
733 // Xhatscale.print(Xyce::dout());
734 
735  // Scale the computed basis vectors before projecting the original system
736  Teuchos::SerialDenseMatrix<int,ST> D(k,k);
737  if ( scaleType != 0 )
738  {
739  RCP<MV> Vtemp = rcp( new Epetra_MultiVector( V->Map(), k ) );
740 // Teuchos::SerialDenseMatrix<int,ST> D(k,k);
741  for (int i=0; i<k; ++i)
742  {
743  if (Xhatscale( i, 0 ) != 0.0)
744  D(i,i) = 1.0/Xhatscale( i, 0 );
745  else
746  D(i,i) = 1.0;
747  }
748  Xyce::dout() << " the scaling matrix " << std::endl;
749 
750 // D.print(Xyce::dout());
751 
752  MVT::MvTimesMatAddMv( 1.0, *V, D, 0.0, *Vtemp );
753  V = Vtemp;
754  }
755 
756 // Xyce::dout() << "Printing out V" << std::endl;
757 // V->Print(Xyce::dout());
758 // Xyce::dout() << "Printing out W" << std::endl;
759 // W->Print(Xyce::dout());
760 
761  // ---------------------------------------------------------------------
762  // Now use the basis vectors for K_k(inv(G + s0*C)*C, R) to compute
763  // the projected system.
764  // ---------------------------------------------------------------------
765  N_LAS_MultiVector xyceV( &*V, false );
766  N_LAS_MultiVector xyceW( &*W, false );
767  N_LAS_MultiVector temp2( *BaseMap_, k );
768 
769 
770 // redL_ = redB_;
771 
773  {
774 // redL_ = redB_;
775  // G * V
776  GPtr_->matvec( false, xyceV, temp2 );
777  // V' * G * V
778  MVT::MvTransMv( 1.0, xyceW.epetraObj(), temp2.epetraObj(), redG_ );
779  //redG_.print( Xyce::dout() );
780 
781  // C * V
782  CPtr_->matvec( false, xyceV, temp2 );
783  // V' * C * V
784  MVT::MvTransMv( 1.0, xyceW.epetraObj(), temp2.epetraObj(), redC_ );
785  //redC_.print( Xyce::dout() );
786 
787  // V' * B
788  MVT::MvTransMv( 1.0, xyceW.epetraObj(), BPtr_->epetraObj(), redB_ );
789  //redB_.print( Xyce::dout() );
790 
791  MVT::MvTransMv( 1.0, xyceV.epetraObj(), BPtr_->epetraObj(), redL_ );
792 
793 
794 // Xyce::dout() << "Printing out redB" << std::endl;
795 // redB_.print(Xyce::dout());
796 // Xyce::dout() << "Printing out redL" << std::endl;
797 // redL_.print(Xyce::dout());
798  }
799  else
800  {
801 // RCP<MV> Vtemp = rcp( new Epetra_MultiVector( V->Map(), k ) );
802 
803 // redL_.print(Xyce::dout());
804 
805  if ( scaleType <= 1 )
806  {
807  redCPtr_->scale(1.0/tiaParams.morScaleFactor);
808  redGPtr_->scale(1.0/tiaParams.morScaleFactor);
809 
810  redL_.scale(1.0/tiaParams.morScaleFactor);
811 // redL_.multiply( Teuchos::NO_TRANS, Teuchos::NO_TRANS, 1.0, D, redL_, 0.0 );
812 
813 // redL_.print(Xyce::dout());
814 
815  }
816  else
817  {
818  std::string msg=
819  "MOR::reduceSystem: MOR options sparsificationType=1 can only be used with scaletype=1. Other scale types have not been supported for sparsification!";
820  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
821  }
822 
823  }
824 // // ---------------------------------------------------------------------
825 // // Sparsify the reduced system, if requested.
826 // // ---------------------------------------------------------------------
827 // if (tiaParams.morSparsificationType)
828 // {
829 
830 // N_LAS_MultiVector xyceV( &*V, false );
831 // N_LAS_MultiVector temp2( *BaseMap_, k );
832 
833 // // G * V
834 // GPtr_->matvec( false, xyceV, temp2 );
835 // // V' * G * V
836 // MVT::MvTransMv( 1.0, xyceV.epetraObj(), temp2.epetraObj(), redG_ );
837 // //redG_.print( Xyce::dout() );
838 
839 // // C * V
840 // CPtr_->matvec( false, xyceV, temp2 );
841 // // V' * C * V
842 // MVT::MvTransMv( 1.0, xyceV.epetraObj(), temp2.epetraObj(), redC_ );
843 // //redC_.print( Xyce::dout() );
844 
845 // // V' * B
846 // MVT::MvTransMv( 1.0, xyceV.epetraObj(), BPtr_->epetraObj(), redB_ );
847 // //redB_.print( Xyce::dout() );
848 
849 // bsuccess = bsuccess & sparsifyRedSystem_();
850 // }
851 //
852  // ---------------------------------------------------------------------
853  // Output the projected system, redG_, redC_, and redB_.
854  // ---------------------------------------------------------------------
855 
857  {
858  // If sparsification was used, write out the N_LAS_Matrix object instead of the dense object.
860  outputMgrAdapterRCPtr_->outputROM ( *redGPtr_, *redCPtr_, redB_, redL_ );
861  else
862  outputMgrAdapterRCPtr_->outputROM ( redG_, redC_, redB_, redL_ ); // L = B'
863  }
864 
865 #else
866 
867  std::string msg=
868  "Belos is necessary to compute a reduced-order model! Please recompile Xyce with Belos enabled!";
869  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
870 
871 #endif // Xyce_BELOS
872 
873  return bsuccess;
874 }
875 
876 //-----------------------------------------------------------------------------
877 // Function : MOR::evalOrigTransferFunction()
878 // Purpose : Evaluate original transfer function.
879 // Special Notes :
880 // Scope : public
881 // Creator : Heidi Thornquist and Ting Mei, SNL
882 // Creation Date : 5/29/2012
883 //-----------------------------------------------------------------------------
885 {
886  bool bsuccess = true;
887 
889 
890  int currentStep = 0;
891  int finalStep = morEvalSize_;
892 
893  bool stepAttemptStatus;
894 
895  while (currentStep < finalStep)
896  {
897  updateCurrentFreq_(currentStep);
898 
900 
901  stepAttemptStatus = solveOrigLinearSystem_();
902 
903  currentStep++;
904 
905  if (stepAttemptStatus)
906  {
907  processSuccessfulStep(true);
908  }
909  else // stepAttemptStatus (ie do this if the step FAILED)
910  {
912  }
913 
914  }
915 
916  return bsuccess;
917 }
918 
919 //-----------------------------------------------------------------------------
920 // Function : MOR::evalRedTransferFunction()
921 // Purpose : Evaluate reduced transfer function.
922 // Special Notes :
923 // Scope : public
924 // Creator : Heidi Thornquist and Ting Mei, SNL
925 // Creation Date : 5/29/2012
926 //-----------------------------------------------------------------------------
928 {
929  bool bsuccess = true;
930 
932 
933  int currentStep = 0;
934  int finalStep = morEvalSize_;
935 
936  bool stepAttemptStatus;
937 
938  while (currentStep < finalStep)
939  {
940  updateCurrentFreq_(currentStep);
941 
943 
944  stepAttemptStatus = solveRedLinearSystem_();
945 
946  currentStep++;
947 
948  if (stepAttemptStatus)
949  {
950  processSuccessfulStep(false);
951  }
952  else // stepAttemptStatus (ie do this if the step FAILED)
953  {
955  }
956  }
957 
958  return bsuccess;
959 }
960 
961 //-----------------------------------------------------------------------------
962 // Function : MOR::createOrigLinearSystem_()
963 // Purpose :
964 // Special Notes :
965 // Scope : public
966 // Creator : Ting Mei, Heidi Thornquist, SNL
967 // Creation Date : 6/20/2011
968 //-----------------------------------------------------------------------------
970 {
971  bool bsuccess = true;
972 
973  RCP<N_PDS_Manager> pdsMgrPtr_;
974  pdsMgrPtr_ = rcp(lasSystemRCPtr_->getPDSManager(), false);
975 
976  RCP<N_PDS_ParMap> BaseMap_, oBaseMap_;
977  RCP<Epetra_CrsGraph> BaseFullGraph_;
978 
979  BaseMap_ = rcp(pdsMgrPtr_->getParallelMap( "SOLUTION" ), false);
980  oBaseMap_ = rcp(pdsMgrPtr_->getParallelMap( "SOLUTION_OVERLAP_GND"), false);
981  BaseFullGraph_ = rcp( pdsMgrPtr_->getMatrixGraph("JACOBIAN"), false );
982 
983  int numBlocks = 2;
984 
985  std::vector<RCP<N_PDS_ParMap> > blockMaps = createBlockParMaps(numBlocks, *BaseMap_, *oBaseMap_);
986 
987  // Create a block vector
988  REFBPtr_ = rcp ( new N_LAS_BlockVector ( numBlocks, blockMaps[0], BaseMap_ ) );
989 
990  std::vector<std::vector<int> > blockPattern(2);
991  blockPattern[0].resize(2);
992  blockPattern[0][0] = 0; blockPattern[0][1] = 1;
993  blockPattern[1].resize(2);
994  blockPattern[1][0] = 0; blockPattern[1][1] = 1;
995 
996  int MaxGID = BaseMap_->maxGlobalEntity();
997  int offset=1;
998  while ( offset <= MaxGID ) offset *= 10;
999 
1000  RCP<Epetra_CrsGraph> blockGraph = createBlockGraph( offset, blockPattern, *blockMaps[0], *BaseFullGraph_);
1001 
1002  sCpG_REFMatrixPtr_ = rcp ( new N_LAS_BlockMatrix( numBlocks, offset, blockPattern, *blockGraph, *BaseFullGraph_) );
1003 
1004  // Load diagonal blocks of real equivalent form: (G - s0*C)
1005  sCpG_REFMatrixPtr_->put( 0.0 ); // Zero out whole matrix
1006 
1007  // Add scaled C matrix first if expansion point is not zero.
1008  if (s0_ != 0.0)
1009  {
1010  sCpG_REFMatrixPtr_->block( 0, 0 ).add(*CPtr_);
1011  sCpG_REFMatrixPtr_->block( 0, 0 ).scale(-s0_);
1012  sCpG_REFMatrixPtr_->block( 1, 1 ).add(*CPtr_);
1013  sCpG_REFMatrixPtr_->block( 1, 1 ).scale(-s0_);
1014  }
1015  // Add G into diagonal block to obtain (G - s0*C)
1016  sCpG_REFMatrixPtr_->block( 0, 0 ).add(*GPtr_);
1017  sCpG_REFMatrixPtr_->block( 1, 1 ).add(*GPtr_);
1018 
1019  // Create solver factory
1020  Amesos amesosFactory;
1021 
1022  REFXPtr_ = rcp ( new N_LAS_BlockVector ( numBlocks, blockMaps[0], BaseMap_ ) );
1023  REFXPtr_->putScalar( 0.0 );
1024 
1025  blockProblem_ = rcp(new Epetra_LinearProblem(&sCpG_REFMatrixPtr_->epetraObj(), &REFXPtr_->epetraObj(), &REFBPtr_->epetraObj() ) );
1026 
1027  blockSolver_ = rcp( amesosFactory.Create( "Klu", *blockProblem_ ) );
1028 
1029  int linearStatus = blockSolver_->SymbolicFactorization();
1030 
1031  if (linearStatus != 0)
1032  {
1033  Xyce::dout() << "Amesos symbolic factorization exited with error: " << linearStatus;
1034  bsuccess = false;
1035  }
1036 
1037  return bsuccess;
1038 
1039 }
1040 
1041 //-----------------------------------------------------------------------------
1042 // Function : MOR::createRedLinearSystem_()
1043 // Purpose :
1044 // Special Notes :
1045 // Scope : public
1046 // Creator : Ting Mei, Heidi Thornquist, SNL
1047 // Creation Date : 6/20/2011
1048 //-----------------------------------------------------------------------------
1050 {
1051  // Get the reduced system size.
1052  int k = redG_.numRows();
1053 
1054  // Resize serial dense matrix for real-equivalent form.
1055  sCpG_redMatrix_.shape(2*k, 2*k);
1056  sCpG_tmpMatrix_.shape(2*k, 2*k);
1057  ref_redB_.shape(2*k, numPorts_);
1058 
1059  // First, load the diagonals.
1060  // Get a view of the primary diagonal block, insert (G - s0*C).
1061  Teuchos::SerialDenseMatrix<int, double> subMtx( Teuchos::View, sCpG_tmpMatrix_, k, k, 0, 0 );
1062  subMtx.assign( redC_ );
1063  subMtx.scale( -s0_ );
1064  subMtx += redG_;
1065 
1066  // Get a view of the lower k x k diagonal block, insert (G - s0*C).
1067  Teuchos::SerialDenseMatrix<int, double> subMtx2( Teuchos::View, sCpG_tmpMatrix_, k, k, k, k );
1068  subMtx2.assign( redC_ );
1069  subMtx2.scale( -s0_ );
1070  subMtx2 += redG_;
1071 
1072  return true;
1073 }
1074 
1075 //-----------------------------------------------------------------------------
1076 // Function : MOR::updateOrigLinearSystemFreq_()
1077 // Purpose :
1078 // Special Notes :
1079 // Scope : public
1080 // Creator : Ting Mei, Heidi Thornquist, SNL
1081 // Creation Date : 6/20/2011
1082 //-----------------------------------------------------------------------------
1083 
1085 {
1086  double omega = 2.0 * M_PI * currentFreq_;
1087 
1088  sCpG_REFMatrixPtr_->block( 0, 1).put( 0.0);
1089  sCpG_REFMatrixPtr_->block( 0, 1).add(*CPtr_);
1090  sCpG_REFMatrixPtr_->block( 0, 1).scale(-omega);
1091 
1092  sCpG_REFMatrixPtr_->block(1, 0).put( 0.0);
1093  sCpG_REFMatrixPtr_->block(1, 0).add(*CPtr_);
1094  sCpG_REFMatrixPtr_->block(1, 0).scale(omega);
1095 
1096  return true;
1097 }
1098 
1099 //-----------------------------------------------------------------------------
1100 // Function : MOR::updateRedLinearSystemFreq_()
1101 // Purpose :
1102 // Special Notes :
1103 // Scope : public
1104 // Creator : Ting Mei, Heidi Thornquist, SNL
1105 // Creation Date : 6/20/2011
1106 //-----------------------------------------------------------------------------
1107 
1109 {
1110  int k = redG_.numRows();
1111 
1112  double omega = 2.0 * M_PI * currentFreq_;
1113 
1114  // Reset reduced real equivalent form matrix to sCpG_tmpMatrix_
1115  sCpG_redMatrix_.assign( sCpG_tmpMatrix_ );
1116 
1117  // Insert off diagonals.
1118  Teuchos::SerialDenseMatrix<int, double> subMtx( Teuchos::View, sCpG_redMatrix_, k, k, 0, k );
1119  subMtx.assign( redC_ );
1120  subMtx.scale( -omega );
1121 
1122  Teuchos::SerialDenseMatrix<int, double> subMtx2( Teuchos::View, sCpG_redMatrix_, k, k, k, 0 );
1123  subMtx2.assign( redC_ );
1124  subMtx2.scale( omega );
1125 
1126  return true;
1127 }
1128 
1129 //-----------------------------------------------------------------------------
1130 // Function : MOR::solveLinearSystem_()
1131 // Purpose :
1132 // Special Notes :
1133 // Scope : public
1134 // Creator : Ting Mei, Heidi Thornquist, SNL
1135 // Creation Date : 6/2011
1136 //-----------------------------------------------------------------------------
1137 
1139 {
1140 
1141  bool bsuccess = true;
1142 
1143  // Solve the block problem
1144  int linearStatus = blockSolver_->NumericFactorization();
1145 
1146  if (linearStatus != 0)
1147  {
1148  Xyce::dout() << "Amesos numeric factorization exited with error: " << linearStatus;
1149  bsuccess = false;
1150  }
1151 
1152  // Loop over number of I/O ports here
1153  for (unsigned int j=0; j < bMatEntriesVec_.size(); ++j)
1154  {
1155  REFBPtr_->putScalar( 0.0 );
1156  (REFBPtr_->block( 0 ))[bMatEntriesVec_[j]] = -1.0;
1157 
1158  linearStatus = blockSolver_->Solve();
1159  if (linearStatus != 0)
1160  {
1161  Xyce::dout() << "Amesos solve exited with error: " << linearStatus;
1162  bsuccess = false;
1163  }
1164 
1165  // Compute transfer function entries for all I/O
1166  for (unsigned int i=0; i < bMatEntriesVec_.size(); ++i)
1167  {
1168  // Populate H for all ports in L
1169  // L is the same as B and also a set of canonical basis vectors (e_i), so
1170  // we can pick off the appropriate entries of REFXPtr to place into H.
1171  origH_(i,j) = std::complex<double>(-(REFXPtr_->block( 0 ))[bMatEntriesVec_[i]],
1172  -(REFXPtr_->block( 1 ))[bMatEntriesVec_[i]]);
1173  }
1174  }
1175  return bsuccess;
1176 }
1177 
1178 //-----------------------------------------------------------------------------
1179 // Function : MOR::solveRedLinearSystem_()
1180 // Purpose :
1181 // Special Notes :
1182 // Scope : public
1183 // Creator : Ting Mei, Heidi Thornquist, SNL
1184 // Creation Date : 6/2011
1185 //-----------------------------------------------------------------------------
1186 
1188 {
1189  bool bsuccess = true;
1190 
1191  int k = redG_.numRows();
1192  int numPorts = bMatEntriesVec_.size();
1193  Teuchos::LAPACK<int, double> lapack;
1194 
1195  ref_redB_.putScalar( 0.0 );
1196  Teuchos::SerialDenseMatrix<int, double> tmpRedB( Teuchos::View, ref_redB_, redB_.numRows(), redB_.numCols(), 0, 0 );
1197  tmpRedB.assign( redB_ );
1198 
1199  // First factor matrix using LU.
1200  int info = 0;
1201  std::vector<int> ipiv( sCpG_redMatrix_.numRows() );
1202  lapack.GETRF( sCpG_redMatrix_.numRows(), sCpG_redMatrix_.numCols(), sCpG_redMatrix_.values(),
1203  sCpG_redMatrix_.stride(), &ipiv[0], &info );
1204  if (info != 0)
1205  {
1206  Xyce::dout() << "LAPACK::GETRF: LU factorization failed with error: " << info << std::endl;
1207  bsuccess = false;
1208  }
1209 
1210  // Next solve for all ports at once using LU factors.
1211  const char trans = 'N';
1212  lapack.GETRS( trans, sCpG_redMatrix_.numRows(), ref_redB_.numCols(), sCpG_redMatrix_.values(),
1213  sCpG_redMatrix_.stride(), &ipiv[0], ref_redB_.values(), ref_redB_.stride(), &info );
1214  if (info != 0)
1215  {
1216  Xyce::dout() << "LAPACK::GETRS: LU solve failed with error: " << info << std::endl;
1217  bsuccess = false;
1218  }
1219 
1220  Teuchos::SerialDenseMatrix<int, double> tmpRedImag( numPorts, numPorts ), tmpRedReal( numPorts, numPorts );
1221 
1222  // Compute real part.
1223  tmpRedReal.multiply( Teuchos::TRANS, Teuchos::NO_TRANS, 1.0, redB_, tmpRedB, 0.0 );
1224 
1225  // Compute imaginary part.
1226  Teuchos::SerialDenseMatrix<int, double> tmpRedB2( Teuchos::View, ref_redB_, redB_.numRows(), redB_.numCols(), k, 0 );
1227  tmpRedImag.multiply( Teuchos::TRANS, Teuchos::NO_TRANS, 1.0, redB_, tmpRedB2, 0.0 );
1228 
1229  // Compute transfer function entries for all I/O
1230  for (unsigned int j=0; j < bMatEntriesVec_.size(); ++j)
1231  {
1232  for (unsigned int i=0; i < bMatEntriesVec_.size(); ++i)
1233  {
1234  redH_(i,j) = std::complex<double>(tmpRedReal(i,j), tmpRedImag(i,j));
1235  }
1236  }
1237 
1238  return bsuccess;
1239 }
1240 
1241 //-----------------------------------------------------------------------------
1242 // Function : MOR::sparsifyRedSystem_()
1243 // Purpose : Use techniques to sparsify the projected system.
1244 // Special Notes :
1245 // Scope : public
1246 // Creator : Heidi Thornquist and Ting Mei, SNL
1247 // Creation Date : 8/20/2012
1248 //-----------------------------------------------------------------------------
1250 {
1251  bool bsuccess = true;
1252 
1253  int k = redB_.numRows();
1254 
1255  // Storage vectors
1256  Teuchos::SerialDenseMatrix<int, double> R(redB_);
1257  Teuchos::SerialDenseMatrix<int, double> A(redC_);
1258 
1259  // Factor Ghat.
1260  Teuchos::LAPACK<int, double> lapack;
1261  Teuchos::SerialDenseMatrix<int, double> tmp_Ghat( redG_ );
1262 
1263  int info = 0;
1264  std::vector<int> ipiv( tmp_Ghat.numRows() );
1265  lapack.GETRF( tmp_Ghat.numRows(), tmp_Ghat.numCols(), tmp_Ghat.values(),
1266  tmp_Ghat.stride(), &ipiv[0], &info );
1267  if (info != 0)
1268  {
1269  Xyce::dout() << "LAPACK::GETRF: LU factorization of Ghat failed with error: " << info << std::endl;
1270  bsuccess = false;
1271  }
1272 
1273  // Compute reciprocal condition estimate of Ghat.
1274  const char norm = '1';
1275  double condGhat = 0.0;
1276  std::vector<double> condWork( 4*k );
1277  std::vector<int> condIWork( k );
1278  lapack.GECON( norm, tmp_Ghat.numRows(), tmp_Ghat.values(), tmp_Ghat.stride(), tmp_Ghat.normOne(), &condGhat, &condWork[0], &condIWork[0], &info );
1279  // Xyce::dout() << "Condition estimate for Ghat is : " << 1.0/ condGhat << std::endl;
1280  if (info != 0)
1281  {
1282  Xyce::dout() << "LAPACK::GECON: Computing condition estimate of Ghat failed with error: " << info << std::endl;
1283  bsuccess = false;
1284  }
1285 
1286  // Compute A = inv(Ghat)* Chat
1287  const char trans = 'N';
1288  lapack.GETRS( trans, tmp_Ghat.numRows(), A.numCols(), tmp_Ghat.values(),
1289  tmp_Ghat.stride(), &ipiv[0], A.values(), A.stride(), &info );
1290  if (info != 0)
1291  {
1292  Xyce::dout() << "LAPACK::GETRS: LU solve failed with error: " << info << std::endl;
1293  bsuccess = false;
1294  }
1295  //Xyce::dout() << "A = inv(Ghat)*Chat" << std::endl;
1296  //A.print(Xyce::dout());
1297 
1298  // Compute R = inv(Ghat)* Bhat
1299  lapack.GETRS( trans, tmp_Ghat.numRows(), R.numCols(), tmp_Ghat.values(),
1300  tmp_Ghat.stride(), &ipiv[0], R.values(), R.stride(), &info );
1301  if (info != 0)
1302  {
1303  Xyce::dout() << "LAPACK::GETRS: LU solve failed with error: " << info << std::endl;
1304  bsuccess = false;
1305  }
1306  //Xyce::dout() << "R = inv(Ghat)*Bhat" << std::endl;
1307  //R.print(Xyce::dout());
1308 
1309  // Reduce A to Schur form and compute the eigenvalues.
1310  // Allocate the work space. This space will be used below for calls to:
1311  // * GEES (requires 3*k for real)
1312  // * TREVC (requires 3*k for real)
1313  // Furthermore, GEES requires a real array of length k
1314  //
1315  int lwork = 8*k;
1316  std::vector<double> work( lwork );
1317  std::vector<double> revals( k );
1318  std::vector<double> ievals( k );
1319  Teuchos::SerialDenseMatrix<int, double> Q(k, k);
1320 
1321  // Create diagonal tmpB for the eigenproblem (A, tmpB), beta should return as a vector of ones.
1322  const int ldvl = 1;
1323  double vl[ ldvl ];
1324  std::vector<double> beta( k );
1325  Teuchos::SerialDenseMatrix<int, double> tmpB( k, k );
1326  for (int i=0; i<k; i++)
1327  tmpB(i,i) = 1.0;
1328  lapack.GGEV( 'N', 'V', k, A.values(), A.stride(), tmpB.values(), tmpB.stride(),
1329  &revals[0], &ievals[0], &beta[0], &vl[0], ldvl, Q.values(), Q.stride(),
1330  &work[0], lwork, &info );
1331  if (info != 0)
1332  {
1333  Xyce::dout() << "LAPACK::GGEV: Computing eigenvectors and values of A = inv(Ghat)*Chat failed with error: " << info << std::endl;
1334  bsuccess = false;
1335  }
1336 
1337  // Scale the eigenvectors returned from GGEV to have 2-norm = 1
1338  // They are initially scaled to have inf-norm = 1 from LAPACK
1339  Teuchos::BLAS<int, double> blas;
1340  std::vector<int> rowIndex( k );
1341  int i = 0;
1342 
1343  while( i < k ) {
1344  if ( ievals[i] != 0.0 )
1345  {
1346  rowIndex[i] = 1;
1347  rowIndex[i+1] = -1;
1348 
1349  // Compute the 2-norm of the complex eigenvector
1350  double norm_r = blas.NRM2( k, Q[i], 1 );
1351  double norm_i = blas.NRM2( k, Q[i+1], 1 );
1352  double norm = lapack.LAPY2( norm_r, norm_i );
1353 
1354  // Scale the complex eigenvector
1355  for (int j=0; j<k; j++)
1356  {
1357  Q(j,i) /= norm;
1358  Q(j,i+1) /= norm;
1359  }
1360  i += 2;
1361  }
1362  else
1363  {
1364  rowIndex[i] = 0;
1365 
1366  // Compute the 2-norm of the i-th column
1367  double norm = blas.NRM2( k, Q[i], 1 );
1368 
1369  // Scale the real eigenvector
1370  for (int j=0; j<k; j++)
1371  {
1372  Q(j,i) /= norm;
1373  }
1374  i++;
1375  }
1376  }
1377 
1378  // Xyce::dout() << "Eigenvalues of A: " << std::endl;
1379  // for (int i=0; i<k; ++i)
1380  // Xyce::dout() << revals[i] << "\t" << ievals[i] << "\t" << beta[i] << std::endl;
1381 
1382  // Xyce::dout() << "Eigenvectors of A: " << std::endl;
1383  // Q.print(Xyce::dout());
1384 
1385  // Construct complex eigenvectors
1386  Teuchos::SerialDenseMatrix<int, std::complex<double> > V(k, k);
1387  for (int i=0; i<k; i++)
1388  {
1389  if (rowIndex[i] == 1)
1390  {
1391  for (int j=0; j<k; j++)
1392  {
1393  // Insert both conjugate pairs simultaneously.
1394  V(j,i) = std::complex<double>( Q(j,i), Q(j,i+1) );
1395  V(j,i+1) = std::complex<double>( Q(j,i), -Q(j,i+1) );
1396  }
1397  i++; // Need to increment an extra value for the conjugate pair.
1398  }
1399  else // The eigenvector is real, copy directly
1400  {
1401  for (int j=0; j<k; j++)
1402  {
1403  V(j,i) = std::complex<double>( Q(j,i), 0.0 );
1404  }
1405  }
1406  }
1407 
1408  // Factor V
1409  Teuchos::LAPACK<int, std::complex<double> > lapack_complex;
1410  lapack_complex.GETRF( V.numRows(), V.numCols(), V.values(), V.stride(), &ipiv[0], &info );
1411  if (info != 0)
1412  {
1413  Xyce::dout() << "LAPACK::GETRF: LU factorization of eigenvectors failed with error: " << info << std::endl;
1414  bsuccess = false;
1415  }
1416 
1417  // Compute condition estimate of V.
1418  double condV = 0.0;
1419  std::vector<std::complex<double> > condCWork( 2*k );
1420  lapack_complex.GECON( norm, V.numRows(), V.values(), V.stride(), V.normOne(), &condV, &condCWork[0], &condWork[0], &info );
1421  //Xyce::dout() << "Condition estimate for V is : " << 1.0/condV << std::endl;
1422  if (info != 0)
1423  {
1424  Xyce::dout() << "LAPACK::GECON: Computing condition estimate of V failed with error: " << info << std::endl;
1425  bsuccess = false;
1426  }
1427 
1428  // Compute inv(V)
1429  std::vector<std::complex<double> > cwork( lwork );
1430  lapack_complex.GETRI( V.numRows(), V.values(), V.stride(), &ipiv[0], &cwork[0], lwork, &info );
1431  if (info != 0)
1432  {
1433  Xyce::dout() << "LAPACK::GETRI: Computing inverse of V failed with error: " << info << std::endl;
1434  bsuccess = false;
1435  }
1436 
1437  // Convert R to a complex vector to use the multiply routine for inv(V).
1438  Teuchos::SerialDenseMatrix<int, std::complex<double> > tmpR( k, numPorts_ );
1439  for (int j=0; j<numPorts_; j++)
1440  for (int i=0; i<k; i++)
1441  tmpR(i,j) = std::complex<double>( R(i,j), 0.0 );
1442 
1443  // Compute inv(V) * R
1444  Teuchos::SerialDenseMatrix<int, std::complex<double> > tmp_redB(k ,numPorts_);
1445  tmp_redB.multiply(Teuchos::NO_TRANS, Teuchos::NO_TRANS, 1.0, V, tmpR, 0.0);
1446 
1447  // Generate compressed real storage of V*R and inv(V)
1448  redL_ = redB_; // Store copy of redB_ before destroying it below.
1449  Teuchos::SerialDenseMatrix<int, double> invV(k, k);
1450  for (int i=0; i<k; i++)
1451  {
1452  if (rowIndex[i] == 1) // Complex conjugate pair.
1453  {
1454  for (int j=0; j<k; j++)
1455  {
1456  invV(i, j) = V(i,j).real();
1457  invV(i+1, j) = V(i,j).imag();
1458  }
1459  for (int j=0; j<numPorts_; j++)
1460  {
1461  redB_(i, j) = tmp_redB(i, j).real();
1462  redB_(i+1, j) = tmp_redB(i, j).imag();
1463  }
1464  i++; // Increment by one to skip complex conjugate.
1465  }
1466  else // Eigenvalue is real, so is eigenvector.
1467  {
1468  for (int j=0; j<k; j++)
1469  invV(i, j) = V(i,j).real();
1470  for (int j=0; j<numPorts_; j++)
1471  redB_(i, j) = tmp_redB(i, j).real();
1472  }
1473  }
1474 
1475  // Factor invV.
1476  lapack.GETRF( invV.numRows(), invV.numCols(), invV.values(), invV.stride(), &ipiv[0], &info );
1477  if (info != 0)
1478  {
1479  Xyce::dout() << "LAPACK::GETRF: LU factorization of inv(V) failed with error: " << info << std::endl;
1480  bsuccess = false;
1481  }
1482 
1483  // Compute A = inv(invV)^T*Lhat
1484  const char trans2 = 'T';
1485  lapack.GETRS( trans2, invV.numRows(), redL_.numCols(), invV.values(),
1486  invV.stride(), &ipiv[0], redL_.values(), redL_.stride(), &info );
1487  if (info != 0)
1488  {
1489  Xyce::dout() << "LAPACK::GETRS: LU solve for Lhat failed with error: " << info << std::endl;
1490  bsuccess = false;
1491  }
1492 
1493  // Xyce::dout() << "Bhat : " << std::endl;
1494  // redB_.print(Xyce::dout());
1495  // Xyce::dout() << "Lhat : " << std::endl;
1496  // redL_.print(Xyce::dout());
1497 
1498  // Create redCPtr_ and redGPtr_
1499  // Generate Epetra_Map that puts all the values of the reduced system on one processor.
1500  RCP<N_PDS_Manager> pdsMgrPtr_ = Teuchos::rcp(lasSystemRCPtr_->getPDSManager(), false);
1501  RCP<N_PDS_ParMap> BaseMap_ = Teuchos::rcp(pdsMgrPtr_->getParallelMap( "SOLUTION" ), false);
1502  RCP<Epetra_Map> serialRedMap;
1503  if (BaseMap_->petraMap()->Comm().MyPID() == 0)
1504  serialRedMap = Teuchos::rcp( new Epetra_Map( k, k, 0, BaseMap_->petraMap()->Comm() ) );
1505  else
1506  serialRedMap = Teuchos::rcp( new Epetra_Map( k, 0, 0, BaseMap_->petraMap()->Comm() ) );
1507 
1508  Epetra_CrsMatrix* tmpRedG = new Epetra_CrsMatrix( Copy, *serialRedMap, 1 );
1509  Epetra_CrsMatrix* tmpRedC = new Epetra_CrsMatrix( Copy, *serialRedMap, 2 );
1510 
1511  // Let processor 0 insert entries into tmpRedG and tmpRedC
1512  if (BaseMap_->petraMap()->Comm().MyPID() == 0)
1513  {
1514  std::vector<int> index(2);
1515  std::vector<double> val(2);
1516  for (int i=0; i<k; i++)
1517  {
1518  // Insert G, which is a diagonal of ones.
1519  index[0] = i; val[0] = 1.0;
1520  tmpRedG->InsertGlobalValues( i, 1, &val[0], &index[0] );
1521 
1522  // Insert C, which is block diagonal, where the blocks represent conjugate eigenvalues.
1523  if (rowIndex[i] == 1)
1524  {
1525  index[0] = i; index[1] = i+1;
1526  val[0] = revals[i]; val[1] = -ievals[i];
1527  tmpRedC->InsertGlobalValues( i, 2, &val[0], &index[0] );
1528  }
1529  else if (rowIndex[i] == -1)
1530  {
1531  index[0] = i-1; index[1] = i;
1532  val[0] = ievals[i-1]; val[1] = revals[i-1];
1533  tmpRedC->InsertGlobalValues( i, 2, &val[0], &index[0] );
1534  }
1535  else // Must be real.
1536  {
1537  index[0] = i; val[0] = revals[i];
1538  tmpRedC->InsertGlobalValues( i, 1, &val[0], &index[0] );
1539  }
1540  }
1541  }
1542  // We are done inserting values.
1543  tmpRedC->FillComplete();
1544  tmpRedG->FillComplete();
1545 
1546  // Pass tmpRedG and tmpRedC into redGPtr_ and redGPtr_, respectively, which will manage the memory.
1547  redGPtr_ = rcp( new N_LAS_Matrix( tmpRedG ) );
1548  redCPtr_ = rcp( new N_LAS_Matrix( tmpRedC ) );
1549 
1550  return bsuccess;
1551 }
1552 
1553 //-----------------------------------------------------------------------------
1554 // Function : MOR::processSuccessfulStep()
1555 // Purpose :
1556 // Special Notes :
1557 // Scope : public
1558 // Creator : Ting Mei, SNL
1559 // Creation Date :
1560 //-----------------------------------------------------------------------------
1561 bool MOR::processSuccessfulStep(bool origSys)
1562 {
1563  bool bsuccess = true;
1564 
1565  // Output H.
1566  if (origSys)
1567  {
1568  outputMgrAdapterRCPtr_->outputMORTF (origSys, currentFreq_, origH_);
1569  }
1570  else
1571  {
1572  outputMgrAdapterRCPtr_->outputMORTF (origSys, currentFreq_, redH_);
1573  }
1574 
1575  if ( !firstDoubleDCOPStep_() )
1576  {
1577  stepNumber += 1;
1580  }
1581 
1582  return bsuccess;
1583 }
1584 
1585 
1586 //-----------------------------------------------------------------------------
1587 // Function : MOR::processFailedStep
1588 // Purpose :
1589 // Special Notes :
1590 // Scope : public
1591 // Creator : Ting Mei, SNL
1592 // Creation Date :
1593 //-----------------------------------------------------------------------------
1595 {
1596  bool bsuccess = true;
1597 
1598  stepNumber += 1;
1599  morEvalFailures_.push_back(stepNumber);
1601  secRCPtr_->numberSuccessiveFailures += 1;
1602 
1603  return bsuccess;
1604 }
1605 
1606 //-----------------------------------------------------------------------------
1607 // Function : MOR::finish
1608 // Purpose :
1609 // Special Notes :
1610 // Scope : public
1611 // Creator : Ting Mei, SNL
1612 // Creation Date :
1613 //-----------------------------------------------------------------------------
1615 {
1616  bool bsuccess = true;
1617 
1618 #ifdef Xyce_DEBUG_ANALYSIS
1619  Xyce::dout() << "Calling MOR::finish() outputs!" << std::endl;
1620 #endif
1621 
1622  if (!(morEvalFailures_.empty()))
1623  {
1624  bsuccess = false;
1625  }
1626 
1627  return bsuccess;
1628 }
1629 
1630 
1631 //-----------------------------------------------------------------------------
1632 // Function : MOR::handlePredictor
1633 // Purpose :
1634 // Special Notes :
1635 // Scope : private
1636 // Creator : Eric Keiter, SNL
1637 // Creation Date : 06/24/2013
1638 //-----------------------------------------------------------------------------
1640 {
1641  anaManagerRCPtr_->getTIADataStore()->setErrorWtVector();
1642  wimRCPtr_->obtainPredictor();
1643  wimRCPtr_->obtainPredictorDeriv();
1644 
1645  // In case this is the upper level of a 2-level sim, tell the
1646  // inner solve to do its prediction:
1647  loaderRCPtr_->startTimeStep ();
1648 
1649  return true;
1650 }
1651 
1652 //-----------------------------------------------------------------------------
1653 // Function : MOR::updateCurrentFreq_(int stepNumber )
1654 // Purpose :
1655 // Special Notes : Used for MOR analysis classes.
1656 // Scope : public
1657 // Creator : Ting Mei, SNL.
1658 // Creation Date :
1659 //-----------------------------------------------------------------------------
1660 bool MOR::updateCurrentFreq_(int stepNumber)
1661 {
1662  double fStart = tiaParams.morCompFStart;
1663 
1664  if (tiaParams.type=="LIN")
1665  {
1666  currentFreq_ = fStart + static_cast<double>(stepNumber)*fStep_;
1667  }
1668  else if(tiaParams.type=="DEC" || tiaParams.type=="OCT")
1669  {
1670  currentFreq_ = fStart*pow(stepMult_, static_cast<double>(stepNumber) );
1671  }
1672  else
1673  {
1674  std::string msg=
1675  "MOR::updateCurrentFreq_: unsupported STEP type";
1676  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
1677  }
1678 
1679  return true;
1680 }
1681 
1682 //-----------------------------------------------------------------------------
1683 // Function : MOR::setupSweepParam_
1684 // Purpose : Processes sweep parameters.
1685 // Special Notes : Used for MOR analysis classes.
1686 // Scope : public
1687 // Creator : Ting Mei, SNL.
1688 // Creation Date :
1689 //-----------------------------------------------------------------------------
1691 {
1692  int fCount = 0;
1693  double fStart = tiaParams.morCompFStart;
1694  double fStop = tiaParams.morCompFStop;
1695 
1696 #ifdef Xyce_DEBUG_ANALYSIS
1697  if (anaManagerRCPtr_->tiaParams.debugLevel > 0)
1698  {
1699  Xyce::dout() << std::endl << std::endl;
1700  Xyce::dout() << section_divider << std::endl;
1701  Xyce::dout() << "MOR::setupSweepParam_" << std::endl;
1702  }
1703 #endif
1704 
1705  if (tiaParams.morCompType=="LIN")
1706  {
1707  if ( tiaParams.morCompNP == 1)
1708  fStep_ = 0;
1709  else
1710  fStep_ = (fStop - fStart)/(tiaParams.morCompNP - 1);
1711 
1712  fCount = tiaParams.morCompNP;
1713 #ifdef Xyce_DEBUG_ANALYSIS
1714  if (anaManagerRCPtr_->tiaParams.debugLevel > 0)
1715  {
1716  Xyce::dout() << "fStep = " << fStep_ << std::endl;
1717  }
1718 #endif
1719  }
1720  else if(tiaParams.morCompType=="DEC")
1721  {
1722  stepMult_ = pow(10,(1/(double)tiaParams.morCompNP));
1723  fCount = (int)(floor(fabs(log10(fStart) - log10(fStop)) * tiaParams.morCompNP + 1));
1724 #ifdef Xyce_DEBUG_ANALYSIS
1725  if (anaManagerRCPtr_->tiaParams.debugLevel > 0)
1726  {
1727  Xyce::dout() << "stepMult_ = " << stepMult_ << std::endl;
1728  }
1729 #endif
1730  }
1731  else if(tiaParams.morCompType=="OCT")
1732  {
1733  stepMult_ = pow(2,1/(double)(tiaParams.morCompNP));
1734 
1735  // changed to remove dependence on "log2" function, which apparently
1736  // doesn't exist in the math libraries of FreeBSD or the mingw
1737  // cross-compilation suite. Log_2(x)=log_e(x)/log_e(2.0)
1738  double ln2=log(2.0);
1739  fCount = floor(fabs(log(fStart) - log(fStop))/ln2 * tiaParams.morCompNP + 1);
1740 #ifdef Xyce_DEBUG_ANALYSIS
1741  if (anaManagerRCPtr_->tiaParams.debugLevel > 0)
1742  {
1743  Xyce::dout() << "stepMult_ = " << stepMult_ << std::endl;
1744  }
1745 #endif
1746  }
1747  else
1748  {
1749  std::string msg=
1750  "MOR::setupSweepParam: unsupported type";
1751  N_ERH_ErrorMgr::report(N_ERH_ErrorMgr::DEV_FATAL_0, msg);
1752  }
1753 
1754  // At this point, pinterval equals the total number of steps
1755  // for the step loop.
1756  return fCount;
1757 }
1758 
1759 } // namespace Analysis
1760 } // namespace Xyce