Пример #1
0
static void computeLevelset(GModel *gm, cartesianBox<double> &box)
{
  // tolerance for desambiguation
  const double tol = box.getLC() * 1.e-12;
  std::vector<SPoint3> nodes;
  std::vector<int> indices;
  for (cartesianBox<double>::valIter it = box.nodalValuesBegin();
       it != box.nodalValuesEnd(); ++it){
    nodes.push_back(box.getNodeCoordinates(it->first));
    indices.push_back(it->first);
  }
  Msg::Info("  %d nodes in the grid at level %d", (int)nodes.size(), box.getLevel());
  std::vector<double> dist, localdist;
  std::vector<SPoint3> dummy;
  for (GModel::fiter fit = gm->firstFace(); fit != gm->lastFace(); fit++){
    for (int i = 0; i < (*fit)->stl_triangles.size(); i += 3){
      int i1 = (*fit)->stl_triangles[i];
      int i2 = (*fit)->stl_triangles[i + 1];
      int i3 = (*fit)->stl_triangles[i + 2];
      GPoint p1 = (*fit)->point((*fit)->stl_vertices[i1]);
      GPoint p2 = (*fit)->point((*fit)->stl_vertices[i2]);
      GPoint p3 = (*fit)->point((*fit)->stl_vertices[i3]);
      SPoint2 p = ((*fit)->stl_vertices[i1] + (*fit)->stl_vertices[i2] +
                   (*fit)->stl_vertices[i3]) * 0.33333333;
      SVector3 N = (*fit)->normal(p);
      SPoint3 P1(p1.x(), p1.y(), p1.z());
      SPoint3 P2(p2.x(), p2.y(), p2.z());
      SPoint3 P3(p3.x(), p3.y(), p3.z());
      SVector3 NN(crossprod(P2 - P1, P3 - P1));
      if (dot(NN, N) > 0)
	signedDistancesPointsTriangle(localdist, dummy, nodes, P1, P2, P3);
      else
	signedDistancesPointsTriangle(localdist, dummy, nodes, P2, P1, P3);
      if(dist.empty())
        dist = localdist;
      else{
        for (unsigned int j = 0; j < localdist.size(); j++){
          // FIXME: if there is an ambiguity assume we are inside (to
          // avoid holes in the structure). This is definitely just a
          // hack, as it could create pockets of matter outside the
          // structure...
          if(dist[j] * localdist[j] < 0 &&
             fabs(fabs(dist[j]) - fabs(localdist[j])) < tol){
            dist[j] = std::max(dist[j], localdist[j]);
          }
          else{
            dist[j] = (fabs(dist[j]) < fabs(localdist[j])) ? dist[j] : localdist[j];
          }
        }
      }
    }
  }
  for (unsigned int j = 0; j < dist.size(); j++)
    box.setNodalValue(indices[j], dist[j]);

  if(box.getChildBox()) computeLevelset(gm, *box.getChildBox());
}
Пример #2
0
int main()
{
    int  dimension  = 3;
    auto resolution = Manta::Vec3i(128);

    if (dimension == 2) resolution.z = 1;

    auto main_solver = Manta::FluidSolver(resolution, dimension);
    main_solver.setTimeStep(0.5f);
    Real minParticles = pow(2, dimension);

    Real radiusFactor = 1.0f;

    // solver grids
    auto flags      = Manta::FlagGrid(&main_solver);
    auto phi        = Manta::LevelsetGrid(&main_solver);

    auto vel        = Manta::MACGrid(&main_solver);
    auto vel_old    = Manta::MACGrid(&main_solver);
    auto pressure   = Manta::Grid<Real>(&main_solver);
    auto tmp_vec3   = Manta::Grid<Manta::Vec3>(&main_solver);
    auto tstGrid    = Manta::Grid<Real>(&main_solver);

    // particles
    auto pp         = Manta::BasicParticleSystem(&main_solver);
    auto pVel       = Manta::PdataVec3(&pp);
    auto pTest      = Manta::PdataReal(&pp);
    auto mesh       = Manta::Mesh(&main_solver);

    // acceleration data for particle nbs
    auto pindex     = Manta::ParticleIndexSystem(&main_solver);
    auto gpi        = Manta::Grid<int>(&main_solver);

    int setup = 0;
    int boundaryWidth = 1;
    flags.initDomain(boundaryWidth);
    auto fluidVel = Manta::Sphere(&main_solver, Manta::Vec3(0.0f), 1.0f);
    Manta::Vec3 fluidSetVel;

    if (setup == 0)
    {
        // breakin dam
        auto fluidbox   = Manta::Box(&main_solver, Manta::Vec3::Invalid,
                                                   Manta::Vec3(0.0f, 0.0f, 0.0f),
                                                   Manta::Vec3(resolution.x * 0.4f, resolution.y * 0.6f, resolution.z * 0.1f));
        phi.copyFrom(fluidbox.computeLevelset());

    } else if (setup == 1)
    {
        // drop into box
        auto fluidbasin = Manta::Box(&main_solver, Manta::Vec3::Invalid,
                                                   Manta::Vec3(0.0f, 0.0f, 0.0f),
                                                   Manta::Vec3(resolution.x * 1.0f, resolution.y * 0.1f, resolution.z * 1.0f));
        auto dropCenter = Manta::Vec3(0.5f, 0.3f, 0.5f);
        Real dropRadius = 0.1f;
        auto fluidDrop  = Manta::Sphere(&main_solver, Manta::Vec3(resolution.x * dropCenter.x, resolution.y * dropCenter.y, resolution.z * dropCenter.z),
                                                      resolution.x * dropRadius);
        fluidVel        = Manta::Sphere(&main_solver, Manta::Vec3(resolution.x * dropCenter.x, resolution.y * dropCenter.y, resolution.z * dropCenter.z),
                                                      resolution.x * (dropRadius + 0.05f));
        fluidSetVel     = Manta::Vec3(0.0f, -1.0f, 0.0f);
        phi.copyFrom(fluidbasin.computeLevelset());
        phi.join(fluidDrop.computeLevelset());
    }

    flags.updateFromLevelset(phi);
    Manta::sampleLevelsetWithParticles(phi, flags, pp, 2, 0.05f);

    if (setup == 1)
    {
        fluidVel.applyToGrid(&vel, fluidSetVel);
        Manta::mapGridToPartsVec3(vel, pp, pVel);
    }

    Manta::testInitGridWithPos(tstGrid);
    pTest.setConst(0.1f);

    for (int t = 0; t < 250; t++)
    {
        // FLIP
        pp.advectInGrid(flags, vel, Manta::IntegrationMode::IntRK4, false);

        // make sure we have velocities throught liquid region
        Manta::mapParticlesToMAC(flags, vel, vel_old, pp, pVel, &tmp_vec3);
        Manta::extrapolateMACFromWeight(vel, tmp_vec3, 2);
        Manta::markFluidCells(pp, flags);

        // create approximate surface level set, resample particles
        Manta::gridParticleIndex(pp, pindex, flags, gpi);
        Manta::unionParticleLevelset(pp, pindex, flags, gpi, phi, radiusFactor);
        Manta::resetOutflow(flags, nullptr, &pp, nullptr, &gpi,&pindex);

	    // extend levelset somewhat, needed by particle resampling in adjustNumber
	    Manta::extrapolateLsSimple(phi, 4, true);

        // forces and pressure solve
        Manta::addGravity(flags, vel, Manta::Vec3(0.0f, -0.001f, 0.0f));
        Manta::setWallBcs(flags, vel);
        Manta::solvePressure(vel, pressure, flags, &phi);
        Manta::setWallBcs(flags, vel);

        // set source grids for resampling, used in adjustNumber!
        pVel.setSource(&vel, true);
        pTest.setSource(&tstGrid);
        Manta::adjustNumber(pp, vel, flags, 1 * minParticles, 2 * minParticles, phi, radiusFactor);

        // make sure we have proper velocities
        Manta::extrapolateMACSimple(flags, vel);
        Manta::flipVelocityUpdate(flags, vel, vel_old, pp, pVel, 0.97f);

        if (dimension == 3) phi.createMesh(mesh);

        main_solver.step();

    	// generate data directly and for flip03_gen.py surface generation scene
        std::stringstream filename1, filename2;
        filename1 << "simulation data\\flip02_surface\\fluidsurface_final_" << std::setw(4) << std::setfill('0') << t << ".bobj.gz";
        filename2 << "simulation data\\flip02_surface\\flipParts_"          << std::setw(4) << std::setfill('0') << t << ".uni";

        mesh.save(filename1.str());
        pp.save(filename2.str());
    }

}
Пример #3
0
int main(int argc,char *argv[])
{
  if(argc < 6){
    printf("Usage: %s file lx ly lz rmax [levels=1] [refcs=1]\n", argv[0]);
    printf("where\n");
    printf("  'file' contains a CAD model\n");
    printf("  'lx', 'ly' and 'lz' are the sizes of the elements along the"
           " x-, y- and z-axis at the coarsest level\n");
    printf("  'rmax' is the radius of the largest sphere that can be inscribed"
           " in the structure\n");
    printf("  'levels' sets the number of levels in the grid\n");
    printf("  'refcs' selects if curved surfaces should be refined\n");
    return -1;
  }

  GmshInitialize();
  GmshSetOption("General", "Terminal", 1.);
  GmshMergeFile(argv[1]);
  double lx = atof(argv[2]), ly = atof(argv[3]), lz = atof(argv[4]);
  double rmax = atof(argv[5]);
  int levels = (argc > 6) ? atof(argv[6]) : 1;
  int refineCurvedSurfaces = (argc > 7) ? atof(argv[7]) : 1;

  // minimum distance between points in the cloud at the coarsest
  // level
  double sampling = std::min(rmax, std::min(lx, std::min(ly, lz)));

  // radius of the "tube" created around parts to refine at the
  // coarsest level
  double rtube = std::max(lx, std::max(ly, lz)) * 2.;

  GModel *gm = GModel::current();

  std::vector<SPoint3> points;
  Msg::Info("Filling coarse point cloud on surfaces");
  for (GModel::fiter fit = gm->firstFace(); fit != gm->lastFace(); fit++)
    (*fit)->fillPointCloud(sampling, &points);
  Msg::Info("  %d points in the surface cloud", (int)points.size());

  std::vector<SPoint3> refinePoints;
  if(levels > 1){
    double s = sampling / pow(2., levels - 1);
    Msg::Info("Filling refined point cloud on curves and curved surfaces");
    for (GModel::eiter eit = gm->firstEdge(); eit != gm->lastEdge(); eit++)
      fillPointCloud(*eit, s, refinePoints);

    // FIXME: refine this by computing e.g. "mean" curvature
    if(refineCurvedSurfaces){
      for (GModel::fiter fit = gm->firstFace(); fit != gm->lastFace(); fit++)
        if((*fit)->geomType() != GEntity::Plane)
          (*fit)->fillPointCloud(2 * s, &refinePoints);
    }
    Msg::Info("  %d points in the refined cloud", (int)refinePoints.size());
  }

  SBoundingBox3d bb;
  for(unsigned int i = 0; i < points.size(); i++) bb += points[i];
  for(unsigned int i = 0; i < refinePoints.size(); i++) bb += refinePoints[i];
  bb.scale(1.21, 1.21, 1.21);
  SVector3 range = bb.max() - bb.min();
  int NX = range.x() / lx;
  int NY = range.y() / ly;
  int NZ = range.z() / lz;
  if(NX < 2) NX = 2;
  if(NY < 2) NY = 2;
  if(NZ < 2) NZ = 2;

  Msg::Info("  bounding box min: %g %g %g -- max: %g %g %g",
            bb.min().x(), bb.min().y(), bb.min().z(),
            bb.max().x(), bb.max().y(), bb.max().z());
  Msg::Info("  Nx=%d Ny=%d Nz=%d", NX, NY, NZ);

  cartesianBox<double> box(bb.min().x(), bb.min().y(), bb.min().z(),
                           SVector3(range.x(), 0, 0),
                           SVector3(0, range.y(), 0),
                           SVector3(0, 0, range.z()),
                           NX, NY, NZ, levels);

  Msg::Info("Inserting active cells in the cartesian grid");
  Msg::Info("  level %d", box.getLevel());
  for (unsigned int i = 0; i < points.size(); i++)
    insertActiveCells(points[i].x(), points[i].y(), points[i].z(), rmax, box);

  cartesianBox<double> *parent = &box, *child;
  while((child = parent->getChildBox())){
    Msg::Info("  level %d", child->getLevel());
    for(unsigned int i = 0; i < refinePoints.size(); i++)
      insertActiveCells(refinePoints[i].x(), refinePoints[i].y(), refinePoints[i].z(),
                        rtube / pow(2., (levels - child->getLevel())), *child);
    parent = child;
  }

  // remove child cells that do not entirely fill parent cell or for
  // which there is no parent neighbor; then remove parent cells that
  // have children
  Msg::Info("Removing cells to match X-FEM mesh topology constraints");
  removeBadChildCells(&box);
  removeParentCellsWithChildren(&box);

  // we generate duplicate nodes at this point so we can easily access
  // cell values at each level; we will clean up by renumbering after
  // filtering
  Msg::Info("Initializing nodal values in the cartesian grid");
  box.createNodalValues();

  Msg::Info("Computing levelset on the cartesian grid");
  computeLevelset(gm, box);

  Msg::Info("Removing cells outside the structure");
  removeOutsideCells(&box);

  Msg::Info("Renumbering mesh vertices across levels");
  box.renumberNodes();

  bool decomposeInSimplex = false;
  box.writeMSH("yeah.msh", decomposeInSimplex);

  Msg::Info("Done!");
  GmshFinalize();
}