Exemple #1
0
// A fill specialized to the single node at the coupling interface
void 
ConvDiff_PDE::computeHeatFlux( const Epetra_Vector * soln )
{
  
  int numDep = depProblems.size();

  // Create the overlapped solution and position vectors
  Epetra_Vector u(*OverlapMap);
  Epetra_Vector uold(*OverlapMap);
  std::vector<Epetra_Vector*> dep(numDep);
  for( int i = 0; i < numDep; ++i)
    dep[i] = new Epetra_Vector(*OverlapMap);

  Epetra_Vector xvec(*OverlapMap);

  // Export Solution to Overlap vector
  // If the vector to be used in the fill is already in the Overlap form,
  // we simply need to map on-processor from column-space indices to
  // OverlapMap indices. Note that the old solution is simply fixed data that
  // needs to be sent to an OverlapMap (ghosted) vector.  The conditional
  // treatment for the current soution vector arises from use of
  // FD coloring in parallel.

  uold.Import(*oldSolution, *Importer, Insert);

  for( int i = 0; i < numDep; ++i )
    (*dep[i]).Import(*( (*(depSolutions.find(depProblems[i]))).second ), *Importer, Insert);

  xvec.Import(*xptr, *Importer, Insert);

  if( NULL == soln )
    u.Import(*initialSolution, *Importer, Insert);
  else
    u.Import(*soln, *Importer, Insert);

  // Declare required variables
  int row;
  double * xx = new double[2];
  double * uu = new double[2]; 
  double * uuold = new double[2];
  std::vector<double*> ddep(numDep);
  for( int i = 0; i < numDep; ++i)
    ddep[i] = new double[2];

  Basis basis;

  // Bundle up the dependent variables in the way needed for computing
  // the source terms of each reaction
  map<string, double*> depVars;
  depVars.insert( pair< std::string, double*>(getName(), uu) );
  for( int i = 0; i < numDep; ++i )
    depVars.insert( pair<string, double*>(myManager->getProblemName(depProblems[i]), ddep[i]) );

  myFlux = 0.0;

  // Loop Over Gauss Points
  for( int gp = 0; gp < 2; ++gp ) 
  {
    // Get the solution and coordinates at the nodes 
    xx[0]=xvec[interface_elem];
    xx[1]=xvec[interface_elem+1];
    uu[0] = u[interface_elem];
    uu[1] = u[interface_elem+1];
    uuold[0] = uold[interface_elem];
    uuold[1] = uold[interface_elem+1];
    for( int i = 0; i < numDep; ++i ) 
    {
      ddep[i][0] = (*dep[i])[interface_elem];
      ddep[i][1] = (*dep[i])[interface_elem+1];
    }

    // Calculate the basis function and variables at the gauss points
    basis.getBasis(gp, xx, uu, uuold, ddep);

    row = OverlapMap->GID( interface_elem + local_node );

    if( StandardMap->MyGID(row) ) 
    {
      myFlux += 
        + basis.wt * basis.dx
        * ( peclet * (basis.duu / basis.dx) * basis.phi[local_node] 
        +   kappa * (1.0/(basis.dx*basis.dx)) * basis.duu * basis.dphide[local_node] );
    }
  }

  // Sync up processors to be safe
  Comm->Barrier();
 
  // Cleanup
  for( int i = 0; i < numDep; ++i)
  {
    delete [] ddep[i];
    delete     dep[i];
  }

  delete [] xx    ;
  delete [] uu    ;
  delete [] uuold ;

  //int lastDof = StandardMap->LID(StandardMap->MaxAllGID());
  //cout << "\t\"" << myName << "\" u[0] = " << u[0] 
  //     << "\tu[N] = " << u[lastDof] << std::endl;
  //cout << u << std::endl;
  //cout << "\t\"" << myName << "\" myFlux = " << myFlux << std::endl << std::endl;

  // Scale domain integration according to interface position
  myFlux *= dirScale;

  // Now add radiation contribution to flux
  myFlux += radiation * ( pow(u[interface_node], 4) - pow(u[opposite_node], 4) );

  return;
}
Exemple #2
0
// Matrix and Residual Fills
bool 
HMX_PDE::evaluate(
                    NOX::Epetra::Interface::Required::FillType flag,
		    const Epetra_Vector* soln, 
		    Epetra_Vector* tmp_rhs)
{
  // Determine what to fill (F or Jacobian)
  bool fillF = false;
  bool fillMatrix = false;
  if (tmp_rhs != 0) {
    fillF = true;
    rhs = tmp_rhs;
  }
  else {
    fillMatrix = true;
  }
  
  // "flag" can be used to determine how accurate your fill of F should be
  // depending on why we are calling evaluate (Could be using computeF to
  // populate a Jacobian or Preconditioner).
  if (flag == NOX::Epetra::Interface::Required::Residual) {
    // Do nothing for now
  }
  else if (flag == NOX::Epetra::Interface::Required::Jac) {
    // Do nothing for now
  }
  else if (flag == NOX::Epetra::Interface::Required::Prec) {
    // Do nothing for now
  }
  else if (flag == NOX::Epetra::Interface::Required::User) {
    // Do nothing for now
  }

  int numDep = depProblems.size();

  // Create the overlapped solution and position vectors
  Epetra_Vector u(*OverlapMap);
  Epetra_Vector uold(*OverlapMap);
  std::vector<Epetra_Vector*> dep(numDep);
  for( int i = 0; i<numDep; i++)
    dep[i] = new Epetra_Vector(*OverlapMap);
  Epetra_Vector xvec(*OverlapMap);

  // Export Solution to Overlap vector
  // If the vector to be used in the fill is already in the Overlap form,
  // we simply need to map on-processor from column-space indices to
  // OverlapMap indices. Note that the old solution is simply fixed data that
  // needs to be sent to an OverlapMap (ghosted) vector.  The conditional
  // treatment for the current soution vector arises from use of
  // FD coloring in parallel.
  uold.Import(*oldSolution, *Importer, Insert);
  for( int i = 0; i<numDep; i++ )
    (*dep[i]).Import(*( (*(depSolutions.find(depProblems[i]))).second ), 
                   *Importer, Insert);
  xvec.Import(*xptr, *Importer, Insert);
  if( flag == NOX::Epetra::Interface::Required::FD_Res)
    // Overlap vector for solution received from FD coloring, so simply reorder
    // on processor
    u.Export(*soln, *ColumnToOverlapImporter, Insert);
  else // Communication to Overlap vector is needed
    u.Import(*soln, *Importer, Insert);

  // Declare required variables
  int OverlapNumMyNodes = OverlapMap->NumMyElements();

  int OverlapMinMyNodeGID;
  if (MyPID==0) OverlapMinMyNodeGID = StandardMap->MinMyGID();
  else OverlapMinMyNodeGID = StandardMap->MinMyGID()-1;

  // Setup iterators for looping over each problem source term contribution
  // to this one's PDE
  map<string, double>::iterator srcTermIter;
  map<string, double>::iterator srcTermEnd = SrcTermWeight.end();

  // Bundle up the dependent variables in the way needed for computing
  // the source terms of each reaction
  /*
  Epetra_Vector debugSrcTerm(*OverlapMap);
  map<string, Epetra_Vector*> debugDepVars;
  debugDepVars.insert( pair<string, Epetra_Vector*>(getName(), &u) );
  for( int i = 0; i<numDep; i++ )
    debugDepVars.insert( pair<string, Epetra_Vector*>
                    (myManager->getName(depProblems[i]), &dep[i]) );

  for( srcTermIter = SrcTermWeight.begin(); 
    srcTermIter != srcTermEnd; srcTermIter++) {
                     HMX_PDE &srcTermProb = 
                     dynamic_cast<HMX_PDE&>(
                     myManager->getProblem(srcTermIter->first) );
    std::cout << "Inside problem: \"" << getName() << "\" calling to get source term "
         << "from problem: \"" << srcTermIter->first << "\" :" << std::endl;
    srcTermProb.computeSourceTerm(debugDepVars, debugSrcTerm);
    std::cout << "Resulting source term :" << debugSrcTerm << std::endl;
  }
  */

  int row;
  double alpha = 500.0;
  double xx[2];
  double uu[2]; 
  double uuold[2];
  std::vector<double*> ddep(numDep);
  for( int i = 0; i<numDep; i++)
    ddep[i] = new double[2];
  double *srcTerm = new double[2];
  Basis basis;

  // Bundle up the dependent variables in the way needed for computing
  // the source terms of each reaction
  map<string, double*> depVars;
  depVars.insert( pair<string, double*>(getName(), uu) );
  for( int i = 0; i<numDep; i++ )
    depVars.insert( pair<string, double*>
                    (myManager->getProblemName(depProblems[i]), ddep[i]) );
  // Do a check on this fill
//  map<string, double*>::iterator iter;
//  for( iter = depVars.begin(); iter != depVars.end(); iter++)
//    std::cout << "Inserted ... " << iter->first << "\t" << iter->second << std::endl;
//  std::cout << "--------------------------------------------------" << std::endl;
//  for( iter = depVars.begin(); iter != depVars.end(); iter++)
//	  std::cout << iter->first << "\t" << (iter->second)[0] << ", " 
//               << (iter->second)[1] << std::endl;
//  std::cout << "--------------------------------------------------" << std::endl;

  // Zero out the objects that will be filled
  if ( fillMatrix ) A->PutScalar(0.0);
  if ( fillF ) rhs->PutScalar(0.0);

  // Loop Over # of Finite Elements on Processor
  for (int ne=0; ne < OverlapNumMyNodes-1; ne++) 
  {
    // Loop Over Gauss Points
    for(int gp=0; gp < 2; gp++) 
    {
      // Get the solution and coordinates at the nodes 
      xx[0]=xvec[ne];
      xx[1]=xvec[ne+1];
      uu[0] = u[ne];
      uu[1] = u[ne+1];
      uuold[0] = uold[ne];
      uuold[1] = uold[ne+1];
      for( int i = 0; i<numDep; i++ ) {
        ddep[i][0] = (*dep[i])[ne];
        ddep[i][1] = (*dep[i])[ne+1];
      }
      // Calculate the basis function and variables at the gauss points
      basis.getBasis(gp, xx, uu, uuold, ddep);

      // Loop over Nodes in Element
      for (int i=0; i< 2; i++) {
	row=OverlapMap->GID(ne+i);
	if (StandardMap->MyGID(row)) {
	  if ( fillF ) {

            // First do time derivative and diffusion operator
	    (*rhs)[StandardMap->LID(OverlapMap->GID(ne+i))]+=
	      +basis.wt*basis.dx
	      *((basis.uu - basis.uuold)/dt * basis.phi[i] 
              +(1.0/(basis.dx*basis.dx))*diffCoef*basis.duu*basis.dphide[i]);

            // Then do source term contributions
	    //
            for( srcTermIter = SrcTermWeight.begin(); 
                          srcTermIter != srcTermEnd; srcTermIter++) {
              HMX_PDE &srcTermProb = 
                       dynamic_cast<HMX_PDE&>(
			       myManager->getProblem((*srcTermIter).first) );
              srcTermProb.computeSourceTerm(2, depVars, srcTerm);
              (*rhs)[StandardMap->LID(OverlapMap->GID(ne+i))]+=
                +basis.wt*basis.dx
                *( basis.phi[i] * ( - (*srcTermIter).second * srcTerm[i] ));
            }
	    //
	  }
	}
	// Loop over Trial Functions
	if ( fillMatrix ) {
		/*
	  for(j=0;j < 2; j++) {
	    if (StandardMap->MyGID(row)) {
	      column=OverlapMap->GID(ne+j);
	      jac=basis.wt*basis.dx*(
                      basis.phi[j]/dt*basis.phi[i] 
                      +(1.0/(basis.dx*basis.dx))*diffCoef*basis.dphide[j]*
                                                        basis.dphide[i]
                      + basis.phi[i] * ( (beta+1.0)*basis.phi[j]
                      - 2.0*basis.uu*basis.phi[j]*basis.ddep[id_spec]) );  
	      ierr=A->SumIntoGlobalValues(row, 1, &jac, &column);
	    }
	  }
   */
	}
      }
    }
  } 

  // Apply Dirichlet BC for Temperature problem only (for now); this implies
  // no-flux across domain boundary for all species.
  if( getName() == tempFieldName ) 
  {
    // Insert Boundary Conditions and modify Jacobian and function (F)
    // U(0)=1
    if (MyPID==0) 
    {
      if ( fillF )
        (*rhs)[0]= (*soln)[0] - alpha;
      if ( fillMatrix ) 
      {
        int column=0;
        double jac=1.0;
        A->ReplaceGlobalValues(0, 1, &jac, &column);
        column=1;
        jac=0.0;
        A->ReplaceGlobalValues(0, 1, &jac, &column);
      }
    }
    // U(1)=1
    if ( StandardMap->LID(StandardMap->MaxAllGID()) >= 0 ) 
    {
      int lastDof = StandardMap->LID(StandardMap->MaxAllGID());
      if ( fillF )
        (*rhs)[lastDof] = (*soln)[lastDof] - alpha;
      if ( fillMatrix ) 
      {
        int row=StandardMap->MaxAllGID();
        int column = row;
        double jac = 1.0;
        A->ReplaceGlobalValues(row, 1, &jac, &column);
        jac=0.0;
        column--;
        A->ReplaceGlobalValues(row, 1, &jac, &column);
      }
    }
  }

  // Sync up processors to be safe
  Comm->Barrier();
 
  A->FillComplete();

#ifdef DEBUG
  A->Print(cout);

  if( fillF )
    std::cout << "For residual fill :" << std::endl << *rhs << std::endl;

  if( fillMatrix ) 
  {
    std::cout << "For jacobian fill :" << std::endl;
    A->Print(cout);
  }
#endif

  // Cleanup
  for( int i = 0; i < numDep; ++i)
  {
    delete [] ddep[i];
    delete     dep[i];
  }
  delete [] srcTerm;

  return true;
}
Exemple #3
0
// Matrix and Residual Fills
bool 
ConvDiff_PDE::evaluate(
                    NOX::Epetra::Interface::Required::FillType flag,
		    const Epetra_Vector * soln, 
		    Epetra_Vector * rhs)
{

  if( rhs == 0 ) 
  {
    std::string msg = "ERROR: ConvDiff_PDE::evaluate : callback appears to be other than a residual fill.  Others are not support for this type.";
    throw msg;
  }

  int numDep = depProblems.size();

  // Create the overlapped solution and position vectors
  Epetra_Vector u(*OverlapMap);
  Epetra_Vector uold(*OverlapMap);
  std::vector<Epetra_Vector*> dep(numDep);
  for( int i = 0; i < numDep; ++i)
    dep[i] = new Epetra_Vector(*OverlapMap);

  Epetra_Vector xvec(*OverlapMap);

  // Export Solution to Overlap vector
  // If the vector to be used in the fill is already in the Overlap form,
  // we simply need to map on-processor from column-space indices to
  // OverlapMap indices. Note that the old solution is simply fixed data that
  // needs to be sent to an OverlapMap (ghosted) vector.  The conditional
  // treatment for the current soution vector arises from use of
  // FD coloring in parallel.

  uold.Import(*oldSolution, *Importer, Insert);

  for( int i = 0; i < numDep; ++i )
    (*dep[i]).Import(*( (*(depSolutions.find(depProblems[i]))).second ), *Importer, Insert);

  xvec.Import(*xptr, *Importer, Insert);

  if( flag == NOX::Epetra::Interface::Required::FD_Res)
    // Overlap vector for solution received from FD coloring, so simply reorder
    // on processor
    u.Export(*soln, *ColumnToOverlapImporter, Insert);
  else // Communication to Overlap vector is needed
    u.Import(*soln, *Importer, Insert);

  // Declare required variables
  int OverlapNumMyNodes = OverlapMap->NumMyElements();

  int OverlapMinMyNodeGID;
  if (MyPID==0) OverlapMinMyNodeGID = StandardMap->MinMyGID();
  else OverlapMinMyNodeGID = StandardMap->MinMyGID()-1;

  int row;

  double * xx    = new double[2];
  double * uu    = new double[2]; 
  double * uuold = new double[2];
  std::vector<double*> ddep(numDep);
  for( int i = 0; i < numDep; ++i)
    ddep[i] = new double[2];

  Basis basis;

  // Bundle up the dependent variables in the way needed for computing
  // the source terms of each reaction
  map<string, double*> depVars;
  depVars.insert( pair< std::string, double*>(getName(), uu) );
  for( int i = 0; i < numDep; ++i )
    depVars.insert( pair<string, double*>(myManager->getProblemName(depProblems[i]), ddep[i]) );

  // Zero out the objects that will be filled
  rhs->PutScalar(0.0);

  // Loop Over # of Finite Elements on Processor
  for( int ne = 0; ne < OverlapNumMyNodes-1; ++ne )
  {
    // Loop Over Gauss Points
    for( int gp = 0; gp < 2; ++gp ) 
    {
      // Get the solution and coordinates at the nodes 
      xx[0]=xvec[ne];
      xx[1]=xvec[ne+1];
      uu[0] = u[ne];
      uu[1] = u[ne+1];
      uuold[0] = uold[ne];
      uuold[1] = uold[ne+1];
      for( int i = 0; i < numDep; ++i ) 
      {
        ddep[i][0] = (*dep[i])[ne];
        ddep[i][1] = (*dep[i])[ne+1];
      }
      // Calculate the basis function and variables at the gauss points
      basis.getBasis(gp, xx, uu, uuold, ddep);

      // Loop over Nodes in Element
      for( int i = 0; i < 2; ++i )
      {
	row = OverlapMap->GID(ne+i);
	if( StandardMap->MyGID(row) ) 
        {
          (*rhs)[StandardMap->LID(OverlapMap->GID(ne+i))] +=
            + basis.wt * basis.dx
            * ( peclet * (basis.duu / basis.dx) * basis.phi[i] 
            +   kappa * (1.0/(basis.dx*basis.dx)) * basis.duu * basis.dphide[i] );
	}
      }
    }
  } 

  //if( NOX::Epetra::Interface::Required::Residual == flag )
  //{
  //  int lastDof = StandardMap->LID(StandardMap->MaxAllGID());
  //  std::cout << "\t\"" << myName << "\" u[0] = " << (*soln)[0] 
  //       << "\tu[N] = " << (*soln)[lastDof] << std::endl;
  //  std::cout << "\t\"" << myName << "\" RHS[0] = " << (*rhs)[0] 
  //       << "\tRHS[N] = " << (*rhs)[lastDof] << std::endl << std::endl;
  //}


  // Apply BCs

  computeHeatFlux( soln );

  double bcResidual = bcWeight         * (myFlux - depProbPtr->getHeatFlux()                 ) -
                      (1.0 - bcWeight) * (u[interface_node] - depProbPtr->getInterfaceTemp() );

  int lastDof = StandardMap->LID(StandardMap->MaxAllGID());

  // "Left" boundary
  if( LEFT == myInterface ) // this may break in parallel
  {
    (*rhs)[0]       = bcResidual;
    (*rhs)[lastDof] = (*soln)[lastDof] - Tright;
  }
  // "Right" boundary
  else
  {
    (*rhs)[0]       = (*soln)[0] - Tleft;
    (*rhs)[lastDof] = bcResidual;
  }

  // Sync up processors to be safe
  Comm->Barrier();
 
  A->FillComplete();

#ifdef DEBUG
  std::cout << "For residual fill :" << std::endl << *rhs << std::endl;
#endif

  // Cleanup
  for( int i = 0; i < numDep; ++i)
  {
    delete [] ddep[i];
    delete     dep[i];
  }

  delete [] xx    ;
  delete [] uu    ;
  delete [] uuold ;

  return true;
}
bool 
PelletTransport::evaluate(NOX::Epetra::Interface::Required::FillType fType, 
				    const Epetra_Vector* soln, 
				    Epetra_Vector* tmp_rhs, 
				    Epetra_RowMatrix* tmp_matrix)
{

  if( fType == NOX::Epetra::Interface::Required::Jac ) 
  {
    cout << "This problem only works for Finite-Difference or Matrix-Free Based Jacobians." 
         << " No analytic Jacobian fill available !!" << endl;
    throw "Problem ERROR";
  }
  else 
    rhs = new Epetra_Vector(*OverlapMap);

  // Create the overlapped solution and position vectors
  Epetra_Vector u(*OverlapMap);
  Epetra_Vector uold(*OverlapMap);
  Epetra_Vector xvec(*OverlapNodeMap);

  // Export Solution to Overlap vector
  uold.Import(*oldSolution, *Importer, Insert);
  xvec.Import(*xptr, *nodeImporter, Insert);
  u.Import(*soln, *Importer, Insert);

  // Declare required variables
  int i;
  int OverlapNumMyNodes = OverlapNodeMap->NumMyElements();

  MaterialPropBase::PropData materialProps;
  // Hard-code use of UO2 for now - RWH 5/14/2007
  string fixedType = "UO2";
  
  int OverlapMinMyNodeGID;
  if (MyPID==0) OverlapMinMyNodeGID = StandardNodeMap->MinMyGID();
  else OverlapMinMyNodeGID = StandardNodeMap->MinMyGID()-1;

  int row1, row2;
  double term1, term2;
  double flux1, flux2;
  double xx[2];
  double uu[2*NUMSPECIES]; // Use of the anonymous enum is needed for SGI builds
  double uuold[2*NUMSPECIES];
  Basis basis(NumSpecies);

  
  // Zero out the objects that will be filled
  rhs->PutScalar(0.0);

  ACTIVE_REGIONS propType;

  // Loop Over # of Finite Elements on Processor
  for( int ne = 0; ne < OverlapNumMyNodes - 1; ++ne )
  {
    propType = (ACTIVE_REGIONS) (*elemTypes)[ne];

    // Loop Over Gauss Points
    for( int gp = 0; gp < 2; ++gp )
    {
      // Get the solution and coordinates at the nodes 
      xx[0] = xvec[ne];
      xx[1] = xvec[ne+1];
      for (int k=0; k<NumSpecies; k++) {
        uu[NumSpecies * 0 + k] = u[NumSpecies * ne + k];
        uu[NumSpecies * 1 + k] = u[NumSpecies * (ne+1) + k];
        uuold[NumSpecies * 0 + k] = uold[NumSpecies * ne + k];
        uuold[NumSpecies * 1 + k] = uold[NumSpecies * (ne+1) + k];
      }
      // Calculate the basis function at the gauss point
      basis.getBasis(gp, xx, uu, uuold);
      MaterialPropFactory::computeProps( propType, basis.uu[0], basis.uu[1], materialProps );
      double & rho1    = materialProps.density  ;
      double & k1      = materialProps.k_thermal;
      double & Cp1     = materialProps.Cp       ;
      double & Qstar1  = materialProps.Qstar    ;
      double & Qdot1   = materialProps.Qdot     ;
      double & Ffunc   = materialProps.thermoF  ;
      double & D_diff1 = materialProps.D_diff   ;

	            
      // Loop over Nodes in Element
      for( i = 0; i < 2; ++i ) 
      {
	row1=OverlapMap->GID(NumSpecies * (ne+i));
	row2=OverlapMap->GID(NumSpecies * (ne+i) + 1);
        flux1 = -k1*basis.duu[0]/basis.dx;
        flux2 = -0.5*D_diff1*(basis.duu[1]/basis.dx 
              + basis.uu[1]*Qstar1/(Ffunc*8.3142*basis.uu[0]*basis.uu[0])*basis.duu[0]/basis.dx);
        term1 = basis.wt*basis.dx*basis.xx*( 
                    rho1*Cp1*(basis.uu[0] - basis.uuold[0])/dt * basis.phi[i] 
                  - flux1*basis.dphide[i]/basis.dx
                  - Qdot1*basis.phi[i]
                );
        term2 = basis.wt*basis.dx*basis.xx*(
                    0.5*(basis.uu[1] - basis.uuold[1])/dt * basis.phi[i] 
                  - flux2*basis.dphide[i]/basis.dx 
                );
        (*rhs)[NumSpecies*(ne+i)]   += term1;
        (*rhs)[NumSpecies*(ne+i)+1] += term2;
      }
    }
  }

  // Insert Boundary Conditions and modify Jacobian and function (F)
  // Dirichlet BCs at xminUO2
  const double xB = dynamic_cast<const MaterialProp_UO2 &>(MaterialPropFactory::factory().get_model(PelletTransport::UO2)).get_xB();
  if (MyPID==0) 
  {
    // Use no-flux BCs
    //(*rhs)[0]= (*soln)[0] - 0.6;
    //(*rhs)[1]= (*soln)[1] - 10.0/3.0;
  }
  // Dirichlet BCs at xmaxUO2
  if( StandardMap->LID(NumSpecies*(NumGlobalElementsUO2)) >= 0 ) 
  {
    int lastUO2Dof = StandardMap->LID(NumSpecies*(NumGlobalElementsUO2) + 1);
    //(*rhs)[lastDof - 1] = (*soln)[lastDof - 1] - 840.0;
    (*rhs)[lastUO2Dof] = (*soln)[lastUO2Dof] - xB;
  }
  // Dirichlet BCs at all He and Clad species variables
  int lastUO2DofGID = NumSpecies*NumGlobalElementsUO2 + 1;
  int lastGID = StandardMap->MaxAllGID();
  for( int i = lastUO2DofGID; i < lastGID; i+=2 )
    if( StandardMap->LID(i) >= 0 ) 
      (*rhs)[StandardMap->LID(i)] = (*soln)[StandardMap->LID(i)] - xB;
    
  // Dirichlet BCs at xmaxClad
  if( StandardMap->LID(StandardMap->MaxAllGID()) >= 0 ) 
  {
    int lastDof = StandardMap->LID(StandardMap->MaxAllGID());
    (*rhs)[lastDof - 1] = (*soln)[lastDof - 1] - 750.0;
    (*rhs)[lastDof] = (*soln)[lastDof] - xB;
  }

  // Sync up processors to be safe
  Comm->Barrier();
 
  // Do an assemble for overlap nodes
  tmp_rhs->Export(*rhs, *Importer, Add);

  delete rhs;

  return true;
}