BoundaryConditionsContainerImplementation.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2009
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #ifndef _BOUNDARYCONDITIONSCONTAINERIMPLEMENTATION_HPP_
00030 #define _BOUNDARYCONDITIONSCONTAINERIMPLEMENTATION_HPP_
00031 
00032 #include "BoundaryConditionsContainer.hpp"
00033 #include "DistributedVector.hpp"
00034 #include "ConstBoundaryCondition.hpp"
00035 
00036 #include "PetscTools.hpp" //temporary
00037 
00038 
00039 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00040 BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::BoundaryConditionsContainer()
00041             : AbstractBoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>()
00042 {
00043     for (unsigned index_of_unknown=0; index_of_unknown<PROBLEM_DIM; index_of_unknown++)
00044     {
00045         mpNeumannMap[index_of_unknown] = new std::map< const BoundaryElement<ELEM_DIM-1, SPACE_DIM> *, const AbstractBoundaryCondition<SPACE_DIM>*>;
00046 
00047         mAnyNonZeroNeumannConditionsForUnknown[index_of_unknown] = false;
00048         mLastNeumannCondition[index_of_unknown] = mpNeumannMap[index_of_unknown]->begin();
00049     }
00050     
00051     // This zero boundary condition is only used in AddNeumannBoundaryCondition
00052     mpZeroBoundaryCondition = new ConstBoundaryCondition<SPACE_DIM>(0.0);
00053 }
00054 
00055 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00056 BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::~BoundaryConditionsContainer()
00057 {
00058     
00059     // Keep track of what boundary condition objects we've deleted
00060     std::set<const AbstractBoundaryCondition<SPACE_DIM>*> deleted_conditions;
00061     for (unsigned i=0; i<PROBLEM_DIM; i++)
00062     {
00063         NeumannMapIterator neumann_iterator = mpNeumannMap[i]->begin();
00064         while (neumann_iterator != mpNeumannMap[i]->end() )
00065         {
00066             
00067             if (deleted_conditions.count(neumann_iterator->second) == 0)
00068             {
00069                 deleted_conditions.insert(neumann_iterator->second);
00070                 //Leave the zero boundary condition until last
00071                 if (neumann_iterator->second != mpZeroBoundaryCondition)
00072                 {
00073                     delete neumann_iterator->second;
00074                 }
00075             }
00076             neumann_iterator++;
00077         }
00078         delete(mpNeumannMap[i]);
00079     }
00080 
00081     delete mpZeroBoundaryCondition;   
00082 
00083     this->DeleteDirichletBoundaryConditions(deleted_conditions);
00084 
00085 }
00086 
00087 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00088 void BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::AddDirichletBoundaryCondition( const Node<SPACE_DIM> *  pBoundaryNode,
00089                                         const AbstractBoundaryCondition<SPACE_DIM> * pBoundaryCondition,
00090                                         unsigned indexOfUnknown,
00091                                         bool checkIfBoundaryNode)
00092 {
00093     assert(indexOfUnknown < PROBLEM_DIM);
00094     if (checkIfBoundaryNode)
00095     {
00096         assert( pBoundaryNode->IsBoundaryNode());
00097     }
00098 
00099     (*(this->mpDirichletMap[indexOfUnknown]))[pBoundaryNode] = pBoundaryCondition;
00100 }
00101 
00102 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00103 void BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::AddNeumannBoundaryCondition( const BoundaryElement<ELEM_DIM-1, SPACE_DIM> * pBoundaryElement,
00104                                       const AbstractBoundaryCondition<SPACE_DIM> * pBoundaryCondition,
00105                                       unsigned indexOfUnknown)
00106 {
00107     assert(indexOfUnknown < PROBLEM_DIM);
00108 
00109     // we assume that this could be a non-zero boundary condition
00110     mAnyNonZeroNeumannConditionsForUnknown[indexOfUnknown] = true;
00111 
00112     for(unsigned unknown=0; unknown<PROBLEM_DIM; unknown++)
00113     {
00114         if(unknown==indexOfUnknown)
00115         {
00116             (*(mpNeumannMap[indexOfUnknown]))[pBoundaryElement] = pBoundaryCondition;
00117         }
00118         else
00119         {
00120             // if can't find pBoundaryElement in map[unknown]
00121             if( mpNeumannMap[unknown]->find(pBoundaryElement)==mpNeumannMap[unknown]->end() )
00122             {
00123                 // add zero bc to other unknowns (so all maps are in sync)
00124                 (*(mpNeumannMap[unknown]))[pBoundaryElement] = mpZeroBoundaryCondition;
00125             }
00126         }
00127     }
00128 }
00129 
00130 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00131 void BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::DefineZeroDirichletOnMeshBoundary(AbstractMesh<ELEM_DIM,SPACE_DIM>* pMesh,
00132                                            unsigned indexOfUnknown)
00133 {
00134     this->DefineConstantDirichletOnMeshBoundary(pMesh, 0.0, indexOfUnknown);
00135 }
00136 
00137 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00138 void BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::DefineConstantDirichletOnMeshBoundary(AbstractMesh<ELEM_DIM,SPACE_DIM>* pMesh,
00139                                                double value,
00140                                                unsigned indexOfUnknown)
00141 {
00142     assert(indexOfUnknown < PROBLEM_DIM);
00143     //In applying a condition to the boundary, we need to be sure that the boundary exists
00144     assert(pMesh->GetNumBoundaryNodes() > 0);
00145 
00146     ConstBoundaryCondition<SPACE_DIM>* p_boundary_condition =
00147         new ConstBoundaryCondition<SPACE_DIM>( value );
00148 
00149     typename AbstractMesh<ELEM_DIM, SPACE_DIM>::BoundaryNodeIterator iter;
00150     iter = pMesh->GetBoundaryNodeIteratorBegin();
00151     while (iter != pMesh->GetBoundaryNodeIteratorEnd())
00152     {
00153         AddDirichletBoundaryCondition(*iter, p_boundary_condition, indexOfUnknown);
00154         iter++;
00155     }
00156 }
00157 
00158 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00159 void BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::DefineZeroNeumannOnMeshBoundary(AbstractMesh<ELEM_DIM,SPACE_DIM>* pMesh,
00160                                          unsigned indexOfUnknown)
00161 {
00162     assert(indexOfUnknown < PROBLEM_DIM);
00163     //In applying a condition to the boundary, we need to be sure that the boundary exists
00164     assert(pMesh->GetNumBoundaryElements() > 0);
00165     ConstBoundaryCondition<SPACE_DIM>* p_zero_boundary_condition =
00166         new ConstBoundaryCondition<SPACE_DIM>( 0.0 );
00167 
00168     typename AbstractMesh<ELEM_DIM, SPACE_DIM>::BoundaryElementIterator iter;
00169     iter = pMesh->GetBoundaryElementIteratorBegin();
00170     while (iter != pMesh->GetBoundaryElementIteratorEnd())
00171     {
00172         AddNeumannBoundaryCondition(*iter, p_zero_boundary_condition, indexOfUnknown);
00173         iter++;
00174     }
00175 
00176     mAnyNonZeroNeumannConditionsForUnknown[indexOfUnknown] = false;
00177 }
00208 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00209 void BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::ApplyDirichletToLinearProblem(LinearSystem& rLinearSystem,
00210                                        bool applyToMatrix)
00211 {
00212     if (applyToMatrix)
00213     {
00214         //Modifications to the RHS are stored in the Dirichlet boundary conditions vector. This is done so 
00215         //that they can be reapplied at each time step.
00216         //Make a new vector to store the Dirichlet offsets in
00217         VecDuplicate(rLinearSystem.rGetRhsVector(), &(rLinearSystem.rGetDirichletBoundaryConditionsVector()));
00218         VecZeroEntries(rLinearSystem.rGetDirichletBoundaryConditionsVector());
00219         
00220 
00221 
00222         for (unsigned index_of_unknown=0; index_of_unknown<PROBLEM_DIM; index_of_unknown++)
00223         {
00224             this->mDirichIterator = this->mpDirichletMap[index_of_unknown]->begin();
00225     
00226             while (this->mDirichIterator != this->mpDirichletMap[index_of_unknown]->end() )
00227             {
00228                 unsigned node_index = this->mDirichIterator->first->GetIndex();
00229                 double value = this->mDirichIterator->second->GetValue(this->mDirichIterator->first->GetPoint());
00230     
00231                 unsigned row = PROBLEM_DIM*node_index + index_of_unknown;
00232                 unsigned col = row;
00233 
00234                 // Set up a vector which will store the columns of the matrix (column d, where d is
00235                 // the index of the row (and column) to be altered for the boundary condition
00236                 Vec matrix_col;
00237                 VecDuplicate(rLinearSystem.rGetRhsVector(), &matrix_col);
00238                 VecZeroEntries(matrix_col);
00239     
00240                 rLinearSystem.AssembleFinalLinearSystem(); 
00241                 Mat& r_mat = rLinearSystem.rGetLhsMatrix();
00242                 MatGetColumnVector(r_mat, matrix_col, col);
00243                 
00244                 //Zero the correct entry of the column
00245                 int indices[1] = {col};
00246                 double zero[1] = {0.0};
00247                 VecSetValues(matrix_col, 1, indices, zero, INSERT_VALUES); 
00248     
00249                 // Set up the RHS Dirichlet boundary conditions vector  
00250                 // Assuming one boundary at the zeroth node (x_0 = value), this is equal to 
00251                 //   -value*[0 a_21 a_31 .. a_N1]
00252                 // and will be added to the RHS.   
00253                 VecAXPY(rLinearSystem.rGetDirichletBoundaryConditionsVector(), -value, matrix_col);  
00254 
00255                 VecDestroy(matrix_col);
00256                 
00257                 //Zero out the appropriate row and column
00258                 rLinearSystem.ZeroMatrixRow(row);
00259                 rLinearSystem.ZeroMatrixColumn(col); // recall row=col
00260                 rLinearSystem.SetMatrixElement(row, row, 1);
00261 
00262                 this->mDirichIterator++;
00263                 
00264             }
00265         }
00266         
00267     }
00268     
00269     //Apply the RHS boundary conditions modification if required.
00270     if(rLinearSystem.rGetDirichletBoundaryConditionsVector())
00271     {
00272         VecAXPY(rLinearSystem.rGetRhsVector(), 1.0, rLinearSystem.rGetDirichletBoundaryConditionsVector());
00273     }
00274      
00275     //Apply the actual boundary condition to the RHS, note this must be done after the modification to the
00276     //RHS vector.
00277     for (unsigned index_of_unknown=0; index_of_unknown<PROBLEM_DIM; index_of_unknown++)
00278     {
00279         this->mDirichIterator = this->mpDirichletMap[index_of_unknown]->begin();
00280 
00281         while (this->mDirichIterator != this->mpDirichletMap[index_of_unknown]->end() )
00282         {
00283             unsigned node_index = this->mDirichIterator->first->GetIndex();
00284             double value = this->mDirichIterator->second->GetValue(this->mDirichIterator->first->GetPoint());
00285 
00286             unsigned row = PROBLEM_DIM*node_index + index_of_unknown;
00287             
00288             rLinearSystem.SetRhsVectorElement(row, value);
00289 
00290             this->mDirichIterator++;
00291         }
00292     }    
00293 }
00294 
00295 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00296 void BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::ApplyDirichletToNonlinearResidual(const Vec currentSolution, Vec residual)
00297 {
00298     for (unsigned index_of_unknown=0; index_of_unknown<PROBLEM_DIM; index_of_unknown++)
00299     {
00300         this->mDirichIterator = this->mpDirichletMap[index_of_unknown]->begin();
00301 
00302         DistributedVector solution_distributed(currentSolution);
00303         DistributedVector residual_distributed(residual);
00304 
00305 
00306         while (this->mDirichIterator != this->mpDirichletMap[index_of_unknown]->end() )
00307         {
00308             DistributedVector::Stripe solution_stripe(solution_distributed, index_of_unknown);
00309             DistributedVector::Stripe residual_stripe(residual_distributed, index_of_unknown);
00310 
00311             unsigned node_index = this->mDirichIterator->first->GetIndex();
00312 
00313             double value = this->mDirichIterator->second->GetValue(this->mDirichIterator->first->GetPoint());
00314 
00315             if (DistributedVector::IsGlobalIndexLocal(node_index))
00316             {
00317                 residual_stripe[node_index]=solution_stripe[node_index] - value;
00318             }
00319             this->mDirichIterator++;
00320         }
00321         solution_distributed.Restore();
00322         residual_distributed.Restore();
00323     }
00324 }
00325     
00326 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>    
00327 void BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::ApplyDirichletToNonlinearJacobian(Mat jacobian)
00328 {
00329     for (unsigned index_of_unknown=0; index_of_unknown<PROBLEM_DIM; index_of_unknown++)
00330     {
00331         this->mDirichIterator = this->mpDirichletMap[index_of_unknown]->begin();
00332         PetscInt irows, icols;
00333         double value;
00334         MatGetSize(jacobian, &irows, &icols);
00335         unsigned cols=icols;
00336 
00337         while (this->mDirichIterator != this->mpDirichletMap[index_of_unknown]->end() )
00338         {
00339             unsigned node_index = this->mDirichIterator->first->GetIndex();
00340 
00341             unsigned row_index = PROBLEM_DIM*node_index + index_of_unknown;
00342             assert(row_index<(unsigned)irows);
00343 
00344             for (unsigned col_index=0; col_index<cols; col_index++)
00345             {
00346                 value = (col_index == row_index) ? 1.0 : 0.0;
00347                 MatSetValue(jacobian, row_index, col_index, value, INSERT_VALUES);
00348             }
00349             this->mDirichIterator++;
00350         }
00351     }
00352 }    
00353 
00354 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00355 bool BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::Validate(AbstractMesh<ELEM_DIM,SPACE_DIM> *pMesh)
00356 {
00357     bool valid = true;
00358 
00359     for (unsigned index_of_unknown=0; index_of_unknown<PROBLEM_DIM; index_of_unknown++)
00360     {
00361         // Iterate over surface elements
00362         typename AbstractMesh<ELEM_DIM,SPACE_DIM>::BoundaryElementIterator elt_iter
00363         = pMesh->GetBoundaryElementIteratorBegin();
00364         while (valid && elt_iter != pMesh->GetBoundaryElementIteratorEnd())
00365         {
00366             if (!HasNeumannBoundaryCondition(*elt_iter, index_of_unknown))
00367             {
00368                 // Check for Dirichlet conditions on this element's nodes
00369                 for (unsigned i=0; i<(*elt_iter)->GetNumNodes(); i++)
00370                 {
00371                     if (!HasDirichletBoundaryCondition((*elt_iter)->GetNode(i)))
00372                     {
00373                         valid = false;
00374                     }
00375                 }
00376             }
00377             elt_iter++;
00378         }
00379     }
00380     return valid;
00381 }
00382 
00383 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00384 double BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::GetNeumannBCValue(const BoundaryElement<ELEM_DIM-1,SPACE_DIM>* pSurfaceElement,
00385                              const ChastePoint<SPACE_DIM>& x,
00386                              unsigned indexOfUnknown)
00387 {
00388     assert(indexOfUnknown < PROBLEM_DIM);
00389 
00390     // Did we see this condition on the last search we did?
00391     if (mLastNeumannCondition[indexOfUnknown] == mpNeumannMap[indexOfUnknown]->end() ||
00392         mLastNeumannCondition[indexOfUnknown]->first != pSurfaceElement)
00393     {
00394         mLastNeumannCondition[indexOfUnknown] = mpNeumannMap[indexOfUnknown]->find(pSurfaceElement);
00395     }
00396     if (mLastNeumannCondition[indexOfUnknown] == mpNeumannMap[indexOfUnknown]->end())
00397     {
00398         // No Neumann condition is equivalent to a zero Neumann condition
00399         return 0.0;
00400     }
00401     else
00402     {
00403         return mLastNeumannCondition[indexOfUnknown]->second->GetValue(x);
00404     }
00405 }
00406 
00407 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00408 bool BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::HasNeumannBoundaryCondition(const BoundaryElement<ELEM_DIM-1,SPACE_DIM>* pSurfaceElement,
00409                                      unsigned indexOfUnknown)
00410 {
00411     assert(indexOfUnknown < PROBLEM_DIM);
00412 
00413     mLastNeumannCondition[indexOfUnknown] = mpNeumannMap[indexOfUnknown]->find(pSurfaceElement);
00414 
00415     return (mLastNeumannCondition[indexOfUnknown] != mpNeumannMap[indexOfUnknown]->end());
00416 }
00417 
00418 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00419 bool BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::AnyNonZeroNeumannConditions()
00420 {
00421     bool ret = false;
00422     for (unsigned index_of_unknown=0; index_of_unknown<PROBLEM_DIM; index_of_unknown++)
00423     {
00424         if (mAnyNonZeroNeumannConditionsForUnknown[index_of_unknown] == true)
00425         {
00426             ret = true;
00427         }
00428     }
00429     return ret;
00430 }
00431 
00432 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00433 typename BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::NeumannMapIterator BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::BeginNeumann()
00434 {
00435     // [0] is ok as all maps will be in sync due to the way ApplyNeumannBoundaryCondition works
00436     return mpNeumannMap[0]->begin();
00437 }
00438 
00439 template<unsigned ELEM_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00440 typename BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::NeumannMapIterator BoundaryConditionsContainer<ELEM_DIM,SPACE_DIM,PROBLEM_DIM>::EndNeumann()
00441 {
00442     // [0] is ok as all maps will be in sync due to the way ApplyNeumannBoundaryCondition works
00443     return mpNeumannMap[0]->end();
00444 }
00445 
00446 #endif // _BOUNDARYCONDITIONSCONTAINERIMPLEMENTATION_HPP_

Generated on Wed Mar 18 12:51:56 2009 for Chaste by  doxygen 1.5.5