// ====================================================================== 
bool BasicTest(string PrecType, const Teuchos::RefCountPtr<Epetra_RowMatrix>& A,bool backward, bool reorder=false)
{
  Epetra_MultiVector LHS(A->RowMatrixRowMap(), NumVectors);
  Epetra_MultiVector RHS(A->RowMatrixRowMap(), NumVectors);
  LHS.PutScalar(0.0); RHS.Random();

  double starting_residual = Galeri::ComputeNorm(&*A, &LHS, &RHS);
  Epetra_LinearProblem Problem(&*A, &LHS, &RHS);

  // Set up the list
  Teuchos::ParameterList List;
  List.set("relaxation: damping factor", 1.0);
  List.set("relaxation: sweeps",2550);
  List.set("relaxation: type", PrecType);
  if(backward) List.set("relaxation: backward mode",backward);

  // Reordering if needed
  int NumRows=A->NumMyRows();
  std::vector<int> RowList(NumRows);
  if(reorder) {
    for(int i=0; i<NumRows; i++)
      RowList[i]=i;
    List.set("relaxation: number of local smoothing indices",NumRows);
    List.set("relaxation: local smoothing indices",RowList.size()>0? &RowList[0] : (int*)0);
  }

  Ifpack_PointRelaxation Point(&*A);

  Point.SetParameters(List);
  Point.Compute();
  // use the preconditioner as solver, with 1550 iterations
  Point.ApplyInverse(RHS,LHS);

  // compute the real residual

  double residual = Galeri::ComputeNorm(&*A, &LHS, &RHS);
  
  if (A->Comm().MyPID() == 0 && verbose)
    cout << "||A * x - b||_2 (scaled) = " << residual / starting_residual << endl;
  
  // Jacobi is very slow to converge here
  if (residual / starting_residual < 1e-2) {
    if (verbose)
      cout << "BasicTest Test passed" << endl;
    return(true);
  }
  else {
    if (verbose)
      cout << "BasicTest Test failed!" << endl;
    return(false);
  }
}
Beispiel #2
0
bool Test(const Teuchos::RefCountPtr<Epetra_RowMatrix>& Matrix, Teuchos::ParameterList& List)
{

  int NumVectors = 1;
  bool UseTranspose = false;

  Epetra_MultiVector LHS(Matrix->OperatorDomainMap(),NumVectors);
  Epetra_MultiVector RHS(Matrix->OperatorRangeMap(),NumVectors);
  Epetra_MultiVector LHSexact(Matrix->OperatorDomainMap(),NumVectors);

  LHS.PutScalar(0.0);
  LHSexact.Random();
  Matrix->Multiply(UseTranspose,LHSexact,RHS);

  Epetra_LinearProblem Problem(&*Matrix,&LHS,&RHS);

  Teuchos::RefCountPtr<T> Prec;
  
  Prec = Teuchos::rcp( new T(&*Matrix) );
  assert(Prec != Teuchos::null);

  IFPACK_CHK_ERR(Prec->SetParameters(List));
  IFPACK_CHK_ERR(Prec->Initialize());
  IFPACK_CHK_ERR(Prec->Compute());

  // create the AztecOO solver
  AztecOO AztecOOSolver(Problem);

  // specify solver
  AztecOOSolver.SetAztecOption(AZ_solver,AZ_gmres);
  AztecOOSolver.SetAztecOption(AZ_output,32);

  AztecOOSolver.SetPrecOperator(&*Prec);

  // solver. The solver should converge in one iteration,
  // or maximum two (numerical errors)
  AztecOOSolver.Iterate(1550,1e-8);

  cout << *Prec;
  
  vector<double> Norm(NumVectors);
  LHS.Update(1.0,LHSexact,-1.0);
  LHS.Norm2(&Norm[0]);
  for (int i = 0 ; i < NumVectors ; ++i) {
    cout << "Norm[" << i << "] = " << Norm[i] << endl;
    if (Norm[i] > 1e-3)
      return(false);
  }
  return(true);

}
// ====================================================================== 
int AllSingle(const Teuchos::RefCountPtr<Epetra_RowMatrix>& A, Teuchos::RCP<Epetra_MultiVector> coord)
{
  Epetra_MultiVector LHS(A->RowMatrixRowMap(), NumVectors);
  Epetra_MultiVector RHS(A->RowMatrixRowMap(), NumVectors);
  LHS.PutScalar(0.0); RHS.Random();

  Epetra_LinearProblem Problem(&*A, &LHS, &RHS);

  Teuchos::ParameterList List;
  List.set("relaxation: damping factor", 1.0);
  List.set("relaxation: type", "symmetric Gauss-Seidel");
  List.set("relaxation: sweeps",1);
  List.set("partitioner: overlap",0);
  List.set("partitioner: type", "line");
  List.set("partitioner: line detection threshold",1.0);
  List.set("partitioner: x-coordinates",&(*coord)[0][0]);
  List.set("partitioner: y-coordinates",&(*coord)[1][0]);
  List.set("partitioner: z-coordinates",(double*) 0);

  RHS.PutScalar(1.0);
  LHS.PutScalar(0.0);

  Ifpack_BlockRelaxation<Ifpack_SparseContainer<Ifpack_Amesos> > Prec(&*A);
  Prec.SetParameters(List);
  Prec.Compute();

  // set AztecOO solver object
  AztecOO AztecOOSolver(Problem);
  AztecOOSolver.SetAztecOption(AZ_solver,Solver);
  if (verbose)
    AztecOOSolver.SetAztecOption(AZ_output,32);
  else
    AztecOOSolver.SetAztecOption(AZ_output,AZ_none);
  AztecOOSolver.SetPrecOperator(&Prec);

  AztecOOSolver.Iterate(2550,1e-5);

  printf(" AllSingle  iters %d \n",AztecOOSolver.NumIters());
  return(AztecOOSolver.NumIters());
}
Beispiel #4
0
QString CEdge::DisplayParse( StringToString* filter )
{
	QString parse = LHS() + "( ";

	if( m_Daughters.count() )
	{
		CEdge* daughter;
		for( daughter = m_Daughters.first(); daughter; daughter = m_Daughters.next() )
		{
			parse += daughter->DisplayParse( filter );
			parse += " ";
		}
	}
	else
	{
		if( filter ) parse += Filter( filter, RHS() );
		else parse += RHS();

		parse += " ";
	}

	return parse + ")";
}
Beispiel #5
0
// ====================================================================== 
int CompareLineSmootherEntries(const Teuchos::RefCountPtr<Epetra_RowMatrix>& A)
{
  Epetra_MultiVector LHS(A->RowMatrixRowMap(), NumVectors);
  Epetra_MultiVector RHS(A->RowMatrixRowMap(), NumVectors);
  LHS.PutScalar(0.0); RHS.Random();

  Epetra_LinearProblem Problem(&*A, &LHS, &RHS);

  Teuchos::ParameterList List;
  List.set("relaxation: damping factor", 1.0);
  List.set("relaxation: type", "symmetric Gauss-Seidel");
  List.set("relaxation: sweeps",1);
  List.set("partitioner: overlap",0);
  List.set("partitioner: type", "line");
  List.set("partitioner: line mode","matrix entries");
  List.set("partitioner: line detection threshold",10.0);

  RHS.PutScalar(1.0);
  LHS.PutScalar(0.0);

  Ifpack_BlockRelaxation<Ifpack_SparseContainer<Ifpack_Amesos> > Prec(&*A);
  Prec.SetParameters(List);
  Prec.Compute();

  // set AztecOO solver object
  AztecOO AztecOOSolver(Problem);
  AztecOOSolver.SetAztecOption(AZ_solver,Solver);
  if (verbose)
    AztecOOSolver.SetAztecOption(AZ_output,32);
  else
    AztecOOSolver.SetAztecOption(AZ_output,AZ_none);
  AztecOOSolver.SetPrecOperator(&Prec);

  AztecOOSolver.Iterate(2550,1e-5);

  return(AztecOOSolver.NumIters());
}
Beispiel #6
0
// ====================================================================== 
int CompareBlockOverlap(const Teuchos::RefCountPtr<Epetra_RowMatrix>& A, int Overlap)
{
  Epetra_MultiVector LHS(A->RowMatrixRowMap(), NumVectors);
  Epetra_MultiVector RHS(A->RowMatrixRowMap(), NumVectors);
  LHS.PutScalar(0.0); RHS.Random();

  Epetra_LinearProblem Problem(&*A, &LHS, &RHS);

  Teuchos::ParameterList List;
  List.set("relaxation: damping factor", 1.0);
  List.set("relaxation: type", "Jacobi");
  List.set("relaxation: sweeps",1);
  List.set("partitioner: overlap", Overlap);
  List.set("partitioner: type", "linear");
  List.set("partitioner: local parts", 16);

  RHS.PutScalar(1.0);
  LHS.PutScalar(0.0);

  Ifpack_BlockRelaxation<Ifpack_SparseContainer<Ifpack_Amesos> > Prec(&*A);
  Prec.SetParameters(List);
  Prec.Compute();

  // set AztecOO solver object
  AztecOO AztecOOSolver(Problem);
  AztecOOSolver.SetAztecOption(AZ_solver,Solver);
  if (verbose)
    AztecOOSolver.SetAztecOption(AZ_output,32);
  else
    AztecOOSolver.SetAztecOption(AZ_output,AZ_none);
  AztecOOSolver.SetPrecOperator(&Prec);

  AztecOOSolver.Iterate(1550,1e-5);

  return(AztecOOSolver.NumIters());
}
Beispiel #7
0
// ======================================================================
bool TestContainer(string Type, const Teuchos::RefCountPtr<Epetra_RowMatrix>& A)
{
  int NumVectors = 3;
  int NumMyRows = A->NumMyRows();

  Epetra_MultiVector LHS_exact(A->RowMatrixRowMap(), NumVectors);
  Epetra_MultiVector LHS(A->RowMatrixRowMap(), NumVectors);
  Epetra_MultiVector RHS(A->RowMatrixRowMap(), NumVectors);
  LHS_exact.Random(); LHS.PutScalar(0.0); 
  A->Multiply(false, LHS_exact, RHS);

  Epetra_LinearProblem Problem(&*A, &LHS, &RHS);

  if (verbose) {
    cout << "Container type = " << Type << endl;
    cout << "NumMyRows = " << NumMyRows << ", NumVectors = " << NumVectors << endl;
  }
  LHS.PutScalar(0.0);
  
  Teuchos::RefCountPtr<Ifpack_Container> Container;

  if (Type == "dense")
    Container = Teuchos::rcp( new Ifpack_DenseContainer(A->NumMyRows(), NumVectors) );
  else
    Container = Teuchos::rcp( new Ifpack_SparseContainer<Ifpack_Amesos>(A->NumMyRows(), NumVectors) );

  assert (Container != Teuchos::null);

  IFPACK_CHK_ERR(Container->Initialize());
  // set as ID all the local rows of A
  for (int i = 0 ; i < A->NumMyRows() ; ++i)
    Container->ID(i) = i;

  // extract submatrix (in this case, the entire matrix)
  // and complete setup
  IFPACK_CHK_ERR(Container->Compute(*A));

  // set the RHS and LHS
  for (int i = 0 ; i < A->NumMyRows() ; ++i)
    for (int j = 0 ; j < NumVectors ; ++j) {
      Container->RHS(i,j) = RHS[j][i];
      Container->LHS(i,j) = LHS[j][i];
    }
  
  // set parameters (empty for dense containers)
  Teuchos::ParameterList List;
  List.set("amesos: solver type", Type);
  IFPACK_CHK_ERR(Container->SetParameters(List));

  // solve the linear system
  IFPACK_CHK_ERR(Container->ApplyInverse());

  // get the computed solution, store it in LHS
  for (int i = 0 ; i < A->NumMyRows() ; ++i)
    for (int j = 0 ; j < NumVectors ; ++j) {
       LHS[j][i] = Container->LHS(i,j);
    }

  double residual = Galeri::ComputeNorm(&LHS, &LHS_exact);

  if (A->Comm().MyPID() == 0 && verbose) {
    cout << "||x_exact - x||_2 = " << residual << endl;
    cout << *Container;
  }

  bool passed = false;
  if (residual < 1e-5)
    passed = true;

  return(passed);
}
Beispiel #8
0
void EventLoop(CCam & Camera1)
{
 bool quitit=false;
 SDL_Event event;
 SDL_MouseMotionEvent event2;
 SDL_keysym  *whatkey;
 bool mousedown=false;

//  Go to while(!quitit) to see what happens once data set up

// Go to Render Scene for graphics bit

    bool exitnow=false;

    double xunit,yunit,zunit;
    xunit=1.0;yunit=1.0;zunit=1.0;


 //   if_stream opens for input
 //   of_stream opens for output
 //   f_stream opens for both
 //
    string filename ="Sphere4.dat";
    ifstream file_in;
    file_in.open(filename.c_str());
    
    file_in >> n_nodes  >> ntri;
    cout <<  n_nodes << "  number of nodes" << endl;
    cout <<  ntri<< "  number of triangles" << endl;
    cout << "read next line\n";


    cout << "start read loop\n";


    Triangles=(Triangle*)calloc(ntri, sizeof(Triangle));
    NodeV=(D3Dvec*)calloc(n_nodes, sizeof(D3Dvec));
    //initiales
    char quad, otherquad;

    int id,l,m,n;
    double x,y,z;

    for(int i=0; i<ntri;i++){
          file_in >>l;
          file_in >>m;
          file_in >>n;
          file_in >>quad;
          // same resuly of file_in >> l >>m >>n;

        Triangles[i]=Triangle();   //initialise
        Triangles[i].SetTri(l,m,n);
        Triangles[i].SetQuad(quad);
    }
     for(int i=0; i<ntri;i++){
        file_in >> l >> m >> n;
        Triangles[i].SetNeighb(l,m,n);
    }
    for(int i=0; i < n_nodes; i++){
          NodeV[i]=D3Dvec();
          file_in >> x >> y >> z;
          NodeV[i].SetVec(x,y,z);
     }

    istart=0;
    istop=ntri;
    
/**********************************************************************************
                   Calculate Metric Tensor
**********************************************************************************/
    double **Gmetric;
    Gmetric =(double**)calloc( ntri, sizeof( double[3] )  );
    if(!Gmetric){ cout << "Memory Failed for Gmetric " << endl; exit(0);}

    // 2D vectors in each triangle
    double **avec, **bvec;
    avec=(double**)calloc( ntri, sizeof(double[2]) );
    if(!avec){ cout << "Memory Failed for avec" << endl; exit(0);}

    bvec=(double**)calloc( ntri, sizeof(double[2]) );
    if(!bvec){ cout << "Memory Failed for bvec" << endl; exit(0);}

    double avecdash[2], bvecdash[2];
    double avecdash_new[2], bvecdash_new[2];

    D3Dvec Ve1,Ve2,VOrig;  //origin and edge vectors
    Ve1=D3Dvec();  Ve2=D3Dvec(); VOrig=D3Dvec(); //Initialise

    D3Dvec Unit_i, Unit_j, Unit_k;
    Unit_i=D3Dvec(); Unit_j=D3Dvec(); Unit_k=D3Dvec();

    int i1,i2,i3;

    double rad=-1;

    for(int i=0; i<ntri; i++){
    Gmetric[i]=new double[3];  //initialise
    i1=Triangles[i].Get1();
    i2=Triangles[i].Get2();
    i3=Triangles[i].Get3();
    x=NodeV[i1].GetX();
    y=NodeV[i1].GetY();
    z=NodeV[i1].GetZ();
    VOrig.SetVec(x,y,z);
    x=NodeV[i2].GetX()-VOrig.GetX();
    y=NodeV[i2].GetY()-VOrig.GetY();
    z=NodeV[i2].GetZ()-VOrig.GetZ();
    Ve1.SetVec(x,y,z);
    x=NodeV[i3].GetX()-VOrig.GetX();
    y=NodeV[i3].GetY()-VOrig.GetY();
    z=NodeV[i3].GetZ()-VOrig.GetZ();
    Ve2.SetVec(x,y,z);
    Gmetric[i][0]=Ve1.Dot(Ve1);
    Gmetric[i][1]=Ve1.Dot(Ve2);
    Gmetric[i][2]=Ve2.Dot(Ve2);
    rad=Gmetric[i][0];
    rad=sqrt(rad)*6370.;

     // local  cartesians
     Unit_i=Ve1;
     Normalise(Unit_i);
     Unit_k=Ve1*Ve2;
     Normalise(Unit_k);
     Unit_j=Unit_k*Unit_i;

     avec[i]=new double[2];
     bvec[i]=new double[2];

     avec[i][0]=Unit_i.Dot(Ve1);
     avec[i][1]=0.0;
     bvec[i][0]=Unit_i.Dot(Ve2);
     bvec[i][1]=Unit_j.Dot(Ve2);

    }  
    
/**********************************************************************************
     GEODESIC- start point
**********************************************************************************/

    // Now for a geodesic !
    //
    int Tstart0=56;
    int Tstart, TNext;
    double xO,yO,zO;
    double x1,y1,z1;
    double x2,y2,z2;
    double x3,y3,z3;
    char qStart,qNext;
    double  d1, d2, lambda;
    double d1dash,d2dash;
    double ds_total, ds_squared;
    double alpha_start, beta_start;

    double alphaTstart, betaTstart; 
//values of lambda to hit the line alpha=0, beta=0, alpha+beta=1
    double Tol1=0.000001;
    // if fabs(d) less than this it lands on edge miles
    // away or never at all
    double Tol2=1e-8;  //possibility that we land on a corner

    double alpha_e1, beta_e1;
    double alpha_e2, beta_e2;
    double alpha_e3, beta_e3;
    bool land_e1, land_e2, land_e3;
    double lambda_edge1, lambda_edge2, lambda_edge3;

    int Node1, Node2, Node3;

    double alphaNext,betaNext;
    double alpha_p, beta_p, alpha_q, beta_q;
    double alpha_p_dash, beta_p_dash, alpha_q_dash, beta_q_dash;

    double CosTheta,SinTheta,Theta,Phi;

    double adot_adash, adot_bdash, bdot_adash, bdot_bdash;

    double W1,W2,X1,X2,Y1,Y2,Z1,Z2,Det;
    double ex1,why1,ex2,why3;

    unsigned int ndim;

    int kount=0;
                              

    Tstart=Tstart0;
    alpha_start=0.25, beta_start=0.25;
    d1=.25; d2=0.19;  

    bool start_e1, start_e2, start_e3;
    start_e1=false;  //assume that for first triangle
    start_e2=false;  //we don't start off on an edge
    start_e3=false;  //change for instance, if we have alpha_start=0
/**********************************************************************************
     GEODESIC- Propagate
**********************************************************************************/

    while(ds_total < 6.3  && kount < GeoPos){
	    if(kount==GeoPos-1){
		    cout <<"Last One! " << endl;
			    }

    Node1=Triangles[Tstart].Get1();
    Node2=Triangles[Tstart].Get2();
    Node3=Triangles[Tstart].Get3();

    D3Dvec Rnode1,Rnode2;
    Rnode1=D3Dvec(); Rnode2=D3Dvec();

    xO=NodeV[Node1].GetX();
    yO=NodeV[Node1].GetY();
    zO=NodeV[Node1].GetZ();

    VOrig.SetVec(xO,yO,zO);

    x1=NodeV[Node2].GetX();
    y1=NodeV[Node2].GetY();
    z1=NodeV[Node2].GetZ();
    Rnode1.SetVec(x1,y1,z1);

    x2=NodeV[Node3].GetX();
    y2=NodeV[Node3].GetY();
    z2=NodeV[Node3].GetZ();
    Rnode2.SetVec(x2,y2,z2);

    Ve1=Rnode1-VOrig;
    Ve2=Rnode2-VOrig;

    x3=VOrig.GetX()+alpha_start*Ve1.GetX()+beta_start*Ve2.GetX();
    y3=VOrig.GetY()+alpha_start*Ve1.GetY()+beta_start*Ve2.GetY();
    z3=VOrig.GetZ()+alpha_start*Ve1.GetZ()+beta_start*Ve2.GetZ();


    Geodesy[kount]=new D3Dvec();
    Geodesy[kount].SetX(x3);
    Geodesy[kount].SetY(y3);
    Geodesy[kount].SetZ(z3);

    cout << Geodesy[kount].GetX() << "  "
	    << Geodesy[kount].GetY()
	    << "  " << Geodesy[kount].GetZ() 
	    << "  kount=" << kount <<
	     "   Tstart=" << Tstart << endl;
    kount++;


    land_e1=false; land_e2=false; land_e3=false;

    //alpha_start + d1 lambda=0 lands on edge2;
    //beta_start+ d2 lambda=0 lands on edge1;
     if( fabs(d1) > Tol1){lambda_edge1=-beta_start/d2; land_e1=true;}
     if( fabs(d2) > Tol1){lambda_edge2=-alpha_start/d1; land_e2=true;}
     if( fabs(d2+d2) > Tol1)
     {lambda_edge3=(1.0-alpha_start-beta_start)/(d1+d2); 
	     land_e3=true;}

     cout << "d1=" << d1 << endl;
     cout << "d2=" << d2 << endl;
     cout << "alpha_s=" << alpha_start << endl;
     cout << "beta_s=" << beta_start << endl;

     alpha_e1=alpha_start+lambda_edge1*d1;
     beta_e1=beta_start+lambda_edge1*d2;
     alpha_e2=alpha_start+lambda_edge2*d1;
     beta_e2=beta_start+lambda_edge2*d2;
     alpha_e3=alpha_start+lambda_edge3*d1;
     beta_e3=beta_start+lambda_edge3*d2;

     ndim=2;
     Dmatrix Mat(ndim,ndim);  //creates 4 by 3 on the heap.

     Dvector RHS(ndim);
     Dvector LHS(ndim);


     if(  (fabs(alpha_e1) < Tol2)  && (fabs(beta_e1) <Tol2) ){
		     // set it safely on edge 1
		     alpha_e1=2.*Tol2;
		     beta_e1=0.0;
		     }
     if(  (fabs(1.0-alpha_e1) < Tol2)  && (fabs(beta_e1) <Tol2) ){
		     // set it safely on edge 1
		     alpha_e1=1.0-2.0*Tol2;
		     beta_e1=0.0;
		     }

     if(  (fabs(alpha_e2) < Tol2)  && (fabs(beta_e2) <Tol2) ){
		     // set it safely on edge 2
		     alpha_e2=0.0;
		     beta_e2=2.0*Tol2;
		     }
     if(  (fabs(1.0-beta_e2) < Tol2)  && (fabs(alpha_e2) <Tol2) ){
		     // set it safely on edge 2
		     alpha_e2=0.0;
		     beta_e2=1.0-2.0*Tol2;
		     }

     if(  (fabs(1.0-alpha_e3-beta_e3) < Tol2)  ){
         if(fabs(alpha_e3) < Tol2){
		 // set it safely on edge 3
		 alpha_e3=2.0*Tol2;
		 beta_e3=1.0-alpha_e3;
	 }
         if(fabs(beta_e3) < Tol2){
		 // set it safely on edge 3
		 beta_e3=2.0*Tol2;
		 alpha_e3=1.0-beta_e3;
	 }
     }

   
/*     cout << "e1 " << alpha_e1 << "  L e1=" << lambda_edge1 << endl;
     cout << "e2 " << beta_e2 <<  "  L_e2=" <<  lambda_edge2 << endl;
     cout << "a e3 " << alpha_e3 << "  L_e3=" << lambda_edge3 << endl;
     cout << "b e3 " << beta_e3 << endl;  */

     if(lambda_edge1 <0.0 || alpha_e1 < 0.0 || alpha_e1 > 1.0)land_e1=false;
     if(lambda_edge2 <0.0 || beta_e2 < 0.0 || beta_e2 > 1.0)land_e2=false;

     if(lambda_edge3 <0.0 || alpha_e3 < 0.0 || alpha_e3 > 1.0)land_e3=false;
     if(lambda_edge3 <0.0 || beta_e3 < 0.0 || beta_e3 > 1.0)land_e3=false;

     cout << land_e1 << land_e2 << land_e3 << " edges 1 2 and 3" << endl;

     // Normally we land on two edges!
     // We start it some point in the start triangle
     // proceed to the edge, but now we start at an edge
     //
     if(start_e1)land_e1=false;
     if(start_e2)land_e2=false;
     if(start_e3)land_e3=false;
     
     start_e1=false;  
     start_e2=false; 
     start_e3=false; 

     if(land_e1){
	     //beta_e1=0
	     ds_squared=
	     Gmetric[Tstart][0]*(alpha_e1-alpha_start)*(alpha_e1-alpha_start)
	     -2.0*Gmetric[Tstart][1]*(alpha_e1-alpha_start)*beta_start
	     +Gmetric[Tstart][2]*beta_start*beta_start;

	     ds_total=ds_total+sqrt(ds_squared);
     }
     if(land_e2){
	     //alpha_e1=0
	     ds_squared=
	     Gmetric[Tstart][0]*alpha_start*alpha_start
	     -2.0*Gmetric[Tstart][1]*alpha_start*(beta_e2-beta_start)
	     +Gmetric[Tstart][2]*(beta_e2-beta_start)*(beta_e2-beta_start);

	     ds_total=ds_total+sqrt(ds_squared);
     }
     if(land_e3){
	     ds_squared=
	     Gmetric[Tstart][0]*(alpha_e3-alpha_start)*(alpha_e3-alpha_start)
	     +2.0*Gmetric[Tstart][1]*(alpha_e3-alpha_start)*(beta_e3-beta_start)
	     +Gmetric[Tstart][2]*(beta_e3-beta_start)*(beta_e3-beta_start);

	     ds_total=ds_total+sqrt(ds_squared);
     }

     if( land_e1 )TNext=Triangles[Tstart].GetN1();
     if( land_e2 )TNext=Triangles[Tstart].GetN2();
     if( land_e3 )TNext=Triangles[Tstart].GetN3();

     avecdash[0]=avec[TNext][0];
     avecdash[1]=avec[TNext][1];
     bvecdash[0]=bvec[TNext][0];
     bvecdash[1]=bvec[TNext][1];

     qStart=Triangles[Tstart].GetQuad();
     qNext=Triangles[TNext].GetQuad();

     // edge 1 always crosses into an edge 1 in the opposite sense
     if(land_e1){
	     alphaNext=1.0-alpha_e1;
	     betaNext=0.0; 
	     start_e1=true;


             alpha_p=0.0;    //edge 1 
	     beta_p=0.0;
	     alpha_q=1.0; 
	     beta_q=0.0;
	     alpha_p_dash=alpha_q;  // same edge, opposite sense
	     beta_p_dash=beta_q;  
	     alpha_q_dash=alpha_p;
	     beta_q_dash=beta_p;  

      }

     // If the neighbour on edge 2 is in a different quad
     // it lands on edge 3, otherwise minus edge 2
      if(land_e2){
              alpha_p=0.0;   
	      beta_p=0.0;
	      alpha_q=0.0;  
	      beta_q=1.0;


	      if(qNext==qStart){
		 //crosses to edge 2 of neighbour- opposite sense
	         betaNext=1.0-beta_e2;
	         alphaNext=0.0;
		 start_e2=true;

	         alpha_p_dash=alpha_q; 
	         beta_p_dash=beta_q;  
	         alpha_q_dash=alpha_p;
	         beta_q_dash=beta_p;  
	      }
	      else
              {
		 //crosses to edge 3 of neighbour- same sense.
		 alphaNext=1.0-beta_e2;
		 betaNext=beta_e2;
		 start_e3=true;

	         alpha_p_dash=1.0; 
	         beta_p_dash=0.0;  
	         alpha_q_dash=0.0;
	         beta_q_dash=1.0;  
	      }
      }
      

     
      if(land_e3){
	      alpha_p=1.0;
	      beta_p=0.0;
	      alpha_q=0.0;
	      beta_q=1.0;
	      if(qNext==qStart){
		 //crosses to edge 3 of neighbour- opposite sense.
		  alphaNext=1.0-alpha_e3;
	          betaNext=alpha_e3;
		  alpha_p_dash=alpha_q;
		  beta_p_dash=beta_q;
		  alpha_q_dash=alpha_p;
		  beta_q_dash=beta_p;
		  start_e3=true;
	      }
	      else
              {
		   //crosses to edge 2 of neighbour -- has same sense
		   alphaNext=0;
		   betaNext=beta_e3;

		   alpha_p_dash=0.0;
		   beta_p_dash=0.0;
		   alpha_q_dash=0.0;
		   beta_q_dash=1.0;
                   start_e2=true;
	      }
      }  
      cout << "ds_total=" << ds_total << endl;

      X1=alpha_p_dash*avecdash[0]+beta_p_dash*bvecdash[0];
      X2=alpha_p_dash*avecdash[1]+beta_p_dash*bvecdash[1];

      Y1=alpha_p*avec[Tstart][0]+beta_p*bvec[Tstart][0];
      Y2=alpha_p*avec[Tstart][1]+beta_p*bvec[Tstart][1];

      W1=alpha_q_dash*avecdash[0]+beta_q_dash*bvecdash[0];
      W2=alpha_q_dash*avecdash[1]+beta_q_dash*bvecdash[1];

      Z1=alpha_q*avec[Tstart][0]+beta_q*bvec[Tstart][0];
      Z2=alpha_q*avec[Tstart][1]+beta_q*bvec[Tstart][1];

      Det=(W2-X2)*(W2-X2)+(W1-X1)*(W1-X1);


      unsigned int ir,ic,ir1,ir2;
      ir=0; ic=0;
      Mat(ir,ic)=W1-X1;
      ir=0; ic=1;
      Mat(ir,ic)=W2-X2;
      ir=1; ic=0;
      Mat(ir,ic)=-(W2-X2);
      ir=1; ic=1;
      Mat(ir,ic)=W1-X1;

      Mat=Mat/Det;
      ir=0;
      RHS(ir)=Z1-Y1;
      ir=1;
      RHS(ir)=Z2-Y2;

      LHS=Mat*RHS;

      ir=0;
      CosTheta=LHS(ir);
      ir=1;
      SinTheta=LHS(ir);

     // cout << "cos and sin "<< CosTheta << "  " << SinTheta << endl; 
     // cout << "cossq+sinsq=" << CosTheta*CosTheta+SinTheta*SinTheta << endl;

      avecdash_new[0]=
	      avecdash[0]*CosTheta-avecdash[1]*SinTheta;
      avecdash_new[1]=
	      avecdash[0]*SinTheta+avecdash[1]*CosTheta;
      bvecdash_new[0]=
	      bvecdash[0]*CosTheta-bvecdash[1]*SinTheta;
      bvecdash_new[1]=
	      bvecdash[0]*SinTheta+bvecdash[1]*CosTheta;

      adot_adash=avec[Tstart][0]*avecdash_new[0]
	      +avec[Tstart][1]*avecdash_new[1];
      adot_bdash=avec[Tstart][0]*bvecdash_new[0]
	      +avec[Tstart][1]*bvecdash_new[1];
      bdot_adash=bvec[Tstart][0]*avecdash_new[0]
	      +bvec[Tstart][1]*avecdash_new[1];
      bdot_bdash=bvec[Tstart][0]*bvecdash_new[0]
	      +bvec[Tstart][1]*bvecdash_new[1];

      /*
      cout  << adot_adash << " a dot adash  "  <<
	      avec[Tstart][0]*avecdash_new[0]+
	      avec[Tstart][1]*avecdash_new[1]  << endl;

      cout << adot_bdash << " a dot bdash  "  << 
	      avec[Tstart][0]*bvecdash_new[0]+
	      avec[Tstart][1]*bvecdash_new[1]  << endl;

      cout << bdot_adash << " b dot adash  "   << 
	      bvec[Tstart][0]*avecdash_new[0]+
	      bvec[Tstart][1]*avecdash_new[1]  << endl;

      cout <<  bdot_bdash << " b dot bdash  "  <<
	      bvec[Tstart][0]*bvecdash_new[0]+
	      bvec[Tstart][1]*bvecdash_new[1]  << endl;
	      */

      // The next couts all check out

  /*    cout  <<  " a dot a  "  <<
	      avec[Tstart][0]*avec[Tstart][0]+
	      avec[Tstart][1]*avec[Tstart][1]  << endl;

      cout << " b dot b  "  << 
	      bvec[Tstart][0]*bvec[Tstart][0]+
	      bvec[Tstart][1]*bvec[Tstart][1]  << endl;

      cout <<  " a dot a in Next  "   << 
	      avec[TNext][0]*avec[TNext][0]+
	      avec[TNext][1]*avec[TNext][1]  << endl;

      cout << bdot_bdash << " b dot b  in Next "  <<
	      bvec[TNext][0]*bvec[TNext][0]+
	      bvec[TNext][1]*bvec[TNext][1]  << endl;

      cout << "a " <<  avec[Tstart][0] 
	               <<  "   " <<  avec[Tstart][1]   << endl;
      cout << "b " <<  bvec[Tstart][0] 
	               << "   " <<   bvec[Tstart][1]   << endl;
		       */
 
       
/*
      cout << "a dash " <<  avecdash[0] 
	               << "   " <<   avecdash[1]   << endl;
      cout << "b dash " <<   bvecdash[0] 
	               <<  "   " <<  bvecdash[1]   << endl;
		       */

 /*     cout << "a dash rotate " <<  avecdash_new[0] 
	               <<  "   " <<  avecdash_new[1]   << endl;
      cout << "b dash rotate " <<   bvecdash_new[0]  
	               <<  "   " <<  bvecdash_new[1]  << endl;
      */


      ir=0;ic=0;
      Mat(ir,ic)=Gmetric[Tstart][2];
      ir=0;ic=1;
      Mat(ir,ic)=-Gmetric[Tstart][1];
      ir=1;ic=0;
      Mat(ir,ic)=-Gmetric[Tstart][1];
      ir=1;ic=1;
      Mat(ir,ic)=Gmetric[Tstart][0];

      Det=Gmetric[Tstart][0]*Gmetric[Tstart][2]
         -Gmetric[Tstart][1]*Gmetric[Tstart][1];

      Mat=Mat/Det;

      ir=0;
      RHS(ir)=adot_adash;
      ir=1;
      RHS(ir)=bdot_adash;

      LHS=Mat*RHS;

      ir=0;
      x1=LHS(ir);
      ir=1;
      y1=LHS(ir);

      ir=0;
      RHS(ir)=adot_bdash;
      ir=1;
      RHS(ir)=bdot_bdash;

      LHS=Mat*RHS;

      ir=0;
      x2=LHS(ir);
      ir=1;
      y2=LHS(ir);

      //check adash=x1 a + y1 b, bdash=x2 a+ y2 b
      cout << x1*avec[Tstart][0]+y1*bvec[Tstart][0] 
	      << "  " << avecdash_new[0] << endl;
      cout << x1*avec[Tstart][1]+y1*bvec[Tstart][1]
	      << "  " << avecdash_new[1] << endl;
      cout << x2*avec[Tstart][0]+y2*bvec[Tstart][0]
	      << "  " << bvecdash_new[0] << endl;
      cout << x2*avec[Tstart][1]+y2*bvec[Tstart][1]
	      << "  " << bvecdash_new[1] << endl;
	      

      ir=0;ic=0;
      Mat(ir,ic)=y2;
      ir=0;ic=1;
      Mat(ir,ic)=-x2;
      ir=1;ic=0;
      Mat(ir,ic)=-y1;
      ir=1;ic=1;
      Mat(ir,ic)=x1;


      Det=x1*y2-x2*y1;

      Mat=Mat/Det;

      cout << "M11=" <<  y2/Det << "  M12=" << -x2/Det << endl;
      cout << "M21=" <<   -y1/Det << "  M12=" << x1/Det << endl;

      ir=0;
      RHS(ir)=d1;
      ir=1;
      RHS(ir)=d2;

      LHS=Mat*RHS;

      ir=0;
      d1dash=LHS(ir);
      ir=1;
      d2dash=LHS(ir);

      // We have finally arrived in TNext, which will be the new Tstart;
      Tstart=TNext;
      alpha_start=alphaNext;
      beta_start=betaNext;
      d1=d1dash;
      d2=d2dash;

    } //end while ds_total

    Geokount=kount;

    cout << "Geokount=" << Geokount << endl;


 while(!quitit){
        
       while(SDL_PollEvent(&event)){

          switch(event.type){
               case SDL_QUIT:
                 quitit=true;
                 break;
                 case SDL_MOUSEBUTTONDOWN:
                    mousedown=true;
                 break;
                 case SDL_MOUSEBUTTONUP:
                    mousedown=false;
                 break;
                 case SDL_MOUSEMOTION:
                  if(mousedown){
                         if(MouseOn)Camera1.MouseView();}
                  else{
                         if(MouseOn)Camera1.MouseLookAt(); }
                 break;  


               case SDL_KEYDOWN:
                   whatkey=&event.key.keysym;
                   HandleKeyPress(whatkey);
                   break;
               case SDL_KEYUP:
                   whatkey=&event.key.keysym;
                   HandleKeyRelease(whatkey);
               default:
                 break;
                     } // end of case
                } //end of inner loop
              CheckMove(Camera1);
              RenderScene(Camera1);
            } //end of outer loop

}
Beispiel #9
0
int main(int argc, char *argv[])
{
  int ierr = 0, i, j, k;

#ifdef EPETRA_MPI
  MPI_Init(&argc,&argv);
  Epetra_MpiComm Comm( MPI_COMM_WORLD );
#else
  Epetra_SerialComm Comm;
#endif

  bool verbose = false;

  // Check if we should print results to standard out
  if (argc>1) if (argv[1][0]=='-' && argv[1][1]=='v') verbose = true;

  if(verbose && Comm.MyPID()==0)
    std::cout << Epetra_Version() << std::endl << std::endl;

  int rank = Comm.MyPID();
  //  char tmp;
  //  if (rank==0) std::cout << "Press any key to continue..."<< std::endl;
  //  if (rank==0) cin >> tmp;
  //  Comm.Barrier();

  Comm.SetTracebackMode(0); // This should shut down any error traceback reporting
  if (verbose) std::cout << Comm << std::endl;

  //  bool verbose1 = verbose;

  // Redefine verbose to only print on PE 0
  if (verbose && rank!=0) verbose = false;

  int N = 20;
  int NRHS = 4;
  double * A = new double[N*N];
  double * A1 = new double[N*N];
  double * X = new double[(N+1)*NRHS];
  double * X1 = new double[(N+1)*NRHS];
  int LDX = N+1;
  int LDX1 = N+1;
  double * B = new double[N*NRHS];
  double * B1 = new double[N*NRHS];
  int LDB = N;
  int LDB1 = N;

  int LDA = N;
  int LDA1 = LDA;
  double OneNorm1;
  bool Upper = false;

  Epetra_SerialSpdDenseSolver solver;
  Epetra_SerialSymDenseMatrix * Matrix;
  for (int kk=0; kk<2; kk++) {
    for (i=1; i<=N; i++) {
      GenerateHilbert(A, LDA, i);
      OneNorm1 = 0.0;
      for (j=1; j<=i; j++) OneNorm1 += 1.0/((double) j); // 1-Norm = 1 + 1/2 + ...+1/n

      if (kk==0) {
	Matrix = new Epetra_SerialSymDenseMatrix(View, A, LDA, i);
	LDA1 = LDA;
      }
      else {
	Matrix = new Epetra_SerialSymDenseMatrix(Copy, A, LDA, i);
	LDA1 = i;
      }
      GenerateHilbert(A1, LDA1, i);
	
      if (kk==1) {
	solver.FactorWithEquilibration(true);
	Matrix->SetUpper();
	Upper = true;
	solver.SolveToRefinedSolution(false);
      }

      for (k=0; k<NRHS; k++)
	for (j=0; j<i; j++) {
	  B[j+k*LDB] = 1.0/((double) (k+3)*(j+3));
	  B1[j+k*LDB1] = B[j+k*LDB1];
	}
      Epetra_SerialDenseMatrix Epetra_B(View, B, LDB, i, NRHS);
      Epetra_SerialDenseMatrix Epetra_X(View, X, LDX, i, NRHS);
      solver.SetMatrix(*Matrix);
      solver.SetVectors(Epetra_X, Epetra_B);

      ierr = check(solver, A1, LDA1,  i, NRHS, OneNorm1, B1, LDB1,  X1, LDX1, Upper, verbose);
      assert (ierr>-1);
      delete Matrix;
      if (ierr!=0) {
	if (verbose) std::cout << "Factorization failed due to bad conditioning.  This is normal if SCOND is small."
			  << std::endl;
	break;
      }
    }
  }

  delete [] A;
  delete [] A1;
  delete [] X;
  delete [] X1;
  delete [] B;
  delete [] B1;

  /////////////////////////////////////////////////////////////////////
  // Now test norms and scaling functions
  /////////////////////////////////////////////////////////////////////

  Epetra_SerialSymDenseMatrix D;
  double ScalarA = 2.0;

  int DM = 10;
  int DN = 10;
  D.Shape(DM);
  for (j=0; j<DN; j++)
    for (i=0; i<DM; i++) D[j][i] = (double) (1+i+j*DM) ;

  //std::cout << D << std::endl;

  double NormInfD_ref = (double)(DM*(DN*(DN+1))/2);
  double NormOneD_ref = NormInfD_ref;

  double NormInfD = D.NormInf();
  double NormOneD = D.NormOne();

  if (verbose) {
    std::cout << " *** Before scaling *** " << std::endl
	 << " Computed one-norm of test matrix = " << NormOneD << std::endl
	 << " Expected one-norm                = " << NormOneD_ref << std::endl
	 << " Computed inf-norm of test matrix = " << NormInfD << std::endl
	 << " Expected inf-norm                = " << NormInfD_ref << std::endl;
  }
  D.Scale(ScalarA); // Scale entire D matrix by this value

  //std::cout << D << std::endl;

  NormInfD = D.NormInf();
  NormOneD = D.NormOne();
  if (verbose) {
    std::cout << " *** After scaling *** " << std::endl
	 << " Computed one-norm of test matrix = " << NormOneD << std::endl
	 << " Expected one-norm                = " << NormOneD_ref*ScalarA << std::endl
	 << " Computed inf-norm of test matrix = " << NormInfD << std::endl
	 << " Expected inf-norm                = " << NormInfD_ref*ScalarA << std::endl;
  }



  /////////////////////////////////////////////////////////////////////
  // Now test for larger system, both correctness and performance.
  /////////////////////////////////////////////////////////////////////


  N = 2000;
  NRHS = 5;
  LDA = N;
  LDB = N;
  LDX = N;

  if (verbose) std::cout << "\n\nComputing factor of an " << N << " x " << N << " SPD matrix...Please wait.\n\n" << std::endl;

  // Define A and X

  A = new double[LDA*N];
  X = new double[LDB*NRHS];

  for (j=0; j<N; j++) {
    for (k=0; k<NRHS; k++) X[j+k*LDX] = 1.0/((double) (j+5+k));
    for (i=0; i<N; i++) {
      if (i==j) A[i+j*LDA] = 100.0 + i;
      else A[i+j*LDA] = -1.0/((double) (i+10)*(j+10));
    }
  }

  // Define Epetra_SerialDenseMatrix object

  Epetra_SerialSymDenseMatrix BigMatrix(Copy, A, LDA, N);
  Epetra_SerialSymDenseMatrix OrigBigMatrix(View, A, LDA, N);

  Epetra_SerialSpdDenseSolver BigSolver;
  BigSolver.FactorWithEquilibration(true);
  BigSolver.SetMatrix(BigMatrix);

  // Time factorization

  Epetra_Flops counter;
  BigSolver.SetFlopCounter(counter);
  Epetra_Time Timer(Comm);
  double tstart = Timer.ElapsedTime();
  ierr = BigSolver.Factor();
  if (ierr!=0 && verbose) std::cout << "Error in factorization = "<<ierr<< std::endl;
  assert(ierr==0);
  double time = Timer.ElapsedTime() - tstart;

  double FLOPS = counter.Flops();
  double MFLOPS = FLOPS/time/1000000.0;
  if (verbose) std::cout << "MFLOPS for Factorization = " << MFLOPS << std::endl;

  // Define Left hand side and right hand side
  Epetra_SerialDenseMatrix LHS(View, X, LDX, N, NRHS);
  Epetra_SerialDenseMatrix RHS;
  RHS.Shape(N,NRHS); // Allocate RHS

  // Compute RHS from A and X

  Epetra_Flops RHS_counter;
  RHS.SetFlopCounter(RHS_counter);
  tstart = Timer.ElapsedTime();
  RHS.Multiply('L', 1.0, OrigBigMatrix, LHS, 0.0); // Symmetric Matrix-multiply
  time = Timer.ElapsedTime() - tstart;

  Epetra_SerialDenseMatrix OrigRHS = RHS;

  FLOPS = RHS_counter.Flops();
  MFLOPS = FLOPS/time/1000000.0;
  if (verbose) std::cout << "MFLOPS to build RHS (NRHS = " << NRHS <<") = " << MFLOPS << std::endl;

  // Set LHS and RHS and solve
  BigSolver.SetVectors(LHS, RHS);

  tstart = Timer.ElapsedTime();
  ierr = BigSolver.Solve();
  if (ierr==1 && verbose) std::cout << "LAPACK guidelines suggest this matrix might benefit from equilibration." << std::endl;
  else if (ierr!=0 && verbose) std::cout << "Error in solve = "<<ierr<< std::endl;
  assert(ierr>=0);
  time = Timer.ElapsedTime() - tstart;

  FLOPS = BigSolver.Flops();
  MFLOPS = FLOPS/time/1000000.0;
  if (verbose) std::cout << "MFLOPS for Solve (NRHS = " << NRHS <<") = " << MFLOPS << std::endl;

  double * resid = new double[NRHS];
  bool OK = Residual(N, NRHS, A, LDA, BigSolver.X(), BigSolver.LDX(),
		     OrigRHS.A(), OrigRHS.LDA(), resid);

  if (verbose) {
    if (!OK) std::cout << "************* Residual do not meet tolerance *************" << std::endl;
    for (i=0; i<NRHS; i++)
      std::cout << "Residual[" << i <<"] = "<< resid[i] << std::endl;
    std::cout  << std::endl;
  }

  // Solve again using the Epetra_SerialDenseVector class for LHS and RHS

  Epetra_SerialDenseVector X2;
  Epetra_SerialDenseVector B2;
  X2.Size(BigMatrix.N());
  B2.Size(BigMatrix.M());
  int length = BigMatrix.N();
  {for (int kk=0; kk<length; kk++) X2[kk] = ((double ) kk)/ ((double) length);} // Define entries of X2

  RHS_counter.ResetFlops();
  B2.SetFlopCounter(RHS_counter);
  tstart = Timer.ElapsedTime();
  B2.Multiply('N', 'N', 1.0, OrigBigMatrix, X2, 0.0); // Define B2 = A*X2
  time = Timer.ElapsedTime() - tstart;

  Epetra_SerialDenseVector OrigB2 = B2;

  FLOPS = RHS_counter.Flops();
  MFLOPS = FLOPS/time/1000000.0;
  if (verbose) std::cout << "MFLOPS to build single RHS = " << MFLOPS << std::endl;

  // Set LHS and RHS and solve
  BigSolver.SetVectors(X2, B2);

  tstart = Timer.ElapsedTime();
  ierr = BigSolver.Solve();
  time = Timer.ElapsedTime() - tstart;
  if (ierr==1 && verbose) std::cout << "LAPACK guidelines suggest this matrix might benefit from equilibration." << std::endl;
  else if (ierr!=0 && verbose) std::cout << "Error in solve = "<<ierr<< std::endl;
  assert(ierr>=0);

  FLOPS = counter.Flops();
  MFLOPS = FLOPS/time/1000000.0;
  if (verbose) std::cout << "MFLOPS to solve single RHS = " << MFLOPS << std::endl;

  OK = Residual(N, 1, A, LDA, BigSolver.X(), BigSolver.LDX(), OrigB2.A(),
		OrigB2.LDA(), resid);

  if (verbose) {
    if (!OK) std::cout << "************* Residual do not meet tolerance *************" << std::endl;
      std::cout << "Residual = "<< resid[0] << std::endl;
  }
  delete [] resid;
  delete [] A;
  delete [] X;

  ///////////////////////////////////////////////////
  // Now test default constructor and index operators
  ///////////////////////////////////////////////////

  N = 5;
  Epetra_SerialSymDenseMatrix C; // Implicit call to default constructor, should not need to call destructor
  C.Shape(5); // Make it 5 by 5
  double * C1 = new double[N*N];
  GenerateHilbert(C1, N, N); // Generate Hilber matrix

  C1[1+2*N] = 1000.0;  // Make matrix nonsymmetric

  // Fill values of C with Hilbert values
  for (i=0; i<N; i++)
    for (j=0; j<N; j++)
      C(i,j) = C1[i+j*N];

  // Test if values are correctly written and read
  for (i=0; i<N; i++)
    for (j=0; j<N; j++) {
      assert(C(i,j) == C1[i+j*N]);
      assert(C(i,j) == C[j][i]);
    }

  if (verbose)
    std::cout << "Default constructor and index operator check OK.  Values of Hilbert matrix = "
	 << std::endl << C << std::endl
	 << "Values should be 1/(i+j+1), except value (1,2) should be 1000" << std::endl;

  delete [] C1;


#ifdef EPETRA_MPI
  MPI_Finalize() ;
#endif

/* end main
*/
return ierr ;
}
Beispiel #10
0
QRect CEdge::drawTree( Q3Canvas* canvas, int left, int depth, StringToString* filter )
{
	int X_PADDING = 10;
	int Y_SPACING = 30;

//	int X_MARGIN = 10; unused variable 'X_Margin'
	int Y_MARGIN = 10;

	//================================================

	Q3CanvasItem* edge = new Q3CanvasText( LHS(), canvas ),
			   * leaf = NULL;
	Q3CanvasLine* line;

	m_CanvasItems.clear();
	m_CanvasItems.append( edge );

	int myLeft = left,
		myTop = ( depth * Y_SPACING ) + Y_MARGIN,
		myCenterX,
		myBottom,
		childCenterX,
		childLeft,
		childTop,
		shiftAmount;

	Q3ValueList<QRect> daughterBoundingRectangles;
	Q3ValueList<QRect>::iterator it;

	QRect myBoundingRect, rectangle;
	myBoundingRect.setTop( myTop );
	myBoundingRect.setLeft( myLeft );
	myBoundingRect.setBottom( myTop + edge->boundingRect().height() - 1 );
	myBoundingRect.setRight( myLeft + edge->boundingRect().width() - 1 );
	
	int count = 0;
//	bool first = TRUE; unused variable 'first'

	CEdge* daughter;
	for( daughter = m_Daughters.first(); daughter; daughter = m_Daughters.next() )
	{
		daughterBoundingRectangles.append( rectangle );

		daughterBoundingRectangles[count] = daughter->drawTree( canvas, left, depth + 1, filter );

		// Adjust left position based on bounding rectangle of last daughter
		left = daughterBoundingRectangles[count].right() + X_PADDING;

		count++;
	}

	if( m_Daughters.isEmpty() )
	{
		// Create leaf node
		childLeft = myLeft;
		childTop = ( ( depth + 1 ) * Y_SPACING ) + Y_MARGIN;

		leaf = new Q3CanvasText( Filter( filter, RHS() ), canvas );
		m_CanvasItems.append( leaf );

		leaf->move( childLeft, childTop );
		leaf->show();

		// Adjust my bounding rect
		if( leaf->boundingRect().right() > myBoundingRect.right() ) myBoundingRect.setRight( leaf->boundingRect().right() );
		myBoundingRect.setBottom( leaf->boundingRect().bottom() );
	}
	else
	{
		for( it = daughterBoundingRectangles.begin(); it != daughterBoundingRectangles.end(); ++it )
		{
			// Adjust my bounding rect
			if( (*it).right() > myBoundingRect.right() ) myBoundingRect.setRight( (*it).right() );
			if( (*it).bottom() > myBoundingRect.bottom() ) myBoundingRect.setBottom( (*it).bottom() );
		}
	}
	
	if( myBoundingRect.width() == edge->boundingRect().width() ) 
	{
		// Shift all children to the right
		if( m_Daughters.isEmpty() )
		{
			shiftAmount = int (( myBoundingRect.width() - leaf->boundingRect().width() ) / 2.0);

			leaf->move( leaf->boundingRect().left() + shiftAmount, leaf->boundingRect().top() );
			leaf->show();
		}
		else
		{
			shiftAmount = int (( myBoundingRect.width() - ( daughterBoundingRectangles.last().right() - daughterBoundingRectangles.first().left() ) ) / 2.0);
			
			for( daughter = m_Daughters.first(); daughter; daughter = m_Daughters.next() )
			{
				daughter->shiftTree( canvas, shiftAmount, 0 );
			}

			for( it = daughterBoundingRectangles.begin(); it != daughterBoundingRectangles.end(); ++it )
			{
				// Adjust the bounding rect position
				(*it).setLeft( (*it).left() + shiftAmount );
				(*it).setRight( (*it).right() + shiftAmount );
			}
		}
	}
	else myLeft = ( myBoundingRect.right() - ( myBoundingRect.width() / 2 ) ) - ( edge->boundingRect().width() / 2 );


	if( myLeft < myBoundingRect.left() ) myLeft = myBoundingRect.left();
	edge->move( myLeft, myTop );

	// Draw lines to daughter nodes
	if( m_Daughters.isEmpty() )
	{
		myCenterX = edge->boundingRect().center().x();
		myBottom = edge->boundingRect().bottom();

		childCenterX = leaf->boundingRect().center().x();
		childTop = leaf->boundingRect().top();

		if( myCenterX - childCenterX == 1 || myCenterX - childCenterX == -1 ) myCenterX = childCenterX;

		line = new Q3CanvasLine( canvas );
		line->setPoints( myCenterX, myBottom, childCenterX, childTop );
		line->show();

		m_CanvasItems.append( line );
	}
	else
	{
		Q3ValueList<QRect>::iterator it;
		for( it = daughterBoundingRectangles.begin(); it != daughterBoundingRectangles.end(); ++it )
		{
			myCenterX = edge->boundingRect().center().x();
			myBottom = edge->boundingRect().bottom();

			childCenterX = (*it).center().x();
			childTop = (*it).top();

			if( myCenterX - childCenterX == 1 || myCenterX - childCenterX == -1 ) myCenterX = childCenterX;

			line = new Q3CanvasLine( canvas );
			line->setPoints( myCenterX, myBottom, childCenterX, childTop );
			line->show();

			m_CanvasItems.append( line );
		}
	}

	edge->show();
	canvas->update();

	return myBoundingRect;
}
// ====================================================================== 
bool KrylovTest(string PrecType, const Teuchos::RefCountPtr<Epetra_RowMatrix>& A, bool backward, bool reorder=false)
{
  Epetra_MultiVector LHS(A->RowMatrixRowMap(), NumVectors);
  Epetra_MultiVector RHS(A->RowMatrixRowMap(), NumVectors);
  LHS.PutScalar(0.0); RHS.Random();

  Epetra_LinearProblem Problem(&*A, &LHS, &RHS);

  // Set up the list
  Teuchos::ParameterList List;
  List.set("relaxation: damping factor", 1.0);
  List.set("relaxation: type", PrecType);
  if(backward) List.set("relaxation: backward mode",backward);  

  // Reordering if needed
  int NumRows=A->NumMyRows();
  std::vector<int> RowList(NumRows);
  if(reorder) {
    for(int i=0; i<NumRows; i++)
      RowList[i]=i;
    List.set("relaxation: number of local smoothing indices",NumRows);
    List.set("relaxation: local smoothing indices",RowList.size()>0? &RowList[0] : (int*)0);
  }


  int Iters1, Iters10;

  if (verbose) {
    cout << "Krylov test: Using " << PrecType 
         << " with AztecOO" << endl;
  }

  // ============================================== //
  // get the number of iterations with 1 sweep only //
  // ============================================== //
  {

    List.set("relaxation: sweeps",1);
    Ifpack_PointRelaxation Point(&*A);
    Point.SetParameters(List);
    Point.Compute();

    // set AztecOO solver object
    AztecOO AztecOOSolver(Problem);
    AztecOOSolver.SetAztecOption(AZ_solver,Solver);
    AztecOOSolver.SetAztecOption(AZ_output,AZ_none);
    AztecOOSolver.SetPrecOperator(&Point);

    AztecOOSolver.Iterate(2550,1e-5);

    double TrueResidual = AztecOOSolver.TrueResidual();
    // some output
    if (verbose && Problem.GetMatrix()->Comm().MyPID() == 0) {
      cout << "Norm of the true residual = " << TrueResidual << endl;
    }
    Iters1 = AztecOOSolver.NumIters();
  }
 
  // ======================================================== //
  // now re-run with 10 sweeps, solver should converge faster
  // ======================================================== //
  {
    List.set("relaxation: sweeps",10);
    Ifpack_PointRelaxation Point(&*A);
    Point.SetParameters(List);
    Point.Compute();
    LHS.PutScalar(0.0);

    // set AztecOO solver object
    AztecOO AztecOOSolver(Problem);
    AztecOOSolver.SetAztecOption(AZ_solver,Solver);
    AztecOOSolver.SetAztecOption(AZ_output,AZ_none);
    AztecOOSolver.SetPrecOperator(&Point);
    AztecOOSolver.Iterate(2550,1e-5);

    double TrueResidual = AztecOOSolver.TrueResidual();
    // some output
    if (verbose && Problem.GetMatrix()->Comm().MyPID() == 0) {
      cout << "Norm of the true residual = " << TrueResidual << endl;
    }
    Iters10 = AztecOOSolver.NumIters();
  }

  if (verbose) {
    cout << "Iters_1 = " << Iters1 << ", Iters_10 = " << Iters10 << endl;
    cout << "(second number should be smaller than first one)" << endl;
  }

  if (Iters10 > Iters1) {
    if (verbose)
      cout << "KrylovTest TEST FAILED!" << endl;
    return(false);
  }
  else {
    if (verbose)
      cout << "KrylovTest TEST PASSED" << endl;
    return(true);
  }
}
// A second pass deriving better H from previous H is worthwhile.
// More such passes gain nothing for the extra compute time.
//
void MHmgphy::HmgphyFromHmgphy( vector<double> &X, int nTr )
{
	double	sc		= 2 * max( gW, gH );
	int		nvars	= nTr * NX;

	printf( "Hmg: %d unknowns; %d constraints.\n",
		nvars, vAllC.size() );

	vector<double> RHS( nvars, 0.0 );
	vector<LHSCol> LHS( nvars );

	X.resize( nvars );

// Apply previous final results at highest level, once only

	SetUniteLayer( LHS, RHS, sc );

// Get the Homographies A

	vector<double>	A;
	HmgphyFromAffine( A, nTr );

// SetPointPairs: H(pi) = A(pj)

	double	fz	= 1.0;
	int		nc	= vAllC.size();

	for( int i = 0; i < nc; ++i ) {

		const Constraint &C = vAllC[i];

		if( !C.used || !C.inlier )
			continue;

		// H(p1) = A(p2)
		{
			int		j  = vRgn[C.r1].itr * NX;
			double	x1 = C.p1.x * fz / sc,
					y1 = C.p1.y * fz / sc,
					x2,
					y2;
			Point	g2 = C.p2;

			L2GPoint( g2, A, vRgn[C.r2].itr );
			x2 = g2.x / sc;
			y2 = g2.y / sc;

			double	v[5]	= { x1, y1, fz, -x1*x2, -y1*x2 };
			int		i1[5]	= {   j, j+1, j+2, j+6, j+7 },
					i2[5]	= { j+3, j+4, j+5, j+6, j+7 };

			AddConstraint( LHS, RHS, 5, i1, v, x2 * fz );

			v[3] = -x1*y2;
			v[4] = -y1*y2;

			AddConstraint( LHS, RHS, 5, i2, v, y2 * fz );
		}

		// H(p2) = A(p1)
		{
			int		j  = vRgn[C.r2].itr * NX;
			double	x1 = C.p2.x * fz / sc,
					y1 = C.p2.y * fz / sc,
					x2,
					y2;
			Point	g2 = C.p1;

			L2GPoint( g2, A, vRgn[C.r1].itr );
			x2 = g2.x / sc;
			y2 = g2.y / sc;

			double	v[5]	= { x1, y1, fz, -x1*x2, -y1*x2 };
			int		i1[5]	= {   j, j+1, j+2, j+6, j+7 },
					i2[5]	= { j+3, j+4, j+5, j+6, j+7 };

			AddConstraint( LHS, RHS, 5, i1, v, x2 * fz );

			v[3] = -x1*y2;
			v[4] = -y1*y2;

			AddConstraint( LHS, RHS, 5, i2, v, y2 * fz );
		}
	}

// Solve

	WriteSolveRead( X, LHS, RHS, "H-FrmH", nproc, false );
	PrintMagnitude( X );

	RescaleAll( X, sc );
}
int main(int argc, char *argv[])
{
  // initialize MPI and Epetra communicator
#ifdef HAVE_MPI
  MPI_Init(&argc,&argv);
  Epetra_MpiComm Comm( MPI_COMM_WORLD );
#else
  Epetra_SerialComm Comm;
#endif

  Teuchos::ParameterList GaleriList;

  // The problem is defined on a 2D grid, global size is nx * nx.
  int nx = 30; 
  GaleriList.set("nx", nx);
  GaleriList.set("ny", nx * Comm.NumProc());
  GaleriList.set("mx", 1);
  GaleriList.set("my", Comm.NumProc());
  Teuchos::RefCountPtr<Epetra_Map> Map = Teuchos::rcp( Galeri::CreateMap64("Cartesian2D", Comm, GaleriList) );
  Teuchos::RefCountPtr<Epetra_RowMatrix> A = Teuchos::rcp( Galeri::CreateCrsMatrix("Laplace2D", &*Map, GaleriList) );

  // =============================================================== //
  // B E G I N N I N G   O F   I F P A C K   C O N S T R U C T I O N //
  // =============================================================== //

  Teuchos::ParameterList List;

  // builds an Ifpack_AdditiveSchwarz. This is templated with
  // the local solvers, in this case Ifpack_BlockRelaxation.
  // Ifpack_BlockRelaxation requires as a templated a container
  // class. A container defines
  // how to store the diagonal blocks. Two choices are available:
  // Ifpack_DenseContainer (to store them as dense block,
  // than use LAPACK' factorization to apply the inverse of
  // each block), of Ifpack_SparseContainer (to store
  // the diagonal block as Epetra_CrsMatrix's). 
  // 
  // Here, we use Ifpack_SparseContainer, which in turn is
  // templated with the class to use to apply the inverse
  // of each block. For example, we can use Ifpack_Amesos.
 
  // We still have to decide the overlap among the processes,
  // and the overlap among the blocks. The two values
  // can be different. The overlap among the blocks is
  // considered only if block Jacobi is used.
  int OverlapProcs = 2;
  int OverlapBlocks = 0;

  // define the block below to use dense containers
#if 0
  Ifpack_AdditiveSchwarz<Ifpack_BlockRelaxation<Ifpack_DenseContainer> > Prec(A, OverlapProcs);
#else
  Ifpack_AdditiveSchwarz<Ifpack_BlockRelaxation<Ifpack_SparseContainer<Ifpack_Amesos> > > Prec(&*A, OverlapProcs);
#endif

  List.set("relaxation: type", "symmetric Gauss-Seidel");
  List.set("partitioner: overlap", OverlapBlocks);
#ifdef HAVE_IFPACK_METIS
  // use METIS to create the blocks. This requires --enable-ifpack-metis.
  // If METIS is not installed, the user may select "linear". 
  List.set("partitioner: type", "metis");
#else
  // or a simple greedy algorithm is METIS is not enabled
  List.set("partitioner: type", "greedy");
#endif
  // defines here the number of local blocks. If 1,
  // and only one process is used in the computation, then
  // the preconditioner must converge in one iteration. 
  List.set("partitioner: local parts", 4);

  // sets the parameters
  IFPACK_CHK_ERR(Prec.SetParameters(List));

  // initialize the preconditioner. 
  IFPACK_CHK_ERR(Prec.Initialize());

  // Builds the preconditioners.
  IFPACK_CHK_ERR(Prec.Compute());

  // =================================================== //
  // E N D   O F   I F P A C K   C O N S T R U C T I O N //
  // =================================================== //

  // At this point, we need some additional objects
  // to define and solve the linear system.

  // defines LHS and RHS
  Epetra_Vector LHS(A->OperatorDomainMap());
  Epetra_Vector RHS(A->OperatorDomainMap());

  LHS.PutScalar(0.0);
  RHS.Random();

  // need an Epetra_LinearProblem to define AztecOO solver
  Epetra_LinearProblem Problem(&*A,&LHS,&RHS);

  // now we can allocate the AztecOO solver
  AztecOO Solver(Problem);

  // specify solver
  Solver.SetAztecOption(AZ_solver,AZ_cg);
  Solver.SetAztecOption(AZ_output,32);

  // HERE WE SET THE IFPACK PRECONDITIONER
  Solver.SetPrecOperator(&Prec);

  // .. and here we solve
  // NOTE: with one process, the solver must converge in
  // one iteration.
  Solver.Iterate(1550,1e-5);

#ifdef HAVE_MPI
  MPI_Finalize() ; 
#endif

  return(EXIT_SUCCESS);
}
// Experiment to use approximations H(pi) = T(pj). In practice
// translations lack the accuracy of affines and are always an
// inferior starting point for homographies.
//
void MHmgphy::HmgphyFromTrans( vector<double> &X, int nTr )
{
	double	sc		= 2 * max( gW, gH );
	int		nvars	= nTr * NX;

	printf( "Hmg: %d unknowns; %d constraints.\n",
		nvars, vAllC.size() );

	vector<double> RHS( nvars, 0.0 );
	vector<LHSCol> LHS( nvars );

	X.resize( nvars );

// Get the pure translations T

	MTrans			M;
	vector<double>	T;

	M.SetModelParams( gW, gH, -1, -1, -1, -1,
		nproc, -1, NULL, NULL, zs );
	M.SolveSystem( T, nTr );

// SetPointPairs: H(pi) = T(pj)

	double	fz	= 1.0;
	int		nc	= vAllC.size();

	for( int i = 0; i < nc; ++i ) {

		const Constraint &C = vAllC[i];

		if( !C.used || !C.inlier )
			continue;

		// H(p1) = T(p2)
		{
			int		j  = vRgn[C.r1].itr * NX,
					k  = vRgn[C.r2].itr * 2;
			double	x1 = C.p1.x * fz / sc,
					y1 = C.p1.y * fz / sc,
					x2 = (C.p2.x + T[k  ]) / sc,
					y2 = (C.p2.y + T[k+1]) / sc;

			double	v[5]	= { x1, y1, fz, -x1*x2, -y1*x2 };
			int		i1[5]	= {   j, j+1, j+2, j+6, j+7 },
					i2[5]	= { j+3, j+4, j+5, j+6, j+7 };

			AddConstraint( LHS, RHS, 5, i1, v, x2 * fz );

			v[3] = -x1*y2;
			v[4] = -y1*y2;

			AddConstraint( LHS, RHS, 5, i2, v, y2 * fz );
		}

		// H(p2) = T(p1)
		{
			int		j  = vRgn[C.r2].itr * NX,
					k  = vRgn[C.r1].itr * 2;
			double	x1 = C.p2.x * fz / sc,
					y1 = C.p2.y * fz / sc,
					x2 = (C.p1.x + T[k  ]) / sc,
					y2 = (C.p1.y + T[k+1]) / sc;

			double	v[5]	= { x1, y1, fz, -x1*x2, -y1*x2 };
			int		i1[5]	= {   j, j+1, j+2, j+6, j+7 },
					i2[5]	= { j+3, j+4, j+5, j+6, j+7 };

			AddConstraint( LHS, RHS, 5, i1, v, x2 * fz );

			v[3] = -x1*y2;
			v[4] = -y1*y2;

			AddConstraint( LHS, RHS, 5, i2, v, y2 * fz );
		}
	}

// Solve

	WriteSolveRead( X, LHS, RHS, "H-FrmT", nproc, false );
	PrintMagnitude( X );

	RescaleAll( X, sc );
}
// Like AffineFromAffine, try another pass of scaffold refinement.
//
void MAffine::AffineFromAffine2( vector<double> &X, int nTr )
{
	double	sc		= 2 * max( gW, gH );
	int		nvars	= nTr * NX;

	printf( "Aff: %d unknowns; %d constraints.\n",
		nvars, vAllC.size() );

	vector<double> RHS( nvars, 0.0 );
	vector<LHSCol> LHS( nvars );

	X.resize( nvars );

// Get the Affines A

	vector<double>	A;
	AffineFromAffine( A, nTr );

// SetPointPairs: A(pi) = A(pj)

	double	fz	= 1.0;
	int		nc	= vAllC.size();

	for( int i = 0; i < nc; ++i ) {

		const Constraint &C = vAllC[i];

		if( !C.used || !C.inlier )
			continue;

		// A(p1) = A(p2)
		{
			int		j  = vRgn[C.r1].itr * NX;
			double	x1 = C.p1.x * fz / sc,
					y1 = C.p1.y * fz / sc,
					x2,
					y2;
			Point	g2 = C.p2;

			L2GPoint( g2, A, vRgn[C.r2].itr );
			x2 = g2.x * fz / sc;
			y2 = g2.y * fz / sc;

			double	v[3]	= {  x1,  y1,  fz };
			int		i1[3]	= {   j, j+1, j+2 },
					i2[3]	= { j+3, j+4, j+5 };

			AddConstraint( LHS, RHS, 3, i1, v, x2 );
			AddConstraint( LHS, RHS, 3, i2, v, y2 );
		}

		// A(p2) = T(p1)
		{
			int		j  = vRgn[C.r2].itr * NX;
			double	x1 = C.p2.x * fz / sc,
					y1 = C.p2.y * fz / sc,
					x2,
					y2;
			Point	g2 = C.p1;

			L2GPoint( g2, A, vRgn[C.r1].itr );
			x2 = g2.x * fz / sc;
			y2 = g2.y * fz / sc;

			double	v[3]	= {  x1,  y1,  fz };
			int		i1[3]	= {   j, j+1, j+2 },
					i2[3]	= { j+3, j+4, j+5 };

			AddConstraint( LHS, RHS, 3, i1, v, x2 );
			AddConstraint( LHS, RHS, 3, i2, v, y2 );
		}
	}

// Solve

	//SolveWithSquareness( X, LHS, RHS, nTr );
	//SolveWithUnitMag( X, LHS, RHS, nTr );

	WriteSolveRead( X, LHS, RHS, "A-FrmA2", nproc, false );
	PrintMagnitude( X );

	RescaleAll( X, sc );
}
// This method for solving montages omits calling SetPointPairs
// to assert A1(p1) - A2(p2). Rather, we only set approximations
// A(pi) = T(pj). This isn't nearly as accurate as the current
// favorite AffineFromTransWt, which combines SetPointPairs with
// downweighted scaffold constraints A(pi) = T(pj).
//
// Rather than give up on this method, I also tried to improve
// results by a series of scaffold refinements. That is, first
// get T's, use those to get A's, use those to get better A's
// do that again. The result of that slowly converges toward
// AffineFromTransWt but a great computaion cost. These iterative
// experiment snippets follow.
//
void MAffine::AffineFromTrans( vector<double> &X, int nTr )
{
	double	sc		= 2 * max( gW, gH );
	int		nvars	= nTr * NX;

	printf( "Aff: %d unknowns; %d constraints.\n",
		nvars, vAllC.size() );

	vector<double> RHS( nvars, 0.0 );
	vector<LHSCol> LHS( nvars );

	X.resize( nvars );

// Get the pure translations T

	MTrans			M;
	vector<double>	T;

	M.SetModelParams( gW, gH, -1, -1, -1, -1,
		nproc, -1, NULL, NULL, zs );
	M.SolveSystem( T, nTr );

// SetPointPairs: A(pi) = T(pj)

	int	nc = vAllC.size();

	for( int i = 0; i < nc; ++i ) {

		const Constraint &C = vAllC[i];

		if( !C.used || !C.inlier )
			continue;

		// A(p1) = T(p2)
		{
			int		j  = vRgn[C.r1].itr * NX,
					k  = vRgn[C.r2].itr * 2;
			double	x1 = C.p1.x * scaf_strength / sc,
					y1 = C.p1.y * scaf_strength / sc,
					x2 = (C.p2.x + T[k  ]) * scaf_strength / sc,
					y2 = (C.p2.y + T[k+1]) * scaf_strength / sc;

			double	v[3]	= {  x1,  y1, scaf_strength };
			int		i1[3]	= {   j, j+1, j+2 },
					i2[3]	= { j+3, j+4, j+5 };

			AddConstraint( LHS, RHS, 3, i1, v, x2 );
			AddConstraint( LHS, RHS, 3, i2, v, y2 );
		}

		// A(p2) = T(p1)
		{
			int		j  = vRgn[C.r2].itr * NX,
					k  = vRgn[C.r1].itr * 2;
			double	x1 = C.p2.x * scaf_strength / sc,
					y1 = C.p2.y * scaf_strength / sc,
					x2 = (C.p1.x + T[k  ]) * scaf_strength / sc,
					y2 = (C.p1.y + T[k+1]) * scaf_strength / sc;

			double	v[3]	= {  x1,  y1, scaf_strength };
			int		i1[3]	= {   j, j+1, j+2 },
					i2[3]	= { j+3, j+4, j+5 };

			AddConstraint( LHS, RHS, 3, i1, v, x2 );
			AddConstraint( LHS, RHS, 3, i2, v, y2 );
		}
	}

// Solve

	//SolveWithSquareness( X, LHS, RHS, nTr );
	//SolveWithUnitMag( X, LHS, RHS, nTr );

	WriteSolveRead( X, LHS, RHS, "A-FrmT", nproc, false );
	PrintMagnitude( X );

	RescaleAll( X, sc );
}
int main(int argc, char *argv[])
{

  // initialize MPI and Epetra communicator
#ifdef HAVE_MPI
  MPI_Init(&argc,&argv);
  Epetra_MpiComm Comm( MPI_COMM_WORLD );
#else
  Epetra_SerialComm Comm;
#endif

  Teuchos::ParameterList GaleriList;

  // The problem is defined on a 2D grid, global size is nx * nx.
  int nx = 30; 
  GaleriList.set("nx", nx);
  GaleriList.set("ny", nx * Comm.NumProc());
  GaleriList.set("mx", 1);
  GaleriList.set("my", Comm.NumProc());
  Teuchos::RefCountPtr<Epetra_Map> Map = Teuchos::rcp( Galeri::CreateMap64("Cartesian2D", Comm, GaleriList) );
  Teuchos::RefCountPtr<Epetra_RowMatrix> A = Teuchos::rcp( Galeri::CreateCrsMatrix("Laplace2D", &*Map, GaleriList) );

  // =============================================================== //
  // B E G I N N I N G   O F   I F P A C K   C O N S T R U C T I O N //
  // =============================================================== //

  Teuchos::ParameterList List;

  // builds an Ifpack_AdditiveSchwarz. This is templated with
  // the local solvers, in this case Ifpack_ICT. Note that any
  // other Ifpack_Preconditioner-derived class can be used
  // instead of Ifpack_ICT.

  // In this example the overlap is zero. Use
  // Prec(A,OverlapLevel) for the general case.
  Ifpack_AdditiveSchwarz<Ifpack_ICT> Prec(&*A);

  // `1.0' means that the factorization should approximatively
  // keep the same number of nonzeros per row of the original matrix.
  List.set("fact: ict level-of-fill", 1.0);
  // no modifications on the diagonal
  List.set("fact: absolute threshold", 0.0);
  List.set("fact: relative threshold", 1.0);
  List.set("fact: relaxation value", 0.0);
  // matrix `laplace_2d_bc' is not symmetric because of the way
  // boundary conditions are imposed. We can filter the singletons,
  // (that is, Dirichlet nodes) and end up with a symmetric
  // matrix (as ICT requires).
  List.set("schwarz: filter singletons", true);

  // sets the parameters
  IFPACK_CHK_ERR(Prec.SetParameters(List));

  // initialize the preconditioner. At this point the matrix must
  // have been FillComplete()'d, but actual values are ignored.
  IFPACK_CHK_ERR(Prec.Initialize());

  // Builds the preconditioners, by looking for the values of 
  // the matrix. 
  IFPACK_CHK_ERR(Prec.Compute());

  // =================================================== //
  // E N D   O F   I F P A C K   C O N S T R U C T I O N //
  // =================================================== //

  // At this point, we need some additional objects
  // to define and solve the linear system.

  // defines LHS and RHS
  Epetra_Vector LHS(A->OperatorDomainMap());
  Epetra_Vector RHS(A->OperatorDomainMap());

  LHS.PutScalar(0.0);
  RHS.Random();

  // need an Epetra_LinearProblem to define AztecOO solver
  Epetra_LinearProblem Problem(&*A,&LHS,&RHS);

  // now we can allocate the AztecOO solver
  AztecOO Solver(Problem);

  // specify solver
  Solver.SetAztecOption(AZ_solver,AZ_cg_condnum);
  Solver.SetAztecOption(AZ_output,32);

  // HERE WE SET THE IFPACK PRECONDITIONER
  Solver.SetPrecOperator(&Prec);

  // .. and here we solve
  // NOTE: with one process, the solver must converge in
  // one iteration.
  Solver.Iterate(1550,1e-5);

  // Prints out some information about the preconditioner
  cout << Prec;

#ifdef HAVE_MPI
  MPI_Finalize(); 
#endif

  return (EXIT_SUCCESS);
}
Beispiel #18
0
//==========================================================================
int Ifpack_ICT::Compute() 
{
  if (!IsInitialized()) 
    IFPACK_CHK_ERR(Initialize());

  Time_.ResetStartTime();
  IsComputed_ = false;

  NumMyRows_ = A_.NumMyRows();
  int Length = A_.MaxNumEntries();
  vector<int>    RowIndices(Length);
  vector<double> RowValues(Length);

  bool distributed = (Comm().NumProc() > 1)?true:false;

  if (distributed)
  {
    SerialComm_ = Teuchos::rcp(new Epetra_SerialComm);
    SerialMap_ = Teuchos::rcp(new Epetra_Map(NumMyRows_, 0, *SerialComm_));
    assert (SerialComm_.get() != 0);
    assert (SerialMap_.get() != 0);
  }
  else
    SerialMap_ = Teuchos::rcp(const_cast<Epetra_Map*>(&A_.RowMatrixRowMap()), false);

  int RowNnz;
#ifdef IFPACK_FLOPCOUNTERS
  double flops = 0.0;
#endif

  H_ = Teuchos::rcp(new Epetra_CrsMatrix(Copy,*SerialMap_,0));
  if (H_.get() == 0)
    IFPACK_CHK_ERR(-5); // memory allocation error

  // get A(0,0) element and insert it (after sqrt)
  IFPACK_CHK_ERR(A_.ExtractMyRowCopy(0,Length,RowNnz,
                                     &RowValues[0],&RowIndices[0]));

  // skip off-processor elements
  if (distributed)
  {
    int count = 0;
    for (int i = 0 ;i < RowNnz ; ++i) 
    {
      if (RowIndices[i] < NumMyRows_){
        RowIndices[count] = RowIndices[i];
        RowValues[count] = RowValues[i];
        ++count;
      }
      else
        continue;
    }
    RowNnz = count;
  }

  // modify diagonal
  double diag_val = 0.0;
  for (int i = 0 ;i < RowNnz ; ++i) {
    if (RowIndices[i] == 0) {
      double& v = RowValues[i];
      diag_val = AbsoluteThreshold() * EPETRA_SGN(v) +
        RelativeThreshold() * v;
      break;
    }
  }

  diag_val = sqrt(diag_val);
  int diag_idx = 0;
  EPETRA_CHK_ERR(H_->InsertGlobalValues(0,1,&diag_val, &diag_idx));

  // The 10 is just a small constant to limit collisons as the actual keys
  // we store are the indices and not integers
  // [0..A_.MaxNumEntries()*LevelofFill()].
  Ifpack_HashTable Hash( 10 * A_.MaxNumEntries() * LevelOfFill(), 1);

  // start factorization for line 1
  for (int row_i = 1 ; row_i < NumMyRows_ ; ++row_i) {

    // get row `row_i' of the matrix
    IFPACK_CHK_ERR(A_.ExtractMyRowCopy(row_i,Length,RowNnz,
                                       &RowValues[0],&RowIndices[0]));

    // skip off-processor elements
    if (distributed)
    {
      int count = 0;
      for (int i = 0 ;i < RowNnz ; ++i) 
      {
        if (RowIndices[i] < NumMyRows_){
          RowIndices[count] = RowIndices[i];
          RowValues[count] = RowValues[i];
          ++count;
        }
        else
          continue;
      }
      RowNnz = count;
    }

    // number of nonzeros in this row are defined as the nonzeros
    // of the matrix, plus the level of fill 
    int LOF = (int)(LevelOfFill() * RowNnz);
    if (LOF == 0) LOF = 1;

    // convert line `row_i' into hash for fast access
    Hash.reset();

    double h_ii = 0.0;
    for (int i = 0 ; i < RowNnz ; ++i) {
      if (RowIndices[i] == row_i) {
        double& v = RowValues[i];
        h_ii = AbsoluteThreshold() * EPETRA_SGN(v) + RelativeThreshold() * v;
      }
      else if (RowIndices[i] < row_i)
      {
        Hash.set(RowIndices[i], RowValues[i], true);
      }
    }
      
    // form element (row_i, col_j)
    // I start from the first row that has a nonzero column
    // index in row_i.
    for (int col_j = RowIndices[0] ; col_j < row_i ; ++col_j) {

      double h_ij = 0.0, h_jj = 0.0;
      // note: get() returns 0.0 if col_j is not found
      h_ij = Hash.get(col_j);

      // get pointers to row `col_j'
      int* ColIndices;
      double* ColValues;
      int ColNnz;
      H_->ExtractGlobalRowView(col_j, ColNnz, ColValues, ColIndices);

      for (int k = 0 ; k < ColNnz ; ++k) {
        int col_k = ColIndices[k];

        if (col_k == col_j)
          h_jj = ColValues[k];
        else {
          double xxx = Hash.get(col_k);
          if (xxx != 0.0)
          {
            h_ij -= ColValues[k] * xxx;
#ifdef IFPACK_FLOPCOUNTERS
            flops += 2.0;
#endif
          }
        }
      }

      h_ij /= h_jj;

      if (IFPACK_ABS(h_ij) > DropTolerance_)
      {
        Hash.set(col_j, h_ij);
      }
    
#ifdef IFPACK_FLOPCOUNTERS
      // only approx
      ComputeFlops_ += 2.0 * flops + 1.0;
#endif
    }

    int size = Hash.getNumEntries();

    vector<double> AbsRow(size);
    int count = 0;
    
    // +1 because I use the extra position for diagonal in insert
    vector<int> keys(size + 1);
    vector<double> values(size + 1);

    Hash.arrayify(&keys[0], &values[0]);

    for (int i = 0 ; i < size ; ++i)
    {
      AbsRow[i] = IFPACK_ABS(values[i]);
    }
    count = size;

    double cutoff = 0.0;
    if (count > LOF) {
      nth_element(AbsRow.begin(), AbsRow.begin() + LOF, AbsRow.begin() + count, 

		  std::greater<double>());
      cutoff = AbsRow[LOF];
    }

    for (int i = 0 ; i < size ; ++i)
    {
      h_ii -= values[i] * values[i];
    }

    if (h_ii < 0.0) h_ii = 1e-12;;

    h_ii = sqrt(h_ii);

#ifdef IFPACK_FLOPCOUNTERS
    // only approx, + 1 == sqrt
    ComputeFlops_ += 2 * size + 1;
#endif

    double DiscardedElements = 0.0;

    count = 0;
    for (int i = 0 ; i < size ; ++i)    
    { 
      if (IFPACK_ABS(values[i]) > cutoff)
      {
        values[count] = values[i];
        keys[count] = keys[i];
        ++count;
      }
      else  
        DiscardedElements += values[i];
    }

    if (RelaxValue() != 0.0) {
      DiscardedElements *= RelaxValue();
      h_ii += DiscardedElements;
    }

    values[count] = h_ii;
    keys[count] = row_i;
    ++count;

    H_->InsertGlobalValues(row_i, count, &(values[0]), (int*)&(keys[0]));
  }

  IFPACK_CHK_ERR(H_->FillComplete());

#if 0
  // to check the complete factorization
  Epetra_Vector LHS(Matrix().RowMatrixRowMap());
  Epetra_Vector RHS1(Matrix().RowMatrixRowMap());
  Epetra_Vector RHS2(Matrix().RowMatrixRowMap());
  Epetra_Vector RHS3(Matrix().RowMatrixRowMap());
  LHS.Random();

  Matrix().Multiply(false,LHS,RHS1);
  H_->Multiply(true,LHS,RHS2);
  H_->Multiply(false,RHS2,RHS3);

  RHS1.Update(-1.0, RHS3, 1.0);
  cout << endl;
  cout << RHS1;
#endif
  int MyNonzeros = H_->NumGlobalNonzeros();
  Comm().SumAll(&MyNonzeros, &GlobalNonzeros_, 1);

  IsComputed_ = true;
#ifdef IFPACK_FLOPCOUNTERS
  double TotalFlops; // sum across all the processors
  A_.Comm().SumAll(&flops, &TotalFlops, 1);
  ComputeFlops_ += TotalFlops;
#endif
  ++NumCompute_;
  ComputeTime_ += Time_.ElapsedTime();

  return(0);

}
Beispiel #19
0
void MeshEnergy::GetKappa( const std::vector<int>& C, const std::vector<double>& phi,
                           std::valarray<double>& kappa)
{
// kappa: divergence of normal
// dy^2 * dxx - 2dxdydxy + dx^2dyy / ( dx^2 + dy^2 )^(3/2)

  vtkPoints*    verts = meshdata->polydata->GetPoints();

  for( ::size_t k_ = 0; k_ < C.size(); k_++ )\
    {
    int k = C[k_];
    std::vector<double> nhat(3);
    nhat[0] = meshdata->nx[k]; // these are normal to surface; the nx_ are the contour normals
    nhat[1] = meshdata->ny[k];
    nhat[2] = meshdata->nz[k];
// step 1. create the rotation matrix that orients the current normal as [0,0,1]'.

    double phiang = atan2( nhat[0], nhat[1] );
    std::vector<double> rotate1(9);
    rotate1[0] = cos(phiang); rotate1[1] = -sin(phiang); rotate1[2] = 0;
    rotate1[3] = sin(phiang); rotate1[4] = cos(phiang); rotate1[5] = 0;
    rotate1[6] = 0; rotate1[7] = 0; rotate1[8] = 1.0;
    std::vector<double> nhat_a(3);
    pkmult( nhat, rotate1, nhat_a );
    double ytilde = nhat_a[1];
    double theta = M_PI_2 - atan2(nhat[2],ytilde);
    std::vector<double> rotate2(9);
    rotate2[0] = 1.0; rotate2[1] = 0; rotate2[2] = 0;
    rotate2[3] = 0; rotate2[4] = cos(theta); rotate2[5] = -sin(theta);
    rotate2[6] = 0; rotate2[7] = sin(theta); rotate2[8] = cos(theta);
    std::vector<double> nhat_b(3);
    pkmult( nhat_a, rotate2, nhat_b );
// nhat_b should now be [0 0 1]'

    double thispt[3];
    verts->GetPoint( k, thispt );
// apply rotate2 * rotate1 to each *translated* neighbor of this k-th point
    ::size_t num_neigh = meshdata->adj[k].myNeighbs.size();
    double vec[3];
    std::vector<double> vv(3);
    std::vector<double> vv_(3);
    std::valarray<double> xdata(num_neigh);
    std::valarray<double> ydata(num_neigh);
    std::valarray<double> zdata(num_neigh);
// step 2. create temporary set of std::vectors as copies of neighboring points
// translated to origin
// step 3. apply the rotation to all these points
    for (::size_t i = 0; i < num_neigh; i++ )
      {
      int idx = meshdata->adj[k].myNeighbs[i];
      verts->GetPoint( idx, vec );
      vv[0] = vec[0] - thispt[0];
      vv[1] = vec[1] - thispt[1];
      vv[2] = vec[2] - thispt[2];
      pkmult( vv, rotate1, vv_ );
      pkmult( vv_, rotate2, vv );
      xdata[i] = vv[0];
      ydata[i] = vv[1];
      zdata[i] = phi[idx] - phi[k]; //vv[2];
// zero reference phi at the vertex where we are forming tangent plane
      }
/*if( abs(zdata).min() < 1e-6 )
continue;*/

// step 4. find first derivatives
    double phi_x = 0.0;
    double phi_y = 0.0;
    {
    std::valarray<double> RHS(2);
    std::valarray<double> ATA(4);
    ATA[0] = (xdata * xdata).sum();
    ATA[1] = (xdata * ydata).sum();
    ATA[2] = ATA[1];
    ATA[3] = (ydata * ydata).sum();

    RHS[0] = (xdata * zdata).sum();
    RHS[1] = (ydata * zdata).sum();

    int maxits = 1000;
    std::valarray<double> ab = RHS; // initial guess
    std::valarray<double> LHS(2);
    pkmult2( ab, ATA, LHS );
    double res = sqrt( ( (LHS - RHS)*(LHS - RHS) ).sum() );
    double tol = 1e-8;
    int iter = 0;
    while( iter < maxits && res > tol )
      {
      iter++;
      ab[0] = (RHS[0] - ( ab[1]*ATA[1] ) )/ ATA[0];
      ab[1] = (RHS[1] - ( ab[0]*ATA[2] ) )/ ATA[3];
      pkmult2( ab, ATA, LHS );
      res = sqrt( ( (LHS - RHS)*(LHS - RHS) ).sum() );
      }
    phi_x = ab[0];
    phi_y = ab[1];
    }

// step 4. find least-squares fit for phi(x,y) = ax^2 + bxy + cy^2
// to get second derivatives
  std::valarray<double> RHS(3); // A'z
    RHS[0] = ( xdata * xdata * zdata  ).sum();
    RHS[1] = ( xdata * ydata * zdata  ).sum();
    RHS[2] = ( ydata * ydata * zdata  ).sum();

    double tik_delta = 1e-1 * abs(RHS).min();

    std::vector<double> ATA(9); // A'A
    ATA[0] = tik_delta + (xdata * xdata * xdata * xdata).sum();
    ATA[1] = (xdata * xdata * xdata * ydata).sum();
    ATA[2] = (xdata * xdata * ydata * ydata).sum();
    ATA[3] = (xdata * ydata * xdata * xdata).sum();
    ATA[4] = tik_delta + (xdata * ydata * xdata * ydata).sum();
    ATA[5] = (xdata * ydata * ydata * ydata).sum();
    ATA[6] = (ydata * ydata * xdata * xdata).sum();
    ATA[7] = (ydata * ydata * xdata * ydata).sum();
    ATA[8] = tik_delta + (ydata * ydata * ydata * ydata).sum();

    int maxits = 1000;
    std::valarray<double> abc = RHS; // initial guess
    std::valarray<double> LHS(3);
    pkmult( abc, ATA, LHS );
    double res = sqrt( ( (LHS - RHS)*(LHS - RHS) ).sum() );
    double tol = 1e-8;
    int iter = 0;
    while( iter < maxits && res > tol )
      {
      iter++;
      abc[0] = (RHS[0] - ( abc[1]*ATA[1] + abc[2]*ATA[2] ) )/ ATA[0];
      abc[1] = (RHS[1] - ( abc[0]*ATA[3] + abc[2]*ATA[5] ) )/ ATA[4];
      abc[2] = (RHS[2] - ( abc[0]*ATA[6] + abc[1]*ATA[7] ) )/ ATA[8];
      pkmult( abc, ATA, LHS );
      res = sqrt( ( (LHS - RHS)*(LHS - RHS) ).sum() );
      }
// step 5. get the derivatives from quadratic form
    double phi_xx = 2*abc[0];
    double phi_xy = abc[1];
    double phi_yy = 2*abc[2];

    kappa[k_] = phi_y * phi_y * phi_xx - 2 * phi_x * phi_y * phi_xy + phi_x * phi_x * phi_yy;
    if( abs(phi_x) + abs(phi_y) > 1e-9 )
      {
      kappa[k_] /= pow( (phi_x*phi_x + phi_y*phi_y), 1.5 );
      }
    }
}
int main(int argc, char *argv[])
{

  // initialize MPI and Epetra communicator
#ifdef HAVE_MPI
  MPI_Init(&argc,&argv);
  Epetra_MpiComm Comm( MPI_COMM_WORLD );
#else
  Epetra_SerialComm Comm;
#endif

  Teuchos::ParameterList GaleriList;

  // The problem is defined on a 2D grid, global size is nx * nx.
  int nx = 30; 
  GaleriList.set("nx", nx);
  GaleriList.set("ny", nx * Comm.NumProc());
  GaleriList.set("mx", 1);
  GaleriList.set("my", Comm.NumProc());
  Teuchos::RefCountPtr<Epetra_Map> Map = Teuchos::rcp( Galeri::CreateMap("Cartesian2D", Comm, GaleriList) );
  Teuchos::RefCountPtr<Epetra_RowMatrix> A = Teuchos::rcp( Galeri::CreateCrsMatrix("Laplace2D", &*Map, GaleriList) );

  // =============================================================== //
  // B E G I N N I N G   O F   I F P A C K   C O N S T R U C T I O N //
  // =============================================================== //

  Teuchos::ParameterList List;

  // allocates an IFPACK factory. No data is associated 
  // to this object (only method Create()).
  Ifpack Factory;

  // create the preconditioner. For valid PrecType values,
  // please check the documentation
  std::string PrecType = "Amesos";
  int OverlapLevel = 2; // must be >= 0. If Comm.NumProc() == 1,
                        // it is ignored.

  Teuchos::RefCountPtr<Ifpack_Preconditioner> Prec = Teuchos::rcp( Factory.Create(PrecType, &*A, OverlapLevel) );
  assert(Prec != Teuchos::null);

  // specify the Amesos solver to be used. 
  // If the selected solver is not available,
  // IFPACK will try to use Amesos' KLU (which is usually always
  // compiled). Amesos' serial solvers are:
  // "Amesos_Klu", "Amesos_Umfpack", "Amesos_Superlu"
  List.set("amesos: solver type", "Amesos_Klu");

  // sets the parameters
  IFPACK_CHK_ERR(Prec->SetParameters(List));

  // initialize the preconditioner. At this point the matrix must
  // have been FillComplete()'d, but actual values are ignored.
  // At this call, Amesos will perform the symbolic factorization.
  IFPACK_CHK_ERR(Prec->Initialize());

  // Builds the preconditioners, by looking for the values of 
  // the matrix. At this call, Amesos will perform the
  // numeric factorization.
  IFPACK_CHK_ERR(Prec->Compute());

  // =================================================== //
  // E N D   O F   I F P A C K   C O N S T R U C T I O N //
  // =================================================== //

  // At this point, we need some additional objects
  // to define and solve the linear system.

  // defines LHS and RHS
  Epetra_Vector LHS(A->OperatorDomainMap());
  Epetra_Vector RHS(A->OperatorDomainMap());

  // solution is constant
  LHS.PutScalar(1.0);
  // now build corresponding RHS
  A->Apply(LHS,RHS);

  // now randomize the solution
  RHS.Random();

  // need an Epetra_LinearProblem to define AztecOO solver
  Epetra_LinearProblem Problem(&*A,&LHS,&RHS);

  // now we can allocate the AztecOO solver
  AztecOO Solver(Problem);

  // specify solver
  Solver.SetAztecOption(AZ_solver,AZ_gmres);
  Solver.SetAztecOption(AZ_output,32);

  // HERE WE SET THE IFPACK PRECONDITIONER
  Solver.SetPrecOperator(&*Prec);

  // .. and here we solve
  // NOTE: with one process, the solver must converge in
  // one iteration.
  Solver.Iterate(1550,1e-8);

#ifdef HAVE_MPI
  MPI_Finalize() ; 
#endif

    return(EXIT_SUCCESS);
}
Beispiel #21
0
void MeshEnergy::GetNormalsTangentPlane( const std::vector<int>& C, const std::vector<double>& phi,
                                         std::valarray<double>& ne1, std::valarray<double>& ne2, 
                                         MeshData* vtkNotUsed(meshdata))
{
  vtkPoints*    verts = meshdata->polydata->GetPoints();

  for( ::size_t k_ = 0; k_ < C.size(); k_++ )
    {
    int k = C[k_];
    std::vector<double> nhat(3);
    nhat[0] = meshdata->nx[k]; // these are normal to surface; the nx_ are the contour normals
    nhat[1] = meshdata->ny[k];
    nhat[2] = meshdata->nz[k];
// step 1. create the rotation matrix that orients the current normal as [0,0,1]'.

    double phiang = atan2( nhat[0], nhat[1] );
    std::vector<double> rotate1(9);
    rotate1[0] = cos(phiang); rotate1[1] = -sin(phiang); rotate1[2] = 0;
    rotate1[3] = sin(phiang); rotate1[4] = cos(phiang); rotate1[5] = 0;
    rotate1[6] = 0; rotate1[7] = 0; rotate1[8] = 1.0;
    std::vector<double> nhat_a(3);
    pkmult( nhat, rotate1, nhat_a );
    double ytilde = nhat_a[1];
    double theta = M_PI_2 - atan2(nhat[2],ytilde);
    std::vector<double> rotate2(9);
    rotate2[0] = 1.0; rotate2[1] = 0; rotate2[2] = 0;
    rotate2[3] = 0; rotate2[4] = cos(theta); rotate2[5] = -sin(theta);
    rotate2[6] = 0; rotate2[7] = sin(theta); rotate2[8] = cos(theta);
    std::vector<double> nhat_b(3);
    pkmult( nhat_a, rotate2, nhat_b );
// nhat_b should now be [0 0 1]'

    double thispt[3];
    verts->GetPoint( k, thispt );
// apply rotate2 * rotate1 to each *translated* neighbor of this k-th point
    ::size_t num_neigh = meshdata->adj[k].myNeighbs.size();
    double vec[3];
    std::vector<double> vv(3);
    std::vector<double> vv_(3);
    std::valarray<double> xdata(num_neigh);
    std::valarray<double> ydata(num_neigh);
    std::valarray<double> zdata(num_neigh);
// step 2. create temporary set of std::vectors as copies of neighboring points
// translated to origin
// step 3. apply the rotation to all these points
    for ( ::size_t i = 0; i < num_neigh; i++ )
      {
      int idx = meshdata->adj[k].myNeighbs[i];
      verts->GetPoint( idx, vec );
      vv[0] = vec[0] - thispt[0];
      vv[1] = vec[1] - thispt[1];
      vv[2] = vec[2] - thispt[2];
      pkmult( vv, rotate1, vv_ );
      pkmult( vv_, rotate2, vv );
      xdata[i] = vv[0];
      ydata[i] = vv[1];
      zdata[i] = phi[idx] - phi[k]; //vv[2];
// zero reference phi at the vertex where we are forming tangent plane
      }
/*if( abs(zdata).min() < 1e-6 )
continue;*/

// step 4. find least-squares fit for H(x,y) = ax + by
    std::valarray<double> RHS(2);
    std::valarray<double> ATA(4);
    ATA[0] = (xdata * xdata).sum();
    ATA[1] = (xdata * ydata).sum();
    ATA[2] = ATA[1];
    ATA[3] = (ydata * ydata).sum();

    RHS[0] = (xdata * zdata).sum();
    RHS[1] = (ydata * zdata).sum();

    int maxits = 1000;
    std::valarray<double> ab = RHS; // initial guess
    std::valarray<double> LHS(2);
    pkmult2( ab, ATA, LHS );
    double res = sqrt( ( (LHS - RHS)*(LHS - RHS) ).sum() );
    double tol = 1e-8;
    int iter = 0;
    while( iter < maxits && res > tol )
      {
      iter++;
      ab[0] = (RHS[0] - ( ab[1]*ATA[1] ) )/ ATA[0];
      ab[1] = (RHS[1] - ( ab[0]*ATA[2] ) )/ ATA[3];
      pkmult2( ab, ATA, LHS );
      res = sqrt( ( (LHS - RHS)*(LHS - RHS) ).sum() );
      }
    ne1[k_] = ab[0] / sqrt( (ab*ab).sum() );
    ne2[k_] = ab[1] / sqrt( (ab*ab).sum() );
// step 5. differentiate the plane along principal directions

    }

}
// ====================================================================== 
bool ComparePointAndBlock(string PrecType, const Teuchos::RefCountPtr<Epetra_RowMatrix>& A, int sweeps)
{
  Epetra_MultiVector RHS(A->RowMatrixRowMap(), NumVectors);
  Epetra_MultiVector LHS(A->RowMatrixRowMap(), NumVectors);
  LHS.PutScalar(0.0); RHS.Random();

  Epetra_LinearProblem Problem(&*A, &LHS, &RHS);

  // Set up the list
  Teuchos::ParameterList List;
  List.set("relaxation: damping factor", 1.0);
  List.set("relaxation: type", PrecType);
  List.set("relaxation: sweeps",sweeps);
  List.set("partitioner: type", "linear");
  List.set("partitioner: local parts", A->NumMyRows());

  int ItersPoint, ItersBlock;

  // ================================================== //
  // get the number of iterations with point relaxation //
  // ================================================== //
  {
    RHS.PutScalar(1.0);
    LHS.PutScalar(0.0);

    Ifpack_PointRelaxation Point(&*A);
    Point.SetParameters(List);
    Point.Compute();

    // set AztecOO solver object
    AztecOO AztecOOSolver(Problem);
    AztecOOSolver.SetAztecOption(AZ_solver,Solver);
    if (verbose)
      AztecOOSolver.SetAztecOption(AZ_output,32);
    else
      AztecOOSolver.SetAztecOption(AZ_output,AZ_none);
    AztecOOSolver.SetPrecOperator(&Point);

    AztecOOSolver.Iterate(2550,1e-2);

    double TrueResidual = AztecOOSolver.TrueResidual();
    ItersPoint = AztecOOSolver.NumIters();
    // some output
    if (verbose && Problem.GetMatrix()->Comm().MyPID() == 0) {
      cout << "Iterations  = " << ItersPoint << endl;
      cout << "Norm of the true residual = " << TrueResidual << endl;
    }
  }

  // ================================================== //
  // get the number of iterations with block relaxation //
  // ================================================== //
  {

    RHS.PutScalar(1.0);
    LHS.PutScalar(0.0);

    Ifpack_BlockRelaxation<Ifpack_SparseContainer<Ifpack_Amesos> > Block(&*A);
    Block.SetParameters(List);
    Block.Compute();

    // set AztecOO solver object
    AztecOO AztecOOSolver(Problem);
    AztecOOSolver.SetAztecOption(AZ_solver,Solver);
    if (verbose)
      AztecOOSolver.SetAztecOption(AZ_output,32);
    else
      AztecOOSolver.SetAztecOption(AZ_output,AZ_none);
    AztecOOSolver.SetPrecOperator(&Block);

    AztecOOSolver.Iterate(2550,1e-2);

    double TrueResidual = AztecOOSolver.TrueResidual();
    ItersBlock = AztecOOSolver.NumIters();
    // some output
    if (verbose && Problem.GetMatrix()->Comm().MyPID() == 0) {
      cout << "Iterations " << ItersBlock << endl;
      cout << "Norm of the true residual = " << TrueResidual << endl;
    }
  }

  int diff = ItersPoint - ItersBlock;
  if (diff < 0) diff = -diff;
    
  if (diff > 10)
  {
    if (verbose)
      cout << "ComparePointandBlock TEST FAILED!" << endl;
    return(false);
  }
  else {
    if (verbose)
      cout << "ComparePointandBlock TEST PASSED" << endl;
    return(true);
  }
}
Beispiel #23
0
int main(int argc, char *argv[])
{
  int ierr = 0, i, j, k;
  bool debug = false;

#ifdef EPETRA_MPI
  MPI_Init(&argc,&argv);
  Epetra_MpiComm Comm( MPI_COMM_WORLD );
#else
  Epetra_SerialComm Comm;
#endif

  bool verbose = false;

  // Check if we should print results to standard out
  if (argc>1) if (argv[1][0]=='-' && argv[1][1]=='v') verbose = true;

  if (verbose && Comm.MyPID()==0)
    cout << Epetra_Version() << endl << endl;

  int rank = Comm.MyPID();
  //  char tmp;
  //  if (rank==0) cout << "Press any key to continue..."<< endl;
  //  if (rank==0) cin >> tmp;
  //  Comm.Barrier();

  Comm.SetTracebackMode(0); // This should shut down any error traceback reporting
  if (verbose) cout << Comm <<endl;

  //  bool verbose1 = verbose;

  // Redefine verbose to only print on PE 0
  if (verbose && rank!=0) verbose = false;
	
  int N = 20;
  int NRHS = 4;
  double * A = new double[N*N];
  double * A1 = new double[N*N];
  double * X = new double[(N+1)*NRHS];
  double * X1 = new double[(N+1)*NRHS];
  int LDX = N+1;
  int LDX1 = N+1;
  double * B = new double[N*NRHS];
  double * B1 = new double[N*NRHS];
  int LDB = N;
  int LDB1 = N;

  int LDA = N;
  int LDA1 = LDA;
  double OneNorm1;
  bool Transpose = false;

  Epetra_SerialDenseSolver solver;
  Epetra_SerialDenseMatrix * Matrix;
  for (int kk=0; kk<2; kk++) {
    for (i=1; i<=N; i++) {
      GenerateHilbert(A, LDA, i);
      OneNorm1 = 0.0;
      for (j=1; j<=i; j++) OneNorm1 += 1.0/((double) j); // 1-Norm = 1 + 1/2 + ...+1/n

      if (kk==0) {
	Matrix = new Epetra_SerialDenseMatrix(View, A, LDA, i, i);
	LDA1 = LDA;
      }
      else {
	Matrix = new Epetra_SerialDenseMatrix(Copy, A, LDA, i, i);
	LDA1 = i;
      }

      GenerateHilbert(A1, LDA1, i);
	
      if (kk==1) {
	solver.FactorWithEquilibration(true);
	solver.SolveWithTranspose(true);
	Transpose = true;
	solver.SolveToRefinedSolution(true);
      }

      for (k=0; k<NRHS; k++)
	for (j=0; j<i; j++) {
	  B[j+k*LDB] = 1.0/((double) (k+3)*(j+3));
	  B1[j+k*LDB1] = B[j+k*LDB1];
	}
      Epetra_SerialDenseMatrix Epetra_B(View, B, LDB, i, NRHS);
      Epetra_SerialDenseMatrix Epetra_X(View, X, LDX, i, NRHS);

      solver.SetMatrix(*Matrix);
      solver.SetVectors(Epetra_X, Epetra_B);

      ierr = check(solver, A1, LDA1,  i, NRHS, OneNorm1, B1, LDB1,  X1, LDX1, Transpose, verbose);
      assert (ierr>-1);
      delete Matrix;
      if (ierr!=0) {
	if (verbose) cout << "Factorization failed due to bad conditioning.  This is normal if RCOND is small."
			  << endl;
	break;
      }
    }
  }

  delete [] A;
  delete [] A1;
  delete [] X;
  delete [] X1;
  delete [] B;
  delete [] B1;

  /////////////////////////////////////////////////////////////////////
  // Now test norms and scaling functions
  /////////////////////////////////////////////////////////////////////

  Epetra_SerialDenseMatrix D;
  double ScalarA = 2.0;

  int DM = 10;
  int DN = 8;
  D.Shape(DM, DN);
  for (j=0; j<DN; j++)
    for (i=0; i<DM; i++) D[j][i] = (double) (1+i+j*DM) ;

  //cout << D << endl;

  double NormInfD_ref = (double)(DM*(DN*(DN+1))/2);
  double NormOneD_ref = (double)((DM*DN*(DM*DN+1))/2 - (DM*(DN-1)*(DM*(DN-1)+1))/2 );

  double NormInfD = D.NormInf();
  double NormOneD = D.NormOne();

  if (verbose) {
    cout << " *** Before scaling *** " << endl
	 << " Computed one-norm of test matrix = " << NormOneD << endl
	 << " Expected one-norm                = " << NormOneD_ref << endl
	 << " Computed inf-norm of test matrix = " << NormInfD << endl
	 << " Expected inf-norm                = " << NormInfD_ref << endl;
  }
  D.Scale(ScalarA); // Scale entire D matrix by this value
  NormInfD = D.NormInf();
  NormOneD = D.NormOne();
  if (verbose) {
    cout << " *** After scaling *** " << endl
	 << " Computed one-norm of test matrix = " << NormOneD << endl
	 << " Expected one-norm                = " << NormOneD_ref*ScalarA << endl
	 << " Computed inf-norm of test matrix = " << NormInfD << endl
	 << " Expected inf-norm                = " << NormInfD_ref*ScalarA << endl;
  }


  /////////////////////////////////////////////////////////////////////
  // Now test that A.Multiply(false, x, y) produces the same result
  // as y.Multiply('N','N', 1.0, A, x, 0.0).
  /////////////////////////////////////////////////////////////////////

  N = 10;
  int M = 10;
  LDA = N;
  Epetra_SerialDenseMatrix smallA(N, M, false);
  Epetra_SerialDenseMatrix x(N, 1, false);
  Epetra_SerialDenseMatrix y1(N, 1, false);
  Epetra_SerialDenseMatrix y2(N, 1, false);

  for(i=0; i<N; ++i) {
    for(j=0; j<M; ++j) {
      smallA(i,j) = 1.0*i+2.0*j+1.0;
    }
    x(i,0) = 1.0;
    y1(i,0) = 0.0;
    y2(i,0) = 0.0;
  }

  //quick check of operator==
  if (x == y1) {
    if (verbose) cout << "err in Epetra_SerialDenseMatrix::operator==, "
        << "erroneously returned true." << std::endl;
    return(-1);
  }

  //quick check of operator!=
  if (x != x) {
    if (verbose) cout << "err in Epetra_SerialDenseMatrix::operator==, "
        << "erroneously returned true." << std::endl;
    return(-1);
  }

  int err1 = smallA.Multiply(false, x, y1);
  int err2 = y2.Multiply('N','N', 1.0, smallA, x, 0.0);
  if (err1 != 0 || err2 != 0) {
    if (verbose) cout << "err in Epetra_SerialDenseMatrix::Multiply"<<endl;
    return(err1+err2);
  }

  for(i=0; i<N; ++i) {
    if (y1(i,0) != y2(i,0)) {
      if (verbose) cout << "different versions of Multiply don't match."<<endl;
      return(-99);
    }
  }

  /////////////////////////////////////////////////////////////////////
  // Now test for larger system, both correctness and performance.
  /////////////////////////////////////////////////////////////////////


  N = 2000;
  NRHS = 5;
  LDA = N;
  LDB = N;
  LDX = N;

  if (verbose) cout << "\n\nComputing factor of an " << N << " x " << N << " general matrix...Please wait.\n\n" << endl;

  // Define A and X

  A = new double[LDA*N];
  X = new double[LDB*NRHS];

  for (j=0; j<N; j++) {
    for (k=0; k<NRHS; k++) X[j+k*LDX] = 1.0/((double) (j+5+k));
    for (i=0; i<N; i++) {
      if (i==((j+2)%N)) A[i+j*LDA] = 100.0 + i;
      else A[i+j*LDA] = -11.0/((double) (i+5)*(j+2));
    }
  }

  // Define Epetra_SerialDenseMatrix object

  Epetra_SerialDenseMatrix BigMatrix(Copy, A, LDA, N, N);
  Epetra_SerialDenseMatrix OrigBigMatrix(View, A, LDA, N, N);

  Epetra_SerialDenseSolver BigSolver;
  BigSolver.FactorWithEquilibration(true);
  BigSolver.SetMatrix(BigMatrix);

  // Time factorization

  Epetra_Flops counter;
  BigSolver.SetFlopCounter(counter);
  Epetra_Time Timer(Comm);
  double tstart = Timer.ElapsedTime();
  ierr = BigSolver.Factor();
  if (ierr!=0 && verbose) cout << "Error in factorization = "<<ierr<< endl;
  assert(ierr==0);
  double time = Timer.ElapsedTime() - tstart;

  double FLOPS = counter.Flops();
  double MFLOPS = FLOPS/time/1000000.0;
  if (verbose) cout << "MFLOPS for Factorization = " << MFLOPS << endl;

  // Define Left hand side and right hand side
  Epetra_SerialDenseMatrix LHS(View, X, LDX, N, NRHS);
  Epetra_SerialDenseMatrix RHS;
  RHS.Shape(N,NRHS); // Allocate RHS

  // Compute RHS from A and X

  Epetra_Flops RHS_counter;
  RHS.SetFlopCounter(RHS_counter);
  tstart = Timer.ElapsedTime();
  RHS.Multiply('N', 'N', 1.0, OrigBigMatrix, LHS, 0.0);
  time = Timer.ElapsedTime() - tstart;

  Epetra_SerialDenseMatrix OrigRHS = RHS;

  FLOPS = RHS_counter.Flops();
  MFLOPS = FLOPS/time/1000000.0;
  if (verbose) cout << "MFLOPS to build RHS (NRHS = " << NRHS <<") = " << MFLOPS << endl;

  // Set LHS and RHS and solve
  BigSolver.SetVectors(LHS, RHS);

  tstart = Timer.ElapsedTime();
  ierr = BigSolver.Solve();
  if (ierr==1 && verbose) cout << "LAPACK guidelines suggest this matrix might benefit from equilibration." << endl;
  else if (ierr!=0 && verbose) cout << "Error in solve = "<<ierr<< endl;
  assert(ierr>=0);
  time = Timer.ElapsedTime() - tstart;

  FLOPS = BigSolver.Flops();
  MFLOPS = FLOPS/time/1000000.0;
  if (verbose) cout << "MFLOPS for Solve (NRHS = " << NRHS <<") = " << MFLOPS << endl;

  double * resid = new double[NRHS];
  bool OK = Residual(N, NRHS, A, LDA, BigSolver.Transpose(), BigSolver.X(), BigSolver.LDX(),
		     OrigRHS.A(), OrigRHS.LDA(), resid);

  if (verbose) {
    if (!OK) cout << "************* Residual do not meet tolerance *************" << endl;
    for (i=0; i<NRHS; i++)
      cout << "Residual[" << i <<"] = "<< resid[i] << endl;
    cout  << endl;
  }

  // Solve again using the Epetra_SerialDenseVector class for LHS and RHS

  Epetra_SerialDenseVector X2;
  Epetra_SerialDenseVector B2;
  X2.Size(BigMatrix.N());
  B2.Size(BigMatrix.M());
  int length = BigMatrix.N();
  {for (int kk=0; kk<length; kk++) X2[kk] = ((double ) kk)/ ((double) length);} // Define entries of X2

  RHS_counter.ResetFlops();
  B2.SetFlopCounter(RHS_counter);
  tstart = Timer.ElapsedTime();
  B2.Multiply('N', 'N', 1.0, OrigBigMatrix, X2, 0.0); // Define B2 = A*X2
  time = Timer.ElapsedTime() - tstart;

  Epetra_SerialDenseVector OrigB2 = B2;

  FLOPS = RHS_counter.Flops();
  MFLOPS = FLOPS/time/1000000.0;
  if (verbose) cout << "MFLOPS to build single RHS = " << MFLOPS << endl;

  // Set LHS and RHS and solve
  BigSolver.SetVectors(X2, B2);

  tstart = Timer.ElapsedTime();
  ierr = BigSolver.Solve();
  time = Timer.ElapsedTime() - tstart;
  if (ierr==1 && verbose) cout << "LAPACK guidelines suggest this matrix might benefit from equilibration." << endl;
  else if (ierr!=0 && verbose) cout << "Error in solve = "<<ierr<< endl;
  assert(ierr>=0);

  FLOPS = counter.Flops();
  MFLOPS = FLOPS/time/1000000.0;
  if (verbose) cout << "MFLOPS to solve single RHS = " << MFLOPS << endl;

  OK = Residual(N, 1, A, LDA, BigSolver.Transpose(), BigSolver.X(), BigSolver.LDX(), OrigB2.A(),
		OrigB2.LDA(), resid);

  if (verbose) {
    if (!OK) cout << "************* Residual do not meet tolerance *************" << endl;
      cout << "Residual = "<< resid[0] << endl;
  }
  delete [] resid;
  delete [] A;
  delete [] X;

  ///////////////////////////////////////////////////
  // Now test default constructor and index operators
  ///////////////////////////////////////////////////

  N = 5;
  Epetra_SerialDenseMatrix C; // Implicit call to default constructor, should not need to call destructor
  C.Shape(5,5); // Make it 5 by 5
  double * C1 = new double[N*N];
  GenerateHilbert(C1, N, N); // Generate Hilber matrix

  C1[1+2*N] = 1000.0;  // Make matrix nonsymmetric

  // Fill values of C with Hilbert values
  for (i=0; i<N; i++)
    for (j=0; j<N; j++)
      C(i,j) = C1[i+j*N];

  // Test if values are correctly written and read
  for (i=0; i<N; i++)
    for (j=0; j<N; j++) {
      assert(C(i,j) == C1[i+j*N]);
      assert(C(i,j) == C[j][i]);
    }

  if (verbose)
    cout << "Default constructor and index operator check OK.  Values of Hilbert matrix = "
	 << endl << C << endl
	 << "Values should be 1/(i+j+1), except value (1,2) should be 1000" << endl;

  delete [] C1;

  // now test sized/shaped constructor
  Epetra_SerialDenseMatrix shapedMatrix(10, 12);
  assert(shapedMatrix.M() == 10);
  assert(shapedMatrix.N() == 12);
  for(i = 0; i < 10; i++)
    for(j = 0; j < 12; j++)
      assert(shapedMatrix(i, j) == 0.0);
  Epetra_SerialDenseVector sizedVector(20);
  assert(sizedVector.Length() == 20);
  for(i = 0; i < 20; i++)
    assert(sizedVector(i) == 0.0);
  if (verbose)
    cout << "Shaped/sized constructors check OK." << endl;

  // test Copy/View mode in op= and cpy ctr
  int temperr = 0;
  temperr = matrixAssignment(verbose, debug);
  if(verbose && temperr == 0)
    cout << "Operator = checked OK." << endl;
  EPETRA_TEST_ERR(temperr, ierr);
  temperr = matrixCpyCtr(verbose, debug);
  if(verbose && temperr == 0)
    cout << "Copy ctr checked OK." << endl;
  EPETRA_TEST_ERR(temperr, ierr);

  // Test some vector methods

  Epetra_SerialDenseVector v1(3);
  v1[0] = 1.0;
  v1[1] = 3.0;
  v1[2] = 2.0;

  Epetra_SerialDenseVector v2(3);
  v2[0] = 2.0;
  v2[1] = 1.0;
  v2[2] = -2.0;

  temperr = 0;
  if (v1.Norm1()!=6.0) temperr++;
  if (fabs(sqrt(14.0)-v1.Norm2())>1.0e-6) temperr++;
  if (v1.NormInf()!=3.0) temperr++;
  if(verbose && temperr == 0)
    cout << "Vector Norms checked OK." << endl;
  temperr = 0;
  if (v1.Dot(v2)!=1.0) temperr++;
  if(verbose && temperr == 0)
    cout << "Vector Dot product checked OK." << endl;

#ifdef EPETRA_MPI
  MPI_Finalize() ;
#endif

/* end main
*/
return ierr ;
}
Beispiel #24
0
double Ifpack_Condest(const Ifpack_Preconditioner& IFP,
		      const Ifpack_CondestType CT,
		      const int MaxIters,
		      const double Tol,
		      Epetra_RowMatrix* Matrix)
{
  double ConditionNumberEstimate = -1.0;

  if (CT == Ifpack_Cheap) {

    // Create a vector with all values equal to one
    Epetra_Vector Ones(IFP.OperatorDomainMap());
    Ones.PutScalar(1.0);
    // Create the vector of results
    Epetra_Vector OnesResult(IFP.OperatorRangeMap());
    // Compute the effect of the solve on the vector of ones
    IFPACK_CHK_ERR(IFP.ApplyInverse(Ones, OnesResult)); 
    // Make all values non-negative
    IFPACK_CHK_ERR(OnesResult.Abs(OnesResult)); 
    // Get the maximum value across all processors
    IFPACK_CHK_ERR(OnesResult.MaxValue(&ConditionNumberEstimate)); 

  }
  else if (CT == Ifpack_CG) {

#ifdef HAVE_IFPACK_AZTECOO
    if (Matrix == 0)
      Matrix = (Epetra_RowMatrix*)&(IFP.Matrix());

    Epetra_Vector LHS(IFP.OperatorDomainMap());
    LHS.PutScalar(0.0);
    Epetra_Vector RHS(IFP.OperatorRangeMap());
    RHS.Random();
    Epetra_LinearProblem Problem;
    Problem.SetOperator(Matrix);
    Problem.SetLHS(&LHS);
    Problem.SetRHS(&RHS);

    AztecOO Solver(Problem);
    Solver.SetAztecOption(AZ_output,AZ_none);
    Solver.SetAztecOption(AZ_solver,AZ_cg_condnum);
    Solver.Iterate(MaxIters,Tol);

    const double* status = Solver.GetAztecStatus();
    ConditionNumberEstimate = status[AZ_condnum];
#endif

  } else if (CT == Ifpack_GMRES) {

#ifdef HAVE_IFPACK_AZTECOO
    if (Matrix == 0)
      Matrix = (Epetra_RowMatrix*)&(IFP.Matrix());

    Epetra_Vector LHS(IFP.OperatorDomainMap());
    LHS.PutScalar(0.0);
    Epetra_Vector RHS(IFP.OperatorRangeMap());
    RHS.Random();
    Epetra_LinearProblem Problem;
    Problem.SetOperator(Matrix);
    Problem.SetLHS(&LHS);
    Problem.SetRHS(&RHS);

    AztecOO Solver(Problem);
    Solver.SetAztecOption(AZ_solver,AZ_gmres_condnum);
    Solver.SetAztecOption(AZ_output,AZ_none);
    // the following can be problematic for large problems,
    // but any restart would destroy useful information about
    // the condition number.
    Solver.SetAztecOption(AZ_kspace,MaxIters);
    Solver.Iterate(MaxIters,Tol);

    const double* status = Solver.GetAztecStatus();
    ConditionNumberEstimate = status[AZ_condnum];
#endif
  }

  return(ConditionNumberEstimate);

}
Beispiel #25
0
vector<T> matrix<T>::solve(vector<T> RHS)
{
#ifdef _DEBUG
  if (this->dims[0] != this->dims[1])
    FatalErrorST("Can only use Gaussian elimination on a square matrix.");
#endif
  // Gaussian elimination with full pivoting
  // not to be used where speed is paramount

  vector<T> vec(this->dims[0]);
  vector<T> solution(this->dims[0]);
  vector<int> swap_0(this->dims[0],1);
  vector<int> swap_1(this->dims[0],1);
  vector<T> tmpRow(this->dims[0]);

  matrix<T> LHS(*this);

  // setup swap arrays
  for(uint i=0; i<this->dims[0]; i++) {
    swap_0[i]=i;
    swap_1[i]=i;
  }

  // make triangular
  for(uint k=0; k<this->dims[0]-1; k++) {
    T max = 0;
    T mag;

    // find pivot
    int pivot_i = 0;
    int pivot_j = 0;
    for(uint i=k; i<this->dims[0]; i++) {
      for(uint j=k; j<this->dims[0]; j++) {
        mag = LHS(i,j)*LHS(i,j);
        if(mag>max) {
          pivot_i = i;
          pivot_j = j;
          max = mag;
        }
      }
    }

    // swap the swap arrays
    int itemp_0 = swap_0[k];
    swap_0[k] = swap_0[pivot_i];
    swap_0[pivot_i] = itemp_0;
    itemp_0 = swap_1[k];
    swap_1[k] = swap_1[pivot_j];
    swap_1[pivot_j] = itemp_0;

    // swap the columns
    for(uint i=0; i<this->dims[0]; i++) {
      tmpRow[i] = LHS(i,pivot_j);
      LHS(i,pivot_j) = LHS(i,k);
      LHS(i,k) = tmpRow[i];
    }

    // swap the rows
    for(uint j=0; j<this->dims[0]; j++) {
      tmpRow[j] = LHS(pivot_i,j);
      LHS(pivot_i,j) = LHS(k,j);
      LHS(k,j) = tmpRow[j];
    }
    T tmp = RHS[pivot_i];
    RHS[pivot_i] = RHS[k];
    RHS[k] = tmp;

    // subtraction
    for(uint i=k+1; i<this->dims[0]; i++) {
      T first = LHS(i,k);
      RHS[i] = RHS[i] - first/LHS(k,k)*RHS[k];
      for(uint j=k; j<this->dims[0]; j++)
        LHS(i,j) = LHS(i,j) - (first/LHS(k,k))*LHS(k,j);
    }

    // exact zero
    for(uint j=0; j<k+1; j++) {
      for(uint i=j+1; i<this->dims[0]; i++) {
        LHS(i,j)=0.0;
      }
    }
  }

  // back substitute
  for(int i=(int)this->dims[0]-1; i>=0; i--) {
    T dtemp_0 = 0.0;
    for(uint k = i+1; k<this->dims[0]; k++) {
      dtemp_0 = dtemp_0 + (LHS(i,k)*vec[k]);
    }
    vec[i] = (RHS[i]-dtemp_0)/LHS(i,i);
  }

  // swap solution rows
  for(uint i=0; i<this->dims[0]; i++)
    solution[swap_1[i]] = vec[i];

  return solution;
}
int main(int argc, char *argv[])
{

#ifdef HAVE_MPI
  MPI_Init(&argc,&argv);
  Epetra_MpiComm Comm( MPI_COMM_WORLD );
#else
  Epetra_SerialComm Comm;
#endif

  Teuchos::ParameterList GaleriList;

  // The problem is defined on a 2D grid, global size is nx * nx.
  int nx = 30; 
  GaleriList.set("n", nx * nx);
  GaleriList.set("nx", nx);
  GaleriList.set("ny", nx);
  Teuchos::RefCountPtr<Epetra_Map> Map = Teuchos::rcp( Galeri::CreateMap64("Linear", Comm, GaleriList) );
  Teuchos::RefCountPtr<Epetra_RowMatrix> A = Teuchos::rcp( Galeri::CreateCrsMatrix("Laplace2D", &*Map, GaleriList) );

  // =============================================================== //
  // B E G I N N I N G   O F   I F P A C K   C O N S T R U C T I O N //
  // =============================================================== //

  Teuchos::ParameterList List;

  // allocates an IFPACK factory. No data is associated 
  // to this object (only method Create()).
  Ifpack Factory;

  // create the preconditioner. For valid PrecType values,
  // please check the documentation
  string PrecType = "ILU"; // incomplete LU
  int OverlapLevel = 1; // must be >= 0. If Comm.NumProc() == 1,
                        // it is ignored.

  Teuchos::RefCountPtr<Ifpack_Preconditioner> Prec = Teuchos::rcp( Factory.Create(PrecType, &*A, OverlapLevel) );
  assert(Prec != Teuchos::null);

  // specify parameters for ILU
  List.set("fact: drop tolerance", 1e-9);
  List.set("fact: level-of-fill", 1);
  // the combine mode is on the following:
  // "Add", "Zero", "Insert", "InsertAdd", "Average", "AbsMax"
  // Their meaning is as defined in file Epetra_CombineMode.h   
  List.set("schwarz: combine mode", "Add");
  // sets the parameters
  IFPACK_CHK_ERR(Prec->SetParameters(List));

  // initialize the preconditioner. At this point the matrix must
  // have been FillComplete()'d, but actual values are ignored.
  IFPACK_CHK_ERR(Prec->Initialize());

  // Builds the preconditioners, by looking for the values of 
  // the matrix.
  IFPACK_CHK_ERR(Prec->Compute());

  // =================================================== //
  // E N D   O F   I F P A C K   C O N S T R U C T I O N //
  // =================================================== //

  // At this point, we need some additional objects
  // to define and solve the linear system.

  // defines LHS and RHS
  Epetra_Vector LHS(A->OperatorDomainMap());
  Epetra_Vector RHS(A->OperatorDomainMap());

  // solution is constant
  LHS.PutScalar(1.0);
  // now build corresponding RHS
  A->Apply(LHS,RHS);

  // now randomize the solution
  RHS.Random();

  // need an Epetra_LinearProblem to define AztecOO solver
  Epetra_LinearProblem Problem(&*A,&LHS,&RHS);

  // now we can allocate the AztecOO solver
  AztecOO Solver(Problem);

  // specify solver
  Solver.SetAztecOption(AZ_solver,AZ_gmres);
  Solver.SetAztecOption(AZ_output,32);

  // HERE WE SET THE IFPACK PRECONDITIONER
  Solver.SetPrecOperator(&*Prec);

  // .. and here we solve
  Solver.Iterate(1550,1e-8);

  cout << *Prec;

#ifdef HAVE_MPI
  MPI_Finalize() ; 
#endif

  return(EXIT_SUCCESS);
}
int main(int argc, char *argv[])
{
  int    Nnodes=32*32;              /* Total number of nodes in the problem.*/
                                    /* 'Nnodes' must be a perfect square.   */

  struct       user_partition Edge_Partition = {NULL, NULL,0,0,NULL,0,0,0}, 
                                Node_Partition = {NULL, NULL,0,0,NULL,0,0,0};

  int          proc_config[AZ_PROC_SIZE];

#ifdef ML_MPI
  MPI_Init(&argc,&argv);
#endif

  AZ_set_proc_config(proc_config, COMMUNICATOR);
  ML_Comm* comm;
  ML_Comm_Create(&comm);

  Node_Partition.Nglobal = Nnodes;
  Edge_Partition.Nglobal = Node_Partition.Nglobal*2;

  user_partition_nodes(&Node_Partition);
  user_partition_edges(&Edge_Partition, &Node_Partition);
  
  AZ_MATRIX * AZ_Ke = user_Ke_build(&Edge_Partition);
  AZ_MATRIX * AZ_Kn = user_Kn_build(&Node_Partition);

  // convert (put wrappers) from Aztec matrices to ML_Operator's

  ML_Operator * ML_Ke, * ML_Kn, * ML_Tmat;

  ML_Ke = ML_Operator_Create( comm );
  ML_Kn = ML_Operator_Create( comm );

  AZ_convert_aztec_matrix_2ml_matrix(AZ_Ke,ML_Ke,proc_config);
  AZ_convert_aztec_matrix_2ml_matrix(AZ_Kn,ML_Kn,proc_config);

  ML_Tmat = user_T_build(&Edge_Partition, &Node_Partition, 
		      ML_Kn, comm);

  Epetra_CrsMatrix * Epetra_Kn, * Epetra_Ke, * Epetra_T;
  
  int MaxNumNonzeros;
  double CPUTime;

  ML_Operator2EpetraCrsMatrix(ML_Ke,Epetra_Ke,
			      MaxNumNonzeros,
			      true,CPUTime);

  ML_Operator2EpetraCrsMatrix(ML_Kn,
			      Epetra_Kn,MaxNumNonzeros,
			      true,CPUTime);

  ML_Operator2EpetraCrsMatrix(ML_Tmat,Epetra_T,MaxNumNonzeros,
			      true,CPUTime);  

  Teuchos::ParameterList MLList;
  ML_Epetra::SetDefaults("maxwell", MLList);
  
  MLList.set("ML output", 0);

  MLList.set("aggregation: type", "Uncoupled");
  MLList.set("coarse: max size", 30);
  MLList.set("aggregation: threshold", 0.0);

  MLList.set("coarse: type", "Amesos-KLU");

  ML_Epetra::MultiLevelPreconditioner * MLPrec =
    new ML_Epetra::MultiLevelPreconditioner(*Epetra_Ke, *Epetra_T, *Epetra_Kn,
					    MLList);

  Epetra_Vector LHS(Epetra_Ke->DomainMap()); LHS.Random();
  Epetra_Vector RHS(Epetra_Ke->DomainMap()); RHS.PutScalar(1.0);
  
  Epetra_LinearProblem Problem(Epetra_Ke,&LHS,&RHS);
  AztecOO solver(Problem);
  solver.SetPrecOperator(MLPrec);

  solver.SetAztecOption(AZ_solver, AZ_cg_condnum);
  solver.SetAztecOption(AZ_output, 32);
  solver.Iterate(500, 1e-8);

  // ========================= //
  // compute the real residual //
  // ========================= //

  Epetra_Vector RHScomp(Epetra_Ke->DomainMap());
  int ierr;
  ierr = Epetra_Ke->Multiply(false, LHS, RHScomp);
  assert(ierr==0);

  Epetra_Vector resid(Epetra_Ke->DomainMap());

  ierr = resid.Update(1.0, RHS, -1.0, RHScomp, 0.0);
  assert(ierr==0);

  double residual;
  ierr = resid.Norm2(&residual);
  assert(ierr==0);
  if (proc_config[AZ_node] == 0) {
    std::cout << std::endl;
    std::cout << "==> Residual = " << residual << std::endl;
    std::cout << std::endl;
  }

  // =============== //
  // C L E A N   U P //
  // =============== //
  
  delete MLPrec;    // destroy phase prints out some information
  delete Epetra_Kn;
  delete Epetra_Ke;
  delete Epetra_T;
  
  ML_Operator_Destroy( &ML_Ke );
  ML_Operator_Destroy( &ML_Kn );
  ML_Comm_Destroy( &comm );

  if (Edge_Partition.my_local_ids != NULL) free(Edge_Partition.my_local_ids);
  if (Node_Partition.my_local_ids != NULL) free(Node_Partition.my_local_ids);
  if (Node_Partition.my_global_ids != NULL) free(Node_Partition.my_global_ids);
  if (Edge_Partition.my_global_ids != NULL) free(Edge_Partition.my_global_ids);
  if (Node_Partition.needed_external_ids != NULL) 
    free(Node_Partition.needed_external_ids);
  if (Edge_Partition.needed_external_ids != NULL) 
    free(Edge_Partition.needed_external_ids);

  if (AZ_Ke!= NULL) {
    AZ_free(AZ_Ke->bindx);
    AZ_free(AZ_Ke->val);
    AZ_free(AZ_Ke->data_org);
    AZ_matrix_destroy(&AZ_Ke);
  }
  if (AZ_Kn!= NULL) {
    AZ_free(AZ_Kn->bindx);
    AZ_free(AZ_Kn->val);
    AZ_free(AZ_Kn->data_org);
    AZ_matrix_destroy(&AZ_Kn);
  }

  ML_Operator_Destroy(&ML_Tmat);

  if (residual > 1e-5) {
    std::cout << "`MultiLevelPreconditioner_Maxwell.exe' failed!" << std::endl;
    exit(EXIT_FAILURE);
  }

#ifdef ML_MPI
  MPI_Finalize();
#endif
		
  if (proc_config[AZ_node] == 0)
    std::cout << "`MultiLevelPreconditioner_Maxwell.exe' passed!" << std::endl;
  exit(EXIT_SUCCESS);
		
}