Xyce  6.1
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-2015 Sandia Corporation
10 //
11 // This program is free software: you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation, either version 3 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 //-------------------------------------------------------------------------
24 
25 //-----------------------------------------------------------------------------
26 // Filename : $RCSfile: N_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.97.2.1 $
35 // Revision Date : $Date: 2015/04/02 18:20:07 $
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 
48 #include <N_ANP_AnalysisManager.h>
49 #include <N_ANP_MOR.h>
50 #include <N_ANP_OutputMgrAdapter.h>
51 #include <N_ANP_Report.h>
52 
53 #include <N_LAS_BlockMatrix.h>
54 #include <N_LAS_BlockSystemHelpers.h>
55 #include <N_LAS_BlockVector.h>
56 #include <N_LAS_MOROperators.h>
57 #include <N_LAS_Matrix.h>
58 #include <N_LAS_MultiVector.h>
59 #include <N_LAS_System.h>
60 
61 #include <N_IO_PkgOptionsMgr.h>
62 #include <N_IO_CmdParse.h>
63 
64 #include <N_LOA_Loader.h>
65 
66 #include <N_NLS_Manager.h>
67 #include <N_NLS_ReturnCodes.h>
68 
69 #include <N_PDS_Comm.h>
70 #include <N_PDS_ParMap.h>
71 #include <N_PDS_Serial.h>
72 #include <N_PDS_MPI.h>
73 
74 #include <N_TIA_DataStore.h>
77 #include <N_TIA_StepErrorControl.h>
78 
79 #include <N_TOP_Topology.h>
80 
81 #include <N_UTL_Diagnostic.h>
82 #include <N_UTL_ExtendedString.h>
83 #include <N_UTL_FeatureTest.h>
84 #include <N_UTL_Math.h>
85 #include <N_UTL_Timer.h>
86 
87 #ifdef Xyce_PARALLEL_MPI
88 #include <N_PDS_ParComm.h>
89 #include <mpi.h>
90 #else
91 #include <N_PDS_SerialComm.h>
92 #endif
93 
94 // ---------- Other Includes ----------
95 
96 #include <Epetra_CrsMatrix.h>
97 #include <Epetra_Operator.h>
98 #include <Epetra_CrsGraph.h>
99 #include <Epetra_MultiVector.h>
100 #include <Epetra_LinearProblem.h>
101 #include <Amesos.h>
102 
103 #ifdef Xyce_BELOS
104 #include <BelosLinearProblem.hpp>
105 #include <BelosBlockGmresIter.hpp>
106 #include <BelosDGKSOrthoManager.hpp>
107 #include <BelosStatusTestMaxIters.hpp>
108 #include <BelosOutputManager.hpp>
109 #include <BelosEpetraAdapter.hpp>
110 #endif
111 
112 #include <Teuchos_SerialDenseMatrix.hpp>
113 #include <Teuchos_ScalarTraits.hpp>
114 #include <Teuchos_LAPACK.hpp>
115 #include <Teuchos_BLAS.hpp>
116 
117 namespace Xyce {
118 namespace Analysis {
119 
120 //-----------------------------------------------------------------------------
121 // Function : MOR::MOR( AnalysisManager * )
122 // Purpose : constructor
123 // Special Notes :
124 // Scope : public
125 // Creator : Ting Mei
126 // Creation Date : 5/11
127 //-----------------------------------------------------------------------------
129  AnalysisManager & analysis_manager,
130  Nonlinear::Manager & nonlinear_manager,
131  Topo::Topology & topology)
132  : AnalysisBase(analysis_manager, "MOR"),
133  comm_(analysis_manager.getPDSManager()->getPDSComm()->comm()),
134  analysisManager_(analysis_manager),
135  loader_(analysis_manager.getLoader()),
136  nonlinearManager_(nonlinear_manager),
137  topology_(topology),
138  outputManagerAdapter_(analysis_manager.getOutputManagerAdapter()),
139  ROMsize_(-1),
140  morMethod_("PRIMA"),
141  morSaveRedSys_(false),
142  morCompOrigTF_(false),
143  morCompRedTF_(false),
144  morCompType_("DEC"),
145  morCompNP_(10),
146  morCompFStart_(1.0),
147  morAutoSize_(false),
148  morMaxSize_(-1),
149  morMaxFreq_(1.0e9),
150  morCompFStop_(1.0),
151  morExpPoint_(0.0),
152  morScaleFactor_(1.0),
153  morScaleType_(0),
154  morScaleFactor1_(1.0),
155  morSparsificationType_(0),
156  isROMSparse_(false),
157  morEvalSize_(0),
158  numPorts_(0),
159  isSingleFreq_(false),
160  stepMult_(0.0),
161  fStep_(0.0),
162  currentFreq_(0.0),
163  s0_(0.0)
164 {}
165 
166 //-----------------------------------------------------------------------------
167 // Function : MOR::~MOR()
168 // Purpose : destructor
169 // Special Notes :
170 // Scope : public
171 // Creator : Ting Mei
172 // Creation Date : 5/11
173 //-----------------------------------------------------------------------------
175 {}
176 
177 //-----------------------------------------------------------------------------
178 // Function : MOR::setAnalysisParams
179 // Purpose :
180 // Special Notes : These are from the .MOR statement.
181 // Scope : public
182 // Creator : Ting Mei, SNL
183 // Creation Date : 6/11
184 //-----------------------------------------------------------------------------
185 bool MOR::setAnalysisParams(const Util::OptionBlock & paramsBlock)
186 {
187  for (Util::ParamList::const_iterator it = paramsBlock.begin(), end = paramsBlock.end(); it != end; ++it)
188  {
189  if ((*it).uTag() == "PORTLIST")
190  {
191  portList_ = (*it).getValue<std::vector<std::string> >();
192  }
193  }
194 
195  if (DEBUG_ANALYSIS && isActive(Diag::TIME_PARAMETERS))
196  {
197  dout() << std::endl
198  << section_divider << std::endl
199  <<" MOR simulation parameters" << std::endl
200  << " size = " << ROMsize_ << std::endl;
201  }
202 
203  return true;
204 }
205 
206 //-----------------------------------------------------------------------------
207 // Function : MOR::setMOROptions
208 // Purpose :
209 // Special Notes : These are from '.options mor'
210 // Scope : public
211 // Creator : Heidi Thornquist and Ting Mei, SNL
212 // Creation Date : 05/31/12
213 //-----------------------------------------------------------------------------
214 bool MOR::setMOROptions(const Util::OptionBlock & OB)
215 {
216  Util::ParamList::const_iterator it_tpL;
217  Util::ParamList::const_iterator first = OB.begin();
218  Util::ParamList::const_iterator last = OB.end();
219 
220  for (it_tpL = first; it_tpL != last; ++it_tpL)
221  {
222  if (it_tpL->uTag()=="METHOD")
223  {
224  ExtendedString stringVal ( it_tpL->stringValue() );
225  stringVal.toUpper();
226  morMethod_ = stringVal;
227  }
228  else if (it_tpL->uTag()=="SAVEREDSYS")
229  {
230  morSaveRedSys_ = static_cast<bool>(it_tpL->getImmutableValue<int>());
231  }
232  else if (it_tpL->uTag()=="COMPORIGTF")
233  {
234  morCompOrigTF_ = static_cast<bool>(it_tpL->getImmutableValue<int>());
235  }
236  else if (it_tpL->uTag()=="COMPREDTF")
237  {
238  morCompRedTF_ = static_cast<bool>(it_tpL->getImmutableValue<int>());
239  }
240  else if (it_tpL->uTag()=="COMPTYPE")
241  {
242  ExtendedString stringVal ( it_tpL->stringValue() );
243  stringVal.toUpper();
244  morCompType_ = stringVal;
245  }
246  else if (it_tpL->uTag()=="COMPNP")
247  {
248  morCompNP_ = it_tpL->getImmutableValue<int>();
249  }
250  else if (it_tpL->uTag()=="COMPFSTART")
251  {
252  morCompFStart_ = it_tpL->getImmutableValue<double>();
253  }
254  else if (it_tpL->uTag()=="AUTOSIZE")
255  {
256  morAutoSize_ = static_cast<bool>(it_tpL->getImmutableValue<int>());
257  }
258  else if (it_tpL->uTag()=="MAXSIZE")
259  {
260  morMaxSize_ = it_tpL->getImmutableValue<int>();
261  }
262  else if (it_tpL->uTag()=="MAXFREQ")
263  {
264  morMaxFreq_ = it_tpL->getImmutableValue< double>();
265  }
266  else if (it_tpL->uTag()=="SIZE")
267  {
268  ROMsize_ = it_tpL->getImmutableValue<int>();
269  }
270  else if (it_tpL->uTag()=="COMPFSTOP")
271  {
272  morCompFStop_ = it_tpL->getImmutableValue<double>();
273  }
274  else if (it_tpL->uTag()=="EXPPOINT")
275  {
276  morExpPoint_ = it_tpL->getImmutableValue<double>();
277  }
278  else if (it_tpL->uTag()=="SCALETYPE")
279  {
280  morScaleType_ = it_tpL->getImmutableValue<int>();
281  }
282  else if (it_tpL->uTag()=="SCALEFACTOR")
283  {
284  morScaleFactor_ = it_tpL->getImmutableValue<double>();
285  }
286  else if (it_tpL->uTag()=="SCALEFACTOR1")
287  {
288  morScaleFactor1_ = it_tpL->getImmutableValue<double>();
289  }
290  else if (it_tpL->uTag()=="SPARSIFICATIONTYPE")
291  {
292  morSparsificationType_ = it_tpL->getImmutableValue<int>();
293  }
294  else if (std::string(it_tpL->uTag(),0,7) == "SUBCKTS" )
295  {
296  ExtendedString stringVal ( it_tpL->stringValue() );
297  stringVal.toUpper();
298  subcircuitNames_.push_back(stringVal);
299  }
300  else
301  {
302  Report::UserError0() << it_tpL->uTag() << " is not a recognized model-order reduction option.";
303  }
304  }
305 
306  // If we are computing the transfer function, make sure the frequency range is valid.
308  {
310  {
311  Report::UserError() << ".options mor COMPFSTART = " << morCompFStart_ << " > " << morCompFStop_ << " = COMPFSTOP!";
312  }
313  }
314 
315  return true;
316 }
317 
318 //-----------------------------------------------------------------------------
319 // Function : MOR::run()
320 // Purpose :
321 // Special Notes :
322 // Scope : public
323 // Creator : Ting Mei, SNL
324 // Creation Date : 5/11
325 //-----------------------------------------------------------------------------
327 {
328  bool bsuccess = doInit() && reduceSystem();
329 
330  if (morCompOrigTF_)
331  {
332  // Evaluate original system
333  bsuccess = bsuccess && evalOrigTransferFunction();
334  }
335 
336  // Reset the output adapter, just in case the reduced system needs to output
337  // its transfer functions.
339 
340  if (morCompRedTF_)
341  {
342  // Evaluate reduced system
343  bsuccess = bsuccess && evalRedTransferFunction();
344  }
345 
346  bsuccess = bsuccess && doFinish();
347 
348  return bsuccess;
349 }
350 
351 //-----------------------------------------------------------------------------
352 // Function : MOR::init()
353 // Purpose :
354 // Special Notes :
355 // Scope : public
356 // Creator : Ting Mei, SNL
357 // Creation Date : 5/11
358 //-----------------------------------------------------------------------------
360 {
361  bool bsuccess = true;
362 
363  // Compute expansion point in transformed space.
364  s0_ = 2.0 * M_PI * morExpPoint_;
365 
367  {
369  }
370 
371  // Get set to do the operating point.
374 
375  stepNumber = 0;
378 
379  // set initial guess, if there is one to be set.
380  // this setInitialGuess call is to up an initial guess in the
381  // devices that have them (usually PDE devices). This is different than
382  // the "intializeProblem" call, which sets IC's. (initial conditions are
383  // different than initial guesses.
385 
386  // If available, set initial solution
391 
392  // Set a constant history for operating point calculation
396 
397  // solving for DC op
404 
406  {
407  Report::UserError() << "Solving for DC operating point failed, cannot continue MOR analysis";
408  return false;
409  }
410 
411  // Create B matrix stamp
412  std::vector<int> tempVec;
414 
415  // Determine how many global ports there are by performing a sumAll()
416  int hsize = tempVec.size();
417  Parallel::AllReduce(comm_, MPI_SUM, &hsize, &numPorts_, 1);
418 
419  // Check that the listed ports on the .mor line are the same number as the B matrix entries.
420  if ( numPorts_ != (int)portList_.size() )
421  {
422  Report::UserError() << "Number of specified ports in .MOR line is inconsistent with number of voltage sources";
423  return false;
424  }
425 
426  // Getting the GIDs for the port list in the order specified in the .MOR line
427  // This is used to permute the bMatEntriesVec_ in the order specified by the user.
428  std::vector<int> gidPosEntries( hsize );
429  for (int i=0; i<hsize; ++i)
430  {
431  std::vector<int> svGIDList1, dummyList;
432  char type1;
433  topology_.getNodeSVarGIDs(NodeID(portList_[i],_VNODE), svGIDList1, dummyList, type1);
434 
435  // Grab the GID for this port.
436  gidPosEntries[i] = svGIDList1.front();
437  }
438 
439  // Use the base map to get the global IDs
440  // Get the parallel maps for the original system
441  N_PDS_Manager &pdsManager = *analysisManager_.getPDSManager();
442  RCP<N_PDS_ParMap> BaseMap = rcp(pdsManager.getParallelMap( Parallel::SOLUTION ), false);
443 
444  // Find the voltage source corresponding to each port and place the LID in the bMatEntriesVec_.
445  bMatEntriesVec_.resize( hsize );
446  for (int i=0; i<hsize; ++i)
447  {
448  int gid = gidPosEntries[i];
449  bool found = false;
450  for (int j=0; j<hsize; ++j)
451  {
452  if (gid == BaseMap->localToGlobalIndex(bMatPosEntriesVec_[j]))
453  {
454  bMatEntriesVec_[i] = tempVec[j];
455  found = true;
456  break;
457  }
458  }
459  if (!found)
460  {
461  Report::UserError() << "Did not find voltage source corresponding to port";
462  return false;
463  }
464  }
465 
466  if (morCompOrigTF_)
467  {
468  // Resize transfer function matrices
469  origH_.shape(numPorts_, numPorts_);
470  }
471  if (morCompRedTF_)
472  {
473  // Resize transfer function matrices
474  redH_.shape(numPorts_, numPorts_);
475  }
476 
477  // Create C and G matrices from DCOP solution
478  analysisManager_.getDataStore()->daeQVectorPtr->putScalar(0.0);
479  analysisManager_.getDataStore()->daeFVectorPtr->putScalar(0.0);
480  analysisManager_.getDataStore()->daeBVectorPtr->putScalar(0.0);
481 
486 
497  );
498 
523 
528 
531 
532 
533  /// Xyce::dout() << "Branch nodes: " << std::endl;
534  /// for (unsigned int i=0; i < bMatEntriesVec_.size(); ++i)
535  /// {
536  /// Xyce::dout() << "Node " << i << " : " << bMatEntriesVec_[i] << std::endl;
537  /// }
538 
539  /// Xyce::dout() << "Printing GPtr: " << std::endl;
540  /// GPtr_->printPetraObject();
541  /// Xyce::dout() << "Printing CPtr: " << std::endl;
542  /// CPtr_->printPetraObject();
543 
544 
545  // Storage for row extraction
546  int length=1, numEntries=0;
547  std::vector<int> colIndices(length);
548  std::vector<double> coeffs(length);
549 
550  for (unsigned int i=0; i < bMatEntriesVec_.size(); ++i)
551  {
552  // Get the number of non-zero entries in this row.
553  numEntries = GPtr_->getLocalRowLength( bMatEntriesVec_[i] );
554  if ( numEntries != 1 )
555  {
556  Report::UserError0() << "Supposed voltage source row has too many entries, cannot continue MOR analysis";
557  return false;
558  }
559 
560  // Extract out rows of G based on indices in bMatEntriesVec_.
561  GPtr_->getLocalRowCopy(bMatEntriesVec_[i], length, numEntries, &coeffs[0], &colIndices[0]);
562 
563  // If the coefficient for this voltage source is positive, make it negative.
564  if ( coeffs[0] > 0.0 )
565  {
566  coeffs[0] *= -1.0;
567  GPtr_->putLocalRow(bMatEntriesVec_[i], length, &coeffs[0], &colIndices[0]);
568  }
569  }
570 
571 
572  /// Xyce::dout() << "Printing GPtr (after scaling): " << std::endl;
573  /// GPtr_->printPetraObject();
574 
575  return bsuccess;
576 }
577 
578 //-----------------------------------------------------------------------------
579 // Function : MOR::reduceSystem()
580 // Purpose :
581 // Special Notes :
582 // Scope : public
583 // Creator : Heidi Thornquist, SNL
584 // Creation Date : 6/4/2012
585 //-----------------------------------------------------------------------------
587 {
588  // At this time, the reduceSystem() method will compute the reduced-order system using
589  // multi-port PRIMA. This method should allow the user multiple algorithms, defined by
590  // the morMethod_ option, which would be best implemented using a factory design.
591 
592  bool bsuccess = true;
593 
594  // Get the parallel maps for the original system
595  N_PDS_Manager &pdsManager = *analysisManager_.getPDSManager();
596 
597  N_PDS_ParMap &BaseMap = *pdsManager.getParallelMap( Parallel::SOLUTION );
598 
599  // Create matrix for (G + s0 * C)
600  if (s0_ != 0.0)
601  {
602  sCpG_MatrixPtr_ = rcp( new Linear::Matrix( &CPtr_->epetraObj(), false ) );
603  sCpG_MatrixPtr_->scale( s0_ );
604  sCpG_MatrixPtr_->add( *GPtr_ );
605  }
606  else
607  {
608  sCpG_MatrixPtr_ = rcp( new Linear::Matrix( &GPtr_->epetraObj(), false ) );
609  }
610 
611  // Create multivector for B and R
612  RPtr_ = rcp( new Linear::MultiVector( BaseMap, numPorts_ ) );
613  RPtr_->putScalar( 0.0 );
614  BPtr_ = rcp( new Linear::MultiVector( BaseMap, numPorts_ ) );
615  for (unsigned int j=0; j < bMatEntriesVec_.size(); ++j)
616  {
617  BPtr_->setElementByGlobalIndex( BaseMap.localToGlobalIndex(bMatEntriesVec_[j]), -1.0, j );
618  }
619 
620  /// Xyce::dout() << "Printing out BPtr" << std::endl;
621  /// BPtr_->epetraObj().Print(Xyce::dout());
622 
623  /// Xyce::dout() << "Printing out sCpG" << std::endl;
624  /// (sCpG_MatrixPtr_->epetraObj()).Print(Xyce::dout());
625 
626  // Create linear problem for (G + s0 * C)
627  origProblem_ = rcp(new Epetra_LinearProblem(&sCpG_MatrixPtr_->epetraObj(), &RPtr_->epetraObj(), &BPtr_->epetraObj() ) );
628 
629  // Create solver object for this linear problem, which will be used to generate the projection basis
630  Amesos amesosFactory;
631  origSolver_ = rcp( amesosFactory.Create( "Klu", *origProblem_ ) );
632 
633  // Solve for R = inv(G + s0*C)*B
634  // Perform symbolic factorization.
635  int linearStatus = origSolver_->SymbolicFactorization();
636  if (linearStatus != 0)
637  {
638  Xyce::dout() << "Amesos symbolic factorization exited with error: " << linearStatus << std::endl;
639  bsuccess = false;
640  }
641 
642  // Perform numeric factorization
643  linearStatus = origSolver_->NumericFactorization();
644  if (linearStatus != 0)
645  {
646  Xyce::dout() << "Amesos numeric factorization exited with error: " << linearStatus << std::endl;
647  bsuccess = false;
648  }
649 
650  // Perform solve for R = inv(G + s0*C)*B
651  linearStatus = origSolver_->Solve();
652  if (linearStatus != 0)
653  {
654  Xyce::dout() << "Amesos solve exited with error: " << linearStatus << std::endl;
655  bsuccess = false;
656  }
657 
658  /// Xyce::dout() << "Printing out R" << std::endl;
659  /// (RPtr_->epetraObj()).Print(Xyce::dout());
660 
661  // Create an Epetra_Operator object to apply the operator inv(G + s0*C)*C
662  RCP<Epetra_Operator> COpPtr_ = rcp( &CPtr_->epetraObj(), false );
663  RCP<Linear::AmesosGenOp> AOp = rcp( new Linear::AmesosGenOp( origSolver_, COpPtr_ ) );
664 
665  // Check to see if the requested size of the ROM is valid.
666  // An orthogonal basis cannot be generated that is larger than the dimension of the original system
667  int kblock = 0;
668 
669 
670 
671  if (morAutoSize_)
672  {
673  if (morMaxSize_ != -1)
675  else
676  ROMsize_ = RPtr_->globalLength()/4;
677  }
678  else
679  {
680 
681  if (ROMsize_ == -1)
682  {
683  Report::UserError() << "Automatic Sizing is OFF. Please specify the ROM dimension";
684  }
685  }
686 
687 
688  if (ROMsize_ > RPtr_->globalLength())
689  {
690  kblock = (int)(RPtr_->globalLength() / numPorts_);
691  UserWarning(*this) << "Requested reduced-order model dimension is larger than original system dimension, resizing to original system dimension";
692  }
693  else
694  {
695  kblock = (int)(ROMsize_ / numPorts_);
696  }
697  int k = kblock * numPorts_;
698 
699  // Resize the projection matrices
700  redG_.shape(k, k);
701  redC_.shape(k, k);
702  redB_.shape(k, numPorts_);
703  redL_.shape(k, numPorts_);
704 
705 #ifdef Xyce_BELOS
706  // ---------------------------------------------------------------------
707  // Now use Belos to compute the basis vectors for K_k(inv(G + s0*C)*C, R)
708  // ---------------------------------------------------------------------
709 
710  // Helpful typedefs for the templates
711  typedef double ST;
712  typedef Epetra_MultiVector MV;
713  typedef Epetra_Operator OP;
714  typedef Belos::MultiVecTraits<ST,MV> MVT;
715 
716  // Output manager.
717  Belos::OutputManager<ST> printer;
718 
719  // Status test.
720  Belos::StatusTestMaxIters<ST, MV, OP> maxIterTest( kblock );
721 
722  // Orthogonalization manager.
723  Belos::DGKSOrthoManager<ST, MV, OP> orthoMgr;
724 
725  // Linear Problem.
726  // Reuse RPtr_. We need the basis vectors for K(inv(G + s0*C)*C, R)
727  Linear::MultiVector temp( BaseMap, numPorts_ );
728  Belos::LinearProblem<ST, MV, OP > problem( AOp,
729  rcp( &temp.epetraObj(), false ),
730  rcp( &RPtr_->epetraObj(), false ));
731  problem.setProblem();
732 
733  // Create parameter list.
734  Teuchos::ParameterList params;
735  params.set("Num Blocks", kblock);
736  params.set("Block Size", numPorts_ );
737 
738  // Create Krylov subspace iteration from Belos
739  Belos::BlockGmresIter<ST, MV, OP> krylovIter( rcp( &problem, false ),
740  rcp( &printer, false ),
741  rcp( &maxIterTest, false ),
742  rcp( &orthoMgr, false ),
743  params );
744 
745  // Get a matrix to hold the orthonormalization coefficients.
746  RCP<Teuchos::SerialDenseMatrix<int,ST> > z
747  = rcp( new Teuchos::SerialDenseMatrix<int,ST>( numPorts_, numPorts_ ) );
748 
749  // Orthonormalize the Krylov kernel vectors V
750  RCP<MV> V = rcp( new Epetra_MultiVector( RPtr_->epetraObj() ) );
751  orthoMgr.normalize( *V, z );
752 
753  // Set the new state and initialize the solver to use R as the kernel vectors.
754  Belos::GmresIterationState<ST,MV> initState;
755  initState.V = V;
756  initState.z = z;
757  initState.curDim = 0;
758  krylovIter.initializeGmres(initState);
759 
760  // Have the solver iterate until the basis size is computed
761  try {
762  krylovIter.iterate();
763  }
764  catch (const Belos::GmresIterationOrthoFailure &e) {
765  // This might happen if the basis size is the same as the operator's dimension.
766  }
767  catch (const std::exception &e) {
768  bsuccess = false; // Anything else is a failure.
769  }
770 
771  // Get the basis vectors back from the iteration object
772  Belos::GmresIterationState<ST,MV> newState = krylovIter.getState();
773 
774  // Create a view into the first k vectors of newState.V
775  // std::vector<int> indices( k );
776 
777  // search for a size for automated MOR
778 
779  RCP<MV> W = rcp( new Epetra_MultiVector( V->Map(), k ) );
780 
781  int low = 1, high = k;
782  if (morAutoSize_)
783  {
784 
785  double abstol = 1e-6;
786  double reltol = 1e-3;
787 
788  int mid;
789 
790  while ((high - low) > 0 )
791  {
792  mid = (low + high)/2;
793 
794  std::vector<int> indices(mid);
795 
796  // Resize the projection matrices
797  redG_.shape(mid, mid);
798  redC_.shape(mid, mid);
799  redB_.shape(mid, numPorts_);
800  redL_.shape(mid, numPorts_);
801 
802  for (int i=0; i<mid; ++i) { indices[i] = i; }
803 
804  V = rcp( new Epetra_MultiVector( View, *newState.V, &indices[0], mid) );
805 
806  W = V;
807 
808 // project the system
809  Linear::MultiVector xyceV( &*V, false );
810  Linear::MultiVector temp2( BaseMap, mid);
811 
812  Linear::MultiVector xyceW( &*W, false );
813  // G * V
814  GPtr_->matvec( false, xyceV, temp2 );
815  // V' * G * V
816 
817  MVT::MvTransMv( 1.0, xyceW.epetraObj(), temp2.epetraObj(), redG_ );
818 
819  // C * V
820  CPtr_->matvec( false, xyceV, temp2 );
821  // V' * C * V
822  MVT::MvTransMv( 1.0, xyceW.epetraObj(), temp2.epetraObj(), redC_ );
823  //redC_.print( Xyce::dout() );
824 
825  // V' * B
826  MVT::MvTransMv( 1.0, xyceW.epetraObj(), BPtr_->epetraObj(), redB_ );
827 
828  MVT::MvTransMv( 1.0, xyceV.epetraObj(), BPtr_->epetraObj(), redL_ );
829 
830  //redB_.print( Xyce::dout() );
831 
832  // calculate transfer functions:
833  isSingleFreq_ = true;
834 
836  origH_.shape(numPorts_, numPorts_);
837  redH_.shape(numPorts_, numPorts_);
838 
841 
842 
843  Teuchos::SerialDenseMatrix<int, double> H_diff, totaltol, errOverTol;
844 
845  totaltol.shape(numPorts_, numPorts_);
846  H_diff.shape(numPorts_, numPorts_);
847 
848 
849  errOverTol.shape(numPorts_, numPorts_);
850  for (unsigned int j=0; j < bMatEntriesVec_.size(); ++j)
851  {
852  for (unsigned int i=0; i < bMatEntriesVec_.size(); ++i)
853  {
854  totaltol(i,j) = reltol*abs( origH_(i,j)) + abstol;
855 
856  H_diff(i,j) = abs( origH_(i,j) - redH_(i, j));
857 
858  errOverTol(i, j) = H_diff(i,j)/totaltol(i,j);
859  }
860  }
861 
862  double totalErrOverTol = errOverTol.normFrobenius()/numPorts_;
863 
864 
865  if( totalErrOverTol < 1)
866  high = mid;
867  else
868  low = mid+1;
869 
870  }
871 
872  isSingleFreq_ = false;
873 
874  ROMsize_ = high;
875 
876  if (ROMsize_ > RPtr_->globalLength())
877  {
878  kblock = (int)(RPtr_->globalLength() / numPorts_);
879  UserWarning(*this) << "Requested reduced-order model dimension is larger than original system dimension, resizing to original system dimension";
880  }
881  else
882  {
883  kblock = (int)(ROMsize_ / numPorts_);
884  }
885 
886  k = kblock * numPorts_;
887 
888  // Resize the projection matrices
889  redG_.shape(k, k);
890  redC_.shape(k, k);
891  redB_.shape(k, numPorts_);
892  redL_.shape(k, numPorts_);
893 
894  }
895  std::vector<int> indices(k);
896  for (int i=0; i<k; ++i) { indices[i] = i; }
897 
898  V = rcp( new Epetra_MultiVector( View, *newState.V, &indices[0], k) );
899  W = V;
900 
901  // ---------------------------------------------------------------------
902  // Sparsify the reduced system, if requested.
903  // ---------------------------------------------------------------------
905  {
906 
907  Linear::MultiVector xyceV( &*V, false );
908  Linear::MultiVector temp2( BaseMap, k );
909 
910  // G * V
911  GPtr_->matvec( false, xyceV, temp2 );
912  // V' * G * V
913  MVT::MvTransMv( 1.0, xyceV.epetraObj(), temp2.epetraObj(), redG_ );
914  //redG_.print( Xyce::dout() );
915 
916  // C * V
917  CPtr_->matvec( false, xyceV, temp2 );
918  // V' * C * V
919  MVT::MvTransMv( 1.0, xyceV.epetraObj(), temp2.epetraObj(), redC_ );
920  //redC_.print( Xyce::dout() );
921 
922  // V' * B
923  MVT::MvTransMv( 1.0, xyceV.epetraObj(), BPtr_->epetraObj(), redB_ );
924  //redB_.print( Xyce::dout() );
925 
926  bsuccess = bsuccess & sparsifyRedSystem_();
927  }
928 
929  // -----------------------------------------------------------------------------
930  // Scale the basis vectors, if requested, before computing the projected system
931  // -----------------------------------------------------------------------------
932 
933  // Create the scaling vector.
934  Teuchos::SerialDenseMatrix<int,ST> Xhatscale( k, 1 );
935 
936  int scaleType = morScaleType_;
937 
938  if ( scaleType == 1 )
939  {
940  for (int i=0; i<k; ++i)
941  {
942  Xhatscale( i, 0 ) = morScaleFactor_;
943  }
944  }
945 
946 // if ( scaleType == 2 )
947 // {
948 
949 // }
950 
951 if ( scaleType == 2 || scaleType == 3 || scaleType ==4)
952  {
953  Epetra_MultiVector Xmag( V->Map(), 1 );
954 
955  if ( scaleType == 2 )
956  Xmag.PutScalar( morScaleFactor_ );
957 
958  if ( scaleType == 4)
959  Xmag.PutScalar(1.0);
960 
961  MVT::MvTransMv( 1.0, *V, Xmag, Xhatscale );
962 
963 // Xhatscale.print(Xyce::dout());
964  for (int i=0; i<k; ++i)
965  {
966 
967  if ( scaleType == 2 )
968  {
969  if ( fabs(Xhatscale( i, 0 )) > morScaleFactor_)
970  {
971  Xhatscale( i, 0 ) = morScaleFactor_ / fabs( Xhatscale( i, 0 ) );
972  }
973  else
974  {
975  Xhatscale( i, 0 ) = morScaleFactor1_ / fabs( Xhatscale( i, 0 ) );
976  }
977  }
978 
979  if ( scaleType == 3 )
980  Xhatscale( i, 0 ) = morScaleFactor_ * fabs( Xhatscale( i, 0 ) );
981 
982  if ( scaleType == 4 )
983  {
984  if ( fabs(Xhatscale( i, 0 )) > 1.0 )
985  {
986  Xhatscale( i, 0 ) = morScaleFactor_ / fabs( Xhatscale( i, 0 ) );
987  }
988  else
989  {
990  Xhatscale( i, 0 ) = morScaleFactor1_ / fabs( Xhatscale( i, 0 ) );
991  }
992  }
993 
994 
995  }
996  }
997 
998 // Xhatscale.print(Xyce::dout());
999 
1000  // Scale the computed basis vectors before projecting the original system
1001  Teuchos::SerialDenseMatrix<int,ST> D(k,k);
1002  if ( scaleType != 0 )
1003  {
1004  RCP<MV> Vtemp = rcp( new Epetra_MultiVector( V->Map(), k ) );
1005 // Teuchos::SerialDenseMatrix<int,ST> D(k,k);
1006  for (int i=0; i<k; ++i)
1007  {
1008  if (Xhatscale( i, 0 ) != 0.0)
1009  D(i,i) = 1.0/Xhatscale( i, 0 );
1010  else
1011  D(i,i) = 1.0;
1012  }
1013  Xyce::dout() << " the scaling matrix " << std::endl;
1014 
1015 // D.print(Xyce::dout());
1016 
1017  MVT::MvTimesMatAddMv( 1.0, *V, D, 0.0, *Vtemp );
1018  V = Vtemp;
1019  }
1020 
1021 // Xyce::dout() << "Printing out V" << std::endl;
1022 // V->Print(Xyce::dout());
1023 // Xyce::dout() << "Printing out W" << std::endl;
1024 // W->Print(Xyce::dout());
1025 
1026  // ---------------------------------------------------------------------
1027  // Now use the basis vectors for K_k(inv(G + s0*C)*C, R) to compute
1028  // the projected system.
1029  // ---------------------------------------------------------------------
1030  Linear::MultiVector xyceV( &*V, false );
1031  Linear::MultiVector xyceW( &*W, false );
1032  Linear::MultiVector temp2( BaseMap, k );
1033 
1035  {
1036  // G * V
1037  GPtr_->matvec( false, xyceV, temp2 );
1038  // V' * G * V
1039  MVT::MvTransMv( 1.0, xyceW.epetraObj(), temp2.epetraObj(), redG_ );
1040  //redG_.print( Xyce::dout() );
1041 
1042  // C * V
1043  CPtr_->matvec( false, xyceV, temp2 );
1044  // V' * C * V
1045  MVT::MvTransMv( 1.0, xyceW.epetraObj(), temp2.epetraObj(), redC_ );
1046 
1047  // V' * B
1048  MVT::MvTransMv( 1.0, xyceW.epetraObj(), BPtr_->epetraObj(), redB_ );
1049 
1050  MVT::MvTransMv( 1.0, xyceV.epetraObj(), BPtr_->epetraObj(), redL_ );
1051  }
1052  else
1053  {
1054  if ( scaleType <= 1 )
1055  {
1056  redCPtr_->scale(1.0/morScaleFactor_);
1057  redGPtr_->scale(1.0/morScaleFactor_);
1058 
1059  redL_.scale(1.0/morScaleFactor_);
1060  }
1061  else
1062  {
1063  Report::UserError0() << "MOR options sparsificationType=1 can only be used with scaletype=1, other scale types have not been supported for sparsification";
1064  return false;
1065  }
1066  }
1067 
1068  // ---------------------------------------------------------------------
1069  // Output the projected system, redG_, redC_, and redB_.
1070  // ---------------------------------------------------------------------
1071 
1072  if (morSaveRedSys_)
1073  {
1074  // If sparsification was used, write out the Linear::Matrix object instead of the dense object.
1077  else
1079  }
1080 
1081 #else
1082  Report::UserError0() << "Belos is necessary to compute a reduced-order model, please recompile Xyce with Belos enabled";
1083  return false;
1084 
1085 #endif // Xyce_BELOS
1086 
1087  return bsuccess;
1088 }
1089 
1090 //-----------------------------------------------------------------------------
1091 // Function : MOR::evalOrigTransferFunction()
1092 // Purpose : Evaluate original transfer function.
1093 // Special Notes :
1094 // Scope : public
1095 // Creator : Heidi Thornquist and Ting Mei, SNL
1096 // Creation Date : 5/29/2012
1097 //-----------------------------------------------------------------------------
1099 {
1100  bool bsuccess = true;
1101 
1103 
1104  int currentStep = 0;
1105  int finalStep = morEvalSize_;
1106 
1107  if ( isSingleFreq_ )
1108  finalStep = 1;
1109 
1110  bool stepAttemptStatus;
1111 
1112  while (currentStep < finalStep)
1113  {
1114 
1115  if (!isSingleFreq_)
1116  updateCurrentFreq_(currentStep);
1117 
1119 
1120  stepAttemptStatus = solveOrigLinearSystem_();
1121 
1122  currentStep++;
1123 
1124  if (stepAttemptStatus)
1125  {
1126  processSuccessfulStep(true);
1127  }
1128  else // stepAttemptStatus (ie do this if the step FAILED)
1129  {
1131  }
1132 
1133  }
1134 
1135  return bsuccess;
1136 }
1137 
1138 //-----------------------------------------------------------------------------
1139 // Function : MOR::evalRedTransferFunction()
1140 // Purpose : Evaluate reduced transfer function.
1141 // Special Notes :
1142 // Scope : public
1143 // Creator : Heidi Thornquist and Ting Mei, SNL
1144 // Creation Date : 5/29/2012
1145 //-----------------------------------------------------------------------------
1147 {
1148  bool bsuccess = true;
1149 
1151 
1152  int currentStep = 0;
1153 
1154  int finalStep = morEvalSize_;
1155 
1156  if ( isSingleFreq_ )
1157  finalStep = 1;
1158 
1159  bool stepAttemptStatus;
1160 
1161  while (currentStep < finalStep)
1162  {
1163  if (!isSingleFreq_)
1164  updateCurrentFreq_(currentStep);
1165 
1167 
1168  stepAttemptStatus = solveRedLinearSystem_();
1169 
1170  currentStep++;
1171 
1172  if (stepAttemptStatus)
1173  {
1174  processSuccessfulStep(false);
1175  }
1176  else // stepAttemptStatus (ie do this if the step FAILED)
1177  {
1179  }
1180  }
1181 
1182  return bsuccess;
1183 }
1184 
1185 //-----------------------------------------------------------------------------
1186 // Function : MOR::createOrigLinearSystem_()
1187 // Purpose :
1188 // Special Notes :
1189 // Scope : public
1190 // Creator : Ting Mei, Heidi Thornquist, SNL
1191 // Creation Date : 6/20/2011
1192 //-----------------------------------------------------------------------------
1194 {
1195  bool bsuccess = true;
1196 
1197  N_PDS_Manager &pdsManager = *analysisManager_.getPDSManager();
1198 
1199  N_PDS_ParMap &BaseMap = *pdsManager.getParallelMap(Parallel::SOLUTION);
1200  N_PDS_ParMap &oBaseMap = *pdsManager.getParallelMap(Parallel::SOLUTION_OVERLAP_GND);
1201  Epetra_CrsGraph &BaseFullGraph = *pdsManager.getMatrixGraph(Parallel::JACOBIAN);
1202 
1203  int numBlocks = 2;
1204 
1205  std::vector<RCP<N_PDS_ParMap> > blockMaps = Linear::createBlockParMaps(numBlocks, BaseMap, oBaseMap);
1206 
1207  std::vector<std::vector<int> > blockPattern(2);
1208  blockPattern[0].resize(2);
1209  blockPattern[0][0] = 0; blockPattern[0][1] = 1;
1210  blockPattern[1].resize(2);
1211  blockPattern[1][0] = 0; blockPattern[1][1] = 1;
1212 
1213  int offset = Linear::generateOffset( BaseMap );
1214  RCP<Epetra_CrsGraph> blockGraph = Linear::createBlockGraph( offset, blockPattern, *blockMaps[0], BaseFullGraph);
1215 
1216  sCpG_REFMatrixPtr_ = rcp ( new Linear::BlockMatrix( numBlocks, offset, blockPattern, *blockGraph, BaseFullGraph) );
1217 
1218  // Load diagonal blocks of real equivalent form: (G - s0*C)
1219  sCpG_REFMatrixPtr_->put( 0.0 ); // Zero out whole matrix
1220 
1221  // Add scaled C matrix first if expansion point is not zero.
1222  if (s0_ != 0.0)
1223  {
1224  sCpG_REFMatrixPtr_->block( 0, 0 ).add(*CPtr_);
1225  sCpG_REFMatrixPtr_->block( 0, 0 ).scale(-s0_);
1226  sCpG_REFMatrixPtr_->block( 1, 1 ).add(*CPtr_);
1227  sCpG_REFMatrixPtr_->block( 1, 1 ).scale(-s0_);
1228  }
1229  // Add G into diagonal block to obtain (G - s0*C)
1230  sCpG_REFMatrixPtr_->block( 0, 0 ).add(*GPtr_);
1231  sCpG_REFMatrixPtr_->block( 1, 1 ).add(*GPtr_);
1232 
1233  // Create solver factory
1234  Amesos amesosFactory;
1235 
1236  // Create block vectors
1237  REFBPtr_ = rcp ( new Linear::BlockVector ( numBlocks, blockMaps[0], rcp(&BaseMap, false) ) );
1238  REFXPtr_ = rcp ( new Linear::BlockVector ( numBlocks, blockMaps[0], rcp(&BaseMap, false) ) );
1239  REFXPtr_->putScalar( 0.0 );
1240 
1241  blockProblem_ = rcp(new Epetra_LinearProblem(&sCpG_REFMatrixPtr_->epetraObj(), &REFXPtr_->epetraObj(), &REFBPtr_->epetraObj() ) );
1242 
1243  blockSolver_ = rcp( amesosFactory.Create( "Klu", *blockProblem_ ) );
1244 
1245  int linearStatus = blockSolver_->SymbolicFactorization();
1246 
1247  if (linearStatus != 0)
1248  {
1249  Xyce::dout() << "Amesos symbolic factorization exited with error: " << linearStatus;
1250  bsuccess = false;
1251  }
1252 
1253  return bsuccess;
1254 
1255 }
1256 
1257 //-----------------------------------------------------------------------------
1258 // Function : MOR::createRedLinearSystem_()
1259 // Purpose :
1260 // Special Notes :
1261 // Scope : public
1262 // Creator : Ting Mei, Heidi Thornquist, SNL
1263 // Creation Date : 6/20/2011
1264 //-----------------------------------------------------------------------------
1266 {
1267  // Create a dense linear system if sparsification has not been, or will not be, performed.
1269  {
1270  // The reduced system is dense, so create a dense linear system for transfer function comparisons.
1271 
1272  // Get the reduced system size.
1273  int k = redG_.numRows();
1274 
1275  // Resize serial dense matrix for real-equivalent form.
1276  sCpG_redMatrix_.shape(2*k, 2*k);
1277  sCpG_tmpMatrix_.shape(2*k, 2*k);
1278  ref_redB_.shape(2*k, numPorts_);
1279 
1280  // First, load the diagonals.
1281  // Get a view of the primary diagonal block, insert (G - s0*C).
1282  Teuchos::SerialDenseMatrix<int, double> subMtx( Teuchos::View, sCpG_tmpMatrix_, k, k, 0, 0 );
1283  subMtx.assign( redC_ );
1284  subMtx.scale( -s0_ );
1285  subMtx += redG_;
1286 
1287  // Get a view of the lower k x k diagonal block, insert (G - s0*C).
1288  Teuchos::SerialDenseMatrix<int, double> subMtx2( Teuchos::View, sCpG_tmpMatrix_, k, k, k, k );
1289  subMtx2.assign( redC_ );
1290  subMtx2.scale( -s0_ );
1291  subMtx2 += redG_;
1292  }
1293  else
1294  {
1295  // The reduced system is sparse, so create a sparse linear system.
1296 
1297  int numBlocks = 2;
1298 
1299  N_PDS_Manager &pdsManager = *analysisManager_.getPDSManager();
1300  N_PDS_ParMap redPDSMap( redMapPtr_.get(), *pdsManager.getPDSComm() );
1301 
1302  RCP<N_PDS_ParMap> redBlockMapPtr = Linear::createBlockParMap(numBlocks, redPDSMap);
1303 
1304  std::vector<std::vector<int> > blockPattern(2);
1305  blockPattern[0].resize(2);
1306  blockPattern[0][0] = 0; blockPattern[0][1] = 1;
1307  blockPattern[1].resize(2);
1308  blockPattern[1][0] = 0; blockPattern[1][1] = 1;
1309 
1310  int offset= Linear::generateOffset( redPDSMap );
1311  RCP<Epetra_CrsGraph> blockGraph = Linear::createBlockGraph( offset, blockPattern, *redBlockMapPtr, (redCPtr_->epetraObj()).Graph() );
1312 
1313  sCpG_ref_redMatrixPtr_ = rcp( new Linear::BlockMatrix( numBlocks, offset, blockPattern, *blockGraph, (redCPtr_->epetraObj()).Graph() ) );
1314 
1315  // Load diagonal blocks of real equivalent form: (G - s0*C)
1316  sCpG_ref_redMatrixPtr_->put( 0.0 ); // Zero out whole matrix
1317 
1318  // Add scaled C matrix first if expansion point is not zero.
1319  if (s0_ != 0.0)
1320  {
1321  sCpG_ref_redMatrixPtr_->block( 0, 0 ).add(*redCPtr_);
1322  sCpG_ref_redMatrixPtr_->block( 0, 0 ).scale(-s0_);
1323  sCpG_ref_redMatrixPtr_->block( 1, 1 ).add(*redCPtr_);
1324  sCpG_ref_redMatrixPtr_->block( 1, 1 ).scale(-s0_);
1325  }
1326  // Add G into diagonal block to obtain (G - s0*C)
1327  sCpG_ref_redMatrixPtr_->block( 0, 0 ).add(*redGPtr_);
1328  sCpG_ref_redMatrixPtr_->block( 1, 1 ).add(*redGPtr_);
1329 
1330  // Create solver factory
1331  Amesos amesosFactory;
1332 
1333  // Create a block vector
1334  ref_redBPtr_ = rcp ( new Linear::BlockVector ( numBlocks, redBlockMapPtr, rcp(&redPDSMap, false) ) );
1335  ref_redXPtr_ = rcp ( new Linear::BlockVector ( numBlocks, redBlockMapPtr, rcp(&redPDSMap, false) ) );
1336  ref_redXPtr_->putScalar( 0.0 );
1337 
1338  blockRedProblem_ = rcp(new Epetra_LinearProblem(&sCpG_ref_redMatrixPtr_->epetraObj(),
1339  &ref_redXPtr_->epetraObj(), &ref_redBPtr_->epetraObj() ) );
1340 
1341  blockRedSolver_ = rcp( amesosFactory.Create( "Klu", *blockRedProblem_ ) );
1342 
1343  int linearStatus = blockRedSolver_->SymbolicFactorization();
1344 
1345  if (linearStatus != 0)
1346  {
1347  Xyce::dout() << "Amesos symbolic factorization exited with error: " << linearStatus;
1348  return false;
1349  }
1350  }
1351 
1352  return true;
1353 }
1354 
1355 //-----------------------------------------------------------------------------
1356 // Function : MOR::updateOrigLinearSystemFreq_()
1357 // Purpose :
1358 // Special Notes :
1359 // Scope : public
1360 // Creator : Ting Mei, Heidi Thornquist, SNL
1361 // Creation Date : 6/20/2011
1362 //-----------------------------------------------------------------------------
1363 
1365 {
1366  double omega = 2.0 * M_PI * currentFreq_;
1367 
1368  sCpG_REFMatrixPtr_->block( 0, 1).put( 0.0);
1369  sCpG_REFMatrixPtr_->block( 0, 1).add(*CPtr_);
1370  sCpG_REFMatrixPtr_->block( 0, 1).scale(-omega);
1371 
1372  sCpG_REFMatrixPtr_->block(1, 0).put( 0.0);
1373  sCpG_REFMatrixPtr_->block(1, 0).add(*CPtr_);
1374  sCpG_REFMatrixPtr_->block(1, 0).scale(omega);
1375 
1376  return true;
1377 }
1378 
1379 //-----------------------------------------------------------------------------
1380 // Function : MOR::updateRedLinearSystemFreq_()
1381 // Purpose :
1382 // Special Notes :
1383 // Scope : public
1384 // Creator : Ting Mei, Heidi Thornquist, SNL
1385 // Creation Date : 6/20/2011
1386 //-----------------------------------------------------------------------------
1387 
1389 {
1390  double omega = 2.0 * M_PI * currentFreq_;
1391 
1393  {
1394  sCpG_ref_redMatrixPtr_->block( 0, 1).put( 0.0);
1395  sCpG_ref_redMatrixPtr_->block( 0, 1).add(*redCPtr_);
1396  sCpG_ref_redMatrixPtr_->block( 0, 1).scale(-omega);
1397 
1398  sCpG_ref_redMatrixPtr_->block(1, 0).put( 0.0);
1399  sCpG_ref_redMatrixPtr_->block(1, 0).add(*redCPtr_);
1400  sCpG_ref_redMatrixPtr_->block(1, 0).scale(omega);
1401  }
1402  else
1403  {
1404  int k = redG_.numRows();
1405 
1406  // Reset reduced real equivalent form matrix to sCpG_tmpMatrix_
1407  sCpG_redMatrix_.assign( sCpG_tmpMatrix_ );
1408 
1409  // Insert off diagonals.
1410  Teuchos::SerialDenseMatrix<int, double> subMtx( Teuchos::View, sCpG_redMatrix_, k, k, 0, k );
1411  subMtx.assign( redC_ );
1412  subMtx.scale( -omega );
1413 
1414  Teuchos::SerialDenseMatrix<int, double> subMtx2( Teuchos::View, sCpG_redMatrix_, k, k, k, 0 );
1415  subMtx2.assign( redC_ );
1416  subMtx2.scale( omega );
1417  }
1418 
1419  return true;
1420 }
1421 
1422 //-----------------------------------------------------------------------------
1423 // Function : MOR::solveLinearSystem_()
1424 // Purpose :
1425 // Special Notes :
1426 // Scope : public
1427 // Creator : Ting Mei, Heidi Thornquist, SNL
1428 // Creation Date : 6/2011
1429 //-----------------------------------------------------------------------------
1430 
1432 {
1433 
1434  bool bsuccess = true;
1435 
1436  // Solve the block problem
1437  int linearStatus = blockSolver_->NumericFactorization();
1438 
1439  if (linearStatus != 0)
1440  {
1441  Xyce::dout() << "Amesos numeric factorization exited with error: " << linearStatus;
1442  bsuccess = false;
1443  }
1444 
1445  // Loop over number of I/O ports here
1446  for (unsigned int j=0; j < bMatEntriesVec_.size(); ++j)
1447  {
1448  REFBPtr_->putScalar( 0.0 );
1449  (REFBPtr_->block( 0 ))[bMatEntriesVec_[j]] = -1.0;
1450 
1451  linearStatus = blockSolver_->Solve();
1452  if (linearStatus != 0)
1453  {
1454  Xyce::dout() << "Amesos solve exited with error: " << linearStatus;
1455  bsuccess = false;
1456  }
1457 
1458  // Compute transfer function entries for all I/O
1459  for (unsigned int i=0; i < bMatEntriesVec_.size(); ++i)
1460  {
1461  // Populate H for all ports in L
1462  // L is the same as B and also a set of canonical basis vectors (e_i), so
1463  // we can pick off the appropriate entries of REFXPtr to place into H.
1464  origH_(i,j) = std::complex<double>(-(REFXPtr_->block( 0 ))[bMatEntriesVec_[i]],
1465  -(REFXPtr_->block( 1 ))[bMatEntriesVec_[i]]);
1466  }
1467  }
1468  return bsuccess;
1469 }
1470 
1471 //-----------------------------------------------------------------------------
1472 // Function : MOR::solveRedLinearSystem_()
1473 // Purpose :
1474 // Special Notes :
1475 // Scope : public
1476 // Creator : Ting Mei, Heidi Thornquist, SNL
1477 // Creation Date : 6/2011
1478 //-----------------------------------------------------------------------------
1479 
1481 {
1482  bool bsuccess = true;
1483 
1485  {
1486  // Solve the block problem
1487  int linearStatus = blockRedSolver_->NumericFactorization();
1488 
1489  if (linearStatus != 0)
1490  {
1491  Xyce::dout() << "Amesos numeric factorization exited with error: " << linearStatus;
1492  bsuccess = false;
1493  }
1494 
1495  // Create a multivector with the reduced B and L vectors.
1496  Epetra_MultiVector tmp_redL( View, *redMapPtr_, redL_.values(), redL_.stride(), numPorts_ );
1497  Epetra_MultiVector tmp_redB( View, *redMapPtr_, redB_.values(), redB_.stride(), numPorts_ );
1498  Linear::MultiVector redBmv( &tmp_redB, false ), redLmv( &tmp_redL, false );
1499 
1500  // Loop over number of I/O ports here
1501  for (int j=0; j < numPorts_; ++j)
1502  {
1503  // Set the B vector for this port.
1504  ref_redBPtr_->putScalar( 0.0 );
1505  (ref_redBPtr_->block( 0 )) = *(redBmv.getVectorView( j ));
1506 
1507  linearStatus = blockRedSolver_->Solve();
1508  if (linearStatus != 0)
1509  {
1510  Xyce::dout() << "Amesos solve exited with error: " << linearStatus;
1511  bsuccess = false;
1512  }
1513 
1514  // Compute transfer function entries for all I/O
1515  for (int i=0; i < numPorts_; ++i)
1516  {
1517  // L is probably not B in this case, so explicitly multiply to compute transfer function entries.
1518  double realPart = ( redLmv.getVectorView( i ) )->dotProduct( ref_redXPtr_->block( 0 ) );
1519  double imagPart = ( redLmv.getVectorView( i ) )->dotProduct( ref_redXPtr_->block( 1 ) );
1520 
1521  redH_(i,j) = std::complex<double>(realPart, imagPart);
1522  }
1523  }
1524  }
1525  else
1526  {
1527  int k = redG_.numRows();
1528  Teuchos::LAPACK<int, double> lapack;
1529 
1530  ref_redB_.putScalar( 0.0 );
1531  Teuchos::SerialDenseMatrix<int, double> tmpRedB( Teuchos::View, ref_redB_, redB_.numRows(), redB_.numCols(), 0, 0 );
1532  tmpRedB.assign( redB_ );
1533 
1534  // First factor matrix using LU.
1535  int info = 0;
1536  std::vector<int> ipiv( sCpG_redMatrix_.numRows() );
1537  lapack.GETRF( sCpG_redMatrix_.numRows(), sCpG_redMatrix_.numCols(), sCpG_redMatrix_.values(),
1538  sCpG_redMatrix_.stride(), &ipiv[0], &info );
1539  if (info != 0)
1540  {
1541  Xyce::dout() << "LAPACK::GETRF: LU factorization failed with error: " << info << std::endl;
1542  bsuccess = false;
1543  }
1544 
1545  // Next solve for all ports at once using LU factors.
1546  const char trans = 'N';
1547  lapack.GETRS( trans, sCpG_redMatrix_.numRows(), ref_redB_.numCols(), sCpG_redMatrix_.values(),
1548  sCpG_redMatrix_.stride(), &ipiv[0], ref_redB_.values(), ref_redB_.stride(), &info );
1549  if (info != 0)
1550  {
1551  Xyce::dout() << "LAPACK::GETRS: LU solve failed with error: " << info << std::endl;
1552  bsuccess = false;
1553  }
1554 
1555  Teuchos::SerialDenseMatrix<int, double> tmpRedImag( numPorts_, numPorts_ ), tmpRedReal( numPorts_, numPorts_ );
1556 
1557  // Compute real part.
1558  tmpRedReal.multiply( Teuchos::TRANS, Teuchos::NO_TRANS, 1.0, redB_, tmpRedB, 0.0 );
1559 
1560  // Compute imaginary part.
1561  Teuchos::SerialDenseMatrix<int, double> tmpRedB2( Teuchos::View, ref_redB_, redB_.numRows(), redB_.numCols(), k, 0 );
1562  tmpRedImag.multiply( Teuchos::TRANS, Teuchos::NO_TRANS, 1.0, redB_, tmpRedB2, 0.0 );
1563 
1564  // Compute transfer function entries for all I/O
1565  for (unsigned int j=0; j < bMatEntriesVec_.size(); ++j)
1566  {
1567  for (unsigned int i=0; i < bMatEntriesVec_.size(); ++i)
1568  {
1569  redH_(i,j) = std::complex<double>(tmpRedReal(i,j), tmpRedImag(i,j));
1570  }
1571  }
1572  }
1573 
1574  return bsuccess;
1575 }
1576 
1577 //-----------------------------------------------------------------------------
1578 // Function : MOR::sparsifyRedSystem_()
1579 // Purpose : Use techniques to sparsify the projected system.
1580 // Special Notes :
1581 // Scope : public
1582 // Creator : Heidi Thornquist and Ting Mei, SNL
1583 // Creation Date : 8/20/2012
1584 //-----------------------------------------------------------------------------
1586 {
1587  bool bsuccess = true;
1588 
1589  int k = redB_.numRows();
1590 
1591  // Storage vectors
1592  Teuchos::SerialDenseMatrix<int, double> R(redB_);
1593  Teuchos::SerialDenseMatrix<int, double> A(redC_);
1594 
1595  // Factor Ghat.
1596  Teuchos::LAPACK<int, double> lapack;
1597  Teuchos::SerialDenseMatrix<int, double> tmp_Ghat( redG_ );
1598 
1599  int info = 0;
1600  std::vector<int> ipiv( tmp_Ghat.numRows() );
1601  lapack.GETRF( tmp_Ghat.numRows(), tmp_Ghat.numCols(), tmp_Ghat.values(),
1602  tmp_Ghat.stride(), &ipiv[0], &info );
1603  if (info != 0)
1604  {
1605  Xyce::dout() << "LAPACK::GETRF: LU factorization of Ghat failed with error: " << info << std::endl;
1606  bsuccess = false;
1607  }
1608 
1609  // Compute reciprocal condition estimate of Ghat.
1610  const char norm = '1';
1611  double condGhat = 0.0;
1612  std::vector<double> condWork( 4*k );
1613  std::vector<int> condIWork( k );
1614  lapack.GECON( norm, tmp_Ghat.numRows(), tmp_Ghat.values(), tmp_Ghat.stride(), tmp_Ghat.normOne(), &condGhat, &condWork[0], &condIWork[0], &info );
1615  // Xyce::dout() << "Condition estimate for Ghat is : " << 1.0/ condGhat << std::endl;
1616  if (info != 0)
1617  {
1618  Xyce::dout() << "LAPACK::GECON: Computing condition estimate of Ghat failed with error: " << info << std::endl;
1619  bsuccess = false;
1620  }
1621 
1622  // Compute A = inv(Ghat)* Chat
1623  const char trans = 'N';
1624  lapack.GETRS( trans, tmp_Ghat.numRows(), A.numCols(), tmp_Ghat.values(),
1625  tmp_Ghat.stride(), &ipiv[0], A.values(), A.stride(), &info );
1626  if (info != 0)
1627  {
1628  Xyce::dout() << "LAPACK::GETRS: LU solve failed with error: " << info << std::endl;
1629  bsuccess = false;
1630  }
1631  //Xyce::dout() << "A = inv(Ghat)*Chat" << std::endl;
1632  //A.print(Xyce::dout());
1633 
1634  // Compute R = inv(Ghat)* Bhat
1635  lapack.GETRS( trans, tmp_Ghat.numRows(), R.numCols(), tmp_Ghat.values(),
1636  tmp_Ghat.stride(), &ipiv[0], R.values(), R.stride(), &info );
1637  if (info != 0)
1638  {
1639  Xyce::dout() << "LAPACK::GETRS: LU solve failed with error: " << info << std::endl;
1640  bsuccess = false;
1641  }
1642  //Xyce::dout() << "R = inv(Ghat)*Bhat" << std::endl;
1643  //R.print(Xyce::dout());
1644 
1645  // Reduce A to Schur form and compute the eigenvalues.
1646  // Allocate the work space. This space will be used below for calls to:
1647  // * GEES (requires 3*k for real)
1648  // * TREVC (requires 3*k for real)
1649  // Furthermore, GEES requires a real array of length k
1650  //
1651  int lwork = 8*k;
1652  std::vector<double> work( lwork );
1653  std::vector<double> revals( k );
1654  std::vector<double> ievals( k );
1655  Teuchos::SerialDenseMatrix<int, double> Q(k, k);
1656 
1657  // Create diagonal tmpB for the eigenproblem (A, tmpB), beta should return as a vector of ones.
1658  const int ldvl = 1;
1659  double vl[ ldvl ];
1660  std::vector<double> beta( k );
1661  Teuchos::SerialDenseMatrix<int, double> tmpB( k, k );
1662  for (int i=0; i<k; i++)
1663  tmpB(i,i) = 1.0;
1664  lapack.GGEV( 'N', 'V', k, A.values(), A.stride(), tmpB.values(), tmpB.stride(),
1665  &revals[0], &ievals[0], &beta[0], &vl[0], ldvl, Q.values(), Q.stride(),
1666  &work[0], lwork, &info );
1667  if (info != 0)
1668  {
1669  Xyce::dout() << "LAPACK::GGEV: Computing eigenvectors and values of A = inv(Ghat)*Chat failed with error: " << info << std::endl;
1670  bsuccess = false;
1671  }
1672 
1673  // Scale the eigenvectors returned from GGEV to have 2-norm = 1
1674  // They are initially scaled to have inf-norm = 1 from LAPACK
1675  Teuchos::BLAS<int, double> blas;
1676  std::vector<int> rowIndex( k );
1677  int i = 0;
1678 
1679  while( i < k ) {
1680  if ( ievals[i] != 0.0 )
1681  {
1682  rowIndex[i] = 1;
1683  rowIndex[i+1] = -1;
1684 
1685  // Compute the 2-norm of the complex eigenvector
1686  double norm_r = blas.NRM2( k, Q[i], 1 );
1687  double norm_i = blas.NRM2( k, Q[i+1], 1 );
1688  double norm = lapack.LAPY2( norm_r, norm_i );
1689 
1690  // Scale the complex eigenvector
1691  for (int j=0; j<k; j++)
1692  {
1693  Q(j,i) /= norm;
1694  Q(j,i+1) /= norm;
1695  }
1696  i += 2;
1697  }
1698  else
1699  {
1700  rowIndex[i] = 0;
1701 
1702  // Compute the 2-norm of the i-th column
1703  double norm = blas.NRM2( k, Q[i], 1 );
1704 
1705  // Scale the real eigenvector
1706  for (int j=0; j<k; j++)
1707  {
1708  Q(j,i) /= norm;
1709  }
1710  i++;
1711  }
1712  }
1713 
1714  // Xyce::dout() << "Eigenvalues of A: " << std::endl;
1715  // for (int i=0; i<k; ++i)
1716  // Xyce::dout() << revals[i] << "\t" << ievals[i] << "\t" << beta[i] << std::endl;
1717 
1718  // Xyce::dout() << "Eigenvectors of A: " << std::endl;
1719  // Q.print(Xyce::dout());
1720 
1721  // Construct complex eigenvectors
1722  Teuchos::SerialDenseMatrix<int, std::complex<double> > V(k, k);
1723  for (int i=0; i<k; i++)
1724  {
1725  if (rowIndex[i] == 1)
1726  {
1727  for (int j=0; j<k; j++)
1728  {
1729  // Insert both conjugate pairs simultaneously.
1730  V(j,i) = std::complex<double>( Q(j,i), Q(j,i+1) );
1731  V(j,i+1) = std::complex<double>( Q(j,i), -Q(j,i+1) );
1732  }
1733  i++; // Need to increment an extra value for the conjugate pair.
1734  }
1735  else // The eigenvector is real, copy directly
1736  {
1737  for (int j=0; j<k; j++)
1738  {
1739  V(j,i) = std::complex<double>( Q(j,i), 0.0 );
1740  }
1741  }
1742  }
1743 
1744  // Factor V
1745  Teuchos::LAPACK<int, std::complex<double> > lapack_complex;
1746  lapack_complex.GETRF( V.numRows(), V.numCols(), V.values(), V.stride(), &ipiv[0], &info );
1747  if (info != 0)
1748  {
1749  Xyce::dout() << "LAPACK::GETRF: LU factorization of eigenvectors failed with error: " << info << std::endl;
1750  bsuccess = false;
1751  }
1752 
1753  // Compute condition estimate of V.
1754  double condV = 0.0;
1755  std::vector<std::complex<double> > condCWork( 2*k );
1756  lapack_complex.GECON( norm, V.numRows(), V.values(), V.stride(), V.normOne(), &condV, &condCWork[0], &condWork[0], &info );
1757  //Xyce::dout() << "Condition estimate for V is : " << 1.0/condV << std::endl;
1758  if (info != 0)
1759  {
1760  Xyce::dout() << "LAPACK::GECON: Computing condition estimate of V failed with error: " << info << std::endl;
1761  bsuccess = false;
1762  }
1763 
1764  // Compute inv(V)
1765  std::vector<std::complex<double> > cwork( lwork );
1766  lapack_complex.GETRI( V.numRows(), V.values(), V.stride(), &ipiv[0], &cwork[0], lwork, &info );
1767  if (info != 0)
1768  {
1769  Xyce::dout() << "LAPACK::GETRI: Computing inverse of V failed with error: " << info << std::endl;
1770  bsuccess = false;
1771  }
1772 
1773  // Convert R to a complex vector to use the multiply routine for inv(V).
1774  Teuchos::SerialDenseMatrix<int, std::complex<double> > tmpR( k, numPorts_ );
1775  for (int j=0; j<numPorts_; j++)
1776  for (int i=0; i<k; i++)
1777  tmpR(i,j) = std::complex<double>( R(i,j), 0.0 );
1778 
1779  // Compute inv(V) * R
1780  Teuchos::SerialDenseMatrix<int, std::complex<double> > tmp_redB(k ,numPorts_);
1781  tmp_redB.multiply(Teuchos::NO_TRANS, Teuchos::NO_TRANS, 1.0, V, tmpR, 0.0);
1782 
1783  // Generate compressed real storage of V*R and inv(V)
1784  redL_ = redB_; // Store copy of redB_ before destroying it below.
1785  Teuchos::SerialDenseMatrix<int, double> invV(k, k);
1786  for (int i=0; i<k; i++)
1787  {
1788  if (rowIndex[i] == 1) // Complex conjugate pair.
1789  {
1790  for (int j=0; j<k; j++)
1791  {
1792  invV(i, j) = V(i,j).real();
1793  invV(i+1, j) = V(i,j).imag();
1794  }
1795  for (int j=0; j<numPorts_; j++)
1796  {
1797  redB_(i, j) = tmp_redB(i, j).real();
1798  redB_(i+1, j) = tmp_redB(i, j).imag();
1799  }
1800  i++; // Increment by one to skip complex conjugate.
1801  }
1802  else // Eigenvalue is real, so is eigenvector.
1803  {
1804  for (int j=0; j<k; j++)
1805  invV(i, j) = V(i,j).real();
1806  for (int j=0; j<numPorts_; j++)
1807  redB_(i, j) = tmp_redB(i, j).real();
1808  }
1809  }
1810 
1811  // Factor invV.
1812  lapack.GETRF( invV.numRows(), invV.numCols(), invV.values(), invV.stride(), &ipiv[0], &info );
1813  if (info != 0)
1814  {
1815  Xyce::dout() << "LAPACK::GETRF: LU factorization of inv(V) failed with error: " << info << std::endl;
1816  bsuccess = false;
1817  }
1818 
1819  // Compute A = inv(invV)^T*Lhat
1820  const char trans2 = 'T';
1821  lapack.GETRS( trans2, invV.numRows(), redL_.numCols(), invV.values(),
1822  invV.stride(), &ipiv[0], redL_.values(), redL_.stride(), &info );
1823  if (info != 0)
1824  {
1825  Xyce::dout() << "LAPACK::GETRS: LU solve for Lhat failed with error: " << info << std::endl;
1826  bsuccess = false;
1827  }
1828 
1829  // Xyce::dout() << "Bhat : " << std::endl;
1830  // redB_.print(Xyce::dout());
1831  // Xyce::dout() << "Lhat : " << std::endl;
1832  // redL_.print(Xyce::dout());
1833 
1834  // Create redCPtr_ and redGPtr_
1835  // Generate Epetra_Map that puts all the values of the reduced system on one processor.
1836  N_PDS_Manager &pdsManager = *analysisManager_.getPDSManager();
1837  N_PDS_ParMap &BaseMap = *pdsManager.getParallelMap(Parallel::SOLUTION);
1838  if (BaseMap.petraMap()->Comm().MyPID() == 0)
1839  redMapPtr_ = Teuchos::rcp( new Epetra_Map( k, k, 0, BaseMap.petraMap()->Comm() ) );
1840  else
1841  redMapPtr_ = Teuchos::rcp( new Epetra_Map( k, 0, 0, BaseMap.petraMap()->Comm() ) );
1842 
1843  Epetra_CrsMatrix* tmpRedG = new Epetra_CrsMatrix( Copy, *redMapPtr_, 1 );
1844  Epetra_CrsMatrix* tmpRedC = new Epetra_CrsMatrix( Copy, *redMapPtr_, 2 );
1845 
1846  // Let processor 0 insert entries into tmpRedG and tmpRedC
1847  if (BaseMap.petraMap()->Comm().MyPID() == 0)
1848  {
1849  std::vector<int> index(2);
1850  std::vector<double> val(2);
1851  for (int i=0; i<k; i++)
1852  {
1853  // Insert G, which is a diagonal of ones.
1854  index[0] = i; val[0] = 1.0;
1855  tmpRedG->InsertGlobalValues( i, 1, &val[0], &index[0] );
1856 
1857  // Insert C, which is block diagonal, where the blocks represent conjugate eigenvalues.
1858  if (rowIndex[i] == 1)
1859  {
1860  index[0] = i; index[1] = i+1;
1861  val[0] = revals[i]; val[1] = -ievals[i];
1862  tmpRedC->InsertGlobalValues( i, 2, &val[0], &index[0] );
1863  }
1864  else if (rowIndex[i] == -1)
1865  {
1866  index[0] = i-1; index[1] = i;
1867  val[0] = ievals[i-1]; val[1] = revals[i-1];
1868  tmpRedC->InsertGlobalValues( i, 2, &val[0], &index[0] );
1869  }
1870  else // Must be real.
1871  {
1872  index[0] = i; val[0] = revals[i];
1873  tmpRedC->InsertGlobalValues( i, 1, &val[0], &index[0] );
1874  }
1875  }
1876  }
1877  // We are done inserting values.
1878  tmpRedC->FillComplete();
1879  tmpRedG->FillComplete();
1880 
1881  // Pass tmpRedG and tmpRedC into redGPtr_ and redGPtr_, respectively, which will manage the memory.
1882  redGPtr_ = rcp( new Linear::Matrix( tmpRedG ) );
1883  redCPtr_ = rcp( new Linear::Matrix( tmpRedC ) );
1884 
1885  // We now have a sparse ROM.
1886  if (bsuccess)
1887  isROMSparse_ = true;
1888 
1889  return bsuccess;
1890 }
1891 
1892 //-----------------------------------------------------------------------------
1893 // Function : MOR::processSuccessfulStep()
1894 // Purpose :
1895 // Special Notes :
1896 // Scope : public
1897 // Creator : Ting Mei, SNL
1898 // Creation Date :
1899 //-----------------------------------------------------------------------------
1900 bool MOR::processSuccessfulStep(bool origSys)
1901 {
1902  bool bsuccess = true;
1903 
1904  // Output H.
1905  if (!isSingleFreq_)
1906  {
1907  if (origSys)
1908  {
1910  }
1911  else
1912  {
1914  }
1915  }
1916 
1917  if ( !firstDoubleDCOPStep() )
1918  {
1919  stepNumber += 1;
1922  }
1923 
1924  return bsuccess;
1925 }
1926 
1927 
1928 //-----------------------------------------------------------------------------
1929 // Function : MOR::processFailedStep
1930 // Purpose :
1931 // Special Notes :
1932 // Scope : public
1933 // Creator : Ting Mei, SNL
1934 // Creation Date :
1935 //-----------------------------------------------------------------------------
1937 {
1938  bool bsuccess = true;
1939 
1940  stepNumber += 1;
1941  morEvalFailures_.push_back(stepNumber);
1944 
1945  return bsuccess;
1946 }
1947 
1948 //-----------------------------------------------------------------------------
1949 // Function : MOR::finish
1950 // Purpose :
1951 // Special Notes :
1952 // Scope : public
1953 // Creator : Ting Mei, SNL
1954 // Creation Date :
1955 //-----------------------------------------------------------------------------
1957 {
1958  bool bsuccess = true;
1959 
1960  if (DEBUG_ANALYSIS)
1961  Xyce::dout() << "Calling MOR::doFinish() outputs!" << std::endl;
1962 
1963  if (!(morEvalFailures_.empty()))
1964  {
1965  bsuccess = false;
1966  }
1967 
1968  return bsuccess;
1969 }
1970 
1971 
1972 //-----------------------------------------------------------------------------
1973 // Function : MOR::doHandlePredictor
1974 // Purpose :
1975 // Special Notes :
1976 // Scope : private
1977 // Creator : Eric Keiter, SNL
1978 // Creation Date : 06/24/2013
1979 //-----------------------------------------------------------------------------
1981 {
1985 
1986  // In case this is the upper level of a 2-level sim, tell the
1987  // inner solve to do its prediction:
1989 
1990  return true;
1991 }
1992 
1993 //-----------------------------------------------------------------------------
1994 // Function : MOR::updateCurrentFreq_(int stepNumber )
1995 // Purpose :
1996 // Special Notes : Used for MOR analysis classes.
1997 // Scope : public
1998 // Creator : Ting Mei, SNL.
1999 // Creation Date :
2000 //-----------------------------------------------------------------------------
2001 bool MOR::updateCurrentFreq_(int stepNumber)
2002 {
2003  double fStart = morCompFStart_;
2004 
2005  if (morCompType_=="LIN")
2006  {
2007  currentFreq_ = fStart + static_cast<double>(stepNumber)*fStep_;
2008  }
2009  else if(morCompType_=="DEC" || morCompType_=="OCT")
2010  {
2011  currentFreq_ = fStart*pow(stepMult_, static_cast<double>(stepNumber) );
2012  }
2013  else
2014  {
2015  Report::DevelFatal().in("MOR::updateCurrentFreq_") << "Unsupported STEP type";
2016  }
2017 
2018  return true;
2019 }
2020 
2021 //-----------------------------------------------------------------------------
2022 // Function : MOR::setupSweepParam_
2023 // Purpose : Processes sweep parameters.
2024 // Special Notes : Used for MOR analysis classes.
2025 // Scope : public
2026 // Creator : Ting Mei, SNL.
2027 // Creation Date :
2028 //-----------------------------------------------------------------------------
2030 {
2031  int fCount = 0;
2032  double fStart = morCompFStart_;
2033  double fStop = morCompFStop_;
2034 
2035  if (DEBUG_ANALYSIS && isActive(Diag::TIME_PARAMETERS))
2036  {
2037  Xyce::dout() << std::endl << std::endl;
2038  Xyce::dout() << section_divider << std::endl;
2039  Xyce::dout() << "MOR::setupSweepParam_" << std::endl;
2040  }
2041 
2042  if (morCompType_=="LIN")
2043  {
2044  if ( morCompNP_ == 1)
2045  fStep_ = 0;
2046  else
2047  fStep_ = (fStop - fStart)/(morCompNP_ - 1);
2048 
2049  fCount = morCompNP_;
2050 
2051  if (DEBUG_ANALYSIS && isActive(Diag::TIME_PARAMETERS))
2052  {
2053  Xyce::dout() << "fStep = " << fStep_ << std::endl;
2054  }
2055  }
2056  else if(morCompType_=="DEC")
2057  {
2058  stepMult_ = pow(10,(1/(double)morCompNP_));
2059  fCount = (int)(floor(fabs(log10(fStart) - log10(fStop)) * morCompNP_ + 1));
2060  if (DEBUG_ANALYSIS && isActive(Diag::TIME_PARAMETERS))
2061  {
2062  Xyce::dout() << "stepMult_ = " << stepMult_ << std::endl;
2063  }
2064  }
2065  else if(morCompType_=="OCT")
2066  {
2067  stepMult_ = pow(2,1/(double)(morCompNP_));
2068 
2069  // changed to remove dependence on "log2" function, which apparently
2070  // doesn't exist in the math libraries of FreeBSD or the mingw
2071  // cross-compilation suite. Log_2(x)=log_e(x)/log_e(2.0)
2072  double ln2=log(2.0);
2073  fCount = floor(fabs(log(fStart) - log(fStop))/ln2 * morCompNP_ + 1);
2074  if (DEBUG_ANALYSIS && isActive(Diag::TIME_PARAMETERS))
2075  {
2076  Xyce::dout() << "stepMult_ = " << stepMult_ << std::endl;
2077  }
2078  }
2079  else
2080  {
2081  Report::DevelFatal().in("MOR::setupSweepParam_") << "Unsupported type";
2082  }
2083 
2084  // At this point, pinterval equals the total number of steps
2085  // for the step loop.
2086  return fCount;
2087 }
2088 
2089 namespace {
2090 
2091 //-----------------------------------------------------------------------------
2092 // Class : MORFactory
2093 // Purpose :
2094 // Special Notes :
2095 // Scope : public
2096 // Creator : David G. Baur Raytheon Sandia National Laboratories 1355
2097 // Creation Date : Thu Jan 29 12:53:02 2015
2098 //-----------------------------------------------------------------------------
2099 ///
2100 /// Factory for parsing MOR parameters from the netlist and creating MOR analysis.
2101 ///
2102 class MORFactory : public Factory<MOR>
2103 {
2104 public:
2105  //-----------------------------------------------------------------------------
2106  // Function : MORFactory
2107  // Purpose :
2108  // Special Notes :
2109  // Scope : public
2110  // Creator : David G. Baur Raytheon Sandia National Laboratories 1355
2111  // Creation Date : Thu Jan 29 12:54:09 2015
2112  //-----------------------------------------------------------------------------
2113  ///
2114  /// Constructs the MOR analysis factory
2115  ///
2116  /// @invariant Stores the results of parsing, so if more than one of the analysis and
2117  /// associated lines are parsed, the second options simply overwrite the previously parsed
2118  /// values.
2119  ///
2120  /// @invariant The existence of the parameters specified in the constructor cannot
2121  /// change.
2122  ///
2123  /// @param analysis_manager
2124  /// @param linear_system
2125  /// @param nonlinear_manager
2126  /// @param topology
2127  ///
2128  MORFactory(
2129  Analysis::AnalysisManager & analysis_manager,
2130  Linear::System & linear_system,
2131  Nonlinear::Manager & nonlinear_manager,
2132  Topo::Topology & topology)
2133  : Factory<MOR>(),
2134  analysisManager_(analysis_manager),
2135  linearSystem_(linear_system),
2136  nonlinearManager_(nonlinear_manager),
2137  topology_(topology)
2138  {}
2139 
2140  virtual ~MORFactory()
2141  {}
2142 
2143  //-----------------------------------------------------------------------------
2144  // Function : create
2145  // Purpose :
2146  // Special Notes :
2147  // Scope : public
2148  // Creator : David G. Baur Raytheon Sandia National Laboratories 1355
2149  // Creation Date : Thu Jan 29 12:59:00 2015
2150  //-----------------------------------------------------------------------------
2151  ///
2152  /// Create a new MOR analysis and applies the analysis and time integrator option blocks.
2153  ///
2154  /// @return new MOR analysis object
2155  ///
2156  MOR *create() const
2157  {
2158  analysisManager_.setAnalysisMode(ANP_MODE_MOR);
2159 
2160  MOR *mor = new MOR(analysisManager_, nonlinearManager_, topology_);
2161  mor->setAnalysisParams(morAnalysisOptionBlock_);
2162  mor->setMOROptions(morOptsOptionBlock_);
2163 
2164  return mor;
2165  }
2166 
2167  //-----------------------------------------------------------------------------
2168  // Function : setMORAnalysisOptionBlock
2169  // Purpose :
2170  // Special Notes :
2171  // Scope : public
2172  // Creator : David G. Baur Raytheon Sandia National Laboratories 1355
2173  // Creation Date : Thu Jan 29 13:00:14 2015
2174  //-----------------------------------------------------------------------------
2175  ///
2176  /// Saves the analysis parsed options block in the factory.
2177  ///
2178  /// @invariant Overwrites any previously specified analysis option block.
2179  ///
2180  /// @param option_block parsed option block
2181  ///
2182  void setMORAnalysisOptionBlock(const Util::OptionBlock &option_block)
2183  {
2184  morAnalysisOptionBlock_ = option_block;
2185  }
2186 
2187  //-----------------------------------------------------------------------------
2188  // Function : setMOROptsOptionBlock
2189  // Purpose :
2190  // Special Notes :
2191  // Scope : public
2192  // Creator : David G. Baur Raytheon Sandia National Laboratories 1355
2193  // Creation Date : Thu Jan 29 13:00:14 2015
2194  //-----------------------------------------------------------------------------
2195  ///
2196  /// Saves the MOR_OPTS parsed options block in the factory.
2197  ///
2198  /// @invariant Overwrites any previously specified MOR_OPTS option block.
2199  ///
2200  /// @param option_block parsed option block
2201  ///
2202  void setMOROptsOptionBlock(const Util::OptionBlock &option_block)
2203  {
2204  morOptsOptionBlock_ = option_block;
2205  }
2206 
2207 public:
2208  AnalysisManager & analysisManager_;
2209  Linear::System & linearSystem_;
2210  Nonlinear::Manager & nonlinearManager_;
2211  Topo::Topology & topology_;
2212 
2213 private:
2214  Util::OptionBlock morAnalysisOptionBlock_;
2215  Util::OptionBlock morOptsOptionBlock_;
2216 };
2217 
2218 // .options MOR_OPTS
2219 struct MOROptsOptionsReg : public IO::PkgOptionsReg
2220 {
2221  MOROptsOptionsReg(
2222  MORFactory & factory )
2223  : factory_(factory)
2224  {}
2225 
2226  bool operator()(const Util::OptionBlock &option_block)
2227  {
2228  factory_.setMOROptsOptionBlock(option_block);
2229 
2230  return true;
2231  }
2232 
2233  MORFactory & factory_;
2234 };
2235 
2236 // .MOR
2237 struct MORAnalysisReg : public IO::PkgOptionsReg
2238 {
2239  MORAnalysisReg(
2240  MORFactory & factory )
2241  : factory_(factory)
2242  {}
2243 
2244  bool operator()(const Util::OptionBlock &option_block)
2245  {
2246  factory_.setMORAnalysisOptionBlock(option_block);
2247 
2248  factory_.analysisManager_.addAnalysis(&factory_);
2249 
2250  return true;
2251  }
2252 
2253  MORFactory & factory_;
2254 };
2255 
2256 } // namespace <unnamed>
2257 
2258 
2259 bool
2261  const std::string & netlist_filename,
2262  IO::PkgOptionsMgr & options_manager,
2263  AnalysisManager & analysis_manager,
2264  Linear::System & linear_system,
2265  Nonlinear::Manager & nonlinear_manager,
2266  Topo::Topology & topology)
2267 {
2268  MORFactory *factory = new MORFactory(analysis_manager, linear_system, nonlinear_manager, topology);
2269 
2270  analysis_manager.addAnalysisFactory(factory);
2271 
2272  options_manager.submitRegistration("MOR", netlist_filename, new MORAnalysisReg(*factory));
2273  options_manager.submitRegistration("MOR_OPTS", netlist_filename, new MOROptsOptionsReg(*factory));
2274 
2275  return true;
2276 }
2277 
2278 } // namespace Analysis
2279 } // namespace Xyce
RCP< Linear::MultiVector > RPtr_
Definition: N_ANP_MOR.h:188
Linear::Vector * lastSolutionPtr
unsigned int successfulStepsTaken_
Number of consecutive successful time-integration steps.
Topo::Topology & topology_
Definition: N_ANP_MOR.h:129
virtual bool setInitialGuess(Linear::Vector *solVectorPtr)
Definition: N_LOA_Loader.h:231
double morScaleFactor_
Definition: N_ANP_MOR.h:148
Linear::Vector * lastLeadDeltaVPtr
Teuchos::SerialDenseMatrix< int, double > redB_
Definition: N_ANP_MOR.h:199
RCP< Epetra_LinearProblem > origProblem_
Definition: N_ANP_MOR.h:221
RCP< Epetra_LinearProblem > blockRedProblem_
Definition: N_ANP_MOR.h:225
RCP< Linear::BlockVector > ref_redBPtr_
Definition: N_ANP_MOR.h:212
virtual bool getBMatrixEntriesforMOR(std::vector< int > &bMatEntriesVec, std::vector< int > &bMatPosEntriesVec)
Definition: N_LOA_Loader.h:225
bool evalOrigTransferFunction()
Definition: N_ANP_MOR.C:1098
Pure virtual class to augment a linear system.
int doubleDCOPStep_
current step in the DCOP loop.
RCP< Linear::MultiVector > BPtr_
Definition: N_ANP_MOR.h:188
Linear::System & linearSystem_
Definition: N_ANP_MOR.C:2209
RCP< Linear::BlockMatrix > sCpG_REFMatrixPtr_
Definition: N_ANP_MOR.h:192
virtual bool loadDAEVectors(Linear::Vector *nextSolVectorPtr, Linear::Vector *currSolVectorPtr, Linear::Vector *lastSolVectorPtr, Linear::Vector *nextStaVectorPtr, Linear::Vector *currStaVectorPtr, Linear::Vector *lastStaVectorPtr, Linear::Vector *StaDerivVectorPtr, Linear::Vector *nextStoVectorPtr, Linear::Vector *currStoVectorPtr, Linear::Vector *lastStoVectorPtr, Linear::Vector *stoLeadCurrQVectorPtr, Linear::Vector *nextLeadFVectorPtr, Linear::Vector *currLeadFVectorPtr, Linear::Vector *lastLeadFVectorPtr, Linear::Vector *nextLeadQVectorPtr, Linear::Vector *nextJunctionVVectorPtr, Linear::Vector *currJunctionVVectorPtr, Linear::Vector *lastJunctionVVectorPtr, Linear::Vector *QVectorPtr, Linear::Vector *FVectorPtr, Linear::Vector *BVectorPtr, Linear::Vector *dFdxdVpVectorPtr, Linear::Vector *dQdxdVpVectorPtr)
Definition: N_LOA_Loader.h:121
unsigned int stepNumber
Time-integration step number counter.
Nonlinear::Manager & nonlinearManager_
Definition: N_ANP_MOR.h:128
std::vector< std::string > portList_
Definition: N_ANP_MOR.h:162
Linear::Vector * currStorePtr
Linear::Vector * lastStatePtr
bool createOrigLinearSystem_()
Definition: N_ANP_MOR.C:1193
Teuchos::SerialDenseMatrix< int, std::complex< double > > origH_
Definition: N_ANP_MOR.h:216
RCP< Linear::BlockMatrix > sCpG_ref_redMatrixPtr_
Definition: N_ANP_MOR.h:211
void gatherStepStatistics(StatCounts &stats, Nonlinear::NonLinearSolver &nonlinear_solver, int newton_convergence_status)
void createTimeIntegratorMethod(const TimeIntg::TIAParams &tia_params, const unsigned int integration_method)
bool setupInitialConditions(Linear::Vector &solnVec, Linear::Vector &flagVec)
RCP< Epetra_LinearProblem > blockProblem_
Definition: N_ANP_MOR.h:221
RCP< Amesos_BaseSolver > blockSolver_
Definition: N_ANP_MOR.h:220
Teuchos::SerialDenseMatrix< int, double > sCpG_redMatrix_
Definition: N_ANP_MOR.h:207
bool updateOrigLinearSystemFreq_()
Definition: N_ANP_MOR.C:1364
Linear::Vector * nextLeadDeltaVPtr
Linear::Vector * currStatePtr
bool setAnalysisParams(const Util::OptionBlock &paramsBlock)
Definition: N_ANP_MOR.C:185
unsigned int failedStepsAttempted_
Total number of failed time-integration steps.
Parallel::Manager * getPDSManager() const
Topo::Topology & topology_
Definition: N_ANP_MOR.C:2211
std::string morMethod_
Definition: N_ANP_MOR.h:135
TimeIntg::StepErrorControl & getStepErrorControl()
NonLinearSolver & getNonlinearSolver()
RCP< Linear::BlockVector > REFXPtr_
Definition: N_ANP_MOR.h:194
AnalysisManager & analysisManager_
Definition: N_ANP_MOR.h:126
Util::OptionBlock morAnalysisOptionBlock_
Definition: N_ANP_MOR.C:2214
Linear::Vector * daeQVectorPtr
Teuchos::SerialDenseMatrix< int, double > sCpG_tmpMatrix_
Definition: N_ANP_MOR.h:207
RCP< Amesos_BaseSolver > origSolver_
Definition: N_ANP_MOR.h:220
Linear::Vector * lastLeadCurrentPtr
virtual bool startTimeStep()
Definition: N_LOA_Loader.h:304
Teuchos::SerialDenseMatrix< int, double > redG_
Definition: N_ANP_MOR.h:198
std::string morCompType_
Definition: N_ANP_MOR.h:139
void setErrorWtVector(const TIAParams &tia_params)
std::vector< int > bMatEntriesVec_
Definition: N_ANP_MOR.h:189
MORFactory & factory_
Definition: N_ANP_MOR.C:2233
RCP< Amesos_BaseSolver > blockRedSolver_
Definition: N_ANP_MOR.h:224
Linear::Vector * daeFVectorPtr
Linear::Vector * currLeadCurrentQPtr
Nonlinear::Manager & nonlinearManager_
Definition: N_ANP_MOR.C:2210
void info(const std::string &msg)
Definition: N_NLS_NOX.C:71
Teuchos::SerialDenseMatrix< int, std::complex< double > > redH_
Definition: N_ANP_MOR.h:217
Teuchos::SerialDenseMatrix< int, double > redL_
Definition: N_ANP_MOR.h:200
MOR(AnalysisManager &analysis_manager, Nonlinear::Manager &nonlinear_manager, Topo::Topology &topology)
Definition: N_ANP_MOR.C:128
Linear::Matrix * dFdxMatrixPtr
Parallel::Machine comm_
Definition: N_ANP_MOR.h:124
bool sparsifyRedSystem_()
Definition: N_ANP_MOR.C:1585
bool solveRedLinearSystem_()
Definition: N_ANP_MOR.C:1480
virtual bool updateSources()
Definition: N_LOA_Loader.h:243
Linear::Vector * nextStatePtr
Linear::Vector * dFdxdVpVectorPtr
RCP< Linear::Matrix > redCPtr_
Definition: N_ANP_MOR.h:203
virtual bool loadDAEMatrices(Linear::Vector *tmpSolVectorPtr, Linear::Vector *tmpStaVectorPtr, Linear::Vector *tmpStaDerivVectorPtr, Linear::Vector *tmpStoVectorPtr, Linear::Matrix *tmpdQdxMatrixPtr, Linear::Matrix *tmpdFdxMatrixPtr)
Definition: N_LOA_Loader.h:109
virtual bool updateState(Linear::Vector *nextSolVectorPtr, Linear::Vector *currSolVectorPtr, Linear::Vector *lastSolVectorPtr, Linear::Vector *nextStaVectorPtr, Linear::Vector *currStaVectorPtr, Linear::Vector *lastStaVectorPtr, Linear::Vector *nextStoVectorPtr, Linear::Vector *currStoVectorPtr, Linear::Vector *lastStoVectorPtr)
Definition: N_LOA_Loader.h:188
Teuchos::SerialDenseMatrix< int, double > redC_
Definition: N_ANP_MOR.h:197
Linear::Vector * currLeadDeltaVPtr
Loader::Loader & loader_
Definition: N_ANP_MOR.h:127
RCP< Epetra_Map > redMapPtr_
Definition: N_ANP_MOR.h:204
AnalysisManager & analysisManager_
Definition: N_ANP_MOR.C:2208
void outputMORTF(bool origSys, double freq, const Teuchos::SerialDenseMatrix< int, std::complex< double > > &H)
RCP< Linear::BlockVector > REFBPtr_
Definition: N_ANP_MOR.h:193
RCP< Linear::BlockVector > ref_redXPtr_
Definition: N_ANP_MOR.h:213
void addAnalysisFactory(Factory< void > *factory)
bool createRedLinearSystem_()
Definition: N_ANP_MOR.C:1265
Linear::Vector * nextSolutionPtr
#define M_PI
virtual bool getDoubleDCOPFlag() const
Definition: N_LOA_Loader.h:255
Linear::Vector * nextStorePtr
std::vector< int > bMatPosEntriesVec_
Definition: N_ANP_MOR.h:189
The analysis factory template defines an interface for analysis type testing and analysis creation...
Definition: N_ANP_Factory.h:65
Linear::Vector * dQdxdVpVectorPtr
bool setMOROptions(const Util::OptionBlock &OB)
Definition: N_ANP_MOR.C:214
virtual bool doProcessFailedStep()
Definition: N_ANP_MOR.C:1936
Linear::Vector * currLeadCurrentPtr
Linear::Vector * lastStorePtr
void setInputOPFlag(bool initial_conditions_loaded)
TimeIntg::WorkingIntegrationMethod & getWorkingIntegrationMethod()
RCP< Linear::Matrix > redGPtr_
Definition: N_ANP_MOR.h:203
std::list< int > morEvalFailures_
Definition: N_ANP_MOR.h:159
RCP< Linear::Matrix > GPtr_
Definition: N_ANP_MOR.h:186
double morScaleFactor1_
Definition: N_ANP_MOR.h:150
Linear::Vector * currSolutionPtr
std::vector< std::string > subcircuitNames_
Definition: N_ANP_MOR.h:153
bool registerMORFactory(const std::string &netlist_filename, IO::PkgOptionsMgr &options_manager, AnalysisManager &analysis_manager, Linear::System &linear_system, Nonlinear::Manager &nonlinear_manager, Topo::Topology &topology)
Definition: N_ANP_MOR.C:2260
TimeIntg::DataStore * getDataStore()
void evaluateStepError(const TIAParams &tia_params)
bool doubleDCOPFlag_
true if doing a double-DCOP is possible.
unsigned int baseIntegrationMethod_
Current time-integration method flag.
bool evalRedTransferFunction()
Definition: N_ANP_MOR.C:1146
#define W
Linear::Vector * nextStoreLeadCurrQPtr
void outputROM(const Teuchos::SerialDenseMatrix< int, double > &Ghat, const Teuchos::SerialDenseMatrix< int, double > &Chat, const Teuchos::SerialDenseMatrix< int, double > &Bhat, const Teuchos::SerialDenseMatrix< int, double > &Lhat)
Util::OptionBlock morOptsOptionBlock_
Definition: N_ANP_MOR.C:2215
RCP< Linear::Matrix > sCpG_MatrixPtr_
Definition: N_ANP_MOR.h:187
Linear::Vector * nextStateDerivPtr
bool updateCurrentFreq_(int stepNumber)
Definition: N_ANP_MOR.C:2001
Teuchos::SerialDenseMatrix< int, double > ref_redB_
Definition: N_ANP_MOR.h:208
RCP< Linear::Matrix > CPtr_
Definition: N_ANP_MOR.h:185
Linear::Matrix * dQdxMatrixPtr
TimeIntg::TIAParams tiaParams_
Definition: N_ANP_MOR.h:132
Linear::Vector * flagSolutionPtr
OutputMgrAdapter & outputManagerAdapter_
Definition: N_ANP_MOR.h:130
Linear::Vector * daeBVectorPtr
bool solveOrigLinearSystem_()
Definition: N_ANP_MOR.C:1431
virtual bool doHandlePredictor()
Definition: N_ANP_MOR.C:1980
bool updateRedLinearSystemFreq_()
Definition: N_ANP_MOR.C:1388
virtual bool doFinish()
Definition: N_ANP_MOR.C:1956
Linear::Vector * nextLeadCurrentPtr