Chaste Release::3.1
BoundaryConditionsContainer.hpp
00001 /*
00002 
00003 Copyright (c) 2005-2012, University of Oxford.
00004 All rights reserved.
00005 
00006 University of Oxford means the Chancellor, Masters and Scholars of the
00007 University of Oxford, having an administrative office at Wellington
00008 Square, Oxford OX1 2JD, UK.
00009 
00010 This file is part of Chaste.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014  * Redistributions of source code must retain the above copyright notice,
00015    this list of conditions and the following disclaimer.
00016  * Redistributions in binary form must reproduce the above copyright notice,
00017    this list of conditions and the following disclaimer in the documentation
00018    and/or other materials provided with the distribution.
00019  * Neither the name of the University of Oxford nor the names of its
00020    contributors may be used to endorse or promote products derived from this
00021    software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 
00036 #ifndef _BOUNDARYCONDITIONSCONTAINER_HPP_
00037 #define _BOUNDARYCONDITIONSCONTAINER_HPP_
00038 
00039 #include <map>
00040 #include "ChasteSerialization.hpp"
00041 #include <boost/serialization/split_member.hpp>
00042 #include <boost/serialization/map.hpp>
00043 
00044 #include "AbstractBoundaryConditionsContainer.hpp"
00045 #include "AbstractBoundaryCondition.hpp"
00046 #include "AbstractTetrahedralMesh.hpp"
00047 #include "BoundaryElement.hpp"
00048 #include "Node.hpp"
00049 #include "LinearSystem.hpp"
00050 #include "PetscException.hpp"
00051 #include "ChastePoint.hpp"
00052 #include "ConstBoundaryCondition.hpp"
00053 #include "DistributedVectorFactory.hpp"
00054 
00066 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00067 class BoundaryConditionsContainer : public AbstractBoundaryConditionsContainer<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>
00068 {
00069 public:
00070 
00072     typedef typename std::map< const BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>*, const AbstractBoundaryCondition<SPACE_DIM>* >::const_iterator
00073         NeumannMapIterator;
00074 
00076     typedef AbstractBoundaryConditionsContainer<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM> BaseClassType;
00077 
00078 private:
00079 
00080     std::map< const BoundaryElement<ELEMENT_DIM-1, SPACE_DIM> *, const AbstractBoundaryCondition<SPACE_DIM>* >*
00081         mpNeumannMap[PROBLEM_DIM]; 
00084     std::map< const Node<SPACE_DIM> *, const Node<SPACE_DIM> * >*  mpPeriodicBcMap[PROBLEM_DIM];
00085 
00089     NeumannMapIterator mLastNeumannCondition[PROBLEM_DIM];
00090 
00094     bool mAnyNonZeroNeumannConditionsForUnknown[PROBLEM_DIM];
00095 
00097     ConstBoundaryCondition<SPACE_DIM>* mpZeroBoundaryCondition;
00098 
00100     bool mLoadedFromArchive;
00101 
00102 public:
00103 
00110     BoundaryConditionsContainer(bool deleteConditions=true);
00111 
00116     ~BoundaryConditionsContainer();
00117 
00130     void AddDirichletBoundaryCondition(const Node<SPACE_DIM>* pBoundaryNode,
00131                                        const AbstractBoundaryCondition<SPACE_DIM>* pBoundaryCondition,
00132                                        unsigned indexOfUnknown = 0,
00133                                        bool checkIfBoundaryNode = true);
00134 
00153     void AddNeumannBoundaryCondition(const BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>* pBoundaryElement,
00154                                      const AbstractBoundaryCondition<SPACE_DIM>* pBoundaryCondition,
00155                                      unsigned indexOfUnknown = 0);
00156 
00157 
00165     void AddPeriodicBoundaryCondition(const Node<SPACE_DIM>* pNode1,
00166                                       const Node<SPACE_DIM>* pNode2);
00167 
00168 
00176     void DefineZeroDirichletOnMeshBoundary(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh,
00177                                            unsigned indexOfUnknown = 0);
00178 
00187     void DefineConstantDirichletOnMeshBoundary(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh,
00188                                                double value,
00189                                                unsigned indexOfUnknown = 0);
00190 
00198     void DefineZeroNeumannOnMeshBoundary(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh,
00199                                          unsigned indexOfUnknown = 0);
00200 
00215     void ApplyDirichletToLinearProblem(LinearSystem& rLinearSystem,
00216                                        bool applyToMatrix = true,
00217                                        bool applyToRhsVector = true);
00218 
00219 
00220 
00240     void ApplyPeriodicBcsToLinearProblem(LinearSystem& rLinearSystem,
00241                                          bool applyToMatrix = true,
00242                                          bool applyToRhsVector = true);
00243 
00256     void ApplyDirichletToNonlinearResidual(const Vec currentSolution, Vec residual,
00257                                            DistributedVectorFactory& rFactory);
00258 
00269     void ApplyDirichletToNonlinearJacobian(Mat jacobian);
00270 
00281     bool Validate(AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh);
00282 
00292     double GetNeumannBCValue(const BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>* pSurfaceElement,
00293                              const ChastePoint<SPACE_DIM>& rX,
00294                              unsigned indexOfUnknown = 0);
00295 
00305     bool HasNeumannBoundaryCondition(const BoundaryElement<ELEMENT_DIM-1,SPACE_DIM>* pSurfaceElement,
00306                                      unsigned indexOfUnknown = 0);
00307 
00311     bool AnyNonZeroNeumannConditions();
00312 
00316     NeumannMapIterator BeginNeumann();
00317 
00321     NeumannMapIterator EndNeumann();
00322 
00336     template <class Archive>
00337     void LoadFromArchive(Archive & archive, AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00338     {
00339         if (mLoadedFromArchive)
00340         {
00341             return;
00342         }
00343 
00344         MergeFromArchive(archive, pMesh);
00345     }
00346 
00356     template <class Archive>
00357     void MergeFromArchive(Archive & archive, AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh);
00358 
00359 private:
00360 
00362     friend class boost::serialization::access;
00363 
00370     template<class Archive>
00371     void save(Archive & archive, const unsigned int version) const;
00372 
00390     template<class Archive>
00391     void load(Archive & archive, const unsigned int version)
00392     {
00393     }
00394 
00395     BOOST_SERIALIZATION_SPLIT_MEMBER()
00396 };
00397 
00398 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00399 template<class Archive>
00400 void BoundaryConditionsContainer<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::save(
00401         Archive & archive, const unsigned int version) const
00402 {
00403     typedef typename std::map<unsigned, const AbstractBoundaryCondition<SPACE_DIM> *> archive_map_type;
00404 
00405     // Save Dirichlet conditions
00406     for (unsigned index_of_unknown=0; index_of_unknown<PROBLEM_DIM; index_of_unknown++)
00407     {
00408         archive_map_type bc_map;
00409         typename BaseClassType::DirichletIteratorType it = this->mpDirichletMap[index_of_unknown]->begin();
00410         while (it != this->mpDirichletMap[index_of_unknown]->end() )
00411         {
00412             unsigned node_index = it->first->GetIndex();
00413             const AbstractBoundaryCondition<SPACE_DIM> * p_cond = it->second;
00414             bc_map[node_index] = p_cond;
00415 
00416             it++;
00417         }
00418         archive & bc_map;
00419     }
00420 
00421     // Save Neumann conditions
00422     for (unsigned index_of_unknown=0; index_of_unknown<PROBLEM_DIM; index_of_unknown++)
00423     {
00424         archive_map_type bc_map;
00425         for (NeumannMapIterator it = mpNeumannMap[index_of_unknown]->begin();
00426              it != mpNeumannMap[index_of_unknown]->end();
00427              ++it)
00428         {
00429             unsigned elem_index = it->first->GetIndex();
00430             const AbstractBoundaryCondition<SPACE_DIM>* p_cond = it->second;
00431             bc_map[elem_index] = p_cond;
00432         }
00433         archive & bc_map;
00434     }
00435 }
00436 
00437 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM, unsigned PROBLEM_DIM>
00438 template<class Archive>
00439 void BoundaryConditionsContainer<ELEMENT_DIM,SPACE_DIM,PROBLEM_DIM>::MergeFromArchive(
00440         Archive & archive, AbstractTetrahedralMesh<ELEMENT_DIM,SPACE_DIM>* pMesh)
00441 {
00442     mLoadedFromArchive = true;
00443 
00444     typedef typename std::map<unsigned, AbstractBoundaryCondition<SPACE_DIM>*> archive_map_type;
00445 
00446     // Keep track of conditions that might need deleting
00447     std::set<const AbstractBoundaryCondition<SPACE_DIM>*> maybe_unused_bcs;
00448     std::set<const AbstractBoundaryCondition<SPACE_DIM>*> used_bcs;
00449 
00450     // Load Dirichlet conditions
00451     for (unsigned index_of_unknown=0; index_of_unknown<PROBLEM_DIM; index_of_unknown++)
00452     {
00453         archive_map_type bc_map;
00454         archive & bc_map;
00455         for (typename archive_map_type::iterator it = bc_map.begin();
00456              it != bc_map.end();
00457              ++it)
00458         {
00459             unsigned node_index = it->first;
00460             this->mHasDirichletBCs=true;  //We know that a Dirichlet is being added, even if not by this process
00461             Node<SPACE_DIM>* p_node;
00462             try
00463             {
00464                 p_node = pMesh->GetNodeFromPrePermutationIndex(node_index);
00465             }
00466             catch (Exception& e)
00467             {
00468                 // It's a distributed mesh and we don't own this node - skip to the next BC
00469                 maybe_unused_bcs.insert(it->second);
00470                 continue;
00471             }
00472             AddDirichletBoundaryCondition(p_node, it->second, index_of_unknown, false);
00473             used_bcs.insert(it->second);
00474         }
00475     }
00476     this->mCheckedAndCommunicatedIfDirichletBcs=true; // Whether the Dirichlet BCC was empty or not, all processes know the status.
00477 
00478     // Load Neumann conditions
00479     for (unsigned index_of_unknown=0; index_of_unknown<PROBLEM_DIM; index_of_unknown++)
00480     {
00481         archive_map_type bc_map;
00482         archive & bc_map;
00483         for (typename archive_map_type::iterator it = bc_map.begin();
00484              it != bc_map.end();
00485              ++it)
00486         {
00487             unsigned boundary_element_index = it->first;
00488             BoundaryElement<ELEMENT_DIM-1, SPACE_DIM>* p_boundary_element;
00489             try
00490             {
00491                 p_boundary_element = pMesh->GetBoundaryElement(boundary_element_index);
00492             }
00493             catch (Exception& e)
00494             {
00495                 // It's a distributed mesh and we don't own this element - skip to the next BC
00496                 maybe_unused_bcs.insert(it->second);
00497                 continue;
00498             }
00499             AddNeumannBoundaryCondition(p_boundary_element, it->second, index_of_unknown);
00500             used_bcs.insert(it->second);
00501         }
00502     }
00503 
00504     // Free any unused BCs
00505     for (typename std::set<const AbstractBoundaryCondition<SPACE_DIM>*>::iterator it=maybe_unused_bcs.begin();
00506          it != maybe_unused_bcs.end();
00507          ++it)
00508     {
00509         typename std::set<const AbstractBoundaryCondition<SPACE_DIM>*>::iterator used = used_bcs.find(*it);
00510         if (used == used_bcs.end())
00511         {
00512             delete (*it);
00513         }
00514     }
00515 }
00516 
00517 #endif //_BOUNDARYCONDITIONSCONTAINER_HPP_