Example #1
0
int main(int argc, char **argv) {
  options.parse(argc, argv);

  carve::input::Input inputs;
  std::vector<carve::mesh::MeshSet<3> *> polys;
  std::vector<carve::line::PolylineSet *> lines;
  std::vector<carve::point::PointSet *> points;

  if (options.file == "") {
    readPLY(std::cin, inputs);
  } else {
    if (endswith(options.file, ".ply")) {
      readPLY(options.file, inputs);
    } else if (endswith(options.file, ".vtk")) {
      readVTK(options.file, inputs);
    } else if (endswith(options.file, ".obj")) {
      readOBJ(options.file, inputs);
    }
  }

  for (std::list<carve::input::Data *>::const_iterator i = inputs.input.begin(); i != inputs.input.end(); ++i) {
    carve::mesh::MeshSet<3> *p;
    carve::point::PointSet *ps;
    carve::line::PolylineSet *l;

    if ((p = carve::input::Input::create<carve::mesh::MeshSet<3> >(*i)) != NULL)  {
      if (options.canonicalize) p->canonicalize();
      if (options.obj) {
        writeOBJ(std::cout, p);
      } else if (options.vtk) {
        writeVTK(std::cout, p);
      } else {
        writePLY(std::cout, p, options.ascii);
      }
      delete p;
    } else if ((l = carve::input::Input::create<carve::line::PolylineSet>(*i)) != NULL)  {
      if (options.obj) {
        writeOBJ(std::cout, l);
      } else if (options.vtk) {
        writeVTK(std::cout, l);
      } else {
        writePLY(std::cout, l, options.ascii);
      }
      delete l;
    } else if ((ps = carve::input::Input::create<carve::point::PointSet>(*i)) != NULL)  {
      if (options.obj) {
        std::cerr << "Can't write a point set in .obj format" << std::endl;
      } else if (options.vtk) {
        std::cerr << "Can't write a point set in .vtk format" << std::endl;
      } else {
        writePLY(std::cout, ps, options.ascii);
      }
      delete ps;
    }
  }

  return 0;
}
Example #2
0
int main(int argc, char **argv) {
  options.parse(argc, argv);

  carve::poly::Polyhedron *poly = readModel(options.file);
  if (!poly) exit(1);

  std::vector<carve::poly::Vertex<3> > out_vertices = poly->vertices;
  std::vector<carve::poly::Face<3> > out_faces;

  size_t N = 0;
  for (size_t i = 0; i < poly->faces.size(); ++i) {
    carve::poly::Face<3> &f = poly->faces[i];
    N += f.nVertices() - 2;
  }
  out_faces.reserve(N);

  for (size_t i = 0; i < poly->faces.size(); ++i) {
    carve::poly::Face<3> &f = poly->faces[i];
    std::vector<carve::triangulate::tri_idx> result;

    std::vector<const carve::poly::Polyhedron::vertex_t *> vloop;
    f.getVertexLoop(vloop);

    carve::triangulate::triangulate(carve::poly::p2_adapt_project<3>(f.project), vloop, result);
    if (options.improve) {
      carve::triangulate::improve(carve::poly::p2_adapt_project<3>(f.project), vloop, result);
    }

    for (size_t j = 0; j < result.size(); ++j) {
      out_faces.push_back(carve::poly::Face<3>(
            &out_vertices[poly->vertexToIndex_fast(vloop[result[j].a])],
            &out_vertices[poly->vertexToIndex_fast(vloop[result[j].b])],
            &out_vertices[poly->vertexToIndex_fast(vloop[result[j].c])]
            ));
    }
  }

  carve::poly::Polyhedron *result = new carve::poly::Polyhedron(out_faces, out_vertices);

  if (options.canonicalize) result->canonicalize();

  if (options.obj) {
    writeOBJ(std::cout, result);
  } else if (options.vtk) {
    writeVTK(std::cout, result);
  } else {
    writePLY(std::cout, result, options.ascii);
  }

  delete result;
  delete poly;
}
// Output an entity as a VTK file
void conservativeMeshToMesh::writeVTK
(
    const word& name,
    const label entity,
    const label primitiveType,
    const bool useOldConnectivity
) const
{
    writeVTK
    (
        name,
        labelList(1, entity),
        primitiveType,
        useOldConnectivity
    );
}
Example #4
0
int main(int argc, char **argv) {
  options.parse(argc, argv);
  carve::mesh::MeshSet<3> *poly;

  if (options.axis == Options::ERR) {
    std::cerr << "need to specify a closure plane." << std::endl;
    exit(1);
  }

  if (options.file == "-") {
    poly = readPLYasMesh(std::cin);
  } else if (endswith(options.file, ".ply")) {
    poly = readPLYasMesh(options.file);
  } else if (endswith(options.file, ".vtk")) {
    poly = readVTKasMesh(options.file);
  } else if (endswith(options.file, ".obj")) {
    poly = readOBJasMesh(options.file);
  }

  if (poly == NULL) {
    std::cerr << "failed to load polyhedron" << std::endl;
    exit(1);
  }

  std::cerr << "poly aabb = " << poly->getAABB() << std::endl;

  if (poly->getAABB().compareAxis(carve::geom::axis_pos(options.axis, options.pos)) == 0) {
    std::cerr << "poly aabb intersects closure plane." << std::endl;
    exit(1);
  }


  for (size_t i = 0; i < poly->meshes.size(); ++i) {
    carve::mesh::MeshSet<3>::mesh_t *mesh = poly->meshes[i];
    const size_t N = mesh->open_edges.size();
    if (N == 0) continue;

    mesh->faces.reserve(N + 1);

    carve::mesh::MeshSet<3>::edge_t *start = mesh->open_edges[0];

    std::vector<carve::mesh::MeshSet<3>::edge_t *> edges_to_close;
    edges_to_close.resize(N);
    carve::mesh::MeshSet<3>::edge_t *edge = start;
    size_t j = 0;
    do {
      edges_to_close[j++] = edge;
      edge = edge->perimNext();
    } while (edge != start);

    CARVE_ASSERT(j == N);

    std::vector<carve::mesh::MeshSet<3>::vertex_t> projected;
    projected.resize(N);

    for (j = 0; j < N; ++j) {
      edge = edges_to_close[j];
      projected[j].v = edge->vert->v;
      projected[j].v.v[options.axis] = options.pos;
    }

    for (j = 0; j < N; ++j) {
      edge = edges_to_close[j];
      carve::mesh::MeshSet<3>::face_t *quad =
        new carve::mesh::MeshSet<3>::face_t(edge->v2(), edge->v1(), &projected[j], &projected[(j+1)%N]);
      quad->mesh = mesh;
      edge->rev = quad->edge;
      quad->edge->rev = edge;
      mesh->faces.push_back(quad);
    }

    for (j = 0; j < N; ++j) {
      carve::mesh::MeshSet<3>::edge_t *e1 = edges_to_close[j]->rev->prev;
      carve::mesh::MeshSet<3>::edge_t *e2 = edges_to_close[(j+1)%N]->rev->next;
      e1->rev = e2;
      e2->rev = e1;
    }

    for (j = 0; j < N; ++j) {
      edge = edges_to_close[j]->rev;
      edge->validateLoop();
    }

    carve::mesh::MeshSet<3>::face_t *loop =
      carve::mesh::MeshSet<3>::face_t::closeLoop(edges_to_close[0]->rev->next->next);

    loop->mesh = mesh;
    mesh->faces.push_back(loop);

    poly->collectVertices();
  }

  if (options.obj) {
    writeOBJ(std::cout, poly);
  } else if (options.vtk) {
    writeVTK(std::cout, poly);
  } else {
    writePLY(std::cout, poly, options.ascii);
  }

  return 0;
}
Example #5
0
void contourFromScratch(Grid* &cGrid, shared_ptr<Var> &a, double d) {

  double val[listVertex.size()]; 
  
  // 00. construct values at vertex; not cell dependent
  for (auto i = 0; i < listVertex.size(); ++i) 
    val[i] = listVertex[i]->evalPhi(a); 
  
  // 01. check near vertices if contour appears
  for (auto ia = 0; ia < listVertex.size(); ++ia) {
    if (otherVertex[ia] >= 0) continue; // already assigned
    auto va = listVertex[ia]; 
    for (auto di = 1; di <= 3; ++di) { 
      if (di == 0) continue; // no such direction
      auto vb = va->ngbr(di); 
      if (vb == nullptr) continue; 
      auto ib = (*vb)->id; 

      auto dp = d;
      if (abs(val[ia] - dp) < 1e-15) dp = d - 1e-14; 
      if (abs(val[ib] - dp) < 1e-15) dp = d - 1e-14; 
            
      if ((val[ia] - dp)*(val[ib] - dp) >= 0) continue; 

      // create a new point along xia - xib if yet not assigned. 
      if (otherVertex[ia] < 0) {
	auto y = (dp - val[ia])/(val[ib] - val[ia]); 
	auto dr = *listVertex[ib] - *listVertex[ia]; 
	auto x = *listVertex[ia] + y*dr; 
	auto i0a = searchVertexbyCoords(x, ia);
	if (i0a >= 0 && i0a < listVertex.size() && otherVertex[i0a] < 0) {
	  cGrid->addVertex(x);
	  auto i1a = cGrid->listVertex.size()-1; 	  
	  // assign this node to a; 	  
	  cGrid->otherVertex[i1a] = i0a; 
	  otherVertex[i0a] = i1a; 
	}
      }      
    }      
  }

  if (cGrid->listVertex.size() == 0) return; 

  cout << " Vertex count: " << cGrid->listVertex.size() << " "  ; 
  // initial point to start tracing interface ! and ends here; 
  auto i1a = 0; 
  auto i0a = cGrid->otherVertex[i1a];
  if (i0a < 0 || i0a > listVertex.size()) {
    cout << " Vertex cannot be placed on the grid" << endl; 
    exit(1); 
  }
  
  ofstream ot; 
  ot.open("log"+std::to_string(filecnt)+".dat"); 
  // now I have the vertices; 
  auto v0 = listVertex[i0a]; 
  int_8 i1b; 
  shared_ptr<Vertex> *vn; 
  // Calculate gradient first; 
  int di; Vec3 gradv; 
  auto i1ref = i1a;

  auto icnt = 0; 
  vector<bool> color(listVertex.size(), false); 

  while (icnt < listVertex.size()) { 
    ++icnt; 
    vector<pair<int, double> > pp; 
    for (auto di = -3; di <= 3; di++) {
      if (di == 0) continue; 
      vn = v0->ngbr(di); 
      if (vn == nullptr) continue; 
      if (color[(*vn)->id]) continue;
      pp.push_back(std::make_pair<int, double>(int(di), abs(val[(*vn)->id] - d)));
      gradv[abs(di)-1] = (val[(*vn)->id]-val[i0a])/((**vn)[abs(di)-1]-(*v0)[abs(di)-1]) ;
    }
    if (pp.size() == 0) break; // nothing to pursue; 

    std::sort(pp.begin(), pp.end(), 
	      [](const std::pair<int,double> &left, const std::pair<int,double> &right) {
		return left.second < right.second;
	      });

    vn = nullptr; 
    for (auto ii = pp.begin(); ii !=pp.end(); ++ii) {
      if (ii->first == 1 && gradv[1] <= 0) continue; 
      if (ii->first == -1 && gradv[1] >= 0) continue; 
      if (ii->first == 2 && gradv[0] >= 0) continue; 
      if (ii->first == -2 && gradv[0] <= 0) continue; 
      vn = v0->ngbr(ii->first); 
      break; 
    } 
    if (vn == nullptr) {
      cout << endl << "Couldn't get the next vertex" << endl; 
      exit(1); 
    } 
    
    ot << i0a << " " << (*vn)->id << endl;     

    i0a = (*vn)->id; 
    v0 = (*vn); 
    color[i0a] = true; 
    if (abs(val[i0a]) < 1e-5 && abs(val[i0a] - 1.0) < 1e-5) {
      cout << "trace is not successful! stopping"<< endl; 
      cGrid->writeVTK("lag"); 
      exit(1); 
    }
    
    if (otherVertex[i0a] < 0) continue; 
    cGrid->addCell({i1a, otherVertex[i0a]}); 
    if (otherVertex[i0a] == i1ref) break; 
    i1a = otherVertex[i0a]; 
  }

  cout  <<" Cell count: " << cGrid->listCell.size() <<endl; 
  if ((*(cGrid->listCell.rbegin()))->node[1] != (*(cGrid->listCell.begin()))->node[0]) {
    cout << " curve is not closed" << endl; 
        cGrid->listVar.clear(); 
    writeVTK("euler"); 
    cGrid->writeVTK("lag"); 
    exit(1); 
  }

  if (icnt >= listVertex.size()) { 
    cout << "Trace is not successful! stopping " << endl; 
    cGrid->listVar.clear(); 
    writeVTK("euler"); 
    cGrid->writeVTK("lag"); 
    exit(1); 
  }
    
  ot.close(); 
  auto nv2 = cGrid->listVertex.size(); 
  auto nc2 = cGrid->listVertex.size(); 


  for (auto v : cGrid->listVar) {
    if (v->loc == 1) v->data.resize(cGrid->listVertex.size());
    else if (v->loc == 0) v->data.resize(cGrid->listCell.size()); 
  }


  cGrid->cleanGrid(); 
  // if (nv2 != cGrid->listVertex.size()) {
  updateOtherVertex(cGrid); 
  //   // for (auto i1 = 0; i1 < cGrid->otherVertex.size(); ++i1) {
  //   //   if (i1 != cGrid->listVertex[i1]->id) {
  //   // 	cout << " Complaint; ids have problems" << i1; 
  //   // 	cout << " " << cGrid->listVertex[i1]->id << endl;
  //   // 	exit(1); 
  //   //   }
  //   //   auto i0 = cGrid->otherVertex[i1]; 
  //   //   auto is = searchVertexbyCoords(*cGrid->listVertex[i1], i0); 
  //   //   otherVertex[i0] = i1; 
  //   // }
  // }

  return; 
}
Example #6
0
int main(int argc, char **argv) {
  std::vector<std::string> tokens;

  options.parse(argc, argv);

  if (options.args.size() != 2) {
    std::cerr << options.usageStr();
    exit(1);
  }

  carve::mesh::MeshSet<3> *object = load(options.args[0]);
  if (object == NULL) {
    std::cerr << "failed to load object file [" << options.args[0] << "]" << std::endl;
    exit(1);
  }

  carve::mesh::MeshSet<3> *planes = load(options.args[1]);
  if (planes == NULL) {
    std::cerr << "failed to load split plane file [" << options.args[1] << "]" << std::endl;
    exit(1);
  }

  carve::mesh::MeshSet<3> *result = NULL;

  carve::csg::CSG csg;

  if (options.triangulate) {
#if !defined(DISABLE_GLU_TRIANGULATOR)
    if (options.glu_triangulate) {
      csg.hooks.registerHook(new GLUTriangulator, carve::csg::CSG::Hooks::PROCESS_OUTPUT_FACE_BIT);
      if (options.improve) {
        csg.hooks.registerHook(new carve::csg::CarveTriangulationImprover, carve::csg::CSG::Hooks::PROCESS_OUTPUT_FACE_BIT);
      }
    } else {
#endif
      if (options.improve) {
        csg.hooks.registerHook(new carve::csg::CarveTriangulatorWithImprovement, carve::csg::CSG::Hooks::PROCESS_OUTPUT_FACE_BIT);
      } else {
        csg.hooks.registerHook(new carve::csg::CarveTriangulator, carve::csg::CSG::Hooks::PROCESS_OUTPUT_FACE_BIT);
      }
#if !defined(DISABLE_GLU_TRIANGULATOR)
    }
#endif
  } else if (options.no_holes) {
    csg.hooks.registerHook(new carve::csg::CarveHoleResolver, carve::csg::CSG::Hooks::PROCESS_OUTPUT_FACE_BIT);
  }

  Slice slice_collector(object, planes);
  result = csg.compute(object, planes, slice_collector, NULL, carve::csg::CSG::CLASSIFY_EDGE);  

  if (result) {
    result->separateMeshes();

    if (options.canonicalize) result->canonicalize();

    if (options.obj) {
      writeOBJ(std::cout, result);
    } else if (options.vtk) {
      writeVTK(std::cout, result);
    } else {
      writePLY(std::cout, result, options.ascii);
    }
  }

  if (object) delete object;
  if (planes) delete planes;
  if (result) delete result;
}
Example #7
0
//------------------------------------------------------------------------------
int main( int argc, char * argv[] )
{
    // basic attributes of the computation
    const unsigned    geomDeg   = 1;
    const unsigned    fieldDegU = 2;
    const unsigned    fieldDegP = 1;
    const unsigned    tiOrder   = 2;   // order of time integrator
    const base::Shape shape     = base::QUAD;

    //typedef  base::time::BDF<tiOrder> MSM;
    typedef base::time::AdamsMoulton<tiOrder> MSM;

    // time stepping method determines the history size
    const unsigned nHist = MSM::numSteps;

    
    const std::string inputFile = "terz.inp";
    double E, nu, alpha, c0, k, H, F, tMax;
    unsigned numSteps, numIntervals;
    {
        base::io::PropertiesParser pp;
        pp.registerPropertiesVar( "E",     E     );
        pp.registerPropertiesVar( "nu",    nu    );
        pp.registerPropertiesVar( "alpha", alpha );
        pp.registerPropertiesVar( "c0",    c0    );
        pp.registerPropertiesVar( "k",     k     );
        pp.registerPropertiesVar( "H",     H     );
        pp.registerPropertiesVar( "F",     F     );

        pp.registerPropertiesVar( "tMax",         tMax  );
        pp.registerPropertiesVar( "numSteps",     numSteps );
        pp.registerPropertiesVar( "numIntervals", numIntervals );

        // Read variables from the input file
        std::ifstream inp( inputFile.c_str() );
        VERIFY_MSG( inp.is_open(), "Cannot open input file" );
        pp.readValues( inp );
        inp.close( );

    }

    const double deltaT = tMax / static_cast<double>( numSteps );

    // usage message
    if ( argc != 2 ) {
        std::cout << "Usage:  " << argv[0] << "  mesh.smf \n";
        return 0;
    }

    const std::string meshFile = boost::lexical_cast<std::string>( argv[1] );

    

    // Analytic solution
    Terzaghi terzaghi( E, nu, alpha, c0, k, H, F );
    

    //--------------------------------------------------------------------------
    // define a mesh
    typedef base::Unstructured<shape,geomDeg>    Mesh;
    const unsigned dim = Mesh::Node::dim;

    // create a mesh and read from input
    Mesh mesh;
    {
        std::ifstream smf( meshFile.c_str() );
        base::io::smf::readMesh( smf, mesh );
        smf.close();
    }

    // quadrature objects for volume and surface
    const unsigned kernelDegEstimate = 3;
    typedef base::Quadrature<kernelDegEstimate,shape> Quadrature;
    Quadrature quadrature;
    typedef base::SurfaceQuadrature<kernelDegEstimate,shape> SurfaceQuadrature;
    SurfaceQuadrature surfaceQuadrature;

    // Create a displacement field
    const unsigned    doFSizeU = dim;
    typedef base::fe::Basis<shape,fieldDegU>           FEBasisU;
    typedef base::Field<FEBasisU,doFSizeU,nHist>       Displacement;
    typedef Displacement::DegreeOfFreedom              DoFU;
    Displacement displacement;

    // Create a pressure field
    const unsigned    doFSizeP = 1;
    typedef base::fe::Basis<shape,fieldDegP>           FEBasisP;
    typedef base::Field<FEBasisP,doFSizeP,nHist>       Pressure;
    typedef Pressure::DegreeOfFreedom                  DoFP;
    Pressure pressure;

    // generate DoFs from mesh
    base::dof::generate<FEBasisU>( mesh, displacement );
    base::dof::generate<FEBasisP>( mesh, pressure );

    // Creates a list of <Element,faceNo> pairs along the boundary
    base::mesh::MeshBoundary meshBoundary;
    meshBoundary.create( mesh.elementsBegin(), mesh.elementsEnd() );

    // Create a boundary mesh from this list
    typedef base::mesh::CreateBoundaryMesh<Mesh::Element> CreateBoundaryMesh;
    typedef CreateBoundaryMesh::BoundaryMesh BoundaryMesh;
    BoundaryMesh boundaryMesh;
    {
        CreateBoundaryMesh::apply( meshBoundary.begin(),
                                   meshBoundary.end(),
                                   mesh, boundaryMesh );
    }



    // material object
    typedef mat::hypel::StVenant Material;
    Material material( mat::Lame::lambda( E, nu), mat::Lame::mu( E, nu ) );

    typedef base::asmb::FieldBinder<Mesh,Displacement,Pressure> Field;
    Field field( mesh, displacement, pressure );

    typedef Field::TupleBinder<1,1>::Type TopLeft;
    typedef Field::TupleBinder<1,2>::Type TopRight;
    typedef Field::TupleBinder<2,1>::Type BotLeft;
    typedef Field::TupleBinder<2,2>::Type BotRight;

    // surface displacement field
    typedef base::asmb::SurfaceFieldBinder<BoundaryMesh,Displacement> SurfaceFieldBinder;
    SurfaceFieldBinder surfaceFieldBinder( boundaryMesh, displacement );
    typedef SurfaceFieldBinder::TupleBinder<1>::Type SFTB;
    
    // kernel objects
    typedef solid::HyperElastic<Material,TopLeft::Tuple> HyperElastic;
    HyperElastic hyperElastic( material );

    typedef fluid::PressureGradient<TopRight::Tuple> GradP;
    GradP gradP;

    //typedef fluid::VelocityDivergence<FieldPUUTuple> DivU;
    //DivU divU( true ); // * alpha
    typedef PoroDivU<BotLeft::Tuple> DivU;
    DivU divU( alpha );

    typedef heat::Laplace<BotRight::Tuple> Laplace;
    Laplace laplace( k );

    // constrain the boundary
    base::dof::constrainBoundary<FEBasisU>( meshBoundary.begin(),
                                            meshBoundary.end(),
                                            mesh, displacement, 
                                            boost::bind( &dirichletU<dim,DoFU>, _1, _2, 1.0 ) );
    
    base::dof::constrainBoundary<FEBasisP>( meshBoundary.begin(),
                                            meshBoundary.end(),
                                            mesh, pressure, 
                                            boost::bind( &dirichletP<dim,DoFP>, _1, _2, H ) );


    // Number the degrees of freedom
    const std::size_t numDoFsU =
        base::dof::numberDoFsConsecutively( displacement.doFsBegin(), displacement.doFsEnd() );
    std::cout << "# Number of displacement dofs " << numDoFsU << std::endl;
    const std::size_t numDoFsP =
        base::dof::numberDoFsConsecutively( pressure.doFsBegin(), pressure.doFsEnd(), numDoFsU );
    std::cout << "# Number of pressure     dofs " << numDoFsP << std::endl;


    // write VTK file
    writeVTK( mesh, displacement, pressure, meshFile, 0 );

    
    for ( unsigned n = 0; n < numSteps; n++ ) {

        const double time = (n+1) * deltaT;
        std::cout << time << "  ";

        // initialise current displacement to zero (linear elasticity)
        std::for_each( displacement.doFsBegin(), displacement.doFsEnd(),
                       boost::bind( &DoFU::clearValue, _1 ) );

        // Create a solver object
        typedef base::solver::Eigen3           Solver;
        Solver solver( numDoFsU + numDoFsP );

        //------------------------------------------------------------------
        base::asmb::stiffnessMatrixComputation<TopLeft>( quadrature, solver, 
                                                         field, hyperElastic );

        base::asmb::stiffnessMatrixComputation<TopRight>( quadrature, solver,
                                                          field, gradP );

        base::asmb::stiffnessMatrixComputation<BotRight>( quadrature, solver,
                                                          field, laplace);

        // time integration terms
        base::time::computeReactionTerms<BotLeft,MSM>( divU, quadrature, solver,
                                                       field, deltaT, n );

        base::time::computeInertiaTerms<BotRight,MSM>( quadrature, solver,
                                                       field, deltaT, n, c0 );
        
        base::time::computeResidualForceHistory<BotRight,MSM>( laplace, 
                                                               quadrature, solver,
                                                               field, n );


        // Neumann boundary condition
        base::asmb::neumannForceComputation<SFTB>( surfaceQuadrature, solver, surfaceFieldBinder,
                                                   boost::bind( &neumannBC<dim>, _1, _2,
                                                                H, F ) );


        // Finalise assembly
        solver.finishAssembly();

        // Solve
        solver.superLUSolve();
            
        // distribute results back to dofs
        base::dof::setDoFsFromSolver( solver, displacement );
        base::dof::setDoFsFromSolver( solver, pressure );
        
        // push history
        std::for_each( displacement.doFsBegin(), displacement.doFsEnd(),
                       boost::bind( &DoFU::pushHistory, _1 ) );
        std::for_each( pressure.doFsBegin(), pressure.doFsEnd(),
                       boost::bind( &DoFP::pushHistory, _1 ) );


        // write VTK file
        writeVTK( mesh, displacement, pressure, meshFile, n+1 );
        
        // Finished time steps
        //--------------------------------------------------------------------------

        const std::pair<double,double> approx = probe( mesh, displacement, pressure );

        const double p = terzaghi.pressure( H/2., time );
        const double u = terzaghi.displacement( H/2., time );
        
        std::cout << u  << "  " << approx.first << "  "
                  << p  << "  " << approx.second << '\n';
    }
    
    return 0;
}
void writeVTK(std::string &out_file, const carve::line::PolylineSet *lines, bool ascii) {
  std::ofstream out(out_file.c_str(), std::ios_base::binary);
  if (!out.is_open()) { std::cerr << "File '" <<  out_file << "' could not be opened." << std::endl; return; }
  writeVTK(out, lines);
}
void writeVTK(std::string &out_file, const carve::poly::Polyhedron *poly) {
  std::ofstream out(out_file.c_str(), std::ios_base::binary);
  if (!out.is_open()) { std::cerr << "File '" <<  out_file << "' could not be opened." << std::endl; return; }
  writeVTK(out, poly);
}