SundanceAToCPointLocator.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 "SundanceAToCPointLocator.hpp"
00032 #include "SundanceOut.hpp"
00033 #include "SundanceTabs.hpp"
00034 #include "SundanceGeomUtils.hpp"
00035 #include "Teuchos_ScalarTraits.hpp"
00036 #include <queue>
00037 
00038 using namespace Sundance;
00039 using namespace Sundance;
00040 using namespace Sundance;
00041 using namespace Sundance;
00042 using namespace Sundance;
00043 using namespace Sundance;
00044 using namespace Sundance;
00045 using namespace Teuchos;
00046 
00047 
00048 
00049 
00050 
00051 static Time& pointLocatorCtorTimer() 
00052 {
00053   static RCP<Time> rtn 
00054     = TimeMonitor::getNewTimer("point locator ctor"); 
00055   return *rtn;
00056 }
00057 
00058 AToCPointLocator::AToCPointLocator(const Mesh& mesh, 
00059                                    const CellFilter& subdomain,
00060                                    const std::vector<int>& nx)
00061   : dim_(mesh.spatialDim()),
00062     mesh_(mesh),
00063     nFacets_(mesh.numFacets(dim_, 0, 0)),
00064     nx_(nx),
00065     low_(nx.size(), 1.0/ScalarTraits<double>::sfmin()),
00066     high_(nx.size(), -1.0/ScalarTraits<double>::sfmin()),
00067     dx_(nx.size()),
00068     table_(),
00069     subdomain_(subdomain),
00070     neighborSet_()
00071 {
00072   TimeMonitor timer(pointLocatorCtorTimer());
00073   
00074   /* allocate the neighbor set table */
00075   neighborSet_.resize(mesh.numCells(dim_));
00076 
00077   /* first pass to find bounding box */
00078   CellSet cells = subdomain.getCells(mesh);
00079   
00080   for (CellIterator i = cells.begin(); i!= cells.end(); i++)
00081     {
00082       int cellLID = *i;
00083       Array<int> facetLIDs;
00084       Array<int> facetOri;
00085       mesh.getFacetArray(dim_, cellLID, 0, facetLIDs, facetOri);
00086       for (int f=0; f<facetLIDs.size(); f++)
00087         {
00088           Point x = mesh.nodePosition(facetLIDs[f]);
00089           for (int d=0; d<dim_; d++)
00090             {
00091               if (x[d] < low_[d]) low_[d] = x[d];
00092               if (x[d] > high_[d]) high_[d] = x[d];
00093             }
00094         }
00095     }
00096 
00097   /* fudge the bounding box */
00098   for (int d=0; d<dim_; d++)
00099     {
00100       low_[d] -= 0.01 * (high_[d] - low_[d]);
00101       high_[d] += 0.01 * (high_[d] - low_[d]);
00102     }
00103 
00104   /* second pass to put cells in lookup table */
00105 
00106   int s = 1;
00107   for (int d=0; d<dim_; d++) 
00108     {
00109       dx_[d] = (high_[d] - low_[d])/nx_[d];
00110       s *= nx_[d];
00111     }
00112 
00113 
00114   table_ = rcp(new Array<int>(s, -1));
00115 
00116 
00117   Array<int> lowIndex;
00118   Array<int> highIndex;
00119   for (CellIterator i = cells.begin(); i!= cells.end(); i++)
00120     {
00121       int cellLID = *i;
00122       getGridRange(mesh, dim_, cellLID, lowIndex, highIndex);
00123       if (dim_==2)
00124         {
00125           for (int ix=lowIndex[0]; ix<=highIndex[0]; ix++)
00126             {
00127               for (int iy=lowIndex[1]; iy<=highIndex[1]; iy++)
00128                 {
00129                   int index = nx_[1]*ix + iy;
00130                   (*table_)[index] = cellLID;
00131                 }
00132             }
00133         }
00134       else
00135         {
00136           TEST_FOR_EXCEPT(true);
00137         }
00138     }
00139 }
00140 
00141 int AToCPointLocator::getGridIndex(const double* x) const 
00142 {
00143   int index = 0;
00144   for (int d=0; d<dim_; d++) 
00145     {
00146       double r = (x[d] - low_[d])/dx_[d];
00147       int ix = (int) floor(r);
00148       index = index*nx_[d] + ix;
00149     }
00150 
00151   return index;
00152 }
00153 
00154 
00155 void AToCPointLocator::getGridRange(const Mesh& mesh, int cellDim, int cellLID,
00156                                     Array<int>& lowIndex, Array<int>& highIndex) const
00157 {
00158   Array<int> facetLIDs;
00159   Array<int> facetOri;
00160   mesh.getFacetArray(cellDim, cellLID, 0, facetLIDs, facetOri);
00161 
00162   lowIndex.resize(cellDim);
00163   highIndex.resize(cellDim);
00164   for (int d=0; d<cellDim; d++) 
00165     {
00166       highIndex[d] = -1;
00167       lowIndex[d] = 1000000; /* This magic number should be much bigger than any 
00168                               * reasonable index size in any one dimension */
00169     }
00170 
00171   for (int f=0; f<facetLIDs.size(); f++)
00172     {
00173       Point x = mesh.nodePosition(facetLIDs[f]);
00174       for (int d=0; d<cellDim; d++)
00175         {
00176           double r = (x[d] - low_[d])/dx_[d];
00177           int ix = (int) floor(r);
00178           if (ix < lowIndex[d]) lowIndex[d] = ix;
00179           if (ix > highIndex[d]) highIndex[d] = ix;
00180         }
00181     }
00182 }
00183                  
00184 
00185 void AToCPointLocator::fillMaximalNeighbors(int cellLID, 
00186                                               const int* facetLID) const
00187 {
00188   static Array<int> tmp(3);
00189 
00190   if (neighborSet_[cellLID].get()==0)
00191     {
00192       neighborSet_[cellLID] = rcp(new Set<int>());
00193 
00194       for (int f=0; f<nFacets_; f++)
00195         {
00196           Array<int> cofacets;
00197           mesh_.getCofacets(0, facetLID[f], dim_, cofacets);
00198           for (int c=0; c<cofacets.size(); c++)
00199             {
00200               if (cofacets[c] != cellLID) neighborSet_[cellLID]->put(cofacets[c]);
00201             }
00202         }
00203     }
00204 }
00205 
00206 
00207 bool AToCPointLocator::cellContainsPoint(int cellLID, 
00208                                            const double* x, 
00209                                            const int* facetLID) const
00210 {
00211   if (dim_==2)
00212     {
00213       const double* A = mesh_.nodePositionView(facetLID[0]);
00214       const double* B = mesh_.nodePositionView(facetLID[1]);
00215       const double* C = mesh_.nodePositionView(facetLID[2]);
00216       /* first determine whether the three points of the triangle
00217        * are in ccw or cw order. */
00218       double sign = orient2D(A, B, C);
00219       if (sign > 0.0)
00220         {
00221           double s1 = orient2D(A, B, x);
00222           double s2 = orient2D(B, C, x);
00223           double s3 = orient2D(C, A, x);
00224           if (s1 >= 0.0 && s2 >= 0.0 && s3 >= 0.0) return true;
00225           return false;
00226         }
00227       else
00228         {
00229           double s1 = orient2D(A, C, x);
00230           double s2 = orient2D(C, B, x);
00231           double s3 = orient2D(B, A, x);
00232           if (s1 >= 0.0 && s2 >= 0.0 && s3 >= 0.0) return true;
00233           return false;
00234         }
00235     }
00236   else if (dim_==3)
00237     {
00238       TEST_FOR_EXCEPT(true);
00239       return false; // -Wall
00240     }
00241   else
00242     {
00243       TEST_FOR_EXCEPTION(dim_<=0 || dim_>3, RuntimeError,
00244                          "invalid point dimension " << dim_);
00245       return false; // -Wall
00246     }
00247 }
00248 
00249 bool AToCPointLocator::cellContainsPoint(int cellLID, 
00250                                          const double* x, 
00251                                          const int* facetLID,
00252                                          double* localCoords) const
00253 {
00254   if (dim_==2)
00255     {
00256       const double* A = mesh_.nodePositionView(facetLID[0]);
00257       const double* B = mesh_.nodePositionView(facetLID[1]);
00258       const double* C = mesh_.nodePositionView(facetLID[2]);
00259       /* first determine whether the three points of the triangle
00260        * are in ccw or cw order. */
00261       double sign = orient2D(A, B, C);
00262       if (sign > 0.0)
00263         {
00264           double s1 = orient2D(A, B, x);
00265           double s2 = orient2D(B, C, x);
00266           double s3 = orient2D(C, A, x);
00267           if (s1 >= 0.0 && s2 >= 0.0 && s3 >= 0.0) 
00268             {
00269               double bax = B[0] - A[0];
00270               double bay = B[1] - A[1];
00271               double cax = C[0] - A[0];
00272               double cay = C[1] - A[1];
00273               double delta = bax*cay - bay*cax;
00274               
00275               double xax = x[0] - A[0];
00276               double xay = x[1] - A[1];
00277 
00278               localCoords[0] = (cay*xax - cax*xay)/delta;
00279               localCoords[1] = (bax*xay - bay*xax)/delta;
00280               return true;
00281             }
00282           return false;
00283         }
00284       else
00285         {
00286           double s1 = orient2D(A, C, x);
00287           double s2 = orient2D(C, B, x);
00288           double s3 = orient2D(B, A, x);
00289           if (s1 >= 0.0 && s2 >= 0.0 && s3 >= 0.0) 
00290             {
00291               /* swap B and C if cell is CW oriented */
00292               std::cout << "swapping!" << std::endl;
00293               double bax = C[0] - A[0];
00294               double bay = C[1] - A[1];
00295               double cax = B[0] - A[0];
00296               double cay = B[1] - A[1];
00297               double delta = bax*cay - bay*cax;
00298               
00299               double xax = x[0] - A[0];
00300               double xay = x[1] - A[1];
00301 
00302               localCoords[0] = (cay*xax - cax*xay)/delta;
00303               localCoords[1] = (bax*xay - bay*xax)/delta;
00304               return true;
00305             }
00306           return false;
00307         }
00308     }
00309   else if (dim_==3)
00310     {
00311       TEST_FOR_EXCEPT(true);
00312       return false; // -Wall
00313     }
00314   else
00315     {
00316       TEST_FOR_EXCEPTION(dim_<=0 || dim_>3, RuntimeError,
00317                          "invalid point dimension " << dim_);
00318       return false; // -Wall
00319     }
00320 }
00321 
00322 int AToCPointLocator::findEnclosingCell(int initialGuessLID,
00323                                         const double* x) const
00324 {
00325   std::queue<int> Q;
00326   Set<int> repeats;
00327 
00328   Q.push(initialGuessLID);
00329 
00330   while (!Q.empty())
00331     {
00332       int next = Q.front();
00333       Q.pop();
00334       if (repeats.contains(next)) continue;
00335       
00336       const int* facets = mesh_.elemZeroFacetView(next);
00337       if (cellContainsPoint(next, x, facets)) return next;
00338       repeats.put(next);
00339       
00340       fillMaximalNeighbors(next, facets);
00341       
00342       for (Set<int>::const_iterator 
00343              i=neighborSet_[next]->begin(); i!=neighborSet_[next]->end(); i++)
00344         {
00345           Q.push(*i);
00346         }
00347     }
00348   return -1; // no containing cell found
00349 }
00350 
00351 
00352 
00353 
00354 int AToCPointLocator::findEnclosingCell(int initialGuessLID,
00355                                         const double* x,
00356                                         double* xLocal) const
00357 {
00358   std::queue<int> Q;
00359   Set<int> repeats;
00360 
00361   Q.push(initialGuessLID);
00362 
00363   while (!Q.empty())
00364     {
00365       int next = Q.front();
00366       Q.pop();
00367       if (repeats.contains(next)) continue;
00368       
00369       const int* facets = mesh_.elemZeroFacetView(next);
00370       if (cellContainsPoint(next, x, facets, xLocal)) return next;
00371       repeats.put(next);
00372       
00373       fillMaximalNeighbors(next, facets);
00374       
00375       for (Set<int>::const_iterator 
00376              i=neighborSet_[next]->begin(); i!=neighborSet_[next]->end(); i++)
00377         {
00378           Q.push(*i);
00379         }
00380     }
00381   return -1; // no containing cell found
00382 }
00383 
00384 
00385 Point AToCPointLocator::makePoint(int dim, const double* x) 
00386 {
00387   if (dim==1) return Point(x[0]);
00388   else if (dim==2) return Point(x[0], x[1]);
00389   else return Point(x[0], x[1], x[2]);
00390 }

Site Contact