Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

hdyn_grape4.C

Go to the documentation of this file.
00001 
00002        //=======================================================//    _\|/_
00003       //  __  _____           ___                    ___       //      /|\ ~
00004      //  /      |      ^     |   \  |         ^     |   \     //          _\|/_
00005     //   \__    |     / \    |___/  |        / \    |___/    //            /|\ ~
00006    //       \   |    /___\   |  \   |       /___\   |   \   // _\|/_
00007   //     ___/   |   /     \  |   \  |____  /     \  |___/  //   /|\ ~
00008  //                                                       //            _\|/_
00009 //=======================================================//              /|\ ~
00010 
00011 //  hdyn_grape4.C: functions to use GRAPE-4 (HARP-3)
00012 //
00013 //  **********************************************************
00014 //  ***  Excess Debugging lines removed by Steve 6/16/00.  ***
00015 //  ***  See 000616hhyn_harp3.C                            ***
00016 //  **********************************************************
00017 //.............................................................................
00018 //    version 1:  Aug 1996   Jun Makino
00019 //    version 2:  Aug 1998   Steve McMillan
00020 //.............................................................................
00021 //
00022 //      Externally visible functions (note that GRAPE number is unspecified):
00023 //
00024 //      void check_release_grape
00025 //      void grape_calculate_energies
00026 //      void grape_calculate_acc_and_jerk
00027 //      void grape_calculate_densities
00028 //      void clean_up_hdyn_grape
00029 //
00030 //.............................................................................
00031 //
00032 //  This file includes:
00033 //
00034 //    -     grape_calculate_acc_and_jerk(next_nodes, n_next)
00035 //          A single function which takes care of everything...
00036 //
00037 //    -     check_release_grape()
00038 //          Releases the GRAPE hardware so that someone else can use it
00039 //          after a prescribed amount of CPU time has passed)
00040 //
00041 //    -     Routines to determine neighbor lists (called from within
00042 //          grape_calculate_acc_and_jerk)
00043 //
00044 //  When called, it performs the following:
00045 //
00046 // -- In the first call, initialize the GRAPE hardware
00047 //
00048 // -- If the tree structure is changed (or in the first call),
00049 //    send all particles anew and store the number of particles
00050 //
00051 // -- If there are particles in "previous blockstep", which are not in
00052 //    present block step, update these particles as well
00053 //
00054 // -- update the particles in the present block
00055 //
00056 // -- For block of particles,
00057 //    --- Perform force calculation
00058 //    --- store the force
00059 //    --- retrieve the neighbor list
00060 //    --- If no neighbor is found for any of particles, change
00061 //        its neighbor sphere radius and try over again
00062 //    --- In the case of CM particle, store the neighbors to the
00063 //        perturber list
00064 //    --- In the case of single particle, find the nearst neighbor
00065 //    --- and "closest surface" particle. In order to be able to
00066 //        find the closest surface particle, the search radius of
00067 //        must be larger than 2*radius (at least the star with
00068 //        larger radius can find colliding star)
00069 //
00070 // -- store the "previous block" particles
00071 
00072 // Class variables related to GRAPE
00073 //
00074 // grape_rnb_sq : neighbour radius (squared) sent to GRAPE hardware
00075 //
00076 // It must be initialized to some value when a particle/node
00077 // is created (or at the first call).  A reasonable value is
00078 // r_min_sq (could be too small, but will be adjusted anyway;
00079 // the details depend on the information required by kira).
00080 //
00081 // - For SINGLE particles, the internal routine should take care
00082 //   of the updating of this variable.
00083 //
00084 // - For CENTER_OF_MASS, there are two possibilities
00085 //   a) if it has a non-null valid perturber list, the perturbation
00086 //      radius can be used.
00087 //   b) if it does not have a non-null valid perturber list, ....
00088 //   c) if it has an overflowed perturber list, I guess you
00089 //      should still set the perturbation radius as the neighbour
00090 //      sphere radius...
00091 
00092 //.............................................................................
00093 //
00094 // Known Problems
00095 //
00096 // 1) Determination of h2 for unperturbed binary is not quite okay.
00097 //    it should maintain the nearest neighbor? --- Well, seems to
00098 //    do that already for most cases
00099 //
00100 // Question: To what extent should GRAPE be integrated into kira?
00101 //           To have a few extra variables should be no problem.
00102 //
00103 //           One could define a derived class which might make
00104 //           it easier to move to newer (if any...) hardware or
00105 //           different software interface
00106 //
00107 //.............................................................................
00108 
00109 // Note from Steve to Steve (7/9/97):
00110 //
00111 // force_by_grape4()         is called only from grape_calculate_acc_and_jerk()
00112 // force_by_grape4_on_leaves()          "        force_by_grape4_on_all_leaves()
00113 // force_by_grape4_on_all_leaves()      "        grape_calculate_energies()
00114 
00115 // force_by_grape4 computes forces between TOP-LEVEL NODES in the
00116 // POINT-MASS approximation (like flat_calculate_acc_and_jerk).
00117 
00118 // force_by_grape4_on_all_leaves loads all LEAVES into the hardware and
00119 // hence effectively resolves all multiples into components.
00120 
00121 //.............................................................................
00122 
00123 // Note the extensive use of static arrays within this file, to allow
00124 // management of the GRAPE interface.
00125 //
00126 // Made these global within the file, even though most are only really
00127 // local to specific functions to allow the possibility of clean-up
00128 // (helpful when using ccmalloc to find real memory leaks).
00129 //
00130 //                                              Steve, 7/99
00131 //.............................................................................
00132 
00133 #include "hdyn.h"
00134 #include "grape4.h"
00135 #include "hdyn_inline.C"
00136 
00137 // Static declarations:
00138 // -------------------
00139 
00140 static bool grape_was_used_to_calculate_potential = false;
00141 static bool grape_is_open = false;
00142 static bool grape_first_attach = true;
00143 
00144 static int nboards;
00145 
00146 #define MINIMUM_GRAPE_RNB_PERT 1e-20
00147 
00148 // Old static memory allocation:
00149 
00150 //#   define HARPNMAX 100000
00151 //#   define HARPNBMAX HARPNMAX
00152 //
00153 // static hdyn* nodes[HARPNMAX];
00154 // static hdyn* next_top[HARPNMAX];
00155 // static hdyn* previous_nodes[HARPNMAX];
00156 // static int nb_check_counter[HARPNMAX];
00157 // static int h3nb[HARPNBMAX];
00158 
00159 
00160 
00161 //  **************************************************************************
00162 //  *                                                                        *
00163 //  * Local functions used by more than one other function (global or local) *
00164 //  *                                                                        *
00165 //  **************************************************************************
00166 //
00167 //      jpdma_nodes
00168 //      force_by_grape4
00169 //      put_grape_index_to_top_level_nodes
00170 //      initialize_array
00171 
00172 // Static data ("j-arrays"):
00173 //
00174 // Initialized by function initialize_node_lists(), called from
00175 //
00176 //      put_grape_index_to_top_level_nodes()
00177 // and
00178 //      put_grape_index_to_leaf_nodes()
00179 
00180 static int grape_n_max = 0;
00181 static int n_previous_nodes = 0;
00182 
00183 static hdyn** nodes = NULL;
00184 static hdyn** next_top = NULL;
00185 static hdyn** previous_nodes = NULL;
00186 static int* nb_check_counter = NULL;
00187 static int* grape_chip = NULL;
00188 
00189 static vector * pxj = NULL;
00190 static vector * pvj = NULL;
00191 static vector * paj = NULL;
00192 static vector * pjj = NULL;
00193 static real   * ptj = NULL;
00194 static real   * pmj = NULL;
00195 static int    * ppj = NULL;
00196 static int    * h3nb = NULL;
00197 
00198 local void initialize_node_lists()
00199 {
00200     if (!nodes) {
00201         nodes = new hdynptr[grape_n_max];
00202         next_top = new hdynptr[grape_n_max];
00203         previous_nodes = new hdynptr[grape_n_max];
00204 
00205         // Initialize nb_check_counter[] to zero when first created.
00206 
00207         nb_check_counter = new int [grape_n_max];
00208         for (int i = 0; i < grape_n_max; i++)
00209             nb_check_counter[i] = 0;
00210 
00211         // Grape_chip useful for hardware debugging...
00212 
00213         grape_chip = new int[grape_n_max];
00214         for (int i = 0; i < grape_n_max; i++)
00215             grape_chip[i] = -1;
00216 
00217         pxj = new vector[grape_n_max];
00218         pvj = new vector[grape_n_max];
00219         paj = new vector[grape_n_max];
00220         pjj = new vector[grape_n_max];
00221         ptj = new real[grape_n_max];
00222         pmj = new real[grape_n_max];
00223         ppj = new int[grape_n_max];
00224         h3nb = new int[grape_n_max];
00225     }
00226 }
00227 
00228 // Specific accessor:
00229 
00230 int get_grape_chip(hdyn *b)
00231 {
00232     int i = b->get_grape_index() - 1;
00233     if (i >= 0 && i < grape_n_max)
00234         return grape_chip[i];
00235     else
00236         return -1;
00237 }
00238 
00239 local void jpdma_nodes(int nnodes, hdyn * nodelist[], bool predicted,
00240                        real predicted_time)
00241 
00242 // Load the j-nodes on the list into the GRAPE.
00243 //
00244 // Called by:   initialize_array()                              local
00245 //              grape_calculate_acc_and_jerk() [twice]          global
00246 //              grape_calculate_densities()                     global
00247 
00248 {
00249     int jpmax;
00250     int j, jp;
00251     hdyn * b;
00252     jpmax = h3jpmax_();
00253 
00254     jp = 0;
00255     for (j = 0; j < nnodes; j++) {
00256         int jj, jm ;
00257         b = nodelist[j];
00258 
00259         jj =  b->get_grape_index();
00260         jm = jj-1;
00261         if (! predicted) {
00262 
00263             pxj[jm] = b->get_pos();
00264             pvj[jm] = b->get_vel();
00265             paj[jm] = b->get_acc()*0.5;
00266             pjj[jm] = b->get_jerk()*0.1666666666666666666666666666666;
00267             ptj[jm] = b->get_time();
00268             pmj[jm] = b->get_mass();
00269 
00270         } else {
00271 
00272             pxj[jm] = b->get_pred_pos();
00273             pvj[jm] = b->get_pred_vel();
00274             ptj[jm] = predicted_time;
00275             pmj[jm] = b->get_mass();
00276 
00277         }
00278         ppj[jp] = jj;
00279         
00280         jp ++;
00281         int bufid = 0;
00282         if ((jp == jpmax) || (j == nnodes - 1)) {
00283             int zero = 0;
00284             int one = 1;
00285             h3mjpdma_indirect_(&jp, ppj, pxj, pvj, paj, pjj, pmj, ptj, &one,
00286                                &bufid);
00287             h3mjpdma_start_(&bufid);
00288             bufid ++;
00289             if (bufid > 5) bufid = 0;  // this 5 should be < JPDMA_BUFFMAX...
00290             h3wait_();
00291             h3wait_();
00292 
00293             jp = 0;
00294         }
00295     }
00296 }
00297 
00298 // More static data:
00299 
00300 static vector * px = NULL;
00301 static vector * pv = NULL;
00302 static vector * pa = NULL;
00303 static vector * pj = NULL;
00304 static real   * ppot = NULL;
00305 static real   * peps2 = NULL;
00306 static real   * ph2 = NULL;
00307 
00308 local void force_by_grape4(real time, int ni, hdyn * nodes[], int nj)
00309 
00310 // Calculate the force on top-level nodes.
00311 //
00312 // Called by:   grape_calculate_acc_and_jerk()                  global
00313 //              grape_calculate_densities()                     global
00314 
00315 {
00316     int npipe;
00317     int i, ip,k;
00318     hdyn * b;
00319     npipe = h3npipe_();
00320 
00321     if (px == NULL) {
00322         px = new vector[npipe];
00323         pv = new vector[npipe];
00324         pa = new vector[npipe];
00325         pj = new vector[npipe];
00326         peps2 = new real[npipe];
00327         ph2 = new real[npipe];
00328         ppot = new real[npipe];
00329         for (i=0; i<npipe; i++) {
00330             peps2[i] = ph2[i] = 0.0;    // hmmm... looks like eps = 0 always
00331         }
00332     }
00333 
00334 #ifdef USE_HALF_CHIP
00335     if (ni*2 > npipe)
00336         err_exit("force by grape4: ni too large");
00337 #else
00338     if (ni > npipe)
00339         err_exit("force by grape4: ni too large\n");
00340 #endif
00341 
00342     static real ti;
00343     ti = time;
00344     int dbg_mode = 0;
00345     if (dbg_mode) {cerr << "force by grape4 "; PRL(time);}
00346 
00347     h3setti_(&ti);
00348 
00349     int j;
00350     for (i = 0; i < ni; i++) {
00351         b = nodes[i];
00352 
00353 #ifndef USE_HALF_CHIP
00354         j = i;
00355 #else   
00356         j= 2*i;
00357 #endif  
00358 
00359         px[j] = b->get_pred_pos();
00360         pv[j] = b->get_pred_vel();
00361         ph2[j] = b->get_grape_rnb_sq();
00362 
00363         if (dbg_mode) {
00364             int p = cerr.precision(HIGH_PRECISION);
00365             cerr << "getting acc on particle " << j << " " << b->format_label()
00366                  << endl;
00367             PRI(8); PRL(px[j]);
00368             PRI(8); PRL(pv[j]);
00369 //          PRI(8); PRL(ph2[j]);
00370             cerr.precision(p);
00371         }
00372 
00373 #ifdef USE_HALF_CHIP
00374         j++;
00375         px[j] = b->get_pred_pos();
00376         pv[j] = b->get_pred_vel();
00377         ph2[j] = b->get_grape_rnb_sq();
00378 #endif  
00379 
00380     }
00381     for (int jj = j + 1; jj < npipe; jj++) {
00382         px[jj] = b->get_pred_pos();
00383         pv[jj] = b->get_pred_vel();
00384         ph2[jj] = b->get_grape_rnb_sq();
00385     }
00386 
00387 //  h3calc_(&nj, &npipe, px, pv, peps2, ph2, pa, pj, ppot);
00388 
00389     h3calc_firsthalf_(&nj, &npipe, px, pv, peps2, ph2);
00390     h3wait_();
00391     h3calc_lasthalf_(&npipe, pa, pj, ppot);
00392 
00393 #if 0
00394     {
00395         int i;
00396         for (i = 0; i < npipe; i++) {
00397 
00398             fprintf(stderr,
00399         "##### %d %21.14e %21.14e %21.14e %21.14e %21.14e %21.14e %21.14e\n",
00400                     i,
00401                     pa[i*3+0], pa[i*3+1], pa[i*3+2],
00402                     pj[i*3+0], pj[i*3+1], pj[i*3+2],
00403                     ppot[i]);
00404         }
00405     }
00406 #endif
00407 
00408     for (k = 0; k < ni; k++) {
00409 
00410 #ifndef USE_HALF_CHIP
00411         int j = k;
00412 #else
00413         int j= 2*k;
00414 #endif
00415 
00416         nodes[k]->set_acc_and_jerk_and_pot(pa[j], pj[j], ppot[j]);
00417     }
00418 
00419     nboards = h3getnboards_();
00420     h3nbread_(&nboards);
00421     if (dbg_mode) {
00422         cerr << "exit force by grape4 "; PRL(time);
00423     }
00424 }
00425 
00426 local int put_grape_index_to_top_level_nodes(hdyn* b)
00427 
00428 // Called by:   initialize_array()                              local
00429 
00430 {
00431     int index = 0;
00432     int node_count = 0;
00433     for_all_daughters(hdyn, b, bb) node_count++;
00434 
00435     if (grape_n_max == 0) {
00436 
00437 //      grape_n_max = (int) (node_count * 1.5) + 10;
00438         grape_n_max = (int) (node_count * 3.0) + 10;
00439 
00440     } else if (grape_n_max < node_count) {
00441 
00442 //      grape_n_max = (int) (node_count * 1.5) + 10;
00443         grape_n_max = (int) (node_count * 3.0) + 10;
00444 
00445         delete [] nodes;
00446         delete [] next_top;
00447         delete [] previous_nodes;
00448         delete [] nb_check_counter;
00449         delete [] grape_chip;
00450         delete [] pxj;
00451         delete [] pvj;
00452         delete [] paj;
00453         delete [] pjj;
00454         delete [] ptj;
00455         delete [] pmj;
00456         delete [] ppj;
00457         delete [] h3nb;
00458         nodes = NULL;
00459     }
00460 
00461     if (nodes == NULL)
00462         initialize_node_lists();
00463 
00464     for_all_daughters(hdyn, b, bbb) {
00465         nodes[index] = bbb;
00466         index++;
00467         bbb->set_grape_index(index);
00468     }
00469     return index;
00470 }
00471 
00472 local int initialize_array(hdyn * root)
00473 
00474 // Called by:   grape_calculate_acc_and_jerk()                  global
00475 //              grape_calculate_densities()                     global
00476 
00477 {
00478     // Make list of and index top-level nodes.
00479 
00480     int nj = put_grape_index_to_top_level_nodes(root);
00481 
00482     for (int i = 0; i < (nj+10); i++)
00483         nb_check_counter[i] = 0;
00484 
00485     // Copy the nodes to the GRAPE.
00486 
00487     jpdma_nodes(nj, nodes, false, 0.0);
00488 
00489     // cerr << "init_array "; PRL(nj);
00490 
00491     return nj;
00492 }
00493 
00494 
00495 
00496 //  **********************************************************************
00497 //  *                                                                    *
00498 //  * Globally visible GRAPE-4 functions (and dedicated local helpers).  *
00499 //  * (Probably should be in separate files, but convenient to combine.) *
00500 //  *                                                                    *
00501 //  **********************************************************************
00502 
00503 //========================================================================
00504 // check_release_grape:  Accessor for GRAPE release/attach.
00505 //========================================================================
00506 
00507 void check_release_grape(kira_options *ko, xreal time,
00508                          bool verbose)          // default = true
00509 {
00510 #ifdef SHARE_GRAPE
00511 
00512     // cerr << "GRAPE CPU check: "; PRL(cpu_time());
00513 
00514     if (cpu_time() - ko->grape_last_cpu > ko->grape_max_cpu) {
00515 
00516         if (verbose)
00517             cerr << "\nReleasing GRAPE-4 at time " << time << " after "
00518                  << cpu_time() - ko->grape_last_cpu <<" CPU sec\n";
00519 
00520         h3close_();
00521         grape_is_open = false;
00522         grape_first_attach = false;
00523     }
00524 
00525 #endif
00526 }
00527 
00528 
00529 
00530 //======================================================================
00531 // grape_calculate_energies:  Calculate total energy of the system
00532 //                            (requires GRAPE reset after use).
00533 //======================================================================
00534 
00535 local int put_grape_index_to_leaf_nodes(hdyn* b,
00536                                         bool cm = false) // use CM approximation
00537 
00538 // Called by:   jpdma_all_leaves()
00539 
00540 {
00541     if (grape_n_max == 0) {
00542         int node_count = 0;
00543         for_all_daughters(hdyn, b, bb) node_count++;
00544         grape_n_max = (int) (node_count * 3.0) + 10;
00545     }
00546 
00547     if (nodes == NULL)
00548         initialize_node_lists();
00549 
00550     // Operation in case cm = true is similar to that of
00551     // put_grape_index_to_top_level_nodes, but details and
00552     // data structures may differ, so don't reuse.
00553 
00554     int index = 0;
00555     if (!cm) {
00556         for_all_leaves(hdyn, b, bb) {
00557             nodes[index] = bb;
00558             index++;
00559             bb->set_grape_index(index);
00560         }
00561     } else {
00562         for_all_daughters(hdyn, b, bb) {
00563             nodes[index] = bb;                  // replicated code...
00564             index++;
00565             bb->set_grape_index(index);
00566         }
00567     }
00568     return index;
00569 }
00570 
00571 local inline void jpdma_node(hdyn *b,
00572                              bool predicted,
00573                              real predicted_time,
00574                              int jpmax, int nj, int& jp)
00575 
00576 // Called by: jpdma_all_leaves()
00577 
00578 {
00579     int jj, jm ;
00580     jj =  b->get_grape_index();
00581     jm = jj-1;
00582 
00583     // Allow the possibility of using already predicted pos and vel
00584     // rather than having the GRAPE do the prediction.
00585 
00586     if (!predicted) {
00587 
00588         pxj[jm] = hdyn_something_relative_to_root(b, &hdyn::get_pos);
00589         pvj[jm] = hdyn_something_relative_to_root(b, &hdyn::get_vel);
00590         paj[jm] = hdyn_something_relative_to_root(b, &hdyn::get_acc)*0.5;
00591         pjj[jm] = hdyn_something_relative_to_root(b, &hdyn::get_jerk)
00592                            * 0.1666666666666666666666666666666;
00593         ptj[jm] = b->get_time();
00594         pmj[jm] = b->get_mass();
00595 
00596     } else {
00597 
00598         pxj[jm] = hdyn_something_relative_to_root(b, &hdyn::get_pred_pos);
00599         pvj[jm] = hdyn_something_relative_to_root(b, &hdyn::get_pred_vel);
00600         ptj[jm] = predicted_time;
00601         pmj[jm] = b->get_mass();
00602 
00603     }
00604     ppj[jp] = jj;
00605         
00606     jp++;
00607     int bufid = 0;
00608     if ((jp == jpmax) || (jj == nj)) {
00609         int zero = 0;
00610         int one = 1;
00611         h3mjpdma_indirect_(&jp, ppj, pxj, pvj, paj, pjj, pmj, ptj,&one,
00612                            &bufid);
00613         h3mjpdma_start_(&bufid);
00614         bufid++;
00615         if (bufid > 5)  // this 5 should be < JPDMA_BUFFMAX...
00616             bufid = 0;
00617         h3wait_();
00618         h3wait_();
00619         
00620         jp = 0;
00621     }
00622 }
00623 
00624 local int jpdma_all_leaves(hdyn *root,
00625                            bool predicted,
00626                            real predicted_time,
00627                            bool cm = false)             // use CM approximation
00628 
00629 // Called by:   grape_calculate_energies()
00630 
00631 {
00632     int jpmax = h3jpmax_();
00633     int nj = put_grape_index_to_leaf_nodes(root, cm);
00634     int jp = 0;
00635 
00636     if (!cm) {
00637         for_all_leaves(hdyn,root,b)
00638             jpdma_node(b, predicted, predicted_time, jpmax, nj, jp);
00639     } else {
00640         for_all_daughters(hdyn,root,b)
00641             jpdma_node(b, predicted, predicted_time, jpmax, nj, jp);
00642     }
00643 
00644     return nj;
00645 }
00646 
00647 // Yet more static data:
00648 
00649 static vector * pxl = NULL;
00650 static vector * pvl = NULL;
00651 static vector * pal = NULL;
00652 static vector * pjl = NULL;
00653 static real   * ppl = NULL;
00654 static real   * peps2l = NULL;
00655 static real   * ph2l = NULL;
00656 
00657 local void force_by_grape4_on_leaves(real time, int ni, hdyn * nodes[], int nj)
00658 
00659 // Note: All pipelines are used; leaves taken from nodes[].
00660 //
00661 // Called by:   force_by_grape4_on_all_leaves()
00662 
00663 {
00664     int npipe;
00665     int i, ip,k;
00666     hdyn * b;
00667     npipe = h3npipe_();
00668 
00669     if (pxl == NULL) {
00670         pxl = new vector[npipe];
00671         pvl = new vector[npipe];
00672         pal = new vector[npipe];
00673         pjl = new vector[npipe];
00674         peps2l = new real[npipe];
00675         ph2l = new real[npipe];
00676         ppl = new real[npipe];
00677         for (i=0; i<npipe; i++) {
00678             peps2l[i] = ph2l[i] = 0.0;
00679         }
00680     }
00681 
00682     if (ni > npipe)
00683         err_exit("force by grape4: ni too large\n");
00684 
00685     static real ti;
00686 
00687     ti = time;
00688     int dbg_mode = 0;
00689     if (dbg_mode) {cerr << "force by grape4 "; PRL(time);}
00690     h3setti_(&ti);
00691 
00692     int j;
00693     for (i = 0; i < ni; i++) {
00694         b = nodes[i];
00695         
00696         j = i;
00697         pxl[j] = hdyn_something_relative_to_root(b, &hdyn::get_pred_pos);
00698         pvl[j] = hdyn_something_relative_to_root(b, &hdyn::get_pred_vel);
00699         ph2l[j] = 0;
00700         if (dbg_mode) {
00701             cerr << "force on  particle "; b->print_label(cerr);
00702             PRL(j);
00703             PRL(pxl[j]);
00704             PRL(pvl[j]);
00705             PRL(ph2l[j]);
00706         }
00707     }
00708 
00709     for (int jj = j + 1; jj < npipe; jj++) {
00710         pxl[jj] = b->get_pred_pos();
00711         pvl[jj] = b->get_pred_vel();
00712         ph2l[jj] = b->get_grape_rnb_sq();
00713     }
00714 
00715     h3calc_firsthalf_(&nj, &npipe, pxl, pvl, peps2l, ph2l);
00716     h3wait_();
00717     h3calc_lasthalf_(&npipe, pal, pjl, ppl);
00718 
00719     for (k = 0; k < ni; k++) {
00720         int j = k;
00721 
00722         // We *don't* want to change/set acc and jerk here!
00723 
00724         // nodes[k]->set_acc_and_jerk_and_pot(pal[j], pjl[j], ppl[j]);
00725 
00726         nodes[k]->set_pot(ppl[j]);
00727 
00728     }
00729     if (dbg_mode) {cerr << "exit force by grape4 "; PRL(time);}
00730 }
00731 
00732 // More static data:
00733 
00734 static hdyn ** allnodes = NULL;
00735 
00736 local void force_by_grape4_on_all_leaves(real time, hdyn * b, int nj,
00737                                          bool cm = false)       // CM approx
00738 
00739 // Called by:   grape_calculate_energies()
00740 
00741 {
00742     int npipe = h3npipe_();
00743 
00744     if (!allnodes)
00745         allnodes = new hdynptr[npipe];
00746 
00747     int i = 0;
00748     int ip = 0;
00749 
00750     if (!cm) {
00751         for_all_leaves(hdyn,b,bb) {
00752             allnodes[ip] = bb;
00753             i++;
00754             ip++;
00755             if (ip == npipe) {
00756                 force_by_grape4_on_leaves(time, ip, allnodes, nj);
00757                 ip = 0;
00758             }
00759         }
00760     } else {
00761         for_all_daughters(hdyn,b,bb) {
00762             allnodes[ip] = bb;                  // more replicated code...
00763             i++;
00764             ip++;
00765             if (ip == npipe) {
00766                 force_by_grape4_on_leaves(time, ip, allnodes, nj);
00767                 ip = 0;
00768             }
00769         }
00770     }
00771 
00772     if (ip)
00773         force_by_grape4_on_leaves(time, ip, allnodes, nj);
00774 }
00775 
00776 //  *****************************
00777 //  *****************************
00778 //  ***                       ***
00779 //  ***  The global function  ***
00780 //  ***                       ***
00781 //  *****************************
00782 //  *****************************
00783 
00784 void grape_calculate_energies(hdyn * b,
00785                               real &epot,
00786                               real &ekin,
00787                               real &etot,
00788                               bool cm)          // default = false
00789 {
00790     if (!grape_is_open) {
00791 
00792         cerr << endl << "grape_calculate_energies: ";
00793         if (!grape_first_attach) cerr << "re";
00794         cerr << "attaching GRAPE" << endl;
00795         h3open_();
00796 
00797         set_time_check_mode(0);
00798         if (b->get_kira_options())
00799             b->get_kira_options()->grape_last_cpu = cpu_time();
00800         int dbgl = 0;
00801         h3setdebuglevel_(&dbgl);
00802         grape_is_open = true;
00803     }
00804 
00805     real time = b->get_system_time();
00806     int nj =  jpdma_all_leaves(b, true, time, cm);
00807 
00808     //                            ^^^^  use predicted pos and vel (unpert. OK)
00809 
00810     force_by_grape4_on_all_leaves(time, b,  nj, cm);    // does *not* change
00811                                                         // acc and jerk
00812 
00813     grape_was_used_to_calculate_potential = true;       // trigger a reset
00814                                                         // next time around
00815 
00816     epot =  ekin = etot = 0;
00817 
00818     if (!cm) {
00819         for_all_leaves(hdyn,b,bb) {
00820             real mi = bb->get_mass();
00821             epot += 0.5*mi*bb->get_pot();
00822             vector vel = hdyn_something_relative_to_root(bb, &hdyn::get_vel);
00823             ekin += 0.5*mi*vel*vel;
00824         }
00825     } else {
00826         for_all_daughters(hdyn,b,bb) {
00827             real mi = bb->get_mass();           // replicated code again...
00828             epot += 0.5*mi*bb->get_pot();
00829             vector vel = bb->get_vel();
00830             ekin += 0.5*mi*vel*vel;
00831         }
00832     }
00833     etot = ekin + epot;
00834 
00835 #if 0
00836     cerr << "grape: "; PRC(etot); PRC(ekin); PRL(epot);
00837     calculate_energies(b, epot, ekin, etot);
00838     cerr << "host:  "; PRC(etot); PRC(ekin); PRL(epot);
00839 #endif
00840 
00841 }
00842 
00843 
00844 //======================================================================
00845 // grape_calculate_acc_and_jerk: Use the GRAPE hardware to compute the
00846 //                                accs and jerks on a list of nodes.
00847 //======================================================================
00848 
00849 local bool get_neighbors_and_adjust_h2(int chip, hdyn * b)
00850 
00851 // This function actually sets nn, coll, d_nn_sq and d_coll_sq.
00852 
00853 // As in the case of flat_calculate_..., these values overwrite
00854 // previous ones.  Previously set values are ignored.
00855 
00856 // Called by:   grape_calculate_acc_and_jerk()
00857 
00858 {
00859     int nnb;
00860     bool no_nb = false;
00861 
00862     nnb = h3nblist_(&nboards, &chip, h3nb);     // get neighbor list for
00863                                                 // current neighbor radius
00864 
00865     // We will determine the nn of all stars (and coll, for leaves),
00866     // and the perturber lists for (the top-level) nodes.
00867 
00868     if (b->is_parent()) {
00869 
00870         if (b->get_oldest_daughter()->get_slow())
00871             clear_perturbers_slow_perturbed(b);
00872 
00873         b->new_perturber_list();
00874     }
00875 
00876     if (nnb < 2) {
00877 
00878         no_nb = true;
00879 
00880     } else {
00881 
00882         // Found at least one neighbor -- find the nearest and
00883         // determine perturber list for a center-of-mass node.
00884 
00885         real dmin_sq = VERY_LARGE_NUMBER;
00886         hdyn * bmin = NULL;
00887         real dcmin_sq = VERY_LARGE_NUMBER;
00888         hdyn * cmin = NULL;
00889         int npl = 0;
00890 
00891         hdyn ** pl;
00892         real rpfac;
00893 
00894         if (b->is_parent()) {
00895             pl = b->get_perturber_list();
00896             rpfac = b->get_perturbation_radius_factor();
00897         }
00898 
00899         for (int j = 0; j < nnb; j++) {
00900 
00901             hdyn *bb = nodes[h3nb[j]];
00902 
00903             // bb is the j-th neighbor of b.
00904 
00905             if (bb != b) {
00906 
00907                 // Note that it is possible that pred_pos of bb
00908                 // is garbage (never updated)...  Use get_pos
00909                 // instead of get_pred_pos here.
00910 
00911                 // Now, get_pred_pos performs Just-In-Time prediction
00912                 // so the above case cannot occur (as of Dec 12, 1996)
00913 
00914                 vector diff = b->get_pred_pos() - bb->get_pred_pos();
00915                 real d2 = diff * diff;
00916 
00917                 real sum_of_radii = get_sum_of_radii(b, bb);
00918                 update_nn_coll(b, 100,          // (100 = ID)       // inlined
00919                                d2, bb, dmin_sq, bmin,
00920                                sum_of_radii,
00921                                dcmin_sq, cmin);
00922 
00923                 // Recompute the perturber list for parent nodes.
00924                 // See equivalent code for use without GRAPE in
00925                 // hdyn_ev.C/flat_calculate_acc_and_jerk.
00926 
00927                 if (b->is_parent()) {
00928 
00929                     if (is_perturber(b, bb->get_mass(),
00930                                      d2, rpfac)) {                  // inlined
00931 
00932                         if (npl < MAX_PERTURBERS) {
00933                             pl[npl] = bb;
00934                         }
00935 
00936                         npl++;
00937                     }
00938                 }
00939             }
00940         }
00941 
00942         if (b->is_parent())
00943             b->set_n_perturbers(npl);
00944 
00945         if (bmin == NULL)
00946             no_nb = true;
00947         else {
00948             b->set_nn(bmin);
00949             b->set_d_nn_sq(dmin_sq);
00950         }
00951 
00952         if (cmin != NULL) {
00953             b->set_coll(cmin);
00954             b->set_d_coll_sq(dcmin_sq);
00955         }       
00956 
00957     }
00958 
00959     if (no_nb) {
00960 
00961         // No nearest neighbor found --  enlarge the neighbour-sphere
00962         // radius and try again...
00963 
00964         b->set_grape_rnb_sq(b->get_grape_rnb_sq()*2);   // 2 --> 3?
00965 
00966         return false;
00967     }
00968 
00969     return true;
00970 }
00971 
00972 // set_grape4_neighbour_radius: adjust the grape4 neighbour radius
00973 //                             to some reasonable value.
00974 
00975 local void set_grape4_neighbour_radius(hdyn * b, int nj_on_grape)
00976 
00977 // Called by:   grape_calculate_acc_and_jerk()
00978 
00979 {
00980     int hindex = b->get_grape_index()-1;
00981 
00982     if (b->is_leaf()) {
00983 
00984         // For a single particle, adjust the nnb radius so that it will
00985         // contain just 1-2 neighbours (set r = sqrt(2)*d_nn, if known).
00986 
00987         if (b->get_nn() && b->get_nn() != b
00988             && b->get_d_nn_sq() < 0.1* VERY_LARGE_NUMBER) {
00989 
00990             // Node seems to have a valid nearest neighbor pointer.
00991             // We can perhaps use the distance as well.
00992         
00993             // Set zero neighbor sphere radius if nb_check_counter is non-zero.
00994 
00995             if (nb_check_counter[hindex] == 0) {
00996 
00997                 // Radius information included here to allow coll
00998                 // criterion to be applied elsewhere.
00999 
01000                 b->set_grape_rnb_sq(max(b->get_d_nn_sq(),
01001                                         4*b->get_radius()*b->get_radius()));
01002 
01003                 // In this case, if the actual value set is zero,
01004                 // one might have to do something.
01005 
01006                 if (b->get_grape_rnb_sq() < MINIMUM_GRAPE_RNB_PERT) {
01007 
01008                     // (Jun says this should never happen, and these
01009                     // messages have never been seen...)
01010 
01011                     cerr << "h2 set to zero for \n";
01012                     pp3(b,cerr);
01013                     PRL(b->get_d_nn_sq());
01014 
01015                     real r90_sq = b->get_d_min_sq()
01016                                         / square(b->get_d_min_fac());
01017 
01018                     b->set_grape_rnb_sq(r90_sq);
01019 
01020                     // Note new relation between d_min_sq and the
01021                     // 90 degree turnaround radius (rvirial/N).
01022                 }
01023 
01024             } else {
01025 
01026                 b->set_grape_rnb_sq(0.0);
01027             }
01028 
01029         } else {
01030 
01031             // Node does not know its nearest neighbor.
01032 
01033             nb_check_counter[hindex] = 0;
01034 
01035             // Note connections between d_min, r90, and rnn.
01036 
01037             real r90_sq = b->get_d_min_sq() / square(b->get_d_min_fac());
01038             real rnn_sq = r90_sq * pow((real)nj_on_grape, 4.0/3);
01039 
01040             // NB: rnn_sq ~ square of the average interparticle spacing.
01041 
01042             b->set_grape_rnb_sq(rnn_sq);        // should be OK on average
01043         }
01044 
01045     } else {
01046 
01047         // For a node, we will want to compute the perturbers, so
01048         // we need a larger value of grape_rnb_sq.
01049 
01050         // If the node does not have a valid perturber list,
01051         // either it has overflowed or nothing has been set before.
01052 
01053         // If it does have non-zero valid perturber list,
01054         // the perturbation radius should be used.
01055 
01056         // Old code (wrong unless we use a distance criterion for
01057         // perturbers):
01058         //
01059         // real r_bin = 2*binary_scale(b);
01060         //
01061         // Use of binary_scale() here is potentially quite inefficient...
01062         //
01063         // real r_pert2 = max(b->get_perturbation_radius_factor(),
01064         //                    r_bin*r_bin);
01065 
01066         // New code (GRAPE-4 and GRAPE-6 versions; Steve, 12/01):
01067 
01068         real r_pert2 = perturbation_scale_sq(b, b->get_gamma23());
01069 
01070         hdyn *nn = b->get_nn();
01071         if (nn && nn != b && b->get_d_nn_sq() < 0.1* VERY_LARGE_NUMBER)
01072             r_pert2 = max(r_pert2, b->get_d_nn_sq());
01073 
01074         // Note that this may cause overflow...
01075 
01076         b->set_grape_rnb_sq(r_pert2);
01077 
01078         nb_check_counter[hindex] = 0;
01079     }
01080 
01081     if (nb_check_counter[hindex] == 0 &&
01082         b->get_grape_rnb_sq() < MINIMUM_GRAPE_RNB_PERT) {
01083         cerr << "set_grape4_neighbor ... error \n",
01084         pp3(b,cerr);
01085         PRL(nb_check_counter[hindex]);
01086         PRL(sqrt(b->get_grape_rnb_sq()));
01087         PRL(b->get_nn());
01088         PRL(b->get_d_min_sq());
01089         PRL(b->get_d_min_fac());
01090     }
01091 }
01092 
01093 //  *****************************
01094 //  *****************************
01095 //  ***                       ***
01096 //  ***  The global function  ***
01097 //  ***                       ***
01098 //  *****************************
01099 //  *****************************
01100 
01101 //  If restart is true, we must reinitialize the GRAPE interface
01102 //  after a change in the tree or other kira configuration.
01103 //
01104 //  This function is called from kira_calculate_top_level_acc_and_jerk,
01105 //  which is called only from calculate_acc_and_jerk_for_list.
01106 
01107 void grape_calculate_acc_and_jerk(hdyn ** next_nodes,
01108                                   int n_next,
01109                                   xreal time,
01110                                   bool restart)
01111 {
01112     static int nj_on_grape4;
01113 
01114     hdyn * root = next_nodes[0]->get_root();
01115     kira_options *ko = root->get_kira_options();
01116 
01117     // if (restart) {
01118     //     cerr << "grape_calculate...: restart\n";
01119     // }
01120 
01121     // Test the state of the GRAPE and open it if necessary.
01122     //
01123     // (The GRAPE release check is now performed externally.  The main
01124     //  advantage to doing the check here was that we only had to do it
01125     //  once.  However, a major disadvantage was that the hardware could
01126     //  get tied up unnecessarily by a process that was stuck elsewhere
01127     //  in the code (e.g. in a multiple encounter.)
01128     //
01129     // It is necessary to know when a restart has been triggered ONLY by
01130     // the release/reattachment of the GRAPE hardware.  Indicator is:
01131     //
01132     //          grape_reattached = true
01133 
01134     bool grape_reattached = false;
01135 
01136     if (!grape_is_open) {
01137 
01138         cerr << endl << "grape_calculate_acc_and_jerk: ";
01139         if (!grape_first_attach) cerr << "re";
01140         cerr << "attaching GRAPE" << endl;
01141         h3open_();
01142 
01143         if (!restart) grape_reattached = true;
01144 
01145         set_time_check_mode(0);
01146         ko->grape_last_cpu = cpu_time();
01147         int dbgl = 0;
01148         h3setdebuglevel_(&dbgl);
01149         grape_is_open = true;
01150 
01151         // If newly opened, restart irrespective of the actual argument.
01152 
01153         restart = true;
01154     }
01155 
01156     if (grape_was_used_to_calculate_potential) {
01157         restart = true;
01158         grape_was_used_to_calculate_potential = false;
01159     }
01160 
01161     if (restart) {
01162 
01163         // cerr << "grape4 restart\n";
01164 
01165         if (grape_reattached)           // save the nb_check_counter[] array
01166                                         // -- unclear why we can't simply modify
01167                                         //    the action of initialize_array...
01168             for_all_daughters(hdyn, root, bi) {
01169 
01170                 putiq(bi->get_dyn_story(), "nb_check_counter",
01171                       nb_check_counter[bi->get_grape_index()-1]);
01172 
01173             }
01174 
01175         nj_on_grape4 = initialize_array(root);
01176 
01177         if (grape_reattached)           // Restore the nb_check_counter[] array
01178             for_all_daughters(hdyn, root, bi) {
01179 
01180                 if (find_qmatch(bi->get_dyn_story(), "nb_check_counter")) {
01181                     nb_check_counter[bi->get_grape_index()-1] =
01182                         getiq(bi->get_dyn_story(), "nb_check_counter");
01183                     rmq(bi->get_dyn_story(), "nb_check_counter");
01184                 }
01185             }
01186 
01187         n_previous_nodes = 0;
01188     }
01189 
01190     int i, j;
01191 
01192     // Create the list of TOP_LEVEL nodes in the present block step.
01193 
01194     for (i = j = 0; i < n_next; i++) {
01195         if (next_nodes[i]->is_top_level_node()) {
01196 
01197             next_top[j] = next_nodes[i];
01198 
01199             // Whether prediction should be performed here
01200             // or not is pretty unclear....
01201 
01202             next_top[j]->predict_loworder(time);
01203             j++;
01204         }
01205     }
01206 
01207     int n_top = j;      // number of top-level nodes in current list
01208 
01209     // Store the predicted positions of top-level
01210     // current-block nodes to GRAPE memory.
01211 
01212     jpdma_nodes(n_top, next_top, true, time);
01213 
01214     // Store the particles in the previous block which are not in
01215     // the present block (update GRAPE for previous step).
01216 
01217     for (i = j = 0; i < n_previous_nodes; i++) {
01218         if (previous_nodes[i]->get_next_time() > time) {
01219             previous_nodes[j] = previous_nodes[i];
01220             j++ ;
01221         }
01222     }
01223 
01224     n_previous_nodes = j;
01225     jpdma_nodes(n_previous_nodes, previous_nodes, false, 0.0);
01226 
01227     for (i = 0; i < n_top; i++) {
01228 
01229         // store current list
01230 
01231         hdyn * b = previous_nodes[i] = next_top[i];
01232 
01233         // Set some reasonable h2 value.
01234 
01235         set_grape4_neighbour_radius(b, nj_on_grape4);
01236 
01237         if (b->is_parent())
01238             b->set_valid_perturbers(true);
01239 
01240     }
01241 
01242     n_previous_nodes = n_top;
01243 
01244     // Now we actually calculate the force...
01245 
01246 #ifndef USE_HALF_CHIP
01247     int nimax = h3npipe_();
01248 #else
01249     int nimax = h3npipe_()/2;
01250 #endif
01251 
01252     // Square of the mean 90-degree turnaround distance:
01253 
01254     real r90_sq = next_top[0]->get_d_min_sq()
01255                             / square(next_top[0]->get_d_min_fac());
01256 
01257 #define H2_FAC 8192                     // pretty arbitrary...
01258 
01259     real h2_critical = H2_FAC * r90_sq;
01260 
01261     // We will stop expanding the GRAPE neighbor sphere once its size
01262     // exceeds this critical value.  However, it is legal to set
01263     // grape_rnb_sq greater than h2_critical -- the neighbor sphere
01264     // then simply won't be expanded if no neighbors are found.
01265 
01266     // *** Should contain a factor of ~(m_max/<m>)^2, but not crucial...
01267 
01268     // Note:  for equal-mass systems and standard units, this critical
01269     //        radius is less than the interparticle spacing for N >~ 1000.
01270 
01271     real d2_max = h2_critical * 2;
01272 
01273     i = 0;
01274 
01275     while (i < n_top) {
01276 
01277         int inext = i;
01278         int ip = min(nimax, n_top - i);
01279 
01280         force_by_grape4(time, ip, next_top+i, nj_on_grape4);
01281 
01282         for (int ichip = 0; ichip < ip ; ichip ++) {
01283             int real_ichip;
01284 
01285 #ifndef USE_HALF_CHIP
01286             real_ichip = ichip;
01287 #else
01288             real_ichip = ichip*2;
01289 #endif
01290 
01291             hdyn * b = next_top[i+ichip];
01292             int hindex = b->get_grape_index()-1;
01293 
01294             grape_chip[hindex] = real_ichip;
01295 
01296             // PRC(ichip); PRL(real_ichip);
01297 
01298             if (nb_check_counter[hindex] == 0) {
01299 
01300                 if (b->get_grape_rnb_sq() <= 0) {
01301 
01302                     // Should not happen!  About to enter an infinite loop...
01303 
01304                     err_exit("grape_calculate_acc_and_jerk: rnb_sq = 0");
01305 
01306                 }
01307 
01308                 // Compute neighbors/perturbers iff nb_check_counter = 0.
01309 
01310                 if (next_top[i+ichip]->get_grape_rnb_sq() < 1e-20) {
01311                     cerr << "h2 = 0 for \n";
01312                     pp3(b,cerr);
01313                     PRC(hindex);
01314                     PRL(nb_check_counter[hindex]);
01315                 }
01316 
01317                 int inew = i+ichip;
01318                 int h2_too_large = 0;
01319 
01320                 while (!(h2_too_large ||
01321                          get_neighbors_and_adjust_h2(real_ichip, b))) {
01322 
01323                     if (b->get_grape_rnb_sq() > h2_critical) {
01324 
01325                         h2_too_large = 1;       // ==> exit while loop
01326 
01327                         b->set_nn(b);           // NB no nbr <==> nn = this
01328                         b->set_d_nn_sq(d2_max);
01329 
01330                         // cerr << "no nb found for particle ";
01331                         // b->print_label(cerr);
01332                         // cerr << " at position " << b->get_pos();
01333                         // cerr << " with radius " << b->get_grape_rnb_sq()
01334                         //      << endl;
01335 
01336                     } else {
01337 
01338                         // Expand the neighbor sphere -- must recompute
01339                         // the force.
01340 
01341                         // cerr << "RETRY: no nb found for particle ";
01342                         // b->print_label(cerr);
01343                         // cerr << " at (" << b->get_pos() << ") with radius "
01344                         //      << b->get_grape_rnb_sq()<< endl;
01345 
01346                         // *** Should count retries for bookeeping... ***
01347 
01348                         force_by_grape4(time, 1, next_top+inew, nj_on_grape4);
01349 
01350                         real_ichip = 0;
01351                         ichip = ip;
01352 
01353                         // Setting ichip = ip here forces exit from the ichip
01354                         // loop when we eventually leave the current while
01355                         // loop.  We will then restart the outermost (i) loop
01356                         // with the *next* particle after this one.
01357                         //
01358                         // Note that, if we somehow get to the "if" part of
01359                         // this structure without first going through this
01360                         // "else" clause, then we will likely make an error.
01361 
01362                     }                   // end of if (..) else (...)
01363                 }                       // end of while (h2...)
01364             }                           // end of if (check_...)
01365             inext ++;
01366         }                               // end of for (ichip...)
01367         i = inext;
01368     }                                   // end of while (i...)
01369 
01370     for (i = 0; i < n_top ; i++) {
01371 
01372         hdyn * b = next_top[i];
01373         int hindex = b->get_grape_index()-1;
01374 
01375         // Reduce frequency of nn checks (every fourth force calculation).
01376 
01377         if (b->is_leaf())
01378             nb_check_counter[hindex] = (nb_check_counter[hindex] + 1)%4;
01379         else
01380             nb_check_counter[hindex] = 0;
01381 
01382     }
01383 }
01384 
01385 
01386 //======================================================================
01387 //  grape_calculate_densities:  Determine particle densities, assigning
01388 //                              zero density to particles with no
01389 //                              neighbor within sqrt(h2_crit).
01390 //======================================================================
01391 
01392 #define DEBUG 0                 // turns on a LOT of output!
01393 
01394 local inline void set_grape4_density_radius(hdyn * b, real rnn_sq)
01395 {
01396     int hindex = b->get_grape_index() - 1;
01397 
01398     // For a single particle, try to adjust the radius so that
01399     // it will contain a small (~10-20) number of neighbours.
01400     //
01401     // Note that nn = b means that no neighbors were found.
01402 
01403     // We will modify rnn_sq for use as the initial GRAPE radius
01404     // (on entry, rnn_sq is the squared average nn distance).
01405 
01406     if (b->get_nn() != NULL && b->get_nn() != b
01407         && b->get_d_nn_sq() < 0.1 * VERY_LARGE_NUMBER
01408         && b->get_d_nn_sq() > 0) {
01409 
01410         // Node seems to have a valid nearest neighbor pointer.
01411         // Modify the initial guess for particles with a close nn.
01412 
01413         if (DEBUG) {
01414             cerr << "nn OK for " << b->format_label() << ",  ";
01415             PRC(rnn_sq); PRL(sqrt(b->get_d_nn_sq()));
01416             PRL(b->get_nn()->format_label());
01417         }
01418 
01419 #if 0
01420         if (b->get_d_nn_sq() < rnn_sq)
01421             rnn_sq = sqrt(rnn_sq * b->get_d_nn_sq());   // empirical
01422         else
01423             rnn_sq = b->get_d_nn_sq();
01424 #endif
01425 
01426         rnn_sq = 5*b->get_d_nn_sq();
01427 
01428     } else {
01429 
01430         // Node does not know its nearest neighbor.  Value of d_nn_sq
01431         // is where the neighbor search stopped.
01432 
01433         rnn_sq = 4*max(rnn_sq, b->get_d_nn_sq());
01434 
01435         if (DEBUG)
01436             cerr << "no nn for " << b->format_label() << ",  ";
01437     }
01438 
01439     b->set_grape_rnb_sq(rnn_sq);
01440     if (DEBUG) PRL(sqrt(b->get_grape_rnb_sq()));
01441 }
01442 
01443 local void count_neighbors(hdyn *b, real r2, int nnb)
01444 {
01445     int nnb_check0 = 0, nnb_check1 = 0, nnb_check2 = 0;
01446     for_all_daughters(hdyn, b->get_root(), bb) {
01447         real sep2 = square(bb->get_pos() - b->get_pos());
01448         if (sep2 <= r2/2) nnb_check0++;
01449         if (sep2 <= r2)   nnb_check1++;
01450         if (sep2 <= 2*r2) nnb_check2++;
01451     }
01452     if (nnb_check2 != nnb) {
01453         cerr << "***1 node " << b->format_label() << ",  "; PRL(sqrt(r2));
01454         PRI(5); PRC(nnb_check0); PRC(nnb_check1); PRL(nnb_check2);
01455     }
01456 }
01457 
01458 real d_nn_sq, d_nn_sq2, d_nn_sq3;
01459 static hdyn *nn2, *nn3;
01460 
01461 local hdyn *find_nn(hdyn *b)
01462 {
01463     hdyn *nn = NULL;
01464     d_nn_sq = d_nn_sq2 = d_nn_sq3 = VERY_LARGE_NUMBER;
01465     nn2 = nn3 = NULL;
01466 
01467     for_all_daughters(hdyn, b->get_root(), bb)
01468         if (bb != b) {
01469             real sep2 = square(bb->get_pos() - b->get_pos());
01470             if (sep2 < d_nn_sq) {
01471                 d_nn_sq3 = d_nn_sq2;
01472                 d_nn_sq2 = d_nn_sq;
01473                 d_nn_sq = sep2;
01474                 nn3 = nn2;
01475                 nn2 = nn;
01476                 nn = bb;
01477             } else if (sep2 < d_nn_sq2) {
01478                 d_nn_sq3 = d_nn_sq2;
01479                 d_nn_sq2 = sep2;
01480                 nn3 = nn2;
01481                 nn2 = bb;
01482             } else if (sep2 < d_nn_sq3) {
01483                 d_nn_sq3 = sep2;
01484                 nn3 = bb;
01485             }
01486         }
01487     return nn;
01488 }
01489 
01490 static hdyn *bprev = NULL;
01491 static real rnb_sq_prev = 0;
01492 static int  nnb_prev = 0;
01493 static int  nnb_count = 0;
01494 
01495 local bool count_neighbors_and_adjust_h2(int chip, hdyn *b)
01496 {
01497     int nnb = h3nblist_(&nboards, &chip, h3nb);         // get neighbor list
01498     real rnb_sq = b->get_grape_rnb_sq();
01499 
01500     if (nnb < 14) {
01501 
01502         if (DEBUG) {
01503             cerr << "increasing grape_rnb_sq for " << b->format_label()
01504                  << " (nnb = " << nnb << ", grape_rnb = "
01505                  << sqrt(rnb_sq) << ")" << endl;
01506 
01507             // count_neighbors(b, rnb_sq, nnb);
01508 
01509             if (bprev) {
01510                 PRC(b->format_label()); PRC(nnb_prev); PRC(nnb); PRL(nnb_count);
01511             }
01512         }
01513 
01514 #if 0
01515         real fac = 1.25;
01516         if (nnb < 12) fac *= 1.25;
01517         if (nnb < 8) fac *= 1.6;
01518         if (nnb < 4) fac *= 1.6;
01519         if (nnb < 2) fac *= 1.6;
01520 #endif
01521 
01522         real fac = min(2.0, pow(15.0/(1.0+nnb), 1.5));
01523 
01524         // About to increase rnb.  Take steps to ensure that we don't
01525         // undo a decrease from last time around...
01526 
01527         real rnb_sq_next =fac * rnb_sq;
01528 
01529         if (bprev == b && nnb_prev >= 14 && rnb_sq_prev > rnb_sq
01530             && rnb_sq_next > 0.95*rnb_sq_prev) {
01531             rnb_sq_next = sqrt(rnb_sq*rnb_sq_prev);
01532         }
01533 
01534         b->set_grape_rnb_sq(rnb_sq_next);
01535 
01536         // For use when iterating:
01537 
01538         bprev = b;
01539         rnb_sq_prev = rnb_sq;
01540         nnb_prev = nnb;
01541         nnb_count++;
01542 
01543         return false;
01544 
01545     } else if (nnb >= 512) {
01546 
01547         // This probably indicates overflow, in which case *none* of the
01548         // neighbor lists for this batch of particles is trustworthy.
01549         // Really should apply this logic to the entire block of nodes,
01550         // not just this one...
01551 
01552         if (DEBUG) {
01553             cerr << "decreasing grape_rnb_sq for " << b->format_label()
01554                  << " (nnb = " << nnb << ", grape_rnb = "
01555                  << sqrt(rnb_sq) << ")" << endl;
01556 
01557             // PRL(chip);
01558             // count_neighbors(b, rnb_sq, nnb);
01559 
01560             if (bprev) {
01561                 PRC(b->format_label()); PRC(nnb_prev); PRC(nnb); PRL(nnb_count);
01562             }
01563         }
01564 
01565         // About to decrease rnb.  Take steps to ensure that we don't
01566         // undo an increase from last time around...
01567 
01568         real fac = 0.5;
01569         real rnb_sq_next =fac * rnb_sq;
01570 
01571         if (bprev == b && nnb_prev < 14 && rnb_sq_prev < rnb_sq
01572             && rnb_sq_next < 1.05*rnb_sq_prev) {
01573             rnb_sq_next = sqrt(rnb_sq*rnb_sq_prev);
01574         }
01575 
01576         b->set_grape_rnb_sq(rnb_sq_next);
01577 
01578         // For use when iterating:
01579 
01580         bprev = b;
01581         rnb_sq_prev = rnb_sq;
01582         nnb_prev = nnb;
01583         nnb_count++;
01584 
01585         return false;
01586     }
01587 
01588     // This node is OK, so discard prev info.
01589 
01590     bprev = NULL;
01591     nnb_count = 0;
01592 
01593     // Make a list of nodes to send to compute_com().
01594 
01595     dyn** dynlist = new dynptr[nnb];
01596 
01597     real d_max = 0, d_min = VERY_LARGE_NUMBER;
01598     hdyn *bmin = NULL;
01599 
01600     for (int j = 0; j < nnb; j++) {
01601 
01602         hdyn * bb = nodes[h3nb[j]];
01603         dynlist[j] = (dyn*)bb;
01604 
01605         // bb is the j-th neighbor of b.
01606 
01607         if (DEBUG) {
01608             if (bb != b) {
01609                 vector diff = b->get_pred_pos() - bb->get_pred_pos();
01610                 real d2 = diff * diff;
01611                 if (d2 < d_min) {
01612                     d_min = d2;
01613                     bmin = bb;
01614                 }
01615                 d_max = max(d_max, d2);
01616             }
01617         }
01618     }
01619 
01620     if (DEBUG) {
01621         real grape_rnb = sqrt(b->get_grape_rnb_sq());
01622         d_max = sqrt(d_max);
01623         d_min = sqrt(d_min);
01624         cerr << b->format_label() << ": ";
01625         PRC(nnb), PRC(grape_rnb), PRC(d_min); PRL(d_max);
01626         if (b->get_nn() != b && b->get_nn() != bmin) {
01627             cerr << "***2 ";
01628             if (bmin) {
01629                 PR(bmin->format_label()); cerr << "  ";
01630             }
01631             if (b->get_nn()) PR(b->get_nn()->format_label());
01632             cerr << endl;
01633             PRL(sqrt(b->get_d_nn_sq()));
01634 #if 0
01635             hdyn *nn = find_nn(b);
01636             if (nn) {
01637                 cerr << "check: "; PRC(nn->format_label()); PRL(sqrt(d_nn_sq));
01638                 if (nn2) {
01639                     PRI(7); PRC(nn2->format_label()); PRL(sqrt(d_nn_sq2));
01640                 }
01641                 if (nn3) {
01642                     PRI(7); PRC(nn3->format_label()); PRL(sqrt(d_nn_sq3));
01643                 }
01644             }
01645 #endif
01646         }
01647     }
01648 
01649     compute_density(b, 12, dynlist, nnb);       // writes to dyn story
01650 
01651     // Compute_density sometimes fails to write the proper info to
01652     // the dyn story.  Reason and circumstances still unknown.
01653 
01654     if (find_qmatch(b->get_dyn_story(), "density_time")
01655         && find_qmatch(b->get_dyn_story(), "density_k_level")
01656         && find_qmatch(b->get_dyn_story(), "density")) {
01657 
01658         real density_time = getrq(b->get_dyn_story(), "density_time");
01659         int  density_k    = getiq(b->get_dyn_story(), "density_k_level");
01660         real density      = getrq(b->get_dyn_story(), "density");
01661 
01662         if (DEBUG)
01663             PRL(density);
01664     }
01665 
01666     delete [] dynlist;
01667     return true;
01668 }
01669 
01670 #define NEW_DENSITY_ALGORITHM
01671 
01672 #ifdef NEW_DENSITY_ALGORITHM
01673 
01674 #define NNB_MIN         14
01675 #define NNB_OVERFLOW    256                     // rather arbitrary...
01676 
01677 #define ITER_MAX        30
01678 
01679 // Experimental (and should carry over to GRAPE-6 code)...
01680 
01681 local int get_densities_for_list(xreal time, int ni, hdynptr list[],
01682                                  int nj_on_grape4, real h2_crit,
01683                                  bool debug = false)
01684 {
01685     // Iterate until densities have been set for all particles on the list.
01686     // On entry, initial guesses have already been assigned to the GRAPE-4
01687     // neighbor radii.  Must watch out for overflow, which will invalidate
01688     // all lists returned from the GRAPE.  Note that the criterion for
01689     // detecting overflow is somewhat unclear...
01690 
01691     bool *done = new bool[ni];                  // density has been computed
01692 
01693     int  *nnb_prev = new int[ni];               // consistent (nnb, rnb) pair
01694     real *rnb_sq_prev = new real[ni];           // from the previous iteration
01695 
01696     int  *nnb_prev_save = new int[ni];          // quantities at the start of
01697     real *rnb_sq_prev_save = new real[ni];      // the do loop, to allow
01698     bool *done_save = new bool[ni];             // recalculation following
01699     real *rnb_sq_save = new real[ni];           // neighbor list overflow
01700 
01701     // The "save" quantities represent the state of the system at the start
01702     // of the do loop, in case of overflow and reset.  The "prev" quantities
01703     // give information on the most recent neighbor calculation.
01704 
01705     // Initialization (not really needed):
01706 
01707     for (int i = 0; i < ni; i++) {
01708         rnb_sq_prev[i] = rnb_sq_save[i] = rnb_sq_prev_save[i] = 0;
01709         nnb_prev[i] = nnb_prev_save[i] = 0;
01710         done[i] = done_save[i] = false;
01711     }
01712 
01713     // Loop until all_done is true.
01714     // (Probably should count and limit iterations also...)
01715 
01716     bool all_done = false;
01717     int ngrape = 0;
01718 
01719     if (debug)
01720         cerr << endl << "Nodes " << list[0]->format_label()
01721              << " to " << list[ni-1]->format_label() << ":" << endl;
01722 
01723     int iter = 0;
01724 
01725     do {
01726 
01727         iter++;
01728         if (debug)
01729             PRL(iter);
01730 
01731         // Save data in case of overflow.
01732 
01733         for (int i = 0; i < ni; i++) {
01734             rnb_sq_save[i] = list[i]->get_grape_rnb_sq();
01735             rnb_sq_prev_save[i] = rnb_sq_prev[i];
01736             nnb_prev_save[i] = nnb_prev[i];
01737             done_save[i] = done[i];
01738         }
01739 
01740         // Compute forces (==> get neighbors).
01741 
01742         force_by_grape4(time, ni, list, nj_on_grape4);
01743         ngrape++;
01744 
01745         // Retrieve neighbor lists and begin density computation.
01746 
01747         all_done = true;
01748         bool overflow = false;
01749 
01750         for (int i = 0; i < ni; i++) {
01751 
01752             if (!done[i]) {
01753 
01754                 hdyn *bb = list[i];
01755                 real rnb_sq = bb->get_grape_rnb_sq();
01756 
01757 #ifndef USE_HALF_CHIP
01758                 int real_chip = i;
01759 #else
01760                 int real_chip = 2*i;
01761 #endif
01762 
01763                 // Get the neighbor list for this node.
01764 
01765                 int nnb = h3nblist_(&nboards, &real_chip, h3nb);
01766 
01767                 // Overflow check:
01768 
01769                 if (nnb >= NNB_OVERFLOW) {
01770 
01771                     if (debug)
01772                         cerr << "    overflow detected at "
01773                              << bb->format_label()
01774                              << ";  rnb = " << sqrt(rnb_sq)
01775                              << ",  nnb = " << nnb << endl;
01776 
01777                     overflow = true;
01778                     break;
01779 
01780                 } else if (nnb < NNB_MIN) {
01781 
01782                     if (rnb_sq > h2_crit) {
01783 
01784                         // Set zero density for this node.
01785 
01786                         putrq(bb->get_dyn_story(), "density_time",
01787                               (real)bb->get_system_time());
01788                         putrq(bb->get_dyn_story(), "density", 0.0);
01789 
01790                         done[i] = true;
01791                         bb->set_grape_rnb_sq(0);
01792 
01793                         if (debug)
01794                             cerr << "    set zero density for "
01795                                  << bb->format_label() << endl;
01796 
01797                     } else {
01798 
01799                         // Modify GRAPE neighbor radius.
01800 
01801                         real fac = min(2.0, pow(15.0/(1.0+nnb), 1.5));
01802 
01803                         // About to increase rnb_sq.  Take steps to ensure that
01804                         // we don't undo a decrease from last time around...
01805 
01806                         real rnb_sq_next =fac * rnb_sq;
01807 
01808                         if (nnb_prev[i] >= NNB_MIN        // <==> prev overflow
01809                             && rnb_sq_prev[i] > rnb_sq
01810                             && rnb_sq_next > 0.95*rnb_sq_prev[i])
01811                             rnb_sq_next = sqrt(rnb_sq*rnb_sq_prev[i]);
01812 
01813                         bb->set_grape_rnb_sq(rnb_sq_next);
01814                         all_done = false;
01815 
01816                         nnb_prev[i] = nnb;
01817                         rnb_sq_prev[i] = rnb_sq;
01818 
01819                         if (debug)
01820                             cerr << "    increased rnb for "
01821                                  << bb->format_label()
01822                                  << " to " << sqrt(rnb_sq_next)
01823                                  << ";  nnb was " << nnb << endl;
01824                     }
01825 
01826                 } else {
01827 
01828                     // Compute density and remove node from further
01829                     // consideration.
01830 
01831                     // Make a list of nodes to send to compute_density().
01832 
01833                     dyn** dynlist = new dynptr[nnb];
01834 
01835                     for (int j = 0; j < nnb; j++) {
01836                         hdyn *nbr = nodes[h3nb[j]];     // j-th neighbor of bb
01837                         dynlist[j] = (dyn*)nbr;
01838                     }
01839 
01840                     // Function compute_density() writes to the  dyn story.
01841 
01842                     compute_density(bb, 12, dynlist, nnb);
01843                     delete [] dynlist;
01844 
01845                     done[i] = true;
01846                     bb->set_grape_rnb_sq(0);            // avoid unnecessary
01847                                                         // neighbors
01848 
01849                     // No need to set prev quantities, as we won't visit
01850                     // this node again (except on overflow).
01851 
01852                     if (debug)
01853                         cerr << "    set density for " << bb->format_label()
01854                              << endl;
01855 
01856                 }
01857             }
01858         }
01859 
01860         if (overflow) {
01861 
01862             // Must revert, adjust all radii, and retry.
01863 
01864             for (int i = 0; i < ni; i++) {
01865 
01866                 // Restore initial settings (discard partial update):
01867 
01868                 done[i] = done_save[i];
01869                 if (!done[i]) {
01870 
01871                     rnb_sq_prev[i] = rnb_sq_prev_save[i];
01872                     nnb_prev[i] = nnb_prev_save[i];
01873 
01874                     real rnb_sq = rnb_sq_save[i];
01875 
01876                     // About to decrease rnb_sq.  Take steps to ensure that
01877                     // we don't undo an increase from last time around...
01878 
01879                     real fac = 0.5;
01880                     real rnb_sq_next =fac * rnb_sq;
01881 
01882                     if (nnb_prev[i] < NNB_MIN
01883                         && rnb_sq_next < 1.05*rnb_sq_prev[i])
01884                         rnb_sq_next = sqrt(rnb_sq*rnb_sq_prev[i]);
01885 
01886                     list[i]->set_grape_rnb_sq(rnb_sq_next);
01887 
01888                     // Flag the overflow:
01889 
01890                     rnb_sq_prev[i] = rnb_sq;
01891                     nnb_prev[i] = NNB_OVERFLOW;
01892                     
01893                 }
01894             }
01895 
01896             all_done = false;
01897         }
01898 
01899     } while (!all_done && iter < ITER_MAX);             // end of do loop
01900 
01901     // Set any remaining densities to zero (exceeded iteration count).
01902 
01903     if (!all_done) {
01904 
01905         if (debug)
01906             cerr << "maximum iterations exceeded" << endl;
01907 
01908         for (int i = 0; i < ni; i++) {
01909 
01910             if (!done[i]) {
01911                 hdyn *bb = list[i];
01912                 putrq(bb->get_dyn_story(), "density_time",
01913                       (real)bb->get_system_time());
01914                 putrq(bb->get_dyn_story(), "density", 0.0);
01915 
01916                 if (debug)
01917                     cerr << "    set zero density for "
01918                          << bb->format_label() << endl;
01919             }
01920         }
01921     }
01922 
01923     // Clean up.
01924 
01925     delete [] done;
01926 
01927     delete [] nnb_prev;
01928     delete [] rnb_sq_prev;
01929 
01930     delete [] nnb_prev_save;
01931     delete [] rnb_sq_prev_save;
01932     delete [] done_save;
01933     delete [] rnb_sq_save;
01934 
01935     if (debug) {
01936         cerr << endl << "Returning "; PRL(ngrape);
01937     }
01938 
01939     return ngrape;
01940 }
01941 
01942 #endif
01943 
01944 //  *****************************
01945 //  *****************************
01946 //  ***                       ***
01947 //  ***  The global function  ***
01948 //  ***                       ***
01949 //  *****************************
01950 //  *****************************
01951 
01952 
01953 local int recount_nblist(int ip)        // ip = number of chips in use
01954 {
01955     int total = 0;
01956 
01957     for (int i = 0; i < ip; i++) {
01958         int real_chip = 2*i;
01959         if (real_chip == 32 || real_chip == 64) PRL(total);
01960         total += h3nblist_(&nboards, &real_chip, h3nb);
01961     }
01962     return total;
01963 }
01964 
01965 void grape_calculate_densities(hdyn* b,
01966                                real h2_crit)    // default = 4
01967 {
01968     if (!grape_is_open) {
01969 
01970         cerr << endl << "grape_calculate_densities: ";
01971         if (!grape_first_attach) cerr << "re";
01972         cerr << "attaching GRAPE" << endl;
01973         h3open_();
01974 
01975         set_time_check_mode(0);
01976         b->get_kira_options()->grape_last_cpu = cpu_time();
01977         int dbgl = 0;
01978         h3setdebuglevel_(&dbgl);
01979         grape_is_open = true;
01980     }
01981 
01982     // Copy all nodes to the GRAPE hardware.
01983     // No need to save counters here, as we will force a restart later...
01984 
01985     int nj_on_grape4 = initialize_array(b);
01986 
01987     // Make a list of all top-level nodes.
01988 
01989     hdyn** top_nodes = new hdynptr[b->n_daughters()];
01990 
01991     int n_top = 0;
01992     for_all_daughters(hdyn, b, bb)
01993         top_nodes[n_top++] = bb;
01994 
01995     // Store the predicted positions of top-level
01996     // current-block nodes to GRAPE memory.
01997 
01998     real time = b->get_system_time();
01999     jpdma_nodes(n_top, top_nodes, true, time);
02000 
02001     // Set h2 values.
02002 
02003     // Determine rnn_sq ~ square of the average interparticle spacing,
02004     // for use as a scale in setting h2.  Note the connections between
02005     // d_min, r90, and rnn.
02006 
02007     real r90_sq = b->get_d_min_sq() / square(b->get_d_min_fac());
02008     real rnn_sq = r90_sq * pow((real)nj_on_grape4, 4.0/3);
02009 
02010     for (int i = 0; i < n_top; i++)
02011         set_grape4_density_radius(top_nodes[i], rnn_sq);
02012 
02013 #ifndef USE_HALF_CHIP
02014     int nimax = h3npipe_();
02015 #else
02016     int nimax = h3npipe_()/2;
02017 #endif
02018 
02019 //------------------------------------------------------------------------
02020 
02021     int n_grape = 0;
02022     int n_retry = 0;
02023 
02024     int i = 0;
02025     while (i < n_top) {
02026 
02027         int inext = i;
02028         int ip = min(nimax, n_top - i);
02029 
02030 #ifdef NEW_DENSITY_ALGORITHM
02031 
02032         n_grape += get_densities_for_list(time, ip, top_nodes+i,
02033                                           nj_on_grape4, h2_crit,
02034                                           false);             // true = verbose
02035         i += ip;
02036 
02037 #else
02038 
02039         // Compute forces and neighbors on the next block of particles,
02040         // of length ip.
02041 
02042         force_by_grape4(time, ip, top_nodes+i, nj_on_grape4);
02043         n_grape++;
02044 
02045         if (DEBUG) {
02046             cerr << endl; PRL(ip);
02047             PRL(count_nblist_low(0, 0));
02048             PRL(count_nblist_low(0, 32));
02049             PRL(count_nblist_low(0, 64));
02050             PRL(recount_nblist(ip));
02051         }
02052 
02053         for (int ichip = 0; ichip < ip ; ichip ++) {
02054 
02055 #ifndef USE_HALF_CHIP
02056             int real_ichip = ichip;
02057 #else
02058             int real_ichip = ichip*2;
02059 #endif
02060 
02061             hdyn * bb = top_nodes[i+ichip];
02062 
02063             // Just count neighbors, for now.
02064 
02065             int inew = i+ichip;
02066             int h2_too_large = 0;
02067 
02068             while (!(h2_too_large ||
02069                      count_neighbors_and_adjust_h2(real_ichip, bb))) {
02070 
02071                 if (bb->get_grape_rnb_sq() > h2_crit) {
02072 
02073                     // Write zero density to dyn story.
02074 
02075                     putrq(bb->get_dyn_story(), "density_time",
02076                           (real)bb->get_system_time());
02077                     putrq(bb->get_dyn_story(), "density", 0.0);
02078 
02079                     if (DEBUG) {
02080                         PR(bb->get_grape_rnb_sq());
02081                         cerr << " too large for "
02082                              << bb->format_label() << endl;
02083                     }
02084 
02085                     h2_too_large = 1;   // ==> exit while loop
02086 
02087                 } else {
02088 
02089                     // Expand the neighbor sphere -- must recompute the
02090                     // force.  Could probably speed this up substantially
02091                     // by checking, correcting and recomputing all
02092                     // particles on the list at once.
02093 
02094                     force_by_grape4(time, 1, top_nodes+inew, nj_on_grape4);
02095                     n_retry++;
02096 
02097                     if (DEBUG) {
02098                         PRL(count_nblist_low(0, 0));
02099                         PRL(recount_nblist(1));
02100                     }
02101 
02102                     real_ichip = 0;
02103                     ichip = ip;
02104                 }
02105             }
02106 
02107             if (DEBUG) {
02108                 real dens = getrq(bb->get_dyn_story(), "density");
02109                 cerr << i << "  (" << bb->format_label() << ")  "; PRL(dens);
02110             }
02111 
02112             inext++;
02113             bprev = NULL;
02114             nnb_count = 0;
02115 
02116         }
02117         i = inext;
02118 
02119 #endif
02120 
02121         // Work around side-effect of inefficient iteration.
02122         // Silently release and reattach the GRAPE hardware.
02123 
02124         check_release_grape(b->get_kira_options(), time, false);
02125 
02126         if (!grape_is_open) {
02127             // cerr << "reattaching GRAPE, i = " << i << endl;
02128             h3open_();
02129             set_time_check_mode(0);
02130             b->get_kira_options()->grape_last_cpu = cpu_time();
02131             int dbgl = 0;
02132             h3setdebuglevel_(&dbgl);
02133             grape_is_open = true;
02134             nj_on_grape4 = initialize_array(b);
02135             jpdma_nodes(n_top, top_nodes, true, time);
02136         }
02137     }
02138 
02139 //------------------------------------------------------------------------
02140 
02141     // Timestamp the root node.
02142 
02143     putrq(b->get_dyn_story(), "density_time", (real)b->get_system_time());
02144 
02145     if (n_retry > 10) {
02146         cerr << "grape_calculate_densities:  ";
02147         PRC(n_grape); PRL(n_retry);
02148     }
02149 
02150     // Force cleanup later.
02151 
02152     grape_was_used_to_calculate_potential = true;
02153     delete [] top_nodes;
02154 
02155 }
02156 
02157 
02158 //========================================================================
02159 // External cleanup -- delete local static arrays.
02160 //========================================================================
02161 
02162 void clean_up_hdyn_grape()
02163 {
02164     // Set in put_grape_index_to_top_level_nodes():
02165 
02166     if (nodes) delete [] nodes;
02167     if (next_top) delete [] next_top;
02168     if (previous_nodes) delete [] previous_nodes;
02169     if (nb_check_counter) delete [] nb_check_counter;
02170     if (grape_chip) delete [] grape_chip;
02171 
02172     if (pxj) delete [] pxj;
02173     if (pvj) delete [] pvj;
02174     if (paj) delete [] paj;
02175     if (pjj) delete [] pjj;
02176     if (ptj) delete [] ptj;
02177     if (pmj) delete [] pmj;
02178     if (ppj) delete [] ppj;
02179     if (h3nb) delete [] h3nb;
02180 
02181     // Set in force_by_grape4():
02182 
02183     if (px) delete [] px;
02184     if (pv) delete [] pv;
02185     if (pa) delete [] pa;
02186     if (pj) delete [] pj;
02187     if (ppot) delete [] ppot;
02188     if (peps2) delete [] peps2;
02189     if (ph2) delete [] ph2;
02190 
02191     // Set in force_by_grape4_on_leaves():
02192 
02193     if (pxl) delete [] pxl;
02194     if (pvl) delete [] pvl;
02195     if (pal) delete [] pal;
02196     if (pjl) delete [] pjl;
02197     if (ppl) delete [] ppl;
02198     if (peps2l) delete [] peps2l;
02199     if (ph2l) delete [] ph2l;
02200 
02201     // Set in force_by_grape4_on_all_leaves():
02202 
02203     if (allnodes) delete [] allnodes;
02204 }

Generated at Sun Feb 24 09:57:02 2002 for STARLAB by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001