// Copyright (C) 2007 Johan Jansson.
// Licensed under the GNU GPL Version 2.

#include <dolfin.h>
#include <unicorn/ElasticSmoother.h>
  
using namespace dolfin;
using namespace dolfin::unicorn;

int main()
{

  // FIXME: PETSc init crashes unless some linear algebra is done
  // beforehand?
  Vector x(3);
  x.norm();

  //File smoothedfile_vtk("smoothed.pvd");

  //Mesh mesh("simple3D.xml.gz");
  Mesh mesh("fsi_femlab_bench.xml");
  //Mesh mesh("testcell2D.xml");
  //UnitSquare mesh(30, 30);
  //Mesh mesh("mixer_mesh.xml");

  //smoothedfile_vtk << mesh;


  MeshQuality qual(mesh);

  real mu_max, mu_min, mu_avg;
  real h_max, h_min, h_avg;
  
  qual.meshQuality(mu_min, mu_max, mu_avg, h_min, h_max, h_avg);
  
  real vol_min = 1.0e12;
  real vol_max = 0.0;
  
  for (CellIterator c(mesh); !c.end(); ++c)
  {
    Cell& cell = *c;
    
    vol_min = std::min(vol_min, cell.volume());
    vol_max = std::max(vol_max, cell.volume());
  }
  
  
  cout << "FSIc: Original mesh quality:" << endl;
  cout << "FSIc: mu_min: " << mu_min << endl;
  cout << "FSIc: mu_max: " << mu_max << endl;
  cout << "FSIc: mu_avg: " << mu_avg << endl;
  cout << "FSIc: h_min: " << h_min << endl;
  cout << "FSIc: h_max: " << h_max << endl;
  cout << "FSIc: h_avg: " << h_avg << endl;
  cout << "FSIc: vol_min: " << vol_min << endl;
  cout << "FSIc: vol_max: " << vol_max << endl;

  //int d = mesh.topology().dim();

  //transform(mesh);
  MeshFunction<bool> smoothed_cells(mesh);
  smoothed_cells.init(mesh.topology().dim());

  // Initialize mesh functions
  for (CellIterator c(mesh); !c.end(); ++c)
  {
    Cell& cell = *c;
    smoothed_cells.set(cell.index(), true);
  }


  MeshFunction<bool> masked_cells(mesh);
  masked_cells.init(mesh.topology().dim());

  // Initialize mesh functions
  for (CellIterator c(mesh); !c.end(); ++c)
  {
    Cell& cell = *c;
    masked_cells.set(cell.index(), false);
  }

  MeshFunction<real> h0(mesh);
  h0.init(mesh.topology().dim());
  
  // Initialize mesh functions
  for (CellIterator c(mesh); !c.end(); ++c)
  {
    Cell& cell = *c;
    h0.set(cell, MeshQuality::myDiameter(cell));
  }

  ElasticSmoother smoother(mesh);
  smoother.smooth(smoothed_cells, h0);

  qual.meshQuality(mu_min, mu_max, mu_avg, h_min, h_max, h_avg);

  cout << "FSIc: mesh quality after:" << endl;
  cout << "FSIc: mu_min: " << mu_min << endl;
  cout << "FSIc: mu_max: " << mu_max << endl;
  cout << "FSIc: mu_avg: " << mu_avg << endl;
  cout << "FSIc: h_min: " << h_min << endl;
  cout << "FSIc: h_max: " << h_max << endl;
  cout << "FSIc: h_avg: " << h_avg << endl;
  cout << "FSIc: vol_min: " << vol_min << endl;
  cout << "FSIc: vol_max: " << vol_max << endl;

  //smoothedfile_vtk << mesh;

  return 0;
}
