Main Page   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

_dyn_ev.C

Go to the documentation of this file.
00001 
00002        //=======================================================//    _\|/_
00003       //  __  _____           ___                    ___       //      /|\ ~
00004      //  /      |      ^     |   \  |         ^     |   \     //          _\|/_
00005     //   \__    |     / \    |___/  |        / \    |___/    //            /|\ ~
00006    //       \   |    /___\   |  \   |       /___\   |   \   // _\|/_
00007   //     ___/   |   /     \  |   \  |____  /     \  |___/  //   /|\ ~
00008  //                                                       //            _\|/_
00009 //=======================================================//              /|\ ~
00010 
00011 //
00012 //  _dyn_ev.C: functions related to orbit integration within the _dyn_ class.
00013 //                   - member functions for FLAT trees only
00014 //.............................................................................
00015 //    version 1:  Jul 1996   Steve McMillan
00016 //    version 2:
00017 //.............................................................................
00018 
00019 #include "_dyn_.h"
00020 
00021 //-----------------------------------------------------------------------------
00022 //  flat_accumulate_acc_and_jerk -- calculates the contribution to the
00023 //                                  acceleration & jerk on this node from
00024 //                                  the node leaf.
00025 //                                  NOTE: for flat trees only
00026 //-----------------------------------------------------------------------------
00027 
00028 void _dyn_::flat_accumulate_acc_and_jerk(_dyn_ * leaf,  // attracting leaf node
00029                                         real eps2)      // softening length^2
00030 {
00031     vector d_pos = leaf->get_pred_pos() - get_pred_pos();
00032     vector d_vel = leaf->get_pred_vel() - get_pred_vel();
00033     real r2inv = 1.0 / (d_pos * d_pos + eps2);
00034     real a3 = -3.0 * (d_pos * d_vel) * r2inv;
00035     real mrinv = leaf->get_mass() * sqrt(r2inv);
00036     pot -= mrinv;
00037     real mr3inv = mrinv * r2inv;
00038     acc += mr3inv * d_pos;
00039     jerk += mr3inv * (d_vel + a3 * d_pos);
00040 }
00041 
00042 //-----------------------------------------------------------------------------
00043 //  flat_calculate_acc_and_jerk -- calculates acceleration & jerk on this node:
00044 //                                 from all nodes under p (if p is root ptr);
00045 //                                 or from the node p (if p is a leaf ptr).
00046 //
00047 //                                 NOTE: for flat trees only
00048 //
00049 //-----------------------------------------------------------------------------
00050 
00051 #ifdef RECURSIVE_LOOP
00052 
00053   void _dyn_::flat_calculate_acc_and_jerk(_dyn_ * p,   // root or leaf
00054                                           real eps2)   // softening length^2
00055   {
00056     if (p->is_root()) {                 // p is root, so
00057                                         // invoke for all leaves
00058         for_all_daughters(_dyn_, p, d)  
00059             flat_calculate_acc_and_jerk(d, eps2);
00060 
00061     } else {                            // p is leaf, but
00062                                         // not this leaf
00063         if (p != this)
00064             flat_accumulate_acc_and_jerk(p, eps2);
00065 
00066     }
00067   }
00068 
00069 #else
00070 
00071   // Looping by recursion (as above) is relatively expensive on many systems.
00072   // Remove the recursion for the sake of efficiency (and readability?) by
00073   // using an explicit loop.
00074 
00075   void _dyn_::flat_calculate_acc_and_jerk(_dyn_ * p,   // root or leaf
00076                                           real eps2)   // softening length^2
00077   {
00078     if (p->is_root()) {                 // p is root, so
00079                                         // invoke for all leaves
00080         for_all_daughters(_dyn_, p, d)  
00081             if (d != this)
00082                 flat_accumulate_acc_and_jerk(d, eps2);
00083 
00084     } else {                            // NOTE: else clause currently not used
00085 
00086         if (p != this)
00087             flat_accumulate_acc_and_jerk(p, eps2);
00088 
00089     }
00090   }
00091 
00092 #endif
00093 
00094 #define SAFETY_FACTOR 16
00095 
00096 void _dyn_::flat_set_first_timestep(real eta_for_firststep,
00097                                     real max_step_size)
00098 {
00099     // Don't have high-order derivatives, so do the best we can
00100     // and include an extra safety factor.
00101 
00102     real a1scaled2 = jerk * jerk;
00103     real a2 = acc * acc;
00104     real newstep;
00105 
00106     if (a1scaled2 > 0.0)
00107         newstep = eta_for_firststep * sqrt(a2 / a1scaled2);
00108     else
00109         newstep = eta_for_firststep / SAFETY_FACTOR;
00110 
00111     newstep = adjust_number_to_power(newstep, max_step_size);
00112     timestep = newstep;
00113 }
00114 
00115 local real flat_new_timestep(vector & at3,      // third order term
00116                              vector & bt2,      // 2nd order term
00117                              vector & jerk,     // 1st order term
00118                              vector & acc,      // 0th order term
00119                              real timestep,     // old timestep
00120                              real time,         // present time
00121                              real eta,          // accuracy parameter
00122                              real dtmax)        // maximum stepsize
00123 {
00124     real a3scaled2 = 36 * at3 * at3;
00125     real a2scaled2 = 4 * bt2 * bt2;
00126     real a1scaled2 = timestep * jerk * jerk;
00127     real a2 = acc * acc;
00128 
00129     // Simple criterion:
00130 
00131     real newstep = eta * sqrt(sqrt(a2 / a2scaled2)) * timestep;
00132 
00133     // Probably should use the Aarseth criterion:
00134 
00135     // (see ../hdyn/evolve/hdyn_ev.C...)
00136 
00137     // Force step into the block scheme.
00138 
00139     if (newstep < timestep)
00140         return timestep * 0.5;
00141     else if (newstep < 2 * timestep)
00142         return timestep;
00143     else if (fmod(time, 2 * timestep) != 0.0 || 2 * timestep > dtmax)
00144         return timestep;
00145     else
00146         return timestep * 2;
00147 }
00148 
00149 void _dyn_::flat_update(const real eta, const real dtmax)
00150 {
00151     vector at3 = 2 * (old_acc - acc) + timestep * (old_jerk + jerk);
00152     vector bt2 = -3 * (old_acc - acc) - timestep * (2 * old_jerk + jerk);
00153     time = time + timestep;
00154     timestep = flat_new_timestep(at3, bt2, jerk, acc,
00155                                  timestep, time, eta, dtmax);
00156 }
00157 
00158 //-----------------------------------------------------------------------------
00159 // flat_correct:  Apply the corrector for 4th-order hermite scheme.
00160 //                See Makino & Aarseth (PASJ 1992) for derivation.
00161 //-----------------------------------------------------------------------------
00162 
00163 #define ONE12 0.0833333333333333333333
00164 #define ONE3  0.3333333333333333333333
00165 
00166 bool _dyn_::flat_correct()
00167 {
00168     vector at3 = 2 * (old_acc - acc) + timestep * (old_jerk + jerk);
00169     vector bt2 = -3 * (old_acc - acc) - timestep * (2 * old_jerk + jerk);
00170     real dt2 = timestep * timestep;
00171 
00172     // Reminder:        at3  =  a''' dt^3 / 6           (a' = j)
00173     //                  bt2  =  a''  dt^2 / 2
00174 
00175     vector new_pos = pred_pos + (0.05 * at3 + ONE12 * bt2) * dt2;
00176     vector new_vel = pred_vel + (0.25 * at3 + ONE3 * bt2) * timestep;
00177 
00178     pos = new_pos;
00179     vel = new_vel;
00180 
00181     return true;                // normal return value
00182 }
00183 
00184 //-----------------------------------------------------------------------------
00185 // predict_loworder_all:  Predict the positions of all nodes below b at time t.
00186 //-----------------------------------------------------------------------------
00187 
00188 //#define FIFTH_ORDER_PRED              // doesn't work yet...
00189 
00190 void predict_loworder_all(_dyn_ * b,
00191                           xreal t)
00192 {
00193     if (!b) return;                     // shouldn't happen -- flag as error?
00194 
00195     // Basic recursion:
00196 
00197     if (b->is_parent())
00198         for_all_daughters(_dyn_, b, d)
00199             predict_loworder_all(d, t);
00200 
00201     if (b->is_top_level_node()) {
00202 
00203 #ifdef FIFTH_ORDER_PRED
00204         real dt = b->get_timestep();
00205         vector kdt = 18*dt*b->get_k_over_18();
00206         PRL(b->get_jerk());
00207         PRC(dt); PRL(kdt);
00208         b->predict_loworder5(t);        // new -- for GRAPE-6 kira...
00209                                         // still being tested...
00210 #else
00211         b->predict_loworder(t);
00212 #endif
00213 
00214     } else {
00215 
00216         // For low-level nodes, the secondary pred_pos and pred_vel are set
00217         // once the primary is known.  May as well take advantage of that...
00218 
00219         _dyn_ *s = b->get_elder_sister();
00220         if (s && s->get_t_pred() == t)
00221 
00222             // This is a younger binary sister.  Use the elder sister
00223             // data to compute pred_pos and pred_vel.
00224 
00225             b->predict_from_elder_sister();
00226 
00227         else
00228 
00229             // This is an elder binary sister, or the elder sister is
00230             // somehow not up to date.
00231 
00232             b->predict_loworder(t);
00233 
00234     }
00235 }
00236 
00237 
00238 
00239 
00240 

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