void VoronoiDustGridStructure::setupSelfBefore() { GenDustGridStructure::setupSelfBefore(); Log* log = find<Log>(); // Determine an appropriate set of particles and construct the Voronoi mesh switch (_distribution) { case Uniform: { if (_numParticles < 10) throw FATALERROR("The number of particles should be at least 10"); vector<Vec> rv(_numParticles); for (int m=0; m<_numParticles; m++) { rv[m] = _random->position(extent()); } log->info("Computing Voronoi tesselation for " + QString::number(_numParticles) + " uniformly distributed random particles..."); _mesh = new VoronoiMesh(rv, extent()); break; } case CentralPeak: { if (_numParticles < 10) throw FATALERROR("The number of particles should be at least 10"); const int a = 1000; // steepness of the peak; the central 1/a portion is NOT covered const double rscale = extent().rmax().norm(); vector<Vec> rv(_numParticles); for (int m=1; m<_numParticles; m++) // skip first particle so that it remains (0,0,0) { while (true) { double r = rscale * pow(1./a, _random->uniform()); // random distribution according to 1/x Direction k = _random->direction(); Position p = Position(r,k); if (extent().contains(p)) // discard any points outside of the domain { rv[m] = p; break; } } } log->info("Computing Voronoi tesselation for " + QString::number(_numParticles) + " random particles distributed in a central peak..."); _mesh = new VoronoiMesh(rv, extent()); break; } case DustDensity: { if (_numParticles < 10) throw FATALERROR("The number of particles should be at least 10"); DustDistribution* dd = find<DustDistribution>(); vector<Vec> rv(_numParticles); for (int m=0; m<_numParticles; m++) { while (true) { Position p = dd->generatePosition(); if (extent().contains(p)) // discard any points outside of the domain { rv[m] = p; break; } } } log->info("Computing Voronoi tesselation for " + QString::number(_numParticles) + " random particles distributed according to dust density..."); _mesh = new VoronoiMesh(rv, extent()); break; } case DustTesselation: { VoronoiMeshInterface* vmi = find<DustDistribution>()->interface<VoronoiMeshInterface>(); if (!vmi) throw FATALERROR("Can't retrieve Voronoi mesh from this dust distribution"); _mesh = vmi->mesh(); _meshOwned = false; log->info("Using Voronoi tesselation from dust distribution with " + QString::number(_mesh->Ncells()) + " particles..."); break; } case SPHParticles: { DustParticleInterface* dpi = find<DustDistribution>()->interface<DustParticleInterface>(); if (!dpi) throw FATALERROR("Can't retrieve particle locations from this dust distribution"); log->info("Computing Voronoi tesselation for " + QString::number(dpi->numParticles()) + " dust distribution particles..."); _mesh = new VoronoiMesh(dpi, extent()); break; } case File: { if (!_meshfile) throw FATALERROR("File containing particle locations is not defined"); log->info("Computing Voronoi tesselation for particles loaded from file " + _meshfile->filename() + "..."); _mesh = new VoronoiMesh(_meshfile, QList<int>(), extent()); break; } default: throw FATALERROR("Unknown distribution type"); } // Communicate the number of dust cells to the base class _Ncells = _mesh->Ncells(); // Log statistics on the cell neighbors double avgNeighbors; int minNeighbors, maxNeighbors; _mesh->neighborStatistics(avgNeighbors, minNeighbors, maxNeighbors); log->info("Computed Voronoi tesselation with " + QString::number(_Ncells) + " cells:"); log->info(" Average number of neighbors per cell: " + QString::number(avgNeighbors,'f',1)); log->info(" Minimum number of neighbors per cell: " + QString::number(minNeighbors)); log->info(" Maximum number of neighbors per cell: " + QString::number(maxNeighbors)); // Log statistics on the block lists int nblocks = _mesh->Nblocks(); double avgRefsPerBlock; int minRefsPerBlock, maxRefsPerBlock; _mesh->blockStatistics(avgRefsPerBlock, minRefsPerBlock, maxRefsPerBlock); log->info("Created grid to accelerate which-cell operations:"); log->info(" Number of cells : " + QString::number(_Ncells)); log->info(" Number of blocks : " + QString::number(nblocks*nblocks*nblocks) + " (" + QString::number(nblocks) + " in each dimension)"); log->info(" Average number of cells per block: " + QString::number(avgRefsPerBlock,'f',1)); log->info(" Minimum number of cells per block: " + QString::number(minRefsPerBlock)); log->info(" Maximum number of cells per block: " + QString::number(maxRefsPerBlock)); // Log statistics on the search trees double avgRefsPerTree; int nTrees, minRefsPerTree, maxRefsPerTree; _mesh->treeStatistics(nTrees, avgRefsPerTree, minRefsPerTree, maxRefsPerTree); log->info("Created search trees to accelerate which-cell operations:"); log->info(" Number of trees : " + QString::number(nTrees) + " (" + QString::number(100.*nTrees/(nblocks*nblocks*nblocks),'f',1) + "% of blocks)"); log->info(" Average number of cells per tree : " + QString::number(avgRefsPerTree,'f',1)); log->info(" Minimum number of cells per tree : " + QString::number(minRefsPerTree)); log->info(" Maximum number of cells per tree : " + QString::number(maxRefsPerTree)); // If requested, output the plot files (we have to reconstruct the Voronoi tesselation...) if (writeGrid()) { setWriteGrid(false); // keep the base class from overwriting our plot files Units* units = find<Units>(); FilePaths* filepaths = find<FilePaths>(); // create the plot files QString name = filepaths->output("ds_grid"); DustGridPlotFile plotxy(name+"xy.dat",log,units); DustGridPlotFile plotxz(name+"xz.dat",log,units); DustGridPlotFile plotyz(name+"yz.dat",log,units); DustGridPlotFile plotxyz(name+"xyz.dat",log,units); // load all particles in a Voro container int nb = max(3, min(1000, static_cast<int>(pow(_Ncells/5.,1./3.)) )); voro::container con(xmin(), xmax(), ymin(), ymax(), zmin(), zmax(), nb, nb, nb, false,false,false, 8); for (int m=0; m<_Ncells; m++) { Vec r = _mesh->particlePosition(m); con.put(m, r.x(),r.y(),r.z()); } // loop over all Voro cells voro::c_loop_all loop(con); if (loop.start()) do { // Compute the cell voro::voronoicell fullcell; con.compute_cell(fullcell, loop); // Get the edges of the cell double x,y,z; loop.pos(x,y,z); vector<double> coords; fullcell.vertices(x,y,z, coords); vector<int> indices; fullcell.face_vertices(indices); // Write the edges of the cell to the plot files Box bounds = _mesh->extent(loop.pid()); if (bounds.zmin()<=0 && bounds.zmax()>=0) plotxy.writePolyhedron(coords, indices); if (bounds.ymin()<=0 && bounds.ymax()>=0) plotxz.writePolyhedron(coords, indices); if (bounds.xmin()<=0 && bounds.xmax()>=0) plotyz.writePolyhedron(coords, indices); if (loop.pid() <= 1000) plotxyz.writePolyhedron(coords, indices); } while (loop.inc()); } }