如何提高四叉树代码的性能以防止程序冻结 我正在模拟两个星团的碰撞,所以基本上是用C++来做一个n-体问题。我用巴恩斯小屋的方法来帮助做这件事。我已经编写了我的四叉树代码和运行模拟的主代码,它一直工作到第201-250步,然后程序就没有响应了。我不确定这是否只是一个性能问题,或者代码中是否发生了令人讨厌的事情。有人可以查看一下它并解释为什么它会冻结,或者如何提高性能吗

如何提高四叉树代码的性能以防止程序冻结 我正在模拟两个星团的碰撞,所以基本上是用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 {

以下是使用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 {
    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
}