如何提高四叉树代码的性能以防止程序冻结 我正在模拟两个星团的碰撞,所以基本上是用C++来做一个n-体问题。我用巴恩斯小屋的方法来帮助做这件事。我已经编写了我的四叉树代码和运行模拟的主代码,它一直工作到第201-250步,然后程序就没有响应了。我不确定这是否只是一个性能问题,或者代码中是否发生了令人讨厌的事情。有人可以查看一下它并解释为什么它会冻结,或者如何提高性能吗
以下是使用Barnes Hut构建和计算四叉树的代码:如何提高四叉树代码的性能以防止程序冻结 我正在模拟两个星团的碰撞,所以基本上是用C++来做一个n-体问题。我用巴恩斯小屋的方法来帮助做这件事。我已经编写了我的四叉树代码和运行模拟的主代码,它一直工作到第201-250步,然后程序就没有响应了。我不确定这是否只是一个性能问题,或者代码中是否发生了令人讨厌的事情。有人可以查看一下它并解释为什么它会冻结,或者如何提高性能吗,c++,performance,freeze,quadtree,C++,Performance,Freeze,Quadtree,以下是使用Barnes Hut构建和计算四叉树的代码: #define threshold 1.0 // threshold for determining "far-ness" // 0.5 for best results, higher means faster #define G 1.57633e-17 // ly^3 Msun^-1 s^-2, gravitational constant struct Body {
#define threshold 1.0 // threshold for determining "far-ness"
// 0.5 for best results, higher means faster
#define G 1.57633e-17 // ly^3 Msun^-1 s^-2, gravitational constant
struct Body {
double mass;
Vector3D position;
Vector3D velocity;
// makes a new body
Body(double m, Vector3D pos, Vector3D vel) : mass(m), position(pos), velocity(vel) {};
Body() : mass(0), position(0, 0, 0), velocity(0, 0, 0) {};
};
struct QuadTreeNode;
struct QuadTreeNode {
/* ---------- Stored Properties of this node ----------- */
// the total mass and CoM for all bodies inserted
// below this node in the tree
Body body;
// rescale positions to fit in nodes
// note: will need to have all bodies in
// at least positive coordinates to be included
// body.position.update(body.position.Getx()/scale,
// body.position.Gety()/scale);
// scale defined in program
// the four subnodes / quadrants
QuadTreeNode* A = NULL;
QuadTreeNode* B = NULL;
QuadTreeNode* C = NULL;
QuadTreeNode* D = NULL;
// location+size parameters of each node (center)
double length; // = 1.0 for depth = 0
double horiz_offset; // = 0.5*length for depth = 0
double vert_offset; // " "
// used to initialize root node parameters
bool root_node = true;
/* ----------------------------------------------------- */
// search which subnode a body is in
int Subnode(Body temp){
double x = temp.position.Getx();
double y = temp.position.Gety();
// define subnode boundaries
double node_xmax = this->horiz_offset + 0.5*this->length;
double node_xmin = this->horiz_offset - 0.5*this->length;
double node_ymax = this->vert_offset + 0.5*this->length;
double node_ymin = this->vert_offset - 0.5*this->length;
// 1 = first quadrant (A), 2 = second quadrant (B), etc.
if ((x > (node_xmax/2.)) && (x < node_xmax) &&
(y > (node_ymax/2.)) && (y < node_ymax)){return(1);
}else if ((x > node_xmin) && (x < (node_xmax/2.)) &&
(y > (node_ymax/2.)) && (y < node_ymax)){return(2);
}else if ((x > node_xmin) && (x < (node_xmax/2.)) &&
(y > node_ymin) && (y < (node_ymax/2.))){return(3);
}else if ((x > (node_xmax/2.)) && (x < node_xmax) &&
(y > node_ymin) && (y < (node_ymax/2.))){return(4);
}else{
temp.mass = 0.0;
return(0);
}
}
// define new parameters of subnodes
void createSubnodes(){
// 1st quadrant / subnode
this->A = new QuadTreeNode();
this->A->length = this->length/2.;
this->A->horiz_offset = this->horiz_offset + 0.25*this->length;
this->A->vert_offset = this->vert_offset + 0.25*this->length;
// 2nd quadrant / subnode
this->B = new QuadTreeNode();
this->B->length = this->length/2.;
this->B->horiz_offset = this->horiz_offset - 0.25*this->length;
this->B->vert_offset = this->vert_offset + 0.25*this->length;
// 3rd quadrant / subnode
this->C = new QuadTreeNode();
this->C->length = this->length/2.;
this->C->horiz_offset = this->horiz_offset - 0.25*this->length;
this->C->vert_offset = this->vert_offset - 0.25*this->length;
// 4th quadrant / subnode
this->D = new QuadTreeNode();
this->D->length = this->length/2.;
this->D->horiz_offset = this->horiz_offset + 0.25*this->length;
this->D->vert_offset = this->vert_offset - 0.25*this->length;
}
// insert body into specific subnode
void insert_Subnode(Body temp){
createSubnodes();
// subnodes are not a root node
this->A->root_node = false;
this->B->root_node = false;
this->C->root_node = false;
this->D->root_node = false;
// recursively insert body into new node
if (Subnode(temp) == 1) {
this->A->insert(temp);
}
else if (Subnode(temp) == 2) {
this->B->insert(temp);
}
else if (Subnode(temp) == 3) {
this->C->insert(temp);
}
else if (Subnode(temp) == 4){
this->D->insert(temp);
}else return;
}
// check if current node is internal or external
bool is_internal(){
this->A = new QuadTreeNode();
this->B = new QuadTreeNode();
this->C = new QuadTreeNode();
this->D = new QuadTreeNode();
if (this->A->body.mass > 0) return true;
if (this->B->body.mass > 0) return true;
if (this->C->body.mass > 0) return true;
if (this->D->body.mass > 0) return true;
return false; // this is an external node
}
// this is the main function for constructing the QuadTree
// insert body into this node
void insert(Body next) { // consider the next body
// to insert into this node
// if there's no body in this node, put the next body in here
if (this->body.mass == 0) {
this->body = next;
return;
}
// initialize to max values if this is a root node
if(this->root_node){
this->length = 1.0;
this->horiz_offset = 0.5*this->length;
this->vert_offset = 0.5*this->length;
}
// if this is an internal node
if (is_internal()) {
// update the node's body.location (CoM)
this->body.position = (this->body.mass*this->body.position
+ next.mass*next.position)*(1./(this->body.mass + next.mass));
// update the node's body.mass
this->body.mass += next.mass;
// recursively insert the next body into appropriate subnode
insert_Subnode(next);
} else { // this is an external node
// since this->body.mass is not 0, then
// this node contains a body
// so then recursively insert this body
// and the next body into their appropriate subnodes
insert_Subnode(this->body);
insert_Subnode(next);
// then update this node's CoM and total mass
this->body.position = (this->body.mass*this->body.position
+ next.mass*next.position)*(1./(this->body.mass + next.mass));
// update the node's body.mass
this->body.mass += next.mass;
}
return;
}
// Now we calculate the force on a body
// calculates gravitational force
Vector3D Fg(Body temp){
double M1, M2, dist;
Vector3D Dr, F;
M1 = this->body.mass;
M2 = temp.mass;
// this takes the position vector difference
Dr = temp.position - this->body.position;
// and this is the magnitude
dist = Dr.GetMagnitude();
if(dist == 0.0) return(Vector3D(0.0, 0.0, 0.0)); // do not divide by 0
// here is the gravitational force
F = (-G*M1*M2/(pow(dist,3.))) * Dr;
return(F);
}
// net force on the next body
Vector3D netforce_on(Body next) {
Vector3D Fnet(0.0, 0.0, 0.0);
Vector3D dvdt;
if ((!is_internal()) && (this->body.mass != next.mass)){
Fnet = Fnet + Fg(next);
}
else {
Vector3D Dr;
double dist;
Dr = next.position - this->body.position;
dist = Dr.GetMagnitude();
// parameter to decide what is 'far'
double dist_ratio = (this->length) / dist;
if (dist_ratio < threshold){ // far enough
Fnet = Fnet + Fg(next);
} else{ // too close, check subnode forces
Fnet = Fnet + this->A->netforce_on(next);
Fnet = Fnet + this->B->netforce_on(next);
Fnet = Fnet + this->C->netforce_on(next);
Fnet = Fnet + this->D->netforce_on(next);
}
}
dvdt = (1./next.mass)*Fnet;
return(dvdt);
}
};
#定义阈值1.0//确定“距离”的阈值
//0.5对于最佳结果,越高意味着速度越快
#定义G 1.57633e-17//ly^3 Msun^-1 s^-2,引力常数
结构体{
双质量;
矢量三维位置;
矢量三维速度;
//创造一个新的身体
身体(双m,向量3D位置,向量3D水平):质量(m),位置(pos),速度(vel){};
Body():质量(0)、位置(0,0,0)、速度(0,0,0){};
};
四元结构;
四元结构{
/*------------此节点的存储属性--------*/
//插入的所有实体的总质量和CoM
//在树中此节点的下方
身体;
//重新缩放位置以适应节点
//注意:将需要将所有实体放入
//至少包括正坐标
//body.position.update(body.position.Getx()/scale,
//body.position.Gety()/scale);
//程序中定义的比例
//四个子节点/象限
四边形节点*A=NULL;
QuadTreeNode*B=NULL;
QuadTreeNode*C=NULL;
QuadTreeNode*D=NULL;
//每个节点的位置+大小参数(中心)
双倍长度;/=1.0表示深度=0
双水平偏移;//=0.5*深度长度=0
双垂直偏移;/“”
//用于初始化根节点参数
bool root_node=true;
/* ----------------------------------------------------- */
//搜索实体所在的子节点
int子节点(身体温度){
double x=临时位置.Getx();
双y=温度位置Gety();
//定义子节点边界
双节点_xmax=此->水平偏移+0.5*此->长度;
双节点_xmin=此->水平偏移-0.5*此->长度;
双节点Y最大=此->垂直偏移+0.5*此->长度;
双节点Y最小=此->垂直偏移-0.5*此->长度;
//1=第一象限(A),2=第二象限(B)等。
如果((x>(node_xmax/2.)&&(x(node_ymax/2.)和&(ynode_xmin)和&(x<(node_xmax/2.))和
(y>(node_ymax/2.)和&(ynode_xmin)和&(x<(node_xmax/2.))和
(y>node_ymin)和&(y<(node_ymax/2.){return(3);
}如果((x>(node_xmax/2.)和&(xnode_ymin)和&(y<(node_ymax/2.){return(4);
}否则{
温度质量=0.0;
返回(0);
}
}
//定义子节点的新参数
void createSubnodes(){
//第1象限/子节点
这->A=新的四元节点();
此->A->长度=此->长度/2。;
此->A->水平偏移=此->水平偏移+0.25*此->长度;
此->A->垂直偏移=此->垂直偏移+0.25*此->长度;
//第二象限/子节点
这->B=新的四元节点();
此->B->长度=此->长度/2。;
此->B->水平偏移=此->水平偏移-0.25*此->长度;
此->B->垂直偏移=此->垂直偏移+0.25*此->长度;
//第三象限/子节点
这->C=新的四元节点();
此->C->长度=此->长度/2。;
此->C->水平偏移=此->水平偏移-0.25*此->长度;
此->C->垂直偏移=此->垂直偏移-0.25*此->长度;
//第四象限/子节点
这->D=新的四元节点();
此->D->长度=此->长度/2。;
此->D->水平偏移=此->水平偏移+0.25*此->长度;
此->垂直偏移=此->垂直偏移-0.25*此->长度;
}
//将主体插入特定子节点
无效插入子节点(车身温度){
创建子节点();
//子节点不是根节点
此->A->根节点=false;
此->B->根节点=false;
此->C->根节点=false;
此->D->根节点=false;
//递归地将主体插入到新节点中
if(子节点(温度)==1){
此->A->插入(临时);
}
否则如果(子节点(温度)==2){
此->B->插入(临时);
}
否则如果(子节点(温度)==3){
此->C->插入(临时);
}
否则如果(子节点(温度)==4){
此->D->插入(临时);
}否则返回;
}
//检查当前节点是内部节点还是外部节点
bool是_internal(){
这->A=新的四元节点();
这->B=新的四元节点();
这->C=新的四元节点();
这->D=新的四元节点();
如果(this->A->body.mass>0)返回true;
如果(this->B->body.mass>0)返回true;
如果(this->C->body.mass>0)返回true;
如果(this->D->body.mass>0)返回true;
return false;//这是一个外部节点
}
//这是构造四叉树的主要功能
//将正文插入此节点
空插入(下一个体){/ /考虑下一个体
//要插入此节点,请执行以下操作:
//如果此节点中没有实体,请将下一个实体放在此处
如果(此->body.mass==0){
这个->主体=下一个;
返回;
}
//如果这是根节点,则初始化为最大值
如果(此->根节点){
这
int ii = 0; // index for printing every 50s
for (double t = 0; t < Tmax; t += dt) {
static int div = (int)(50/dt); // print only every 50s
// create a new QuadTree
if(t==0) cerr << "Creating 1st QuadTree..." << endl; // checking if this works the first time
// QuadTreeNode tree;
QuadTreeNode* tree;
tree = new QuadTreeNode();
// insert all of the masses into the tree
if(t==0) cerr << "Inserting Bodies into 1st QuadTree..." << endl;
for (int i = 0; i < bodies.size(); i++) {
if(t==0){
if(i%50 == 0){
cerr << "Inserting " << i << "th body..." << endl;
}
}
tree->insert(bodies[i]);
}
if(t==0) cerr << "1st Body insertion finished." << endl;
if(t==0) cerr << "Beginning RK4 Calculation..." << endl;
for(int j = 0; j < bodies.size(); j++){
Vector3D rtold, vtold, rt, vt;
if(ii%div == 0){
outfile << t+dt << " ";
}
// compute force on each body
// vector<Vector3D> forces; // declared globally for f_v
for (int i = 0; i < bodies.size(); i++) {
forces.push_back(tree->netforce_on(bodies[i]));
}
/* These lines update the position and velocity of jth body */
rtold = bodies[j].position;
vtold = bodies[j].velocity;
rt = rtold + VecFRK4(0,f_r,f_v,j,t,rtold,vtold,dt);
vt = vtold + VecFRK4(1,f_r,f_v,j,t,rtold,vtold,dt);
/* set the old values to the new updated values for next iteration */
bodies[j].position = rt;
bodies[j].velocity = vt;
if(ii%div == 0){
outfile << rt.Getx() << " " << rt.Gety() << " ";
}
}
if(ii%div == 0){
outfile << endl;
}
if(ii%(50) == 0){ // note every 1e4 seconds
cerr << "Calculating... t = " << t+dt << " ..." << endl;
}
ii++;
delete tree;
}
bool is_internal(){
createSubnodes();
if (this->A->body.mass > 0) return true;
if (this->B->body.mass > 0) return true;
if (this->C->body.mass > 0) return true;
if (this->D->body.mass > 0) return true;
return false; // this is an external node
}
void createSubnodes(){
// 1st quadrant / subnode
if (!this->A) { // create and initialize subnode if there's
// not an existing one already
this->A = new QuadTreeNode();
this->A->length = this->length/2.;
this->A->horiz_offset = this->horiz_offset + 0.25*this->length;
this->A->vert_offset = this->vert_offset + 0.25*this->length;
}
// repeat for B, C, and D subnodes
}
void free() { // delete the quadtree after use
if (this->A) { // if this subnode exists,
this->A->free(); // delete it's subnodes (keeps checking)
delete this->A; // until a NULL subnode is reached
}
// repeat for B, C, D
}