IFPACK  Development
 All Classes Files Functions Variables Enumerations Friends
Ifpack_LinePartitioner.cpp
00001 /*@HEADER
00002 // ***********************************************************************
00003 //
00004 //       Ifpack: Object-Oriented Algebraic Preconditioner Package
00005 //                 Copyright (2002) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ***********************************************************************
00040 //@HEADER
00041 */
00042 
00043 #include "Ifpack_ConfigDefs.h"
00044 #include "Ifpack_Partitioner.h"
00045 #include "Ifpack_OverlappingPartitioner.h"
00046 #include "Ifpack_LinePartitioner.h"
00047 #include "Ifpack_Graph.h"
00048 #include "Epetra_Util.h"
00049 
00050 // ============================================================================
00051 inline void Ifpack_LinePartitioner::local_automatic_line_search(int NumEqns, int * blockIndices, int last, int next, int LineID, double tol, int *itemp, double * dtemp) const {
00052   double *xvals=xcoord_, *yvals=ycoord_, *zvals=zcoord_;
00053 
00054   int N = NumMyRows();
00055 
00056   int allocated_space = MaxNumEntries();
00057   int * cols    = itemp;
00058   int * indices = &itemp[allocated_space];
00059   double * dist = dtemp;
00060 
00061 
00062   while (blockIndices[next] == -1) {
00063     // Get the next row
00064     int n=0;
00065     int neighbors_in_line=0;
00066 
00067     Graph_->ExtractMyRowCopy(next,allocated_space,n,cols);
00068     double x0 = (xvals) ? xvals[next/NumEqns] : 0.0;
00069     double y0 = (yvals) ? yvals[next/NumEqns] : 0.0;
00070     double z0 = (zvals) ? zvals[next/NumEqns] : 0.0;
00071 
00072     // Calculate neighbor distances & sort
00073     int neighbor_len=0;
00074     for(int i=0; i<n; i+=NumEqns) {
00075       double mydist = 0.0;
00076       if(cols[i] >=N) continue; // Check for off-proc entries
00077       int nn = cols[i] / NumEqns;
00078       if(blockIndices[nn]==LineID) neighbors_in_line++;
00079       if(xvals) mydist += (x0 - xvals[nn]) * (x0 - xvals[nn]);
00080       if(yvals) mydist += (y0 - yvals[nn]) * (y0 - yvals[nn]);
00081       if(zvals) mydist += (z0 - zvals[nn]) * (z0 - zvals[nn]);
00082       dist[neighbor_len] = sqrt(mydist);
00083       indices[neighbor_len]=cols[i];
00084       neighbor_len++;
00085     }
00086     // If more than one of my neighbors is already in this line.  I
00087     // can't be because I'd create a cycle
00088     if(neighbors_in_line > 1) break;
00089 
00090     // Otherwise add me to the line 
00091     for(int k=0; k<NumEqns; k++) 
00092       blockIndices[next + k] = LineID;
00093     
00094     // Try to find the next guy in the line (only check the closest two that aren't element 0 (diagonal))
00095     Epetra_Util::Sort(true,neighbor_len,dist,0,0,1,&indices,0,0);
00096 
00097     if(neighbor_len > 2 && indices[1] != last && blockIndices[indices[1]] == -1 && dist[1]/dist[neighbor_len-1] < tol) {
00098       last=next;
00099       next=indices[1];
00100     }
00101     else if(neighbor_len > 3 && indices[2] != last && blockIndices[indices[2]] == -1 && dist[2]/dist[neighbor_len-1] < tol) {
00102       last=next;
00103       next=indices[2];
00104     }
00105     else {
00106       // I have no further neighbors in this line
00107       break;
00108     }
00109   }
00110 }
00111 
00112 // ============================================================================
00113 int Ifpack_LinePartitioner::Compute_Blocks_AutoLine(int * blockIndices) const {
00114   double *xvals=xcoord_, *yvals=ycoord_, *zvals=zcoord_;
00115   int NumEqns = NumEqns_;
00116   double tol = threshold_;
00117   int N = NumMyRows();
00118   int allocated_space = MaxNumEntries();
00119     
00120   int * cols    = new int[2*allocated_space];
00121   int * indices = &cols[allocated_space];
00122   double * dist = new double[allocated_space];
00123 
00124   int * itemp   = new int[2*allocated_space];
00125   double *dtemp = new double[allocated_space];
00126 
00127   int num_lines = 0;
00128 
00129   for(int i=0; i<N; i+=NumEqns) {
00130     int nz=0;
00131     // Short circuit if I've already been blocked
00132     if(blockIndices[i] !=-1) continue;
00133 
00134     // Get neighbors and sort by distance
00135     Graph_->ExtractMyRowCopy(i,allocated_space,nz,cols);
00136     double x0 = (xvals) ? xvals[i/NumEqns] : 0.0;
00137     double y0 = (yvals) ? yvals[i/NumEqns] : 0.0;
00138     double z0 = (zvals) ? zvals[i/NumEqns] : 0.0;
00139 
00140     int neighbor_len=0;
00141     for(int j=0; j<nz; j+=NumEqns) {
00142       double mydist = 0.0;
00143       int nn = cols[j] / NumEqns;
00144       if(cols[j] >=N) continue; // Check for off-proc entries
00145       if(xvals) mydist += (x0 - xvals[nn]) * (x0 - xvals[nn]);
00146       if(yvals) mydist += (y0 - yvals[nn]) * (y0 - yvals[nn]);
00147       if(zvals) mydist += (z0 - zvals[nn]) * (z0 - zvals[nn]);
00148       dist[neighbor_len] = sqrt(mydist);
00149       indices[neighbor_len]=cols[j];
00150       neighbor_len++;
00151     }
00152 
00153     Epetra_Util::Sort(true,neighbor_len,dist,0,0,1,&indices,0,0);
00154 
00155     // Number myself
00156     for(int k=0; k<NumEqns; k++)
00157       blockIndices[i + k] = num_lines;
00158 
00159     // Fire off a neighbor line search (nearest neighbor)
00160     if(neighbor_len > 2 && dist[1]/dist[neighbor_len-1] < tol) {
00161       local_automatic_line_search(NumEqns,blockIndices,i,indices[1],num_lines,tol,itemp,dtemp);
00162     }
00163     // Fire off a neighbor line search (second nearest neighbor)
00164     if(neighbor_len > 3 && dist[2]/dist[neighbor_len-1] < tol) {
00165       local_automatic_line_search(NumEqns,blockIndices,i,indices[2],num_lines,tol,itemp,dtemp);
00166     }
00167 
00168     num_lines++;
00169   }
00170   
00171   // Cleanup
00172   delete [] cols;
00173   delete [] dist;
00174   delete [] itemp;
00175   delete [] dtemp;
00176 
00177   return num_lines;
00178 }
00179 //==============================================================================
00180 int Ifpack_LinePartitioner::ComputePartitions()
00181 {
00182   // Sanity Checks
00183   if(!xcoord_ && !ycoord_ && !zcoord_)  IFPACK_CHK_ERR(-1);
00184   if((int)Partition_.size() != NumMyRows())  IFPACK_CHK_ERR(-2);
00185 
00186   // Short circuit
00187   if(Partition_.size() == 0) {NumLocalParts_ = 0; return 0;}
00188 
00189   // Set partitions to -1 to initialize algorithm
00190   for(int i=0; i<NumMyRows(); i++)
00191     Partition_[i] = -1;
00192 
00193   // Use the auto partitioner 
00194   NumLocalParts_ = Compute_Blocks_AutoLine(&Partition_[0]);
00195   
00196   // Resize Parts_
00197   Parts_.resize(NumLocalParts_);
00198   return(0);
00199 }
 All Classes Files Functions Variables Enumerations Friends