因此,您可以做的一件事是将结构化区域(例如 3D 矩形体积)隐式表示为一组切碎的子体积,其中每个子体积会自动执行您需要的空间约束。您将隐含地执行此操作,只需存储将每个维度单独切片的数量,并使用唯一的索引元组引用每个子卷。
然后,您可以使用粒子半径和容差的值来计算每个维度应该有多少切片,以便满足您的空间约束。
然后从这里你可以迭代地蒙特卡罗下一个子卷以插入一个粒子。为了有效地检查你是否蒙特卡罗一个你已经使用过的子卷,你可以计算一个唯一的哈希,给定一个子卷的索引元组, 并将其存储在有效的数据结构中,例如C++std::map或std::unordered_mapC++,以便能够快速检查是否存在。
我为此用 C++ 编写的示例代码如下:
粒子云.hpp
#ifndef _particle_cloud_
#define _particle_cloud_
#include <vector>
#include <cstdint>
namespace particle {
class cloud {
public:
// useful typedefs
typedef std::vector<double> position;
typedef std::vector<position> positions;
// ctors / initializers
cloud();
cloud(int num_particles, double xrng[2], double yrng[2], double zrng[2], double radius, double tolerance);
void init(int num_particles, double xrng[2], double yrng[2], double zrng[2], double radius, double tolerance);
// getter for particle position
const position & getParticlePositionAt(int idx) const;
// get number of particles in particle cloud
int numParticles() const;
private:
typedef uint64_t h_int;
enum Bounds { Low = 0, High = 1};
positions ps;
// unique hash function
static h_int hash(h_int ix, h_int iy, h_int iz, h_int Nx, h_int Ny);
};
}
#endif
粒子云.cpp
#include "particle_cloud.hpp"
#include <map>
#include <random>
#include <cmath>
namespace particle {
cloud::cloud()
{
}
cloud::cloud(int num_particles, double xrng[2], double yrng[2], double zrng[2], double radius, double tolerance)
{
init(num_particles, xrng, yrng, zrng, radius, tolerance);
}
void cloud::init(int num_particles, double xrng[2], double yrng[2], double zrng[2], double radius, double tolerance)
{
// init constant quantities
const double r = radius;
const double e = tolerance;
const double lb[3] = { xrng[Low], yrng[Low], zrng[Low] };
const double ub[3] = { xrng[High], yrng[High], zrng[High] };
const double span[3] = { ub[0]- lb[0], ub[1]- lb[1], ub[2]- lb[2] };
const h_int N[3] = { std::floor(0.5*span[0]/(r+e)), std::floor(0.5*span[1] / (r + e)), std::floor(0.5*span[2] / (r + e)) };
const double del[3] = { span[0] / static_cast<double>(N[0]), span[1] / static_cast<double>(N[1]) , span[2] / static_cast<double>(N[2]) };
// init array of temp map indices
h_int idx[3] = { 0 };
// init temp position vector
position tmp(3, 0.0);
// size up the positions container correctly
ps.resize(num_particles, tmp);
// init the uniform distribution random number generator
std::default_random_engine generator;
std::uniform_real_distribution<double> U(0, 1);
// create a map container to check if a given hash
// has already been created
std::map<h_int, bool> exist_map;
// init variable that will say if the new position generated
// is valid or not
bool noGoodPos = false;
// loop and generate the particle positions
for (unsigned int i = 0; i < num_particles; ++i) {
noGoodPos = true;
// try to generate a valid position via Monte Carlo sampling until one has been made
while (noGoodPos) {
for (int d = 0; d < 3; ++d) { idx[d] = U(generator)*N[d]; }
h_int h_ = hash(idx[0], idx[1], idx[2], N[0], N[1]);
if (exist_map.count(h_) != 0) { }
else {
exist_map[h_] = true;
noGoodPos = false;
}
}
// compute each component of position
// based on indices and dimensions of container
for (int d = 0; d < 3; ++d) {
tmp[d] = lb[d] + (del[d] * idx[d]) + (del[d] * 0.5);
}
// copy temp position to ith position in positions container
ps[i] = tmp;
}
}
const typename cloud::position & cloud::getParticlePositionAt(int idx) const
{
return ps[idx];
}
int cloud::numParticles() const
{
return (int)ps.size();
}
typename cloud::h_int cloud::hash(h_int ix, h_int iy, h_int iz, h_int Nx, h_int Ny)
{
return ix + Nx*(iy + Ny*iz); // unique hash based on spatial indices
}
}
主文件
#include <stdio.h>
#include "particle_cloud.hpp"
int main(int argc, char** argv) {
particle::cloud pc;
double v[2] = { 0, 1 };
pc.init(100000, v, v, v, 1e-4, 1e-8);
FILE * file_ = fopen("points.csv", "w");
if (file_) {
for (int i = 0; i < pc.numParticles(); ++i) {
const particle::cloud::position & p = pc.getParticlePositionAt(i);
fprintf(file_, "%0.8e, %0.8e, %0.8e\n", p[0], p[1], p[2]);
}
fclose(file_); file_ = nullptr;
}
return 0;
}
基于使用上述代码生成 1000 个粒子位置的示例图形如下所示:
