SundanceAssembler.cpp
Go to the documentation of this file.
00001 /* @HEADER@ */
00002 // ************************************************************************
00003 // 
00004 //                              Sundance
00005 //                 Copyright (2005) Sandia Corporation
00006 // 
00007 // Copyright (year first published) Sandia Corporation.  Under the terms 
00008 // of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government 
00009 // retains certain rights in this software.
00010 // 
00011 // This library is free software; you can redistribute it and/or modify
00012 // it under the terms of the GNU Lesser General Public License as
00013 // published by the Free Software Foundation; either version 2.1 of the
00014 // License, or (at your option) any later version.
00015 //  
00016 // This library is distributed in the hope that it will be useful, but
00017 // WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019 // Lesser General Public License for more details.
00020 //                                                                                 
00021 // You should have received a copy of the GNU Lesser General Public
00022 // License along with this library; if not, write to the Free Software
00023 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00024 // USA                                                                                
00025 // Questions? Contact Kevin Long (krlong@sandia.gov), 
00026 // Sandia National Laboratories, Livermore, California, USA
00027 // 
00028 // ************************************************************************
00029 /* @HEADER@ */
00030 
00031 #include "SundanceAssembler.hpp"
00032 #include "SundanceDOFMapBuilder.hpp"
00033 #include "SundanceOut.hpp"
00034 #include "PlayaTabs.hpp"
00035 #include "SundanceCellFilter.hpp"
00036 #include "SundanceCellSet.hpp"
00037 #include "SundanceTrivialGrouper.hpp"
00038 #include "SundanceDOFMapBase.hpp"
00039 #include "SundanceEquationSet.hpp"
00040 #include "SundanceDiscreteSpace.hpp"
00041 #include "SundanceDiscreteFunction.hpp"
00042 #include "SundanceIntegralGroup.hpp"
00043 #include "SundanceGrouperBase.hpp"
00044 #include "SundanceEvalManager.hpp"
00045 #include "SundanceStdFwkEvalMediator.hpp"
00046 #include "SundanceEvaluatableExpr.hpp"
00047 #include "PlayaLoadableVector.hpp"
00048 #include "PlayaLoadableMatrix.hpp"
00049 #include "SundanceQuadratureEvalMediator.hpp"
00050 #include "SundanceCurveEvalMediator.hpp"
00051 #include "SundanceEvaluator.hpp"
00052 #include "Teuchos_Time.hpp"
00053 #include "Teuchos_TimeMonitor.hpp"
00054 #include "Epetra_HashTable.h"
00055 #include "SundanceIntHashSet.hpp"
00056 #include "PlayaDefaultBlockVectorSpaceDecl.hpp"
00057 #include "PlayaBlockOperatorBaseDecl.hpp"
00058 #include "PlayaSimpleBlockOpDecl.hpp"
00059 #include "SundanceAssemblyKernelBase.hpp"
00060 #include "SundanceVectorAssemblyKernel.hpp"
00061 #include "SundanceMatrixVectorAssemblyKernel.hpp"
00062 #include "SundanceFunctionalAssemblyKernel.hpp"
00063 #include "SundanceFunctionalGradientAssemblyKernel.hpp"
00064 #include "SundanceAssemblyTransformationBuilder.hpp"
00065 #ifndef HAVE_TEUCHOS_EXPLICIT_INSTANTIATION
00066 #include "PlayaLinearOperatorImpl.hpp"
00067 #include "PlayaSimpleBlockOpImpl.hpp"
00068 #include "PlayaDefaultBlockVectorImpl.hpp"
00069 #endif
00070 
00071 
00072 
00073 using namespace Teuchos;
00074 using namespace Playa;
00075 using std::max;
00076 using std::min;
00077 
00078 
00079 static Time& assemblerCtorTimer() 
00080 {
00081   static RCP<Time> rtn 
00082     = TimeMonitor::getNewTimer("assembler ctor"); 
00083   return *rtn;
00084 }
00085 
00086 
00087 
00088 
00089 static Time& graphBuildTimer() 
00090 {
00091   static RCP<Time> rtn 
00092     = TimeMonitor::getNewTimer("matrix graph determination"); 
00093   return *rtn;
00094 }
00095 
00096 static Time& colSearchTimer() 
00097 {
00098   static RCP<Time> rtn 
00099     = TimeMonitor::getNewTimer("graph column processing"); 
00100   return *rtn;
00101 }
00102 
00103 
00104 
00105 static Time& matAllocTimer() 
00106 {
00107   static RCP<Time> rtn 
00108     = TimeMonitor::getNewTimer("matrix allocation"); 
00109   return *rtn;
00110 }
00111 
00112 static Time& matFinalizeTimer() 
00113 {
00114   static RCP<Time> rtn 
00115     = TimeMonitor::getNewTimer("matrix graph packing"); 
00116   return *rtn;
00117 }
00118 
00119 static Time& graphFlatteningTimer() 
00120 {
00121   static RCP<Time> rtn 
00122     = TimeMonitor::getNewTimer("tmp graph flattening"); 
00123   return *rtn;
00124 }
00125 
00126 
00127 
00128 Assembler
00129 ::Assembler(const Mesh& mesh, 
00130   const RCP<EquationSet>& eqn,
00131   const Array<VectorType<double> >& rowVectorType,
00132   const Array<VectorType<double> >& colVectorType,
00133   bool partitionBCs)
00134   : partitionBCs_(partitionBCs),
00135     numConfiguredColumns_(0),
00136     mesh_(mesh),
00137     eqn_(eqn),
00138     rowMap_(),
00139     colMap_(),
00140     externalRowSpace_(eqn->numVarBlocks()),
00141     externalColSpace_(eqn->numUnkBlocks()),
00142     privateRowSpace_(eqn->numVarBlocks()),
00143     privateColSpace_(eqn->numUnkBlocks()),
00144     bcRows_(eqn->numVarBlocks()),
00145     rqc_(),
00146     contexts_(),
00147     isBCRqc_(),
00148     isInternalBdry_(),
00149     groups_(),
00150     mediators_(),
00151     evalExprs_(),
00152     evalMgr_(rcp(new EvalManager())),
00153     isBCRow_(eqn->numVarBlocks()),
00154     isBCCol_(eqn->numUnkBlocks()),
00155     remoteBCCols_(eqn->numUnkBlocks()),
00156     lowestRow_(eqn->numVarBlocks()),
00157     lowestCol_(eqn->numUnkBlocks()),
00158     rowVecType_(rowVectorType),
00159     colVecType_(colVectorType),
00160     testIDToBlockMap_(),
00161     unkIDToBlockMap_()
00162 {
00163   TimeMonitor timer(assemblerCtorTimer());
00164   init(mesh, eqn);
00165 }
00166 
00167 Assembler
00168 ::Assembler(const Mesh& mesh, 
00169   const RCP<EquationSet>& eqn)
00170   : partitionBCs_(false),
00171     numConfiguredColumns_(0),
00172     mesh_(mesh),
00173     eqn_(eqn),
00174     rowMap_(),
00175     colMap_(),
00176     externalRowSpace_(eqn->numVarBlocks()),
00177     externalColSpace_(eqn->numUnkBlocks()),
00178     privateRowSpace_(eqn->numVarBlocks()),
00179     privateColSpace_(eqn->numUnkBlocks()),
00180     bcRows_(eqn->numVarBlocks()),
00181     rqc_(),
00182     contexts_(),
00183     isBCRqc_(),
00184     isInternalBdry_(),
00185     groups_(),
00186     mediators_(),
00187     evalExprs_(),
00188     evalMgr_(rcp(new EvalManager())),
00189     isBCRow_(eqn->numVarBlocks()),
00190     isBCCol_(eqn->numUnkBlocks()),
00191     remoteBCCols_(eqn->numUnkBlocks()),
00192     lowestRow_(eqn->numVarBlocks()),
00193     lowestCol_(eqn->numUnkBlocks()),
00194     rowVecType_(),
00195     colVecType_(),
00196     testIDToBlockMap_(),
00197     unkIDToBlockMap_(),
00198     fixedParamIDToVectorNumber_()
00199 {
00200   TimeMonitor timer(assemblerCtorTimer());
00201   init(mesh, eqn);
00202 }
00203 
00204 // Utility function
00205 namespace {
00206 const Set<int> &
00207 findNonZeroIndices(const Array<int> &source, Set<int> &result)
00208 {
00209   result.clear();
00210   for (int i=0; i<source.size(); ++i)
00211   {
00212     if (source[i] != 0)
00213     {
00214       result.insert(result.end(), i);
00215     }
00216   }
00217   return result;
00218 }
00219 }
00220 
00221 void Assembler::init(const Mesh& mesh, const RCP<EquationSet>& eqn)
00222 {
00223   Tabs tab0(0);
00224 
00225   /* Decide a verbosity level for the overall setup */
00226   int verb = 0;
00227   if (eqn->hasActiveWatchFlag())
00228     verb = eqn->maxWatchFlagSetting("assembler setup");
00229 
00230   SUNDANCE_BANNER1(verb, tab0, "Assembler setup");
00231 
00232 
00233   /* Create an integral grouper */
00234   RCP<GrouperBase> grouper 
00235     = rcp(new TrivialGrouper());
00236 
00237 
00238   /* Find out which types of computations this assembler will 
00239    * be required to carry out */
00240   const Set<ComputationType>& compTypes = eqn->computationTypes();
00241 
00242 
00243   /* Create the DOF map for the row space */
00244   DOFMapBuilder mapBuilder(eqn->maxWatchFlagSetting("dof map setup"));
00245 
00246   if (compTypes.contains(VectorOnly) 
00247     || compTypes.contains(Sensitivities) 
00248     || compTypes.contains(FunctionalAndGradient))
00249   {
00250     Tabs tab1;
00251     SUNDANCE_MSG2(verb, tab1 << "building row spaces");
00252     mapBuilder = DOFMapBuilder(mesh, eqn->fsr(), partitionBCs_, 
00253       eqn->maxWatchFlagSetting("dof map setup"));
00254 
00255     rowMap_ = mapBuilder.rowMap();
00256     isBCRow_ = mapBuilder.isBCRow();
00257     isBCCol_ = mapBuilder.isBCCol();
00258 
00259     bcRows_.resize(isBCRow_.size());
00260     for (int b=0; b<isBCRow_.size(); ++b)
00261     {
00262       bcRows_[b] = rcp(new Set<int>);
00263       findNonZeroIndices(*isBCRow_[b], *bcRows_[b]);
00264     }
00265 
00266     lowestRow_.resize(eqn_->numVarBlocks());
00267     /* create discrete space for each block */
00268     for (int b=0; b<eqn_->numVarBlocks(); b++) 
00269     {
00270       Tabs tab2;
00271       lowestRow_[b] = rowMap_[b]->lowestLocalDOF();
00272       SUNDANCE_MSG2(verb, tab2 << "block " << b << ": lowest row="
00273         << lowestRow_[b]);
00274       externalRowSpace_[b] = rcp(
00275         new DiscreteSpace(mesh, testBasisArray(mapBuilder.fsr())[b], 
00276           rowMap_[b], rowVecType_[b]));
00277       privateRowSpace_[b] = externalRowSpace_[b];
00278       SUNDANCE_MSG2(verb, tab2 << "block " << b << ": done forming row space");
00279     }
00280   }
00281 
00282   if (!eqn->isFunctionalCalculator())
00283   {
00284     Tabs tab1;
00285     /* Create the DOF map for the column space */
00286     SUNDANCE_MSG2(verb, tab1 << "building column spaces");
00287     colMap_ = mapBuilder.colMap();
00288     /* create discrete space for each block */
00289     for (int b=0; b<eqn_->numUnkBlocks(); b++) 
00290     {
00291       Tabs tab2;
00292       externalColSpace_[b] 
00293         = rcp(new DiscreteSpace(mesh, unkBasisArray(mapBuilder.fsr())[b], 
00294             colMap_[b], colVecType_[b]));
00295       privateColSpace_[b] = externalColSpace_[b];
00296       SUNDANCE_MSG2(verb, tab2 << "block " << b << ": done forming col space");
00297     }
00298 
00299     /* initialize empty tables of information for each RQC in a 
00300      * matrix-vector calculation */
00301     groups_.put(MatrixAndVector, Array<Array<RCP<IntegralGroup> > >());
00302     rqcRequiresMaximalCofacets_.put(MatrixAndVector, 
00303       Array<IntegrationCellSpecifier>());
00304     skipRqc_.put(MatrixAndVector, Array<int>());
00305     contexts_.put(MatrixAndVector, Array<EvalContext>());
00306     evalExprs_.put(MatrixAndVector, Array<const EvaluatableExpr*>());
00307 
00308     /* create tables for vector calculation */
00309     groups_.put(VectorOnly, Array<Array<RCP<IntegralGroup> > >());
00310     rqcRequiresMaximalCofacets_.put(VectorOnly, 
00311       Array<IntegrationCellSpecifier>());
00312     skipRqc_.put(VectorOnly, Array<int>());
00313     contexts_.put(VectorOnly, Array<EvalContext>());
00314     evalExprs_.put(VectorOnly, Array<const EvaluatableExpr*>());
00315 
00316     if (eqn->isSensitivityCalculator())
00317     {
00318       fixedParamIDToVectorNumber_ 
00319         = eqn->fsr()->fixedParamIDToReducedFixedParamIDMap();
00320 
00321       /* create tables for sensitivity calculation */
00322       groups_.put(Sensitivities, Array<Array<RCP<IntegralGroup> > >());
00323       rqcRequiresMaximalCofacets_.put(Sensitivities, 
00324         Array<IntegrationCellSpecifier>());
00325       skipRqc_.put(Sensitivities, Array<int>());
00326       contexts_.put(Sensitivities, Array<EvalContext>());
00327       evalExprs_.put(Sensitivities, Array<const EvaluatableExpr*>());
00328       
00329     }
00330   }
00331   else
00332   {
00333     /* create tables for functional and gradient calculation */
00334     groups_.put(FunctionalAndGradient, Array<Array<RCP<IntegralGroup> > >());
00335     rqcRequiresMaximalCofacets_.put(FunctionalAndGradient, 
00336       Array<IntegrationCellSpecifier>());
00337     skipRqc_.put(FunctionalAndGradient, Array<int>());
00338     contexts_.put(FunctionalAndGradient, Array<EvalContext>());
00339     evalExprs_.put(FunctionalAndGradient, Array<const EvaluatableExpr*>());
00340     /* create tables for functional calculation */
00341     groups_.put(FunctionalOnly, Array<Array<RCP<IntegralGroup> > >());
00342     rqcRequiresMaximalCofacets_.put(FunctionalOnly, 
00343       Array<IntegrationCellSpecifier>());
00344     skipRqc_.put(FunctionalOnly, Array<int>());
00345     contexts_.put(FunctionalOnly, Array<EvalContext>());
00346     evalExprs_.put(FunctionalOnly, Array<const EvaluatableExpr*>());
00347   }
00348 
00349 
00350 
00351 
00352 
00353   /* --- We now loop over non-BC RQCs, doing initialization tasks for each */
00354   SUNDANCE_MSG1(verb, tab0 << std::endl 
00355     << tab0 << "=== setting up non-BC region-quadrature combinations");
00356 
00357   for (int r=0; r<eqn->regionQuadCombos().size(); r++)
00358   {
00359     Tabs tab1;
00360     Tabs tab12;
00361     const RegionQuadCombo& rqc = eqn->regionQuadCombos()[r];
00362 
00363     /* Determine the verbosity setting for this RQC */
00364     bool watchMe = rqc.watch().isActive();
00365 
00366     int rqcVerb = verb;
00367     int integralCtorVerb = 0;
00368     int integrationVerb = 0;
00369     int integralTransformVerb = 0;
00370     if (watchMe) 
00371     {
00372       rqcVerb = max(4,rqcVerb);
00373       integralCtorVerb = rqc.watch().param("integration setup");
00374       integrationVerb = rqc.watch().param("integration");
00375       integralTransformVerb = rqc.watch().param("integral transformation");
00376     }
00377 
00378 
00379     /* Note that I'm not an essential BC */
00380     rqc_.append(rqc);
00381     isBCRqc_.append(false);
00382 
00383     /* Find the expression for this RQC */
00384     const Expr& expr = eqn->expr(rqc);
00385 
00386     SUNDANCE_MSG2(rqcVerb, tab1 << std::endl << tab1 << "------------------------------------------------");
00387     SUNDANCE_MSG2(rqcVerb, tab1 << "initializing assembly for"
00388       << std::endl << tab12 << "r=" << r << " rqc=" 
00389       << rqc << std::endl << tab12 << std::endl << tab12 << "------------------------------"
00390       << std::endl << tab12 << "expr = " << expr
00391       << std::endl << tab12 << "------------------------------"
00392       );
00393 
00394     
00395     /* Find the cell type needed for this RQC */
00396     int cellDim = CellFilter(rqc.domain()).dimension(mesh);
00397     CellType cellType = mesh.cellType(cellDim);
00398     CellType maxCellType = mesh.cellType(mesh.spatialDim());
00399     QuadratureFamily quad(rqc.quad());
00400 
00401     /* Detect internal boundaries. These need special handling */
00402     bool isInternalBdry = detectInternalBdry(cellDim, rqc.domain());
00403     isInternalBdry_.append(isInternalBdry);
00404 
00405     SUNDANCE_MSG2(rqcVerb, tab12 << "isInternalBdry=" << isInternalBdry);
00406 
00407     /* Do setup for each required computation type */
00408     bool rqcUsed = false;
00409 
00410     for (Set<ComputationType>::const_iterator 
00411            i=eqn->computationTypes().begin(); 
00412          i!=eqn->computationTypes().end();
00413          i++)
00414     {
00415       Tabs tab2;
00416       const ComputationType& compType = *i;
00417       SUNDANCE_MSG2(rqcVerb, tab12 << std::endl << tab12
00418         << "** computation type " << compType);
00419       /* Some RQCs may be unused in a given calculation. For example, an RQC
00420        * may be needed for vector calculation but not matrix-vector 
00421        * calculation. See if this RQC is needed for the present 
00422        * computation type. If not, there's nothing more to do here. */
00423       if (eqn->skipRqc(compType, rqc))
00424       {
00425         SUNDANCE_MSG2(rqcVerb, tab2 << "RQC not needed for computation type  " 
00426           << compType);
00427         skipRqc_[compType].append(true);
00428         EvalContext dummy;
00429         const EvaluatableExpr* dummyEx = 0;
00430         Array<RCP<IntegralGroup> > dummyGroups;
00431         IntegrationCellSpecifier dummyCellSpec ;
00432         contexts_[compType].append(dummy);
00433         evalExprs_[compType].append(dummyEx);
00434         groups_[compType].append(dummyGroups);
00435         rqcRequiresMaximalCofacets_[compType].append(dummyCellSpec);
00436       }
00437       else
00438       {
00439         /* If we're to this point, we know the RQC is needed for this 
00440          * computation type */
00441         rqcUsed = true;
00442         skipRqc_[compType].append(false);
00443 
00444         /* Look up a "context" object that we'll use as a key for different
00445          * evaluations of this expression */
00446         EvalContext context = eqn->rqcToContext(compType, rqc);
00447 
00448         SUNDANCE_MSG2(rqcVerb, tab2 << "context " << context.brief());
00449 
00450         /* Register the context */
00451         contexts_[compType].append(context);
00452 
00453         /* Register the expression */
00454         const EvaluatableExpr* ee = EvaluatableExpr::getEvalExpr(expr);
00455         evalExprs_[compType].append(ee);
00456 
00457         /* Get the "sparsity superset" which is a description of all 
00458          * derivatives that must be computed by this expression in the
00459          * present context */
00460         const RCP<SparsitySuperset>& sparsity 
00461           = ee->sparsitySuperset(context);
00462         SUNDANCE_MSG3(rqcVerb, tab2 << "sparsity pattern " << *sparsity);
00463 
00464         /* We're now ready to create integration groups for doing the 
00465          * integrals needed in this computation for the present RQC. */
00466         Array<RCP<IntegralGroup> > groups;
00467         grouper->setVerb(integralCtorVerb, integrationVerb, integralTransformVerb);
00468         grouper->findGroups(*eqn, maxCellType, mesh.spatialDim(),
00469           cellType, cellDim, quad, sparsity, isInternalBdry, groups , rqc.paramCurve() , mesh_ );
00470         grouper->setVerb(0,0,0);
00471         groups_[compType].append(groups);
00472 
00473         /* Record whether or not integrations need to be done by reference
00474          * to maximal cofacets. */ 
00475         IntegrationCellSpecifier cellSpec 
00476           = whetherToUseCofacets(groups, ee, 
00477             cellDim==mesh_.spatialDim(), rqcVerb);
00478         SUNDANCE_MSG2(rqcVerb, tab2 << "integration: " << cellSpec);
00479         rqcRequiresMaximalCofacets_[compType].append(cellSpec);
00480       }
00481       SUNDANCE_MSG2(rqcVerb, tab12
00482         << "done with computation type " << compType);
00483     }
00484     
00485     /* If this RQC has never been used, we've made a mistake */
00486     /* Actually, no! Some terms might be unused in reduced-space methods */
00487 //    TEUCHOS_TEST_FOR_EXCEPTION(!rqcUsed, std::logic_error, "rqc=" << rqc 
00488 //      << " never used for any computation???");
00489 
00490     if (rqcUsed)
00491     {
00492       SUNDANCE_MSG2(rqcVerb, tab12 << "creating evaluation mediator for rqc=" 
00493         << rqc);
00494       SUNDANCE_MSG2(rqcVerb, tab12 << "expr = " << expr);
00495       
00496       /* Finally, create an evaluation mediator for this RQC. The evaluation
00497        * mediator is the object through which symbolic objects refer to
00498        * mesh-dependent quantities (e.g., discrete functions) during
00499        * evaluation.  , if we have to evaluate a curve integral then
00500        * use a special mediator */
00501       if ( rqc.paramCurve().isCurveIntegral() && rqc.paramCurve().isCurveValid() )
00502       { // ----- curve Integral ------
00503          mediators_.append(rcp(new CurveEvalMediator(mesh, rqc.paramCurve() , cellDim, quad)));
00504       }
00505       else
00506       {
00507          mediators_.append(rcp(new QuadratureEvalMediator(mesh, cellDim, quad)));
00508       }
00509     }
00510     else
00511     {
00512         SUNDANCE_MSG2(rqcVerb, tab1 << "creating empty eval mediator for unused rqc");
00513         mediators_.append(RCP<StdFwkEvalMediator>());
00514     }
00515     SUNDANCE_MSG2(rqcVerb, tab1 
00516       << "done with RQC");
00517   }
00518 
00519 
00520 
00521   /* --- We now loop over BC RQCs, doing initialization tasks for each */
00522   SUNDANCE_MSG1(verb, tab0 << std::endl 
00523     << tab0 << "=== setting up BC region-quadrature combinations");
00524   
00525   for (int r=0; r<eqn->bcRegionQuadCombos().size(); r++)
00526   {
00527     Tabs tab1;
00528     const RegionQuadCombo& rqc = eqn->bcRegionQuadCombos()[r];
00529 
00530     /* Determine the verbosity setting for this RQC */
00531     bool watchMe = rqc.watch().isActive();
00532     int rqcVerb = verb;
00533     int integralCtorVerb = 0;
00534     int integrationVerb = 0;
00535     int integralTransformVerb = 0;
00536     if (watchMe) 
00537     {
00538       rqcVerb = max(4,rqcVerb);
00539       integralCtorVerb = rqc.watch().param("integration setup");
00540       integrationVerb = rqc.watch().param("integration");
00541       integralTransformVerb = rqc.watch().param("integral transformation");
00542     }
00543 
00544     /* Note that I am an essential BC */
00545     rqc_.append(rqc);
00546     isBCRqc_.append(true);
00547 
00548 
00549     /* Find the expression for this RQC */    
00550     const Expr& expr = eqn->bcExpr(rqc);
00551 
00552     SUNDANCE_MSG2(rqcVerb, tab1 << std::endl << tab1 
00553       << "------------------------------------------------");
00554     SUNDANCE_MSG1(rqcVerb, tab1 << "initializing assembly for BC r=" << r
00555       << " rqc=" 
00556       << rqc << std::endl << tab1 
00557       << "expr = " << expr);
00558       
00559     /* Find the cell type needed for this RQC */    
00560     int cellDim = CellFilter(rqc.domain()).dimension(mesh);
00561     CellType cellType = mesh.cellType(cellDim);
00562     CellType maxCellType = mesh.cellType(mesh.spatialDim());
00563     QuadratureFamily quad(rqc.quad());
00564 
00565     /* Detect internal boundaries. These need special handling */
00566     bool isInternalBdry = detectInternalBdry(cellDim, rqc.domain());
00567     isInternalBdry_.append(isInternalBdry);
00568 
00569     /* Do setup for each required computation type */
00570     bool rqcUsed = false;
00571 
00572     for (Set<ComputationType>::const_iterator 
00573            i=eqn->computationTypes().begin(); 
00574          i!=eqn->computationTypes().end();
00575          i++)
00576     {
00577       Tabs tab2;
00578       const ComputationType& compType = *i;
00579       SUNDANCE_MSG2(rqcVerb, tab1 << std::endl << tab1 
00580         << "** computation type " << compType);
00581       
00582       /* Some RQCs may be unused in a given calculation. For example, an RQC
00583        * may be needed for vector calculation but not matrix-vector 
00584        * calculation. See if this RQC is needed for the present 
00585        * computation type. If not, there's nothing more to do here. */
00586       if (eqn->skipBCRqc(compType, rqc))
00587       {
00588         SUNDANCE_MSG2(rqcVerb, 
00589           tab2 << "this rqc not needed for computation type " << compType);
00590         skipRqc_[compType].append(true);
00591         EvalContext dummy;
00592         const EvaluatableExpr* dummyEx = 0;
00593         Array<RCP<IntegralGroup> > dummyGroups;
00594         IntegrationCellSpecifier dummyCellSpec ;
00595         contexts_[compType].append(dummy);
00596         evalExprs_[compType].append(dummyEx);
00597         groups_[compType].append(dummyGroups);
00598         rqcRequiresMaximalCofacets_[compType].append(dummyCellSpec);
00599       }
00600       else
00601       {
00602         /* If we're to this point, we know the RQC is needed for this 
00603          * computation type */   
00604         rqcUsed = true;
00605         skipRqc_[compType].append(false);
00606 
00607         /* Look up a "context" object that we'll use as a key for different
00608          * evaluations of this expression */
00609         EvalContext context = eqn->bcRqcToContext(compType, rqc);
00610         SUNDANCE_MSG2(rqcVerb, tab2 << "context " << context);
00611 
00612       
00613         contexts_[compType].append(context);
00614         const EvaluatableExpr* ee = EvaluatableExpr::getEvalExpr(expr);
00615         evalExprs_[compType].append(ee);
00616         const RCP<SparsitySuperset>& sparsity 
00617           = ee->sparsitySuperset(context);
00618         SUNDANCE_MSG3(rqcVerb, tab2 << "sparsity pattern " << *sparsity);
00619 
00620         Array<RCP<IntegralGroup> > groups;
00621         grouper->setVerb(integralCtorVerb, integrationVerb, integralTransformVerb);
00622         grouper->findGroups(*eqn, maxCellType, mesh.spatialDim(),
00623           cellType, cellDim, quad, sparsity, isInternalBdry, groups , rqc.paramCurve() , mesh_ );
00624         grouper->setVerb(0,0,0);
00625         groups_[compType].append(groups);
00626         IntegrationCellSpecifier cellSpec 
00627           = whetherToUseCofacets(groups, ee, 
00628             cellDim==mesh_.spatialDim(), rqcVerb);
00629         SUNDANCE_MSG2(rqcVerb, tab2 << "integration: " << cellSpec);
00630         rqcRequiresMaximalCofacets_[compType].append(cellSpec);
00631         SUNDANCE_MSG2(rqcVerb, tab1
00632           << "done with computation type " << compType);
00633       }
00634 /* Turn this test off, because some terms might be unused in reduced-space
00635  * methods */
00636 //      TEUCHOS_TEST_FOR_EXCEPTION(!rqcUsed, std::logic_error, "BC rqc=" << rqc 
00637 //        << " never used for any computation???");
00638       if (rqcUsed)
00639       {
00640         SUNDANCE_MSG2(rqcVerb, tab1 << "creating evaluation mediator for BC rqc=" 
00641           << rqc << std::endl << tab1 << "expr = " << expr);
00642         // in case of curve integral use a special mediator
00643         if ( rqc.paramCurve().isCurveIntegral() && rqc.paramCurve().isCurveValid() )
00644         { // ----- curve Integral ------
00645           mediators_.append(rcp(new CurveEvalMediator(mesh, rqc.paramCurve(), cellDim, quad)));
00646         }
00647         else
00648         {
00649           mediators_.append(rcp(new QuadratureEvalMediator(mesh, cellDim, quad)));
00650         }
00651       }
00652       else
00653       {
00654         SUNDANCE_MSG2(rqcVerb, tab1 << "creating empty eval mediator for unused BC rqc");
00655         mediators_.append(RCP<StdFwkEvalMediator>());
00656       }
00657     }
00658     SUNDANCE_MSG2(rqcVerb, tab1 
00659       << "done with BC RQC");
00660   }
00661 }
00662 
00663 bool Assembler::detectInternalBdry(int cellDim,
00664   const CellFilter& filter) const
00665 {
00666   int d = mesh_.spatialDim();
00667   if (cellDim == d-1)
00668   {
00669     CellSet cells = filter.getCells(mesh_);
00670     for (CellIterator c=cells.begin(); c!=cells.end(); c++)
00671     {
00672       if (mesh_.numMaxCofacets(cellDim, *c) > 1) return true;
00673     }      
00674   }
00675   return false;
00676 }
00677 
00678 IntegrationCellSpecifier Assembler::whetherToUseCofacets(
00679   const Array<RCP<IntegralGroup> >& groups,
00680   const EvaluatableExpr* ee,
00681   bool isMaximalCell,
00682   int verb) const
00683 {
00684   Tabs tab;
00685   SUNDANCE_MSG2(verb, 
00686     tab << "deciding whether to use cofacet cells for some integrations");
00687 
00688   if (isMaximalCell)
00689   {
00690     Tabs tab1;
00691     SUNDANCE_MSG2(verb, 
00692       tab1 << "cofacets not needed because cells are maximal");
00693     return NoTermsNeedCofacets;
00694   }
00695   
00696   IntegrationCellSpecifier cellSpec = SomeTermsNeedCofacets;
00697 
00698   bool allTermsNeedCofacets = true;
00699   bool noTermsNeedCofacets = true;
00700   for (int g=0; g<groups.size(); g++)
00701   {
00702     Tabs tab1;
00703     switch(groups[g]->usesMaximalCofacets()) 
00704     {
00705       case NoTermsNeedCofacets:
00706         allTermsNeedCofacets = false;
00707         SUNDANCE_MSG2(verb, 
00708           tab1 << "integral group " << g << " does not need cofacets");
00709         break;
00710       case AllTermsNeedCofacets:
00711       case SomeTermsNeedCofacets:
00712         noTermsNeedCofacets = false;
00713         SUNDANCE_MSG2(verb, 
00714           tab1 << "integral group " << g << " needs cofacets");
00715         break;
00716       default:
00717         TEUCHOS_TEST_FOR_EXCEPT(1);
00718     }
00719   } 
00720 
00721   if (allTermsNeedCofacets)
00722   {
00723     cellSpec = AllTermsNeedCofacets;
00724   }
00725   else if (noTermsNeedCofacets)
00726   {
00727     cellSpec = NoTermsNeedCofacets;
00728   }
00729 
00730   if (!isMaximalCell && ee->maxDiffOrderOnDiscreteFunctions() > 0)
00731   {
00732     Tabs tab1;
00733     SUNDANCE_MSG2(verb, tab1 
00734       << "(*) discrete functions will require cofacet-based transformations");
00735     if (cellSpec==NoTermsNeedCofacets) 
00736     {
00737       cellSpec = SomeTermsNeedCofacets;
00738     }
00739   }
00740   
00741   SUNDANCE_MSG2(verb, tab << "found: " << cellSpec);
00742   
00743   return cellSpec;
00744 }
00745   
00746 
00747 void Assembler::configureVector(Array<Vector<double> >& b) const 
00748 {
00749   /* Start timer, stopped upon dtor */
00750   TimeMonitor timer(configTimer());
00751 
00752   Tabs tab0;
00753   int verb = eqn_->maxWatchFlagSetting("vector config");
00754   
00755   SUNDANCE_MSG1(verb, tab0 << "in Assembler::configureVector()");
00756 
00757   /* Get the vector spaces for each block of equations */
00758   Array<VectorSpace<double> > vs(eqn_->numVarBlocks());
00759   for (int i=0; i<eqn_->numVarBlocks(); i++)
00760   {
00761     vs[i] = privateRowSpace_[i]->vecSpace();
00762   }
00763   VectorSpace<double> rowSpace;
00764   
00765   /* If we have more than one block, we make a Cartesian product space containing
00766    * the spaces for each block */
00767   if (eqn_->numVarBlocks() > 1)
00768   {
00769     rowSpace = Playa::blockSpace(vs);
00770   }
00771   else /* Otherwise we have a single, monolithic vector space */
00772   {
00773     rowSpace = vs[0];
00774   }
00775 
00776   /* Create each vector in the multivector */
00777   for (int i=0; i<b.size(); i++)
00778   {
00779     /* Create the vector. Recall that the vector space is a factory used to 
00780      * create a vector of specified size and distribution */
00781     b[i] = rowSpace.createMember();
00782 
00783     /* If the vector is blocked, configure the blocks */
00784     if (!partitionBCs_ && eqn_->numVarBlocks() > 1)
00785     {
00786       /* configure the blocks */
00787       Vector<double> vecBlock;
00788       for (int br=0; br<eqn_->numVarBlocks(); br++)
00789       {
00790         configureVectorBlock(br, vecBlock);
00791         b[i].setBlock(br, vecBlock);
00792       }
00793     }
00794     else  
00795     {
00796       /* nothing to do here except check that the vector is loadable */
00797       if (!partitionBCs_)
00798       {
00799         Playa::LoadableVector<double>* lv 
00800           = dynamic_cast<Playa::LoadableVector<double>* >(b[i].ptr().get());
00801         
00802         TEUCHOS_TEST_FOR_EXCEPTION(lv == 0, std::runtime_error,
00803           "vector is not loadable in Assembler::configureVector()");
00804       }
00805       else
00806       {
00807       }
00808     }
00809   }
00810   numConfiguredColumns_ = b.size();
00811 }
00812 
00813 void Assembler::configureVectorBlock(int br, Vector<double>& b) const 
00814 {
00815   Tabs tab0;
00816   int verb = eqn_->maxWatchFlagSetting("vector config");
00817   SUNDANCE_MSG2(verb, tab0 << "in Assembler::configureVectorBlock()");
00818   VectorSpace<double> vecSpace = privateRowSpace_[br]->vecSpace();
00819 
00820   b = vecSpace.createMember();
00821   
00822   if (!partitionBCs_)
00823   {
00824     Playa::LoadableVector<double>* lv 
00825       = dynamic_cast<Playa::LoadableVector<double>* >(b.ptr().get());
00826     
00827     TEUCHOS_TEST_FOR_EXCEPTION(lv == 0, std::runtime_error,
00828       "vector block is not loadable "
00829       "in Assembler::configureVectorBlock()");
00830   }
00831 }
00832 
00833 
00834 void Assembler::configureMatrix(LinearOperator<double>& A,
00835   Array<Vector<double> >& b) const
00836 {
00837   TimeMonitor timer(configTimer());
00838   int verb = eqn_->maxWatchFlagSetting("matrix config");
00839   Tabs tab;
00840   SUNDANCE_MSG1(verb, tab << "in Assembler::configureMatrix()");
00841   
00842 
00843   SUNDANCE_MSG1(verb,  tab << "before config: A=" << A.description());
00844   if (matNeedsConfiguration())
00845   {
00846     Tabs tab0;
00847 
00848     int nRowBlocks = rowMap_.size();
00849     int nColBlocks = colMap_.size();
00850     Array<Array<int> > isNonzero = findNonzeroBlocks();
00851 
00852     if (nRowBlocks==1 && nColBlocks==1)
00853     {
00854       configureMatrixBlock(0,0,A);
00855     }
00856     else
00857     {
00858       A = makeBlockOperator(solnVecSpace(), rowVecSpace());
00859       for (int br=0; br<nRowBlocks; br++)
00860       {
00861         for (int bc=0; bc<nColBlocks; bc++)
00862         {
00863           if (isNonzero[br][bc])
00864           {
00865             LinearOperator<double> matBlock;
00866             configureMatrixBlock(br, bc, matBlock);
00867             A.setBlock(br, bc, matBlock);
00868           }
00869         }
00870       }
00871       A.endBlockFill();
00872     }
00873     cachedAssembledMatrix_ = A;
00874   }
00875   else
00876   {
00877     Tabs tab0;
00878     SUNDANCE_MSG1(verb,
00879       tab0 << "Assembler::configureMatrix() not needed, proceeding to configure vector");
00880     A = cachedAssembledMatrix_;
00881   }
00882   SUNDANCE_MSG1(verb,  tab << "after config: A=" << A.description());
00883   configureVector(b);
00884 }
00885 
00886 void Assembler::configureMatrixBlock(int br, int bc,
00887   LinearOperator<double>& A) const 
00888 {
00889   Tabs tab;
00890   TimeMonitor timer(configTimer());
00891   int verb = eqn_->maxWatchFlagSetting("matrix config");
00892 
00893   SUNDANCE_MSG1(verb, tab << "in configureMatrixBlock()");
00894   
00895   SUNDANCE_MSG2(verb, tab << "num rows = " << rowMap()[br]->numDOFs());
00896   
00897   SUNDANCE_MSG2(verb, tab << "num cols = " << colMap()[bc]->numDOFs());
00898   
00899   VectorSpace<double> rowSpace = privateRowSpace_[br]->vecSpace();
00900   VectorSpace<double> colSpace = privateColSpace_[bc]->vecSpace();
00901 
00902   RCP<MatrixFactory<double> > matFactory ;
00903 
00904   matFactory = rowVecType_[br].createMatrixFactory(colSpace, rowSpace);
00905 
00906   IncrementallyConfigurableMatrixFactory* icmf 
00907     = dynamic_cast<IncrementallyConfigurableMatrixFactory*>(matFactory.get());
00908 
00909   CollectivelyConfigurableMatrixFactory* ccmf 
00910     = dynamic_cast<CollectivelyConfigurableMatrixFactory*>(matFactory.get());
00911 
00912   TEUCHOS_TEST_FOR_EXCEPTION(ccmf==0 && icmf==0, std::runtime_error,
00913     "Neither incremental nor collective matrix structuring "
00914     "appears to be available");
00915 
00916 
00917   /* If collective structuring is the user preference, or if incremental
00918    * structuring is not supported, do collective structuring */
00919   if (false /* (icmf==0 || !matrixEliminatesRepeatedCols()) && ccmf != 0 */)
00920   {
00921     Tabs tab1;
00922     SUNDANCE_MSG2(verb, tab1 << "Assembler: doing collective matrix structuring...");
00923     Array<int> graphData;
00924     Array<int> nnzPerRow;
00925     Array<int> rowPtrs;
00926       
00927     using Teuchos::createVector;
00928 
00929     getGraph(br, bc, graphData, rowPtrs, nnzPerRow);
00930     ccmf->configure(lowestRow_[br], createVector(rowPtrs), createVector(nnzPerRow), createVector(graphData));
00931   }
00932   else
00933   {
00934     Tabs tab1;
00935     SUNDANCE_MSG2(verb, tab1 << "Assembler: doing incremental matrix structuring...");
00936     incrementalGetGraph(br, bc, icmf);
00937     {
00938       TimeMonitor timer1(matFinalizeTimer());
00939       icmf->finalize();
00940     }
00941   }
00942   
00943   SUNDANCE_MSG3(verb, tab << "Assembler: allocating matrix...");
00944   {
00945     TimeMonitor timer1(matAllocTimer());
00946     A = matFactory->createMatrix();
00947   }
00948 }
00949 
00950 Playa::LinearOperator<double> Assembler::allocateMatrix() const
00951 {
00952   LinearOperator<double> A;
00953   Array<Vector<double> > b;
00954   configureMatrix(A, b);
00955   return A;
00956 }
00957 
00958 
00959 
00960 
00961 
00962   
00963 void Assembler::displayEvaluationResults(
00964   const EvalContext& context, 
00965   const EvaluatableExpr* evalExpr, 
00966   const Array<double>& constantCoeffs, 
00967   const Array<RCP<EvalVector> >& vectorCoeffs) const 
00968 {
00969   Tabs tab;
00970   FancyOStream& os = Out::os();
00971 
00972   os << tab << "evaluation results: " << std::endl;
00973 
00974   const RCP<SparsitySuperset>& sparsity 
00975     = evalExpr->sparsitySuperset(context);
00976   
00977   sparsity->print(os, vectorCoeffs, constantCoeffs);
00978 }
00979 
00980 
00981 
00982 void Assembler::assemblyLoop(const ComputationType& compType,
00983   RCP<AssemblyKernelBase> kernel) const
00984 {
00985   Tabs tab;
00986   int verb = 0;
00987   if (eqn_->hasActiveWatchFlag()) verb = max(eqn_->maxWatchFlagSetting("assembly loop"), 1);
00988   
00989 
00990   SUNDANCE_BANNER1(verb, tab, "Assembly loop");
00991 
00992   SUNDANCE_MSG1(verb, tab << "computation type is " << compType); 
00993   /* Allocate space for the workset's list of cell local IDs.
00994    * Currently, a workset is an array of cell indices. It could be an array
00995    * of pointers to cell objects, cell iterators, or whatever is needed to
00996    * work with something like a Peano curve data structure. */
00997   SUNDANCE_MSG2(verb, tab << "work set size is " << workSetSize()); 
00998   RCP<Array<int> > workSet = rcp(new Array<int>());
00999   workSet->reserve(workSetSize());
01000 
01001   /* Allocate isLocalFlag array, which distinguishes between local
01002    * and non-local cells in the workset. This is used to prevent 
01003    * adding multiple copies of zero-form values for border cells. */
01004   RCP<Array<int> > isLocalFlag = rcp(new Array<int>());
01005   isLocalFlag->reserve(workSetSize());
01006 
01007   /* Declare objects for storage of coefficient evaluation results 
01008    * that are returned from the symbolic evaluation system. EvalVector
01009    * is the object in which a vector of numerical values for a 
01010    * given functional derivative are returned from an evaluation of
01011    * a symbolic DAG. */
01012   Array<RCP<EvalVector> > vectorCoeffs;
01013   Array<double> constantCoeffs;
01014 
01015   /* Create an object in which to store local integration results */
01016   RCP<Array<double> > localValues = rcp(new Array<double>());
01017 
01018   /* Get the symbolic specification of the current computation.
01019    * The "context" is simply a unique ID used to distinguish different
01020    * settings in which evaluation might be made. The same expression might be
01021    * evaluated in a context where some subset of all possible functional
01022    * derivatives are needed, and later in another context where a different 
01023    * subset of functional derivatives is needed. The "context" object lets
01024    * us associate a different Evaluator object with each such set of
01025    * requirements. */
01026   const Array<EvalContext>& contexts = contexts_.get(compType);
01027   /* Get the integral groups needed for this calculation */
01028   const Array<Array<RCP<IntegralGroup> > >& groups = groups_.get(compType);
01029   /* Get the expressions needed for this calculation */
01030   const Array<const EvaluatableExpr*>& evalExprs 
01031     = evalExprs_.get(compType);
01032   /* Get the flags indicating shich, if any, RQCs are to be skipped in this
01033    * calculation */
01034   const Array<int>& skipRqc = skipRqc_.get(compType);
01035 
01036   
01037   /* === Start main loop. 
01038    * The outer loop is over RQCs, that is, over unique combinations of subregions
01039    * (CellFilters) and quadrature rules.   */
01040   SUNDANCE_MSG1(verb, 
01041     tab << "---------- outer assembly loop over subregions");
01042   //SUNDANCE_MSG3(verb, tab << "Row DoF:" << rowMap_.size());
01043   //SUNDANCE_MSG3(verb, tab << "Column DoF:" << colMap_.size());
01044   //SUNDANCE_MSG3(verb, tab << "Region Quadratic Comb:" << rqc_.size());
01045 
01046   /* The double array which contains the transformations*/
01047   Array< Array<RCP<AssemblyTransformationBuilder> > > transformations;
01048 
01049   /** ----- Create Transformation objects for each integral group ------- */
01050   transformations.resize(rqc_.size());
01051   for (int r=0; r<rqc_.size(); r++)
01052   {
01053     transformations[r].resize(groups[r].size());
01054     for (int g=0; g<groups[r].size(); g++)
01055     {
01056       const RCP<IntegralGroup>& group = groups[r][g];
01057       /* Here we create the transformation object, if they are not needed
01058        * there would be no operation done to the array of local stiffness matrix */
01059       transformations[r][g] = rcp(new AssemblyTransformationBuilder( group , rowMap_ , colMap_ , mesh_));
01060     }
01061   }
01062 
01063 
01064   /* Record the default kernel verbosity so that it if changes we can
01065    * reset it at the end of a loop iteration */
01066   int oldKernelVerb = kernel->verb();
01067   
01068   TEUCHOS_TEST_FOR_EXCEPT(rqc_.size() != evalExprs.size());
01069 
01070   /* Looping over RQCs */
01071   for (int r=0; r<rqc_.size(); r++)
01072   {
01073     Tabs tab0;
01074 
01075     /* Set the verbosity level for this RQC */
01076     int rqcVerb = 0;
01077     int evalVerb = 0;
01078     int evalMedVerb = 0;
01079     int dfEvalVerb = 0;
01080     int fillVerb = 0;
01081 
01082     /* Check for watch point, and set verbosity accordingly */
01083     if (rqc_[r].watch().isActive()) 
01084     {
01085       Tabs tab01;
01086       rqcVerb=verb;
01087       evalVerb = rqc_[r].watch().param("evaluation");
01088       evalMedVerb = rqc_[r].watch().param("eval mediator");
01089       dfEvalVerb = rqc_[r].watch().param("discrete function evaluation");
01090       fillVerb = rqc_[r].watch().param("fill");
01091 
01092       SUNDANCE_MSG1(rqcVerb, tab0 << std::endl 
01093         << tab0 << "-------------"
01094         << std::endl << tab0 << " doing watched subregion r=" << r << " of " 
01095         << rqc_.size() << ", rqc=" 
01096         << rqc_[r]);    
01097       if (skipRqc[r]) 
01098       {
01099         SUNDANCE_MSG2(rqcVerb, tab01 << "this rqc is not needed in comp type = " << compType);
01100       }
01101       else
01102       {
01103         SUNDANCE_MSG2(rqcVerb, tab01 << "expr is " << evalExprs[r]->toString());
01104         SUNDANCE_MSG2(rqcVerb, tab01 << "isBC= " << isBCRqc_[r]); 
01105       }
01106     }
01107     else
01108     {
01109       SUNDANCE_MSG1(verb, tab0 << "unwatched region r=" << r << " of " << rqc_.size());
01110     }
01111     Tabs tab01;
01112 
01113     kernel->setVerb(fillVerb);
01114     
01115     /* Deciding whether we should skip this RQC in the current computation 
01116      * type. For example, a certain boundary surface might appear in the
01117      * computation of a functional but not in the state equation. */
01118     if ((!isBCRqc_[r] && eqn_->skipRqc(compType, rqc_[r]))
01119       || (isBCRqc_[r] && eqn_->skipBCRqc(compType, rqc_[r])))
01120     {
01121       Tabs tab012;
01122       SUNDANCE_MSG2(rqcVerb, tab012 << "nothing to do for comp type " 
01123         << compType);
01124       continue;
01125     }
01126 
01127     /* specify the evaluation mediator for this RQC.
01128      * Recall that the evaluation mediator is the object responsible for communication
01129      * between the symbolic expression tree and discretization-dependent data structures
01130      * such as discrete functions. 
01131      *
01132      * The evaluation manager is an object that is responsible for management
01133      * of the symbolic evaluation; it controls allocation of memory for evaluation
01134      * results, access to the evaluation mediator, and other administrative tasks. 
01135      */
01136     evalMgr_->setMediator(mediators_[r]);
01137     mediators_[r]->setVerb(evalMedVerb, dfEvalVerb);
01138 
01139     /* Tell the manager which CellFilter and QuadratureFamily we're currently working with. 
01140      * This is simply forwarded to the mediator, which needs to know the number
01141      * of quadrature points as well as mesh properties such as cell dimension. */
01142     evalMgr_->setRegion(contexts_.get(compType)[r]);
01143   
01144     /* get the cell filter for the current RQC */
01145     CellFilter filter = rqc_[r].domain();
01146     /* Find the cells that "pass" the predicate in the filter. Note: a CellFilter
01147      * will cache the cell sets it has computed, so the predicate computation will
01148      * only be done once per mesh, regardless of how often this function is called. 
01149      * Todo: the cache needs to be reset upon mesh refinement. 
01150      */
01151     CellSet cells = filter.getCells(mesh_);
01152     /* Find the dimension of cells that pass the current filter. */
01153     int cellDim = filter.dimension(mesh_);
01154     /* Find the type of cells in the current filter. Note: we've assumed here that all
01155      * cells have identical topology, and need to work out how to deal with 
01156      * meshes with mxed cell types. That will usually be handled by grouping similar
01157      * cells into "blocks" (as is done in Exodus files, for instance) in which case 
01158      * will still work, but there should be an error check to ensure that that assumption
01159      * is never violated. */ 
01160     CellType cellType = mesh_.cellType(cellDim);
01161     /* Get the cell type of the maximal-dimension cofacets, in case we need 
01162      * integrals or DOF maps done on the maximal cofacets. Todo: this code will break
01163      * for internal boundaries at the interface between cofacets of different types,
01164      * e.g., a face joining a prism and a hex. Not sure how to handle that case. */
01165     CellType maxCellType = mesh_.cellType(mesh_.spatialDim());
01166 
01167     SUNDANCE_MSG2(rqcVerb, tab01 << "cell type = " << cellType 
01168       << ", cellDim = " << cellDim 
01169       << ", max cell type = " << maxCellType 
01170       << ", max cell dim = " << mesh_.spatialDim());
01171 
01172 
01173     /* Determine whether we need to refer to maximal cofacets for 
01174      * some or all integrations and DOF mappings. */
01175     IntegrationCellSpecifier intCellSpec
01176       = rqcRequiresMaximalCofacets_.get(compType)[r];
01177     SUNDANCE_MSG2(rqcVerb, tab01 
01178       << "whether we need to refer to maximal cofacets: " << intCellSpec);
01179 
01180     /* Find the unknowns and variations appearing on the current domain. This
01181      * information is stored in the EquationSet object.  */
01182     const Array<Set<int> >& requiredVars = eqn_->reducedVarsOnRegion(filter);
01183     const Array<Set<int> >& requiredUnks = eqn_->reducedUnksOnRegion(filter);
01184 
01185     /* Prepare for evaluation on the current domain:
01186      * Tell the mediator whether maximal cofacets should be used (which will determine
01187      * how discrete functions are computed). */
01188     SUNDANCE_MSG2(rqcVerb, tab01 << "setting integration specifier in mediator");
01189     mediators_[r]->setIntegrationSpec(intCellSpec);
01190     /*
01191      * Tell the mediator the cell type, and whether we are on an internal
01192      * boundary. We need to know if we're on an internal boundary so that 
01193      * we can use DOF lookup logic that's capable of figuring out which
01194      * of two cofacets contains DOF information for those functions defined
01195      * on only one side of the boundary (as in, e.g., fluid-structure boundaries).
01196      */
01197     SUNDANCE_MSG2(rqcVerb, tab01 << "setting cell type=" << cellType << " in mediator");
01198     mediators_[r]->setCellType(cellType, maxCellType, isInternalBdry_[r]);    
01199     /* Get the Evaluator object that will actually carry out calculations on
01200      * the expression DAG in the current context (recall that a single expression
01201      * may support multiple evaluators). */
01202     const Evaluator* evaluator 
01203       = evalExprs[r]->evaluator(contexts[r]).get();
01204 
01205     /* Loop over cells in batches of the work set size.
01206      * At present, we're accumulating cell indices into an array. That would
01207      * need to be changed to work with Peano. */
01208     CellIterator iter=cells.begin();
01209     int workSetCounter = 0;
01210     int myRank = mesh_.comm().getRank();
01211 
01212     SUNDANCE_MSG2(rqcVerb, tab01 << "----- looping over worksets");
01213     while (iter != cells.end())
01214     {
01215       Tabs tab1;
01216       /* build up the work set: add cells until the work set size is 
01217        * reached or we run out of cells. To begin with, empty both the
01218        * workset array and the isLocalFlag array. Note that the reserve()
01219        * method has been called previously, so that as we append cells
01220        * to the array, no memory allocation is done (unless we run over 
01221        * the reserved size). */
01222       workSet->resize(0);
01223       isLocalFlag->resize(0);
01224       for (int c=0; c<workSetSize() && iter != cells.end(); c++, iter++)
01225       {
01226         workSet->append(*iter);
01227         /* we need the isLocalFlag values so that we can ignore contributions
01228          * to zero-forms from off-processor elements */
01229         isLocalFlag->append(myRank==mesh_.ownerProcID(cellDim, *iter));
01230       }
01231       /* The work set has now been accumulated */
01232       SUNDANCE_MSG2(rqcVerb,
01233         tab1 << "doing work set " << workSetCounter
01234         << " consisting of " << workSet->size() << " cells");
01235       {
01236         Tabs tab2;
01237         SUNDANCE_MSG4(rqcVerb, tab2 << "cells are " << *workSet);
01238       }
01239       workSetCounter++;
01240 
01241       /* set the verbosity for the evaluation mediator */
01242       evalMgr_->setVerb(evalVerb);
01243 
01244       /* Register the workset with the mediator. Internally, the mediator
01245        * will look up the cell Jacobians and facet indices needed for this calculation. It 
01246        * uses them for discrete function transformation. */
01247       mediators_[r]->setCellBatch(workSet);
01248       /* Get the Jacobians from the mediator, so that we can use the same Jacobian
01249        * objects for discrete function transformation and for integral 
01250        * transformation. The "volume" Jacobian is used to scale the integration
01251        * cell volume by det(J). The "transformation" Jacobian is used to
01252        * transform vectors. These will be the same, except for the case
01253        * where we integrate on a facet but do transformations by reference to 
01254        * a maximal cofacet. */
01255       const CellJacobianBatch& JVol = mediators_[r]->JVol();
01256       const CellJacobianBatch& JTrans = mediators_[r]->JTrans();
01257       /* Get from the mediator the facet indices for each cell. If I am integrating
01258        * on a facet (e.g., a boundary cell) but getting DOFs or JTrans from
01259        * a maximal cofacet, I need to know my index in the array of 
01260        * that cofacet's facets. */
01261       const Array<int>& facetIndices = mediators_[r]->facetIndices();
01262       if (facetIndices.size() > 0)
01263   {
01264     Tabs tab2;
01265     SUNDANCE_MSG2(rqcVerb, tab2 << "facet indices are " << facetIndices);
01266   }
01267 
01268       /* Reset the assembly kernel for the current workset. What happens at this
01269        * step depends on the specific kernel being used. The kernel might, for instance,
01270        * build local DOF maps for the current batch of cells. */
01271       kernel->prepareForWorkSet(
01272         requiredVars, 
01273         requiredUnks, 
01274         mediators_[r]);
01275         
01276       /* Evaluate the coefficient expressions. Recall that each coefficient
01277        * appearing in an integral is a particular functional derivative of the
01278        * integrand. The constant-valued coefficients are written into the
01279        * constantCoeffs array, the variable coefficients into the vectorCoeffs
01280        * array. 
01281        *
01282        * Recall that the eval manager contains the current evaluation mediator, so that
01283        * by passing the evaluation manager as an argument to evaluate(), the evaluation
01284        * is aware of the mediator and can therefore access discrete functions, etc.
01285        */ 
01286       evaluator->resetNumCalls();
01287       SUNDANCE_MSG2(rqcVerb, tab1 
01288         << "====== evaluating coefficient expressions") ;
01289       try
01290       {
01291         evalExprs[r]->evaluate(*evalMgr_, constantCoeffs, vectorCoeffs);
01292       }
01293       catch(std::exception& exc)
01294       {
01295         Tabs tabX;
01296         SUNDANCE_BANNER1(10, tabX, 
01297           "DETECTED EXCEPTION DURING EXPR EVALUATION CALL IN ASSEMBLY LOOP");
01298         Tabs tabX1;
01299         SUNDANCE_MSG1(10, tabX1 << "While working on RQC="
01300           << rqc_[r]);
01301         SUNDANCE_MSG1(10, tabX1 << "While evaluating expr="
01302           << evalExprs[r]->toString());
01303         throw (std::runtime_error(exc.what()));
01304       }
01305 
01306       /* Optionally, print the evaluation results */
01307       SUNDANCE_MSG2(rqcVerb, tab1 << "====== done evaluating expressions") ;
01308       if (evalVerb > 3) 
01309       {
01310         displayEvaluationResults(contexts[r], evalExprs[r], constantCoeffs, 
01311           vectorCoeffs);
01312       }
01313     
01314       /* ---- Do the element integrals and insertions ------ */
01315 
01316       /* The matrices used to transform integrals are built upon first use by 
01317        * this workset, then cached because they may be needed for several 
01318        * integrals on the same workset. As we're now in a new workset with
01319        * new cells, they should be rebuilt if needed. This step informs all integrals
01320        * that the cache is out of date. 
01321        *
01322        * Todo: this uses a static function that contains static data (via the "Meyers
01323        * trick") and so is not thread-safe. If we want to do multithreaded parallelism
01324        * for multicore architectures, this implementation will need to be changed.
01325        */ 
01326       ElementIntegral::invalidateTransformationMatrices();
01327       
01328       /* Loop over the integral groups */
01329       SUNDANCE_MSG2(rqcVerb, tab1 << "----- looping over integral groups");
01330       for (int g=0; g<groups[r].size(); g++)
01331       {
01332         Tabs tab2;
01333         SUNDANCE_MSG2(rqcVerb, tab2 << std::endl << tab2 
01334           << "--- evaluating integral group g=" << g << " of " 
01335           << groups[r].size() );
01336 
01337         /* Do the integrals. The integration results will be written into
01338          * the array "localValues". */
01339         const RCP<IntegralGroup>& group = groups[r][g];
01340         if (!group->evaluate(JTrans, JVol, *isLocalFlag, facetIndices, workSet,
01341             vectorCoeffs, constantCoeffs, localValues)) continue;
01342 
01343         /* Here we call the transformation object, if they are not needed
01344          * (the function might be one return) there would be no operation
01345          * done to the array of local stiffness matrix
01346          * Do the actual transformation (transformations for Matrix)*/
01347         transformations[r][g]->applyTransformsToAssembly(
01348             g , (localValues->size() / workSet->size()),
01349                 cellType, cellDim , maxCellType,
01350             JTrans, JVol, facetIndices, workSet, localValues);
01351 
01352         /* add the integration results into the output objects by a call
01353          * to the kernel's fill() function. We need to pass isBCRqc to the kernel
01354          * because it might handle BC rows differently. The integral group
01355          * data structure contains information about which test and unknown
01356          * functions were used in this integration, and so provides to the assembly
01357          * kernel such information as is needed to look up the correct DOFs for this
01358          * batch of integrals. */
01359         {
01360           TimeMonitor fillTM(fillTimer());
01361           kernel->fill(isBCRqc_[r], *group, localValues);
01362         }
01363       }
01364       SUNDANCE_MSG2(rqcVerb, tab1 << "----- done looping over integral groups");
01365     }
01366     SUNDANCE_MSG2(rqcVerb, tab0 << "----- done looping over worksets");
01367     /* reset the kernel verbosity to the default */
01368     kernel->setVerb(oldKernelVerb);
01369     SUNDANCE_MSG1(verb, tab0 << "----- done rqc");
01370   }
01371   SUNDANCE_MSG1(verb, tab << "----- done looping over rqcs");
01372 
01373 
01374   /* Do any post-fill processing, such as MPI_AllReduce add on functional values. */
01375   SUNDANCE_MSG2(verb, tab << "doing post-loop processing"); 
01376   kernel->postLoopFinalization();
01377   SUNDANCE_BANNER1(verb, tab, "done assembly loop"); 
01378 
01379   /* All done with assembly! */
01380 }
01381 
01382 
01383 
01384 /* ------------  assemble both the vector and the matrix  ------------- */
01385 
01386 void Assembler::assemble(LinearOperator<double>& A,
01387   Array<Vector<double> >& mv) const 
01388 {
01389   TimeMonitor timer(assemblyTimer());
01390   Tabs tab;
01391   int verb = 0;
01392   if (eqn_->hasActiveWatchFlag()) verb = max(verb, 1);
01393   
01394   SUNDANCE_BANNER1(verb, tab, "Assembling matrix and vector");
01395 
01396   TEUCHOS_TEST_FOR_EXCEPTION(!contexts_.containsKey(MatrixAndVector),
01397     std::runtime_error,
01398     "Assembler::assemble(A, b) called for an assembler that "
01399     "does not support matrix/vector assembly");
01400 
01401   configureMatrix(A, mv);
01402   
01403   RCP<AssemblyKernelBase> kernel 
01404     = rcp(new MatrixVectorAssemblyKernel(
01405             rowMap_, isBCRow_, lowestRow_,
01406             colMap_, isBCCol_, lowestCol_,
01407             A, mv, partitionBCs_, 
01408             0));
01409 
01410   assemblyLoop(MatrixAndVector, kernel);
01411 
01412   SUNDANCE_MSG1(verb, tab << "matrix=" << A);
01413   if (verb>0) A.print(Out::os());
01414   SUNDANCE_MSG1(verb, tab << "vectors=" << mv);
01415   for (int i=0; i<mv.size(); i++) 
01416   {
01417     SUNDANCE_MSG1(verb, tab << "vectors #" << i);
01418     if (verb>0) mv[i].print(Out::os());
01419   }
01420 
01421   SUNDANCE_MSG1(verb, tab << "Assembler: done assembling matrix and vector");
01422 }
01423 
01424 /* ------------  assemble the matrix and sensitivity RHS ------------- */
01425 
01426 void Assembler::assembleSensitivities(LinearOperator<double>& A,
01427   Array<Vector<double> >& mv) const 
01428 {
01429   TimeMonitor timer(assemblyTimer());
01430   Tabs tab;
01431   int verb = 0;
01432   if (eqn_->hasActiveWatchFlag()) verb = max(verb, 1);
01433   
01434   SUNDANCE_BANNER1(verb, tab, "Assembling matrix and sensitivity vector");
01435 
01436   TEUCHOS_TEST_FOR_EXCEPTION(!contexts_.containsKey(Sensitivities),
01437     std::runtime_error,
01438     "Assembler::assembleSensitivities(A, b) called for an assembler that "
01439     "does not support sensitivity assembly");
01440 
01441   configureMatrix(A, mv);
01442   
01443   
01444   RCP<AssemblyKernelBase> kernel 
01445     = rcp(new MatrixVectorAssemblyKernel(
01446             rowMap_, isBCRow_, lowestRow_,
01447             colMap_, isBCCol_, lowestCol_,
01448             A, mv, partitionBCs_, 
01449             0));
01450 
01451   assemblyLoop(Sensitivities, kernel);
01452   SUNDANCE_MSG1(verb, tab << "Assembler: done assembling matrix and sensitivity vector");
01453 }
01454 
01455 
01456 /* ------------  assemble the vector alone  ------------- */
01457 
01458 void Assembler::assemble(Array<Vector<double> >& mv) const 
01459 {
01460   /* Tab is advanced by ctor, taken back by dtor upon leaving scope */
01461   Tabs tab;
01462   /* Timer is started by ctor, stopped by dtor upon leaving scope */
01463   TimeMonitor timer(assemblyTimer());  
01464 
01465   /* If any subexpression is watched, print basic information */ 
01466   int verb = 0;
01467   if (eqn_->hasActiveWatchFlag()) verb = max(verb, 1);
01468 
01469   SUNDANCE_BANNER1(verb, tab, "Assembling vector");
01470 
01471   /* Throw an exception if we don't know how to compute a vector */
01472   TEUCHOS_TEST_FOR_EXCEPTION(!contexts_.containsKey(VectorOnly),
01473     std::runtime_error,
01474     "Assembler::assemble(b) called for an assembler that "
01475     "does not support vector-only assembly");
01476 
01477   /* The vector is not configured yet. Do so here. */
01478   configureVector(mv);
01479   
01480   /* Create an assembly kernel that knows how to fill a vector */
01481   RCP<AssemblyKernelBase> kernel 
01482     = rcp(new VectorAssemblyKernel(
01483             rowMap_, isBCRow_, lowestRow_,
01484             mv, partitionBCs_, 0));
01485 
01486   assemblyLoop(VectorOnly, kernel);
01487 
01488   SUNDANCE_MSG1(verb, tab << "Assembler: done assembling vector");
01489 }
01490 
01491 
01492 /* ------------  evaluate a functional and its gradient ---- */
01493 
01494 void Assembler::evaluate(double& value, Array<Vector<double> >& gradient) const 
01495 {
01496   Tabs tab;
01497   TimeMonitor timer(assemblyTimer());
01498   int verb = 0;
01499   if (eqn_->hasActiveWatchFlag()) verb = max(verb, 1);
01500 
01501   SUNDANCE_BANNER1(verb, tab, "Computing functional and gradient");
01502 
01503   TEUCHOS_TEST_FOR_EXCEPTION(!contexts_.containsKey(FunctionalAndGradient),
01504     std::runtime_error,
01505     "Assembler::evaluate(f,df) called for an assembler that "
01506     "does not support value/gradient assembly");
01507 
01508   configureVector(gradient);
01509 
01510   value = 0.0;
01511   
01512   RCP<AssemblyKernelBase> kernel 
01513     = rcp(new FunctionalGradientAssemblyKernel(
01514             mesh_.comm(),
01515             rowMap_, isBCRow_, lowestRow_,
01516             gradient, partitionBCs_, &value, verb));
01517 
01518   assemblyLoop(FunctionalAndGradient, kernel);
01519 
01520   SUNDANCE_BANNER1(verb, tab, "Done computing functional and gradient");
01521 
01522 }
01523 
01524 
01525 
01526 
01527 /* ------------  evaluate a functional ---- */
01528 
01529 void Assembler::evaluate(double& value) const 
01530 {
01531   Tabs tab;
01532   TimeMonitor timer(assemblyTimer());
01533   int verb = 0;
01534   if (eqn_->hasActiveWatchFlag()) verb = max(verb, 1);
01535 
01536   SUNDANCE_BANNER1(verb, tab, "Computing functional");
01537 
01538   TEUCHOS_TEST_FOR_EXCEPTION(!contexts_.containsKey(FunctionalOnly),
01539     std::runtime_error,
01540     "Assembler::evaluate(f) called for an assembler that "
01541     "does not support functional evaluation");
01542 
01543   value = 0.0;
01544   
01545   RCP<AssemblyKernelBase> kernel 
01546     = rcp(new FunctionalAssemblyKernel(mesh_.comm(), &value, verb));
01547 
01548   assemblyLoop(FunctionalOnly, kernel);
01549 
01550   SUNDANCE_BANNER1(verb, tab, "Done computing functional");
01551 }
01552 
01553 
01554 
01555 
01556 /* ------------  get the nonzero pattern for the matrix ------------- */
01557                        
01558                        
01559 void Assembler::getGraph(int br, int bc, 
01560   Array<int>& graphData,
01561   Array<int>& rowPtrs,
01562   Array<int>& nnzPerRow) const 
01563 {
01564   TimeMonitor timer(graphBuildTimer());
01565   Tabs tab;
01566   int verb = eqn_->maxWatchFlagSetting("matrix config");
01567 
01568 
01569   RCP<Array<int> > workSet = rcp(new Array<int>());
01570   workSet->reserve(workSetSize());
01571 
01572   RCP<Array<Array<int> > > testLocalDOFs 
01573     = rcp(new Array<Array<int> >());
01574 
01575   RCP<Array<Array<int> > > unkLocalDOFs
01576     = rcp(new Array<Array<int> >());
01577 
01578   SUNDANCE_MSG3(verb, tab << "Creating graph: there are " 
01579     << rowMap_[br]->numLocalDOFs()
01580     << " local equations");
01581 
01582 
01583   Array<Set<int> > tmpGraph;
01584   tmpGraph.resize(rowMap_[br]->numLocalDOFs());
01585 
01586   {
01587     TimeMonitor timer2(colSearchTimer());
01588     for (int d=0; d<eqn_->numRegions(); d++)
01589     {
01590       Tabs tab0;
01591       CellFilter domain = eqn_->region(d);
01592       const Array<Set<int> >& requiredVars = eqn_->reducedVarsOnRegion(domain);
01593       const Array<Set<int> >& requiredUnks = eqn_->reducedUnksOnRegion(domain);
01594       SUNDANCE_MSG2(verb,
01595         tab0 << "cell set " << domain
01596         << " isBCRegion=" << eqn_->isBCRegion(d));
01597       int dim = domain.dimension(mesh_);
01598       CellSet cells = domain.getCells(mesh_);
01599 
01600       RCP<Set<OrderedPair<int, int> > > pairs ;
01601       if (eqn_->hasVarUnkPairs(domain)) pairs = eqn_->varUnkPairs(domain);
01602 
01603       SUNDANCE_OUT(verb > 2 && pairs.get() != 0, 
01604         tab0 << "non-BC pairs = "
01605         << *pairs);
01606        
01607       RCP<Set<OrderedPair<int, int> > > bcPairs ;
01608       if (eqn_->isBCRegion(d))
01609       {
01610         if (eqn_->hasBCVarUnkPairs(domain)) 
01611         {
01612           bcPairs = eqn_->bcVarUnkPairs(domain);
01613           SUNDANCE_OUT(verb > 2, tab0 << "BC pairs = "
01614             << *bcPairs);
01615         }
01616       }
01617       Array<Set<int> > unksForTestsSet(eqn_->numVarIDs(bc));
01618       Array<Set<int> > bcUnksForTestsSet(eqn_->numVarIDs(bc));
01619 
01620       Set<OrderedPair<int, int> >::const_iterator i;
01621       
01622       if (pairs.get() != 0)
01623       {
01624         for (i=pairs->begin(); i!=pairs->end(); i++)
01625         {
01626           const OrderedPair<int, int>& p = *i;
01627           int t = p.first();
01628           int u = p.second();
01629 
01630           TEUCHOS_TEST_FOR_EXCEPTION(!eqn_->hasVarID(t), std::logic_error,
01631             "Test function ID " << t << " does not appear "
01632             "in equation set");
01633           TEUCHOS_TEST_FOR_EXCEPTION(!eqn_->hasUnkID(u), std::logic_error,
01634             "Unk function ID " << u << " does not appear "
01635             "in equation set");
01636 
01637           if (eqn_->blockForVarID(t) != br) continue;
01638           if (eqn_->blockForUnkID(u) != bc) continue;
01639 
01640           unksForTestsSet[eqn_->reducedVarID(t)].put(eqn_->reducedUnkID(u));
01641         }
01642       }
01643       if (bcPairs.get() != 0)
01644       {
01645         for (i=bcPairs->begin(); i!=bcPairs->end(); i++)
01646         {
01647           const OrderedPair<int, int>& p = *i;
01648           int t = p.first();
01649           int u = p.second();
01650 
01651           if (eqn_->blockForVarID(t) != br) continue;
01652           if (eqn_->blockForUnkID(u) != bc) continue;
01653 
01654           TEUCHOS_TEST_FOR_EXCEPTION(!eqn_->hasVarID(t), std::logic_error,
01655             "Test function ID " << t << " does not appear "
01656             "in equation set");
01657           TEUCHOS_TEST_FOR_EXCEPTION(!eqn_->hasUnkID(u), std::logic_error,
01658             "Unk function ID " << u << " does not appear "
01659             "in equation set");
01660           bcUnksForTestsSet[eqn_->reducedVarID(t)].put(eqn_->reducedUnkID(u));
01661         }
01662       }
01663 
01664       Array<Array<int> > unksForTests(unksForTestsSet.size());
01665       Array<Array<int> > bcUnksForTests(bcUnksForTestsSet.size());
01666 
01667       for (int t=0; t<unksForTests.size(); t++)
01668       {
01669         unksForTests[t] = unksForTestsSet[t].elements();
01670         bcUnksForTests[t] = bcUnksForTestsSet[t].elements();
01671       }
01672       
01673       Array<int> numTestNodes;
01674       Array<int> numUnkNodes;
01675 
01676       
01677 
01678       int highestRow = lowestRow_[br] + rowMap_[br]->numLocalDOFs();
01679 
01680       int nt = eqn_->numVarIDs(br);
01681 
01682       CellIterator iter=cells.begin();
01683       while (iter != cells.end())
01684       {
01685         /* build a work set */
01686         workSet->resize(0);
01687         for (int c=0; c<workSetSize() && iter != cells.end(); c++, iter++)
01688         {
01689           workSet->append(*iter);
01690         }
01691 
01692         int nCells = workSet->size();
01693 
01694         RCP<const MapStructure> colMapStruct; 
01695         RCP<const MapStructure> rowMapStruct 
01696           = rowMap_[br]->getDOFsForCellBatch(dim, *workSet, 
01697             requiredVars[br], *testLocalDOFs,
01698             numTestNodes, verb);
01699         if (rowMap_[br].get()==colMap_[bc].get())
01700         {
01701           unkLocalDOFs = testLocalDOFs;
01702           numUnkNodes = numTestNodes;
01703           colMapStruct = rowMapStruct;
01704         }
01705         else
01706         {
01707           colMapStruct = colMap_[br]->getDOFsForCellBatch(dim, *workSet, 
01708             requiredUnks[bc], 
01709             *unkLocalDOFs, numUnkNodes, verb);
01710         }
01711 
01712         if (pairs.get() != 0)
01713         {
01714           for (int c=0; c<nCells; c++)
01715           {
01716             for (int t=0; t<nt; t++)
01717             {
01718               int tChunk = rowMapStruct->chunkForFuncID(t);
01719               int nTestFuncs = rowMapStruct->numFuncs(tChunk);
01720               int testFuncIndex = rowMapStruct->indexForFuncID(t);
01721               int nTestNodes = numTestNodes[tChunk];
01722               const Array<int>& testDOFs = (*testLocalDOFs)[tChunk];
01723               for (int uit=0; uit<unksForTests[t].size(); uit++)
01724               {
01725                 Tabs tab2;
01726                 int u = unksForTests[t][uit];
01727                 int uChunk = colMapStruct->chunkForFuncID(u);
01728                 int nUnkFuncs = colMapStruct->numFuncs(uChunk);
01729                 int unkFuncIndex = colMapStruct->indexForFuncID(u);
01730                 const Array<int>& unkDOFs = (*unkLocalDOFs)[uChunk];
01731                 int nUnkNodes = numUnkNodes[uChunk];
01732                 for (int n=0; n<nTestNodes; n++)
01733                 {
01734                   int row
01735                     = testDOFs[(c*nTestFuncs + testFuncIndex)*nTestNodes + n];
01736                   if (row < lowestRow_[br] || row >= highestRow
01737                     || (*(isBCRow_[br]))[row-lowestRow_[br]]) continue;
01738                   Set<int>& colSet = tmpGraph[row-lowestRow_[br]];
01739                   for (int m=0; m<nUnkNodes; m++)
01740                   {
01741                     int col 
01742                       = unkDOFs[(c*nUnkFuncs + unkFuncIndex)*nUnkNodes + m];
01743                     colSet.put(col);
01744                   }
01745                 }
01746               }
01747             }
01748           }
01749         }
01750         if (bcPairs.get() != 0)
01751         {
01752           for (int c=0; c<nCells; c++)
01753           {
01754             for (int t=0; t<nt; t++)
01755             {
01756               int tChunk = rowMapStruct->chunkForFuncID(t);
01757               int nTestFuncs = rowMapStruct->numFuncs(tChunk);
01758               int testFuncIndex = rowMapStruct->indexForFuncID(t);
01759               int nTestNodes = numTestNodes[tChunk];
01760               const Array<int>& testDOFs = (*testLocalDOFs)[tChunk];
01761               for (int uit=0; uit<bcUnksForTests[t].size(); uit++)
01762               {
01763                 Tabs tab2;
01764                 int u = bcUnksForTests[t][uit];
01765                 int uChunk = colMapStruct->chunkForFuncID(u);
01766                 int nUnkFuncs = colMapStruct->numFuncs(uChunk);
01767                 int unkFuncIndex = colMapStruct->indexForFuncID(u);
01768                 const Array<int>& unkDOFs = (*unkLocalDOFs)[uChunk];
01769                 int nUnkNodes = numUnkNodes[uChunk];
01770                 for (int n=0; n<nTestNodes; n++)
01771                 {
01772                   int row
01773                     = testDOFs[(c*nTestFuncs + testFuncIndex)*nTestNodes + n];
01774                   if (row < lowestRow_[br] || row >= highestRow
01775                     || !(*(isBCRow_[br]))[row-lowestRow_[br]]) continue;
01776                   Set<int>& colSet = tmpGraph[row-lowestRow_[br]];
01777                   for (int m=0; m<nUnkNodes; m++)
01778                   {
01779                     int col 
01780                       = unkDOFs[(c*nUnkFuncs + unkFuncIndex)*nUnkNodes + m];
01781                     colSet.put(col);
01782                   }
01783                 }
01784               }
01785             }
01786           }
01787         }
01788       }
01789     }
01790   }
01791 
01792   
01793   {
01794     TimeMonitor t2(graphFlatteningTimer());
01795     int nLocalRows = rowMap_[br]->numLocalDOFs();
01796 
01797     int nnz = 0;
01798     rowPtrs.resize(nLocalRows);
01799     nnzPerRow.resize(rowMap_[br]->numLocalDOFs());
01800     for (int i=0; i<nLocalRows; i++) 
01801     {
01802       rowPtrs[i] = nnz;
01803       nnzPerRow[i] = tmpGraph[i].size();
01804       nnz += nnzPerRow[i];
01805     }
01806 
01807     graphData.resize(nnz);
01808     int* base = &(graphData[0]);
01809     for (int i=0; i<nLocalRows; i++)
01810     {
01811       //        tmpGraph[i].fillArray(base + rowPtrs[i]);
01812       int* rowBase = base + rowPtrs[i];
01813       const Set<int>& rowSet = tmpGraph[i];
01814       int k = 0;
01815       for (Set<int>::const_iterator 
01816              j=rowSet.begin(); j != rowSet.end(); j++, k++)
01817       {
01818         rowBase[k] = *j;
01819       }
01820     }
01821   }
01822 
01823 }
01824 /* ------------  get the nonzero pattern for the matrix ------------- */
01825                        
01826                        
01827 void Assembler
01828 ::incrementalGetGraph(int br, int bc,
01829   IncrementallyConfigurableMatrixFactory* icmf) const 
01830 {
01831   TimeMonitor timer(graphBuildTimer());
01832   Tabs tab;
01833   int verb = eqn_->maxWatchFlagSetting("matrix config");
01834 
01835   RCP<Array<int> > workSet = rcp(new Array<int>());
01836   workSet->reserve(workSetSize());
01837 
01838   RCP<Array<Array<int> > > testLocalDOFs 
01839     = rcp(new Array<Array<int> >());
01840 
01841   RCP<Array<Array<int> > > unkLocalDOFs
01842     = rcp(new Array<Array<int> >());
01843 
01844   SUNDANCE_MSG2(verb, tab << "Creating graph: there are " 
01845     << rowMap_[br]->numLocalDOFs()
01846     << " local equations");
01847 
01848 
01849   for (int d=0; d<eqn_->numRegions(); d++)
01850   {
01851     Tabs tab0;
01852     CellFilter domain = eqn_->region(d);
01853     const Array<Set<int> >& requiredVars = eqn_->reducedVarsOnRegion(domain);
01854     const Array<Set<int> >& requiredUnks = eqn_->reducedUnksOnRegion(domain);
01855     Array<int> localVars = requiredVars[br].elements();
01856     Array<int> localUnks = requiredUnks[bc].elements();
01857     SUNDANCE_MSG3(verb,
01858       tab0 << "cell set " << domain
01859       << " isBCRegion=" << eqn_->isBCRegion(d));
01860     int dim = domain.dimension(mesh_);
01861     CellSet cells = domain.getCells(mesh_);
01862 
01863     RCP<Set<OrderedPair<int, int> > > pairs ;
01864     if (eqn_->hasVarUnkPairs(domain)) pairs = eqn_->varUnkPairs(domain);
01865 
01866     SUNDANCE_OUT(verb > 2 && pairs.get() != 0, 
01867       tab0 << "non-BC pairs = "
01868       << *pairs);
01869        
01870     RCP<Set<OrderedPair<int, int> > > bcPairs ;
01871     if (eqn_->isBCRegion(d))
01872     {
01873       if (eqn_->hasBCVarUnkPairs(domain)) 
01874       {
01875         bcPairs = eqn_->bcVarUnkPairs(domain);
01876         SUNDANCE_MSG3(verb, tab0 << "BC pairs = "
01877           << *bcPairs);
01878       }
01879     }
01880     Array<Set<int> > unksForTestsSet(eqn_->numVarIDs(br));
01881     Array<Set<int> > bcUnksForTestsSet(eqn_->numVarIDs(br));
01882 
01883     Set<OrderedPair<int, int> >::const_iterator i;
01884       
01885     if (pairs.get() != 0)
01886     {
01887       for (i=pairs->begin(); i!=pairs->end(); i++)
01888       {
01889         const OrderedPair<int, int>& p = *i;
01890         int t = p.first();
01891         int u = p.second();
01892 
01893         TEUCHOS_TEST_FOR_EXCEPTION(!eqn_->hasVarID(t), std::logic_error,
01894           "Test function ID " << t << " does not appear "
01895           "in equation set");
01896         TEUCHOS_TEST_FOR_EXCEPTION(!eqn_->hasUnkID(u), std::logic_error,
01897           "Unk function ID " << u << " does not appear "
01898           "in equation set");
01899 
01900 
01901         if (eqn_->blockForVarID(t) != br) continue;
01902         if (eqn_->blockForUnkID(u) != bc) continue;
01903 
01904         unksForTestsSet[eqn_->reducedVarID(t)].put(eqn_->reducedUnkID(u));
01905       }
01906     }
01907     if (bcPairs.get() != 0)
01908     {
01909       for (i=bcPairs->begin(); i!=bcPairs->end(); i++)
01910       {
01911         const OrderedPair<int, int>& p = *i;
01912         int t = p.first();
01913         int u = p.second();
01914         TEUCHOS_TEST_FOR_EXCEPTION(!eqn_->hasVarID(t), std::logic_error,
01915           "Test function ID " << t << " does not appear "
01916           "in equation set");
01917         TEUCHOS_TEST_FOR_EXCEPTION(!eqn_->hasUnkID(u), std::logic_error,
01918           "Unk function ID " << u << " does not appear "
01919           "in equation set");
01920 
01921         if (eqn_->blockForVarID(t) != br) continue;
01922         if (eqn_->blockForUnkID(u) != bc) continue;
01923 
01924         bcUnksForTestsSet[eqn_->reducedVarID(t)].put(eqn_->reducedUnkID(u));
01925       }
01926     }
01927 
01928     Array<Array<int> > unksForTests(unksForTestsSet.size());
01929     Array<Array<int> > bcUnksForTests(bcUnksForTestsSet.size());
01930 
01931     for (int t=0; t<unksForTests.size(); t++)
01932     {
01933       unksForTests[t] = unksForTestsSet[t].elements();
01934       bcUnksForTests[t] = bcUnksForTestsSet[t].elements();
01935     }
01936       
01937     Array<int> numTestNodes;
01938     Array<int> numUnkNodes;
01939       
01940     int highestRow = lowestRow_[br] + rowMap_[br]->numLocalDOFs();
01941 
01942     CellIterator iter=cells.begin();
01943 
01944     while (iter != cells.end())
01945     {
01946       /* build a work set */
01947       workSet->resize(0);
01948       for (int c=0; c<workSetSize() && iter != cells.end(); c++, iter++)
01949       {
01950         workSet->append(*iter);
01951       }
01952 
01953       int nCells = workSet->size();
01954 
01955       RCP<const MapStructure> colMapStruct; 
01956       RCP<const MapStructure> rowMapStruct 
01957         = rowMap_[br]->getDOFsForCellBatch(dim, *workSet, 
01958           requiredVars[br],
01959           *testLocalDOFs,
01960           numTestNodes, verb);
01961 
01962       if (rowMap_[br].get()==colMap_[bc].get())
01963       {
01964         unkLocalDOFs = testLocalDOFs;
01965         numUnkNodes = numTestNodes;
01966         colMapStruct = rowMapStruct;
01967       }
01968       else
01969       {
01970         colMapStruct = colMap_[bc]->getDOFsForCellBatch(dim, *workSet, 
01971           requiredUnks[bc],
01972           *unkLocalDOFs, numUnkNodes, verb);
01973       }
01974 
01975           
01976       if (pairs.get() != 0)
01977       {
01978         for (int c=0; c<nCells; c++)
01979         {
01980           for (int tIndex=0; tIndex<localVars.size(); tIndex++)
01981           {
01982             int t = localVars[tIndex];
01983             int tChunk = rowMapStruct->chunkForFuncID(t);
01984             int nTestFuncs = rowMapStruct->numFuncs(tChunk);
01985             int testFuncIndex = rowMapStruct->indexForFuncID(t);
01986             int nTestNodes = numTestNodes[tChunk];
01987             const Array<int>& testDOFs = (*testLocalDOFs)[tChunk];
01988             for (int uit=0; uit<unksForTests[t].size(); uit++)
01989             {
01990               Tabs tab2;
01991               int u = unksForTests[t][uit];
01992               int uChunk = colMapStruct->chunkForFuncID(u);
01993               int nUnkFuncs = colMapStruct->numFuncs(uChunk);
01994               int unkFuncIndex = colMapStruct->indexForFuncID(u);
01995               const Array<int>& unkDOFs = (*unkLocalDOFs)[uChunk];
01996               int nUnkNodes = numUnkNodes[uChunk];
01997               for (int n=0; n<nTestNodes; n++)
01998               {
01999                 int row
02000                   = testDOFs[(c*nTestFuncs + testFuncIndex)*nTestNodes + n];
02001                 if (row < lowestRow_[br] || row >= highestRow
02002                   || (*(isBCRow_[br]))[row-lowestRow_[br]]) continue;
02003                 const int* colPtr = &(unkDOFs[(c*nUnkFuncs + unkFuncIndex)*nUnkNodes]);
02004                 icmf->initializeNonzerosInRow(row, nUnkNodes, colPtr);
02005               }
02006             }
02007           }
02008         }
02009       }
02010       if (bcPairs.get() != 0)
02011       {
02012         for (int c=0; c<nCells; c++)
02013         {
02014           for (int tIndex=0; tIndex<localVars.size(); tIndex++)
02015           {
02016             int t = localVars[tIndex];
02017             int tChunk = rowMapStruct->chunkForFuncID(t);
02018             int nTestFuncs = rowMapStruct->numFuncs(tChunk);
02019             int testFuncIndex = rowMapStruct->indexForFuncID(t);
02020             int nTestNodes = numTestNodes[tChunk];
02021             const Array<int>& testDOFs = (*testLocalDOFs)[tChunk];
02022             for (int uit=0; uit<bcUnksForTests[t].size(); uit++)
02023             {
02024               Tabs tab2;
02025               int u = bcUnksForTests[t][uit];
02026               int uChunk = colMapStruct->chunkForFuncID(u);
02027               int nUnkFuncs = colMapStruct->numFuncs(uChunk);
02028               int unkFuncIndex = colMapStruct->indexForFuncID(u);
02029               const Array<int>& unkDOFs = (*unkLocalDOFs)[uChunk];
02030               int nUnkNodes = numUnkNodes[uChunk];
02031               for (int n=0; n<nTestNodes; n++)
02032               {
02033                 int row
02034                   = testDOFs[(c*nTestFuncs + testFuncIndex)*nTestNodes + n];
02035                 if (row < lowestRow_[br] || row >= highestRow
02036                   || !(*(isBCRow_[br]))[row-lowestRow_[br]]) continue;
02037 
02038                 const int* colPtr = &(unkDOFs[(c*nUnkFuncs + unkFuncIndex)*nUnkNodes]);
02039                 icmf->initializeNonzerosInRow(row, nUnkNodes, colPtr);
02040               }
02041             }
02042           }
02043         }
02044       }
02045     }
02046   }
02047 }
02048 
02049 
02050 Array<Array<int> > Assembler::findNonzeroBlocks() const
02051 {
02052   int verb = eqn_->maxWatchFlagSetting("assembler setup");
02053 
02054   Array<Array<int> > rtn(eqn_->numVarBlocks());
02055   for (int br=0; br<rtn.size(); br++)
02056   {
02057     rtn[br].resize(eqn_->numUnkBlocks());
02058     for (int bc=0; bc<rtn[br].size(); bc++)
02059     {
02060       rtn[br][bc] = 0 ;
02061     }
02062   }
02063 
02064   for (int d=0; d<eqn_->numRegions(); d++)
02065   {
02066     Tabs tab0;
02067     CellFilter domain = eqn_->region(d);
02068     SUNDANCE_MSG3(verb,
02069       tab0 << "cell set " << domain
02070       << " isBCRegion=" << eqn_->isBCRegion(d));
02071 
02072     RCP<Set<OrderedPair<int, int> > > pairs ;
02073     if (eqn_->hasVarUnkPairs(domain)) pairs = eqn_->varUnkPairs(domain);
02074 
02075     SUNDANCE_OUT(verb > 2 && pairs.get() != 0, 
02076       tab0 << "non-BC pairs = "
02077       << *pairs);
02078        
02079     RCP<Set<OrderedPair<int, int> > > bcPairs ;
02080     if (eqn_->isBCRegion(d))
02081     {
02082       if (eqn_->hasBCVarUnkPairs(domain)) 
02083       {
02084         bcPairs = eqn_->bcVarUnkPairs(domain);
02085         SUNDANCE_MSG3(verb, tab0 << "BC pairs = "
02086           << *bcPairs);
02087       }
02088     }
02089 
02090     Set<OrderedPair<int, int> >::const_iterator i;
02091       
02092     if (pairs.get() != 0)
02093     {
02094       for (i=pairs->begin(); i!=pairs->end(); i++)
02095       {
02096         const OrderedPair<int, int>& p = *i;
02097         int t = p.first();
02098         int u = p.second();
02099 
02100         TEUCHOS_TEST_FOR_EXCEPTION(!eqn_->hasVarID(t), std::logic_error,
02101           "Test function ID " << t << " does not appear "
02102           "in equation set");
02103         TEUCHOS_TEST_FOR_EXCEPTION(!eqn_->hasUnkID(u), std::logic_error,
02104           "Unk function ID " << u << " does not appear "
02105           "in equation set");
02106 
02107 
02108         int br = eqn_->blockForVarID(t);
02109         int bc = eqn_->blockForUnkID(u);
02110         rtn[br][bc] = 1;
02111       }
02112     }
02113     if (bcPairs.get() != 0)
02114     {
02115       for (i=bcPairs->begin(); i!=bcPairs->end(); i++)
02116       {
02117         const OrderedPair<int, int>& p = *i;
02118         int t = p.first();
02119         int u = p.second();
02120         TEUCHOS_TEST_FOR_EXCEPTION(!eqn_->hasVarID(t), std::logic_error,
02121           "Test function ID " << t << " does not appear "
02122           "in equation set");
02123         TEUCHOS_TEST_FOR_EXCEPTION(!eqn_->hasUnkID(u), std::logic_error,
02124           "Unk function ID " << u << " does not appear "
02125           "in equation set");
02126         int br = eqn_->blockForVarID(t);
02127         int bc = eqn_->blockForUnkID(u);
02128         rtn[br][bc] = 1;
02129       }
02130     }
02131   }
02132 
02133   return rtn;
02134 }
02135 
02136 VectorSpace<double> Assembler::solnVecSpace() const
02137 {
02138   Array<VectorSpace<double> > rtn(eqn_->numUnkBlocks());
02139 
02140   for (int i=0; i<rtn.size(); i++)
02141   {
02142     rtn[i] = solutionSpace()[i]->vecSpace();
02143   }
02144 
02145   if ((int) rtn.size() == 1)
02146   {
02147     return rtn[0];
02148   }
02149   return blockSpace(rtn);
02150 }
02151 
02152 
02153 VectorSpace<double> Assembler::rowVecSpace() const
02154 {
02155   Array<VectorSpace<double> > rtn(eqn_->numVarBlocks());
02156 
02157   for (int i=0; i<rtn.size(); i++)
02158   {
02159     rtn[i] = rowSpace()[i]->vecSpace();
02160   }
02161 
02162   if ((int) rtn.size() == 1)
02163   {
02164     return rtn[0];
02165   }
02166   return blockSpace(rtn);
02167 }
02168 
02169 
02170 
02171 int& Assembler::workSetSize()
02172 {
02173   static int rtn = defaultWorkSetSize(); 
02174   return rtn;
02175 }
02176 
02177 int Assembler::maxWatchFlagSetting(const std::string& name) const 
02178 {
02179   return eqnSet()->maxWatchFlagSetting(name);
02180 }
02181 
02182 bool Assembler::matNeedsConfiguration() const
02183 {
02184   return Teuchos::is_null(cachedAssembledMatrix_.ptr());
02185 }
02186 
02187 
02188 void Assembler::flushConfiguration() const
02189 {
02190     numConfiguredColumns_ = 0;
02191     cachedAssembledMatrix_ = LinearOperator<double>();
02192     mesh_.flushSpecialWeights();
02193     mesh_.flushCurvePoints();
02194 
02195     // empty the cache from the cell filters
02196     for (int r=0; r<rqc_.size(); r++)
02197     {
02198       const CellFilter filter = rqc_[r].domain();
02199       filter.cfbPtr()->flushCache();
02200     }
02201 }

Site Contact