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
1.2.6 written by Dimitri van Heesch,
© 1997-2001