FineCoarseMeshPair.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
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 
00030 #include "FineCoarseMeshPair.hpp"
00031 
00032 
00033 template<unsigned DIM>
00034 FineCoarseMeshPair<DIM>::FineCoarseMeshPair(TetrahedralMesh<DIM,DIM>& rFineMesh, QuadraticMesh<DIM>& rCoarseMesh)
00035     : mrFineMesh(rFineMesh),
00036       mrCoarseMesh(rCoarseMesh)
00037 {
00038     // compute min and max values for the fine mesh nodes
00039     for(unsigned j=0; j<DIM; j++)
00040     {
00041         double min = 1e200;
00042         double max = -1e200;
00043 
00044         for(unsigned i=0; i<mrFineMesh.GetNumNodes(); i++)
00045         {
00046             if( mrFineMesh.GetNode(i)->rGetLocation()[j] < min)
00047             {
00048                 min = mrFineMesh.GetNode(i)->rGetLocation()[j];
00049             }
00050 
00051             if( mrFineMesh.GetNode(i)->rGetLocation()[j] > max)
00052             {
00053                 max = mrFineMesh.GetNode(i)->rGetLocation()[j];
00054             }
00055         }
00056 
00057         mMinValuesFine(j) = min;
00058         mMaxValuesFine(j) = max;
00059     }
00060 
00061     mpFineMeshBoxCollection = NULL;
00062     mCounters.resize(4,0);
00063 
00065 //    // check whether the two meshes are the same (ie the linear part of the quad mesh is the
00066 //    // linear mesh, by checking whether the number of elements match and the vertex indices of
00067 //    // each element match.
00068 //    mIdenticalMeshes = false;
00069 //    if(mrFineMesh.GetNumElements()==mrCoarseMesh.GetNumElements())
00070 //    {
00071 //        mIdenticalMeshes = true;
00072 //        for (unsigned i=0; i<mrFineMesh.GetNumElements(); i++)
00073 //        {
00074 //            for (unsigned j=0; j<mrFineMesh.GetElement(i)->GetNumNodes(); j++)
00075 //            {
00076 //                if (mrFineMesh.GetElement(i)->GetNodeGlobalIndex(j)!=mrCoarseMesh.GetElement(i)->GetNodeGlobalIndex(j) )
00077 //                {
00078 //                    mIdenticalMeshes = false;
00079 //                    break;
00080 //                }
00081 //            }
00082 //        }
00083 //    }
00084 }
00085 
00086 
00087 template<unsigned DIM>
00088 FineCoarseMeshPair<DIM>::~FineCoarseMeshPair()
00089 {
00090     DeleteBoxCollection();
00091 }
00092 
00093 template<unsigned DIM>
00094 void FineCoarseMeshPair<DIM>::SetUpBoxesOnFineMesh(double boxWidth)
00095 {
00096     // set up the boxes. Use a domain which is a touch larger than the fine mesh
00097     c_vector<double,2*DIM> min_and_max;
00098     for(unsigned i=0; i<DIM; i++)
00099     {
00100         min_and_max(2*i) = mMinValuesFine(i) - 0.05*fabs(mMinValuesFine(i));
00101         min_and_max(2*i+1) = mMaxValuesFine(i) + 0.05*fabs(mMaxValuesFine(i));
00102     }
00103 
00104     if(boxWidth < 0)
00105     {
00106         // use default value = max( max_edge_length, w20),  where w20 is the width corresponding to 
00107         // 20 boxes in the x-direction 
00108 
00109         // BoxCollection creates an extra box so divide by 19 not 20.  Add a little bit on to ensure
00110         // minor numerical fluctuations don't change the answer.
00111         boxWidth = (min_and_max(1) - min_and_max(0))/19.000000001;
00112 
00113         // determine the maximum edge length
00114         double max_edge_length = -1;
00115 
00116         for (typename TetrahedralMesh<DIM,DIM>::EdgeIterator edge_iterator=mrFineMesh.EdgesBegin();
00117              edge_iterator!=mrFineMesh.EdgesEnd();
00118              ++edge_iterator)
00119         {
00120             c_vector<double, 3> location1 = edge_iterator.GetNodeA()->rGetLocation();
00121             c_vector<double, 3> location2 = edge_iterator.GetNodeB()->rGetLocation();
00122             double edge_length = norm_2(location1-location2);
00123 
00124             if(edge_length>max_edge_length)
00125             {
00126                 max_edge_length = edge_length;
00127             }
00128         }
00129         
00130         if(boxWidth < max_edge_length)
00131         {
00132             boxWidth = 1.1*max_edge_length;
00133         }
00134     }
00135  
00136     mpFineMeshBoxCollection = new BoxCollection<DIM>(boxWidth, min_and_max);
00137     mpFineMeshBoxCollection->SetupAllLocalBoxes();
00138 
00139     // for each element, if ANY of its nodes are physically in a box, put that element
00140     // in that box
00141     for(unsigned i=0; i<mrFineMesh.GetNumElements(); i++)
00142     {
00143         Element<DIM,DIM>* p_element = mrFineMesh.GetElement(i);
00144 
00145         std::set<unsigned> box_indices_each_node_this_elem;
00146         for(unsigned j=0; j<DIM+1; j++) // num vertices per element
00147         {
00148             Node<DIM>* p_node = p_element->GetNode(j);
00149             unsigned box_index = mpFineMeshBoxCollection->CalculateContainingBox(p_node);
00150             box_indices_each_node_this_elem.insert(box_index);
00151         }
00152 
00153         for(std::set<unsigned>::iterator iter = box_indices_each_node_this_elem.begin();
00154             iter != box_indices_each_node_this_elem.end();
00155             ++iter)
00156         {
00157             mpFineMeshBoxCollection->rGetBox( *iter ).AddElement(p_element);
00158         }
00159     }
00160 }
00161 
00162 
00163 template<unsigned DIM>
00164 void FineCoarseMeshPair<DIM>::ComputeFineElementsAndWeightsForCoarseQuadPoints(GaussianQuadratureRule<DIM>& rQuadRule,
00165                                                                                bool safeMode)
00166 {
00167     if(mpFineMeshBoxCollection==NULL)
00168     {
00169         EXCEPTION("Call SetUpBoxesOnFineMesh() before ComputeFineElementsAndWeightsForCoarseQuadPoints()");
00170     }
00171 
00172     // get the quad point (physical) positions
00173     QuadraturePointsGroup<DIM> quad_point_posns(mrCoarseMesh, rQuadRule);
00174 
00175     // resize the elements and weights vector.
00176     mElementsAndWeights.resize(quad_point_posns.Size());
00177 
00178 
00180 //    if (mIdenticalMeshes)
00181 //    {
00182 //        for(unsigned i=0; i<quad_point_posns.Size(); i++)
00183 //        {
00184 //            //std::cout << "\r (Identical meshes) " << i << " of " << quad_point_posns.Size() << std::flush;
00185 //
00186 //            ChastePoint<DIM> point;
00187 //            for(unsigned j=0; j<DIM; j++)
00188 //            {
00189 //                point.rGetLocation()[j]=quad_point_posns.Get(i)[j];
00190 //            }
00191 //            
00192 //            unsigned num_quad_points_per_element = quad_point_posns.Size() / mrCoarseMesh.GetNumElements(); 
00193 //            
00194 //            std::set<unsigned> test_element;
00195 //            test_element.insert( i/num_quad_points_per_element /* integer division */ );
00196 //    
00197 //            unsigned elem_index = mrFineMesh.GetContainingElementIndex(point,
00198 //                                                                       false,
00199 //                                                                       test_element,
00200 //                                                                       true /* quit if not in test_element */);
00201 //            c_vector<double,DIM+1> weight = mrFineMesh.GetElement(elem_index)->CalculateInterpolationWeights(point);
00202 //                
00203 //                
00204 //            mElementsAndWeights[i].ElementNum = elem_index;
00205 //            mElementsAndWeights[i].Weights = weight;
00206 //        }
00207 //    }
00208 //    else
00209 //    {
00210 
00211     for(unsigned i=0; i<quad_point_posns.Size(); i++)
00212     {
00213         //std::cout << "\r " << i << " of " << quad_point_posns.Size() << std::flush;
00214         
00215         // get the box this point is in
00216         unsigned box_for_this_point = mpFineMeshBoxCollection->CalculateContainingBox( quad_point_posns.Get(i) );
00217 
00218         // a chaste point version of the c-vector is needed for the GetContainingElement call.
00219         ChastePoint<DIM> point;
00220         for(unsigned j=0; j<DIM; j++)
00221         {
00222             point.rGetLocation()[j]=quad_point_posns.Get(i)[j];
00223         }
00224 
00225         std::set<unsigned> test_element_indices;
00226 
00227         // the elements to try (initially) are those contained in the box the point is in
00228         // NOTE: it is possible the point to be in an element inot 'in' this box, as it is possible
00229         // for all element nodes to be in different boxes.
00230         for(typename std::set<Element<DIM,DIM>*>::iterator elem_iter = mpFineMeshBoxCollection->rGetBox(box_for_this_point).rGetElementsContained().begin();
00231             elem_iter != mpFineMeshBoxCollection->rGetBox(box_for_this_point).rGetElementsContained().end();
00232             ++elem_iter)
00233         {
00234             test_element_indices.insert((*elem_iter)->GetIndex());
00235         }
00236 
00237         unsigned elem_index;
00238         c_vector<double,DIM+1> weight;
00239 
00240         try
00241         {
00242             //std::cout << "\n" << "# test elements initially " << test_element_indices.size() << "\n";
00243             // try these elements only, initially
00244             elem_index = mrFineMesh.GetContainingElementIndex(point,
00245                                                               false,
00246                                                               test_element_indices,
00247                                                               true /* quit if not in test_elements */);
00248             weight = mrFineMesh.GetElement(elem_index)->CalculateInterpolationWeights(point);
00249 
00250             mCounters[0]++;
00251         }
00252         catch(Exception& e)
00253         {
00254             // now try all the elements, but trying the elements contained in the boxes local to this
00255             // element first
00256             std::set<unsigned> test_element_indices;
00257 
00258             std::set<unsigned> local_boxes = mpFineMeshBoxCollection->GetLocalBoxes(box_for_this_point);
00259             for(std::set<unsigned>::iterator local_box_iter = local_boxes.begin();
00260                 local_box_iter != local_boxes.end();
00261                 ++local_box_iter)
00262             {
00263                 for(typename std::set<Element<DIM,DIM>*>::iterator elem_iter = mpFineMeshBoxCollection->rGetBox(*local_box_iter).rGetElementsContained().begin();
00264                     elem_iter != mpFineMeshBoxCollection->rGetBox(*local_box_iter).rGetElementsContained().end();
00265                     ++elem_iter)
00266                 {
00267                     test_element_indices.insert((*elem_iter)->GetIndex());
00268                 }
00269             }
00270 
00271             try
00272             {
00273                 elem_index = mrFineMesh.GetContainingElementIndex(point,
00274                                                                   false,
00275                                                                   test_element_indices,
00276                                                                   true);
00277                 weight = mrFineMesh.GetElement(elem_index)->CalculateInterpolationWeights(point);
00278 
00279                 mCounters[1]++;
00280 
00281             }
00282             catch(Exception& e)
00283             {
00284                 if(safeMode)
00285                 {
00286                     // try the remaining elements
00287                     try
00288                     {
00289                         elem_index = mrFineMesh.GetContainingElementIndex(point,
00290                                                                           false);
00291                         weight = mrFineMesh.GetElement(elem_index)->CalculateInterpolationWeights(point);
00292                         mCounters[2]++;
00293 
00294                     }
00295                     catch (Exception& e)
00296                     {
00297                         // the point is not in ANY element, store the nearest element and corresponding weights
00298                         elem_index = mrFineMesh.GetNearestElementIndexFromTestElements(point,test_element_indices);
00299                         weight = mrFineMesh.GetElement(elem_index)->CalculateInterpolationWeights(point);
00300     
00301                         mNotInMesh.push_back(i);
00302                         mNotInMeshNearestElementWeights.push_back(weight);
00303                         mCounters[3]++;
00304                     }
00305                 }
00306                 else
00307                 {
00308                     assert(test_element_indices.size()>0); // boxes probably too small if this fails
00309                     
00310                     // immediately assume it isn't in the rest of the mesh - this should be the 
00311                     // case assuming the box width was chosen suitably.
00312                     // Store the nearest element and corresponding weights
00313                     elem_index = mrFineMesh.GetNearestElementIndexFromTestElements(point,test_element_indices);
00314                     weight = mrFineMesh.GetElement(elem_index)->CalculateInterpolationWeights(point);
00315     
00316                     mNotInMesh.push_back(i);
00317                     mNotInMeshNearestElementWeights.push_back(weight);
00318                     mCounters[3]++;
00319                 }
00320             }
00321         }
00322 
00323         mElementsAndWeights[i].ElementNum = elem_index;
00324         mElementsAndWeights[i].Weights = weight;
00325     }
00326 //    }
00327 }
00328 
00329 template<unsigned DIM>
00330 void FineCoarseMeshPair<DIM>::PrintStatistics()
00331 {
00332     assert(mNotInMesh.size()==mCounters[3]);
00333     assert(mNotInMesh.size()==mNotInMeshNearestElementWeights.size());
00334     std::cout << "\nFineCoarseMeshPair statistics:\n";
00335     std::cout << "\tNum points for which containing (fine) element was found, using box containing that point = " << mCounters[0] << "\n";
00336     std::cout << "\tNum points for which containing (fine) element was in local box = " << mCounters[1] << "\n";
00337     std::cout << "\tNum points for which containing (fine) element was in non-local element = " << mCounters[2] << "\n";
00338     std::cout << "\tNum points for which no containing element was found in fine mesh = " << mCounters[3] << "\n";
00339     if(mCounters[3]>0)
00340     {
00341         std::cout << "\tIndices and weights for points for which no containing element was found:\n";
00342         for(unsigned i=0; i<mNotInMesh.size(); i++)
00343         {
00344             std::cout << "\t\t" << mNotInMesh[i] << ", " << mNotInMeshNearestElementWeights[i] << "\n";
00345         }
00346     }
00347 }
00348 
00349 
00350 template<unsigned DIM>
00351 void FineCoarseMeshPair<DIM>::DeleteBoxCollection()
00352 {
00353     if(mpFineMeshBoxCollection != NULL)
00354     {
00355         delete mpFineMeshBoxCollection;
00356         mpFineMeshBoxCollection = NULL;
00357     }
00358 }
00359 
00360 
00362 // Explicit instantiation
00364 
00365 
00366 template class FineCoarseMeshPair<1>;
00367 template class FineCoarseMeshPair<2>;
00368 template class FineCoarseMeshPair<3>;

Generated by  doxygen 1.6.2