22 fout<<
"Use AR TTL method\n";
24 fout<<
"Use AR LogH method\n";
26 #ifdef AR_SLOWDOWN_TREE
27 fout<<
"Use slowdown Tree method\n";
29 #ifdef AR_SLOWDOWN_ARRAY
30 fout<<
"Use slowdown array method\n";
32 #ifdef AR_SLOWDOWN_TIMESCALE
33 fout<<
"Use slowdown timescale criterion\n";
35 #ifdef AR_SLOWDOWN_MASSRATIO
36 fout<<
"Use slowdown mass ratio criterion\n";
43 fout<<
"Debug mode: AR\n";
49 for (
int i=0; i<offset; i++) fout<<
" ";
50 fout<<
"SDAR: Wang L., Nitadori K., Makino J., 2020, MNRAS, 493, 3398"
57 template <
class Tmethod>
65 #ifdef AR_SLOWDOWN_MASSRATIO
66 Float slowdown_mass_ref;
77 #ifdef AR_SLOWDOWN_MASSRATIO
78 slowdown_mass_ref(
Float(-1.0)),
94 #ifdef AR_SLOWDOWN_MASSRATIO
95 ASSERT(slowdown_mass_ref>0.0);
109 fwrite(
this, size, 1,_fout);
121 size_t rcount = fread(
this, size, 1, _fin);
123 std::cerr<<
"Error: TimeTransformedSymplecticManager parameter reading fails! requiring data number is 1, only obtain "<<rcount<<
".\n";
127 else if (_version==1) {
128 size_t rcount = fread(
this,
sizeof(
Float), 3, _fin);
130 std::cerr<<
"Error: TimeTransformedSymplecticManager parameter data reading fails! requiring data number is 3, only obtain "<<rcount<<
".\n";
137 std::cerr<<
"Error: TimeTransformedSymplecticManager parameter data reading fails! requiring data number is 1, only obtain "<<rcount<<
".\n";
142 std::cerr<<
"Error: TimeTransformedSymplecticManager.readBinary unknown version "<<_version<<
", should be 0 or 1."<<std::endl;
150 void print(std::ostream & _fout)
const{
155 #ifdef AR_SLOWDOWN_MASSRATIO
156 <<
"slowdown_mass_ref : "<<slowdown_mass_ref<<std::endl
160 <<
"ds_scale : "<<
ds_scale<<std::endl;
174 template <
class Tparticle,
class Tpcm,
class Tpert,
class Tmethod,
class Tinfo>
186 Float de_change_interrupt_;
187 Float dH_change_interrupt_;
189 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
194 Float de_sd_change_cum_;
195 Float dH_sd_change_cum_;
196 Float de_sd_change_interrupt_;
197 Float dH_sd_change_interrupt_;
212 #ifdef AR_SLOWDOWN_ARRAY
221 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
222 ekin_sd_(0), epot_sd_(0), etot_sd_ref_(0),
223 de_sd_change_cum_(0), dH_sd_change_cum_(0), de_sd_change_interrupt_(0), dH_sd_change_interrupt_(0),
226 gt_drift_inv_(0), gt_kick_inv_(0),
229 #ifdef AR_SLOWDOWN_ARRAY
239 ASSERT(
manager->checkParams());
241 ASSERT(
info.checkParams());
254 #ifdef AR_SLOWDOWN_ARRAY
268 de_change_interrupt_ = 0.0;
269 dH_change_interrupt_ = 0.0;
270 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
274 de_sd_change_cum_ = 0.0;
275 dH_sd_change_cum_ = 0.0;
276 de_sd_change_interrupt_ = 0.0;
277 dH_sd_change_interrupt_ = 0.0;
285 #ifdef AR_SLOWDOWN_ARRAY
286 binary_slowdown.
clear();
304 etot_ref_ = _sym.etot_ref_;
308 de_change_interrupt_= _sym.de_change_interrupt_;
309 dH_change_interrupt_= _sym.dH_change_interrupt_;
310 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
311 ekin_sd_= _sym.ekin_sd_;
312 epot_sd_= _sym.epot_sd_;
313 etot_sd_ref_= _sym.etot_sd_ref_;
314 de_sd_change_cum_= _sym.de_sd_change_cum_;
315 dH_sd_change_cum_= _sym.dH_sd_change_cum_;
316 de_sd_change_interrupt_= _sym.de_sd_change_interrupt_;
317 dH_sd_change_interrupt_= _sym.dH_sd_change_interrupt_;
320 gt_drift_inv_ = _sym.gt_drift_inv_;
321 gt_kick_inv_ = _sym.gt_kick_inv_;
323 force_ = _sym.force_;
325 #ifdef AR_SLOWDOWN_ARRAY
326 binary_slowdown = _sym.binary_slowdown;
329 info = _sym.binarytree;
337 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
346 ASSERT(&_bini != &_binj);
349 for (
int k=0; k<2; k++) {
354 if (bink->semi>0.0)
manager->interaction.calcSlowDownPertOne(_pert_out, _t_min_sq, _bini, *bink);
355 else calcSlowDownPertInnerBinaryIter(_pert_out, _t_min_sq, _bini, *bink);
357 else if (check_flag==-2) {
358 calcSlowDownPertInnerBinaryIter(_pert_out, _t_min_sq, _bini, *bink);
364 if (pk->mass>0.0)
manager->interaction.calcSlowDownPertOne(_pert_out, _t_min_sq, _bini, *pk);
373 void calcSlowDownInnerBinary(BinaryTree<Tparticle>& _bin) {
374 _bin.slowdown.pert_in =
manager->interaction.calcPertFromBinary(_bin);
376 Float pert_out = 0.0;
378 auto& bin_root =
info.getBinaryTreeRoot();
380 calcSlowDownPertInnerBinaryIter(pert_out, t_min_sq, _bin, bin_root);
382 _bin.slowdown.pert_out = pert_out + bin_root.slowdown.pert_out;
384 #ifdef AR_SLOWDOWN_TIMESCALE
389 _bin.slowdown.timescale = std::min(_bin.slowdown.getTimescaleMax(), sqrt(t_min_sq));
394 Float semi_amplify_max = std::max(
Float(1.0),1.0/_bin.stab);
395 Float period_amplify_max = pow(semi_amplify_max,3.0/2.0);
396 Float timescale_stab = period_amplify_max*_bin.period;
397 _bin.slowdown.timescale = std::min(_bin.slowdown.timescale, timescale_stab);
401 _bin.slowdown.timescale = _bin.slowdown.getTimescaleMax();
405 bool set_sd_flag =
true;
407 for (
int k=0; k<2; k++) {
408 if (_bin.isMemberTree(k)) {
409 auto* bink = _bin.getMemberAsTree(k);
410 if (bink->stab>1.0) set_sd_flag =
false;
414 else set_sd_flag =
false;
417 _bin.slowdown.period = _bin.period;
418 _bin.slowdown.calcSlowDownFactor();
421 _bin.slowdown.setSlowDownFactor(1.0);
424 #endif // AR_SLOWDOWN_TREE || AR_SLOWDOWN_ARRAY
426 #ifdef AR_SLOWDOWN_TREE
434 Float inv_nest_sd = _inv_nest_sd_up/_bin.slowdown.getSlowDownFactor();
435 Float* vel_cm = _bin.getVel();
436 for (
int k=0; k<2; k++) {
443 calcTwoEKinIter(inv_nest_sd, *bink);
449 ekin_ += mk * (vk[0]*vk[0]+vk[1]*vk[1]+vk[2]*vk[2]);
451 Float vrel[3] = {vk[0] - vel_cm[0],
454 ekin_sd_ += mk * inv_nest_sd * (vrel[0]*vrel[0] + vrel[1]*vrel[1] + vrel[2]*vrel[2]);
460 ekin_ = ekin_sd_ = 0.0;
461 auto& bin_root=
info.getBinaryTreeRoot();
464 calcTwoEKinIter(sd_factor, bin_root);
465 Float* vcm = bin_root.getVel();
467 ekin_sd_ += bin_root.mass*(vcm[0]*vcm[0] + vcm[1]*vcm[1] + vcm[2]*vcm[2]);
478 void kickVel(
const Float& _dt) {
480 Tparticle* pdat =
particles.getDataAddress();
482 for (
int i=0; i<num; i++) {
484 Float* vel = pdat[i].getVel();
485 Float* acc = force[i].acc_in;
486 Float* pert= force[i].acc_pert;
488 vel[0] += _dt * (acc[0] + pert[0]);
489 vel[1] += _dt * (acc[1] + pert[1]);
490 vel[2] += _dt * (acc[2] + pert[2]);
493 updateBinaryVelIter(
info.getBinaryTreeRoot());
505 Float inv_nest_sd = _inv_nest_sd_up/_bin.slowdown.getSlowDownFactor();
507 Float* vel_cm = _bin.getVel();
511 vel_sd[0] = (vel[0] - vel_cm[0]) * inv_nest_sd + _vel_sd_up[0];
512 vel_sd[1] = (vel[1] - vel_cm[1]) * inv_nest_sd + _vel_sd_up[1];
513 vel_sd[2] = (vel[2] - vel_cm[2]) * inv_nest_sd + _vel_sd_up[2];
515 pos[0] += _dt * vel_sd[0];
516 pos[1] += _dt * vel_sd[1];
517 pos[2] += _dt * vel_sd[2];
520 for (
int k=0; k<2; k++) {
523 Float* pos = pj->getPos();
524 Float* vel = pj->getVel();
526 driftPos(pos, vel, vel_sd);
527 driftPosTreeIter(_dt, vel_sd, inv_nest_sd, *pj);
545 Float* pos = pj->getPos();
546 Float* vel = pj->getVel();
548 driftPos(pos, vel, vel_sd);
557 void driftTimeAndPos(
const Float& _dt) {
563 auto& bin_root=
info.getBinaryTreeRoot();
564 Float vel_cm[3] = {0.0,0.0,0.0};
567 driftPosTreeIter(_dt, vel_cm, sd_factor, bin_root);
570 #ifdef AR_TIME_FUNCTION_MULTI_R
571 Float calcInvR(Tparticle& _p1, Tparticle& _p2) {
573 Float dr[3] = {_p1.pos[0] - _p2.pos[0],
574 _p1.pos[1] - _p2.pos[1],
575 _p1.pos[2] - _p2.pos[2]};
576 Float r2 = dr[0]*dr[0] + dr[1]*dr[1] + dr[2]*dr[2];
577 Float invr = 1/sqrt(r2);
584 for (
int k=0; k<2; k++) {
594 for (
int k=0; k<2; k++) {
609 Float calcAccPotAndGTKickInvTwo(
const Float& _inv_nest_sd,
const int _i,
const int _j) {
619 force_[_i].acc_in[0] += fij[0].acc_in[0]*_inv_nest_sd;
620 force_[_i].acc_in[1] += fij[0].acc_in[1]*_inv_nest_sd;
621 force_[_i].acc_in[2] += fij[0].acc_in[2]*_inv_nest_sd;
622 force_[_j].acc_in[0] += fij[1].acc_in[0]*_inv_nest_sd;
623 force_[_j].acc_in[1] += fij[1].acc_in[1]*_inv_nest_sd;
624 force_[_j].acc_in[2] += fij[1].acc_in[2]*_inv_nest_sd;
627 epot_sd_ += epotij*_inv_nest_sd;
631 force_[_i].gtgrad[0] += fij[0].gtgrad[0]*_inv_nest_sd;
632 force_[_i].gtgrad[1] += fij[0].gtgrad[1]*_inv_nest_sd;
633 force_[_i].gtgrad[2] += fij[0].gtgrad[2]*_inv_nest_sd;
634 force_[_j].gtgrad[0] += fij[1].gtgrad[0]*_inv_nest_sd;
635 force_[_j].gtgrad[1] += fij[1].gtgrad[1]*_inv_nest_sd;
636 force_[_j].gtgrad[2] += fij[1].gtgrad[2]*_inv_nest_sd;
639 return gt_kick_inv * _inv_nest_sd;
650 Float gt_kick_inv=0.0;
651 for (
int k=0; k<2; k++) {
653 gt_kick_inv += calcAccPotAndGTKickInvOneTreeIter(_inv_nest_sd, _i, *(_bin.
getMemberAsTree(k)));
655 gt_kick_inv += calcAccPotAndGTKickInvTwo(_inv_nest_sd, _i, _bin.
getMemberIndex(k));
668 ASSERT(&_bini!=&_binj);
669 Float gt_kick_inv=0.0;
670 for (
int k=0; k<2; k++) {
672 gt_kick_inv += calcAccPotAndGTKickInvCrossTreeIter(_inv_nest_sd, *(_bini.
getMemberAsTree(k)), _binj);
674 gt_kick_inv += calcAccPotAndGTKickInvOneTreeIter(_inv_nest_sd, _bini.
getMemberIndex(k), _binj);
687 Float inv_nest_sd = _inv_nest_sd_up/_bin.slowdown.getSlowDownFactor();
688 Float gt_kick_inv = 0.0;
694 gt_kick_inv += calcAccPotAndGTKickInvTreeIter(inv_nest_sd, *bin_left);
700 gt_kick_inv += calcAccPotAndGTKickInvTreeIter(inv_nest_sd, *bin_right);
703 gt_kick_inv += calcAccPotAndGTKickInvCrossTreeIter(inv_nest_sd, *bin_left, *bin_right);
707 gt_kick_inv += calcAccPotAndGTKickInvOneTreeIter(inv_nest_sd, _bin.
getMemberIndex(1), *bin_left);
714 gt_kick_inv += calcAccPotAndGTKickInvTreeIter(inv_nest_sd, *bin_right);
717 gt_kick_inv += calcAccPotAndGTKickInvOneTreeIter(inv_nest_sd, _bin.
getMemberIndex(0), *bin_right);
726 #ifdef AR_TIME_FUNCTION_MULTI_R
727 gt_kick_inv = calcMultiInvRIter(_bin);
738 inline Float calcAccPotAndGTKickInv() {
741 for (
int i=0; i<force_.
getSize(); i++) force_[i].
clear();
743 Float gt_kick_inv = calcAccPotAndGTKickInvTreeIter(1.0,
info.getBinaryTreeRoot());
760 Float inv_nest_sd = _inv_nest_sd_up/_bin.slowdown.getSlowDownFactor();
761 Float dgt_drift_inv = 0.0;
764 Float* vel_cm = _bin.getVel();
766 for (
int k=0; k<2; k++) {
769 Float* vel = bink->getVel();
770 Float vel_sd[3] = {(vel[0] - vel_cm[0]) * inv_nest_sd + _vel_sd_up[0],
771 (vel[1] - vel_cm[1]) * inv_nest_sd + _vel_sd_up[1],
772 (vel[2] - vel_cm[2]) * inv_nest_sd + _vel_sd_up[2]};
773 dgt_drift_inv += kickEtotAndGTDriftTreeIter(_dt, vel_sd, inv_nest_sd, *bink);
780 Float* gtgrad = force_[i].gtgrad;
781 Float* pert = force_[i].acc_pert;
783 Float vel_sd[3] = {(vel[0] - vel_cm[0]) * inv_nest_sd + _vel_sd_up[0],
784 (vel[1] - vel_cm[1]) * inv_nest_sd + _vel_sd_up[1],
785 (vel[2] - vel_cm[2]) * inv_nest_sd + _vel_sd_up[2]};
787 de +=
particles[i].mass * (vel[0] * pert[0] +
790 #ifndef AR_TIME_FUNCTION_MULTI_R
791 dgt_drift_inv += (vel_sd[0] * gtgrad[0] +
792 vel_sd[1] * gtgrad[1] +
793 vel_sd[2] * gtgrad[2]);
797 etot_ref_ += _dt * de;
798 etot_sd_ref_ += _dt * de;
800 return dgt_drift_inv;
807 void kickEtotAndGTDrift(
const Float _dt) {
810 auto& bin_root=
info.getBinaryTreeRoot();
811 Float vel_cm[3] = {0.0,0.0,0.0};
814 Float dgt_drift_inv = kickEtotAndGTDriftTreeIter(_dt, vel_cm, sd_factor, bin_root);
815 #ifdef AR_TIME_FUNCTION_MULTI_R
816 dgt_drift_inv = calcGTDriftInvIter(bin_root);
818 gt_drift_inv_ += dgt_drift_inv*_dt;
826 inline void kickEtot(const Float _dt) {
829 Tparticle* pdat =
particles.getDataAddress();
831 for (
int i=0;i<num;i++) {
832 Float mass= pdat[i].mass;
833 Float* vel = pdat[i].getVel();
834 Float* pert= force[i].acc_pert;
835 de += mass * (vel[0] * pert[0] +
839 etot_sd_ref_ += _dt * de;
840 etot_ref_ += _dt * de;
846 #ifdef AR_SLOWDOWN_ARRAY
851 inline void correctAccPotGTKickInvSlowDownInner(
Float& _gt_kick_inv) {
852 int n = binary_slowdown.
getSize();
853 Float gt_kick_inv_cor = 0.0;
855 for (
int i=1; i<n; i++) {
856 auto& sdi = binary_slowdown[i];
858 int i1 = sdi->getMemberIndex(0);
859 int i2 = sdi->getMemberIndex(1);
860 Float kappa = sdi->slowdown.getSlowDownFactor();
861 Float kappa_inv = 1.0/kappa;
865 ASSERT(i1<particles.
getSize());
866 ASSERT(i2<particles.
getSize());
871 Float gt_kick_inv_i = manager->
interaction.calcInnerAccPotAndGTKickInvTwo(fi[0], fi[1], epoti, particles[i1], particles[i2]);
873 force_[i1].acc_in[0] += fi[0].acc_in[0]*kappa_inv - fi[0].acc_in[0];
874 force_[i1].acc_in[1] += fi[0].acc_in[1]*kappa_inv - fi[0].acc_in[1];
875 force_[i1].acc_in[2] += fi[0].acc_in[2]*kappa_inv - fi[0].acc_in[2];
876 force_[i2].acc_in[0] += fi[1].acc_in[0]*kappa_inv - fi[1].acc_in[0];
877 force_[i2].acc_in[1] += fi[1].acc_in[1]*kappa_inv - fi[1].acc_in[1];
878 force_[i2].acc_in[2] += fi[1].acc_in[2]*kappa_inv - fi[1].acc_in[2];
880 de += epoti*kappa_inv - epoti;
883 force_[i1].gtgrad[0] += fi[0].gtgrad[0]*kappa_inv - fi[0].gtgrad[0];
884 force_[i1].gtgrad[1] += fi[0].gtgrad[1]*kappa_inv - fi[0].gtgrad[1];
885 force_[i1].gtgrad[2] += fi[0].gtgrad[2]*kappa_inv - fi[0].gtgrad[2];
886 force_[i2].gtgrad[0] += fi[1].gtgrad[0]*kappa_inv - fi[1].gtgrad[0];
887 force_[i2].gtgrad[1] += fi[1].gtgrad[1]*kappa_inv - fi[1].gtgrad[1];
888 force_[i2].gtgrad[2] += fi[1].gtgrad[2]*kappa_inv - fi[1].gtgrad[2];
892 gt_kick_inv_cor += gt_kick_inv_i*(kappa_inv - 1.0);
897 const Float kappa_inv_global = 1.0/binary_slowdown[0]->slowdown.getSlowDownFactor();
898 for (
int i=0; i<force_.
getSize(); i++) {
899 force_[i].acc_in[0] *= kappa_inv_global;
900 force_[i].acc_in[1] *= kappa_inv_global;
901 force_[i].acc_in[2] *= kappa_inv_global;
903 force_[i].gtgrad[0] *= kappa_inv_global;
904 force_[i].gtgrad[1] *= kappa_inv_global;
905 force_[i].gtgrad[2] *= kappa_inv_global;
909 epot_sd_ = (epot_ + de)*kappa_inv_global;
910 _gt_kick_inv = (_gt_kick_inv + gt_kick_inv_cor)*kappa_inv_global;
918 inline void correctPosSlowDownInner(
const Float _dt,
const Float _sd_global_inv) {
919 int n = binary_slowdown.
getSize();
920 for (
int i=1; i<n; i++) {
921 auto& sdi = binary_slowdown[i];
923 Float kappa = sdi->slowdown.getSlowDownFactor();
924 Float kappa_inv_m_one = (1.0/kappa - 1.0)*_sd_global_inv;
925 Float* velcm = sdi->getVel();
926 for (
int k=0; k<2; k++) {
927 int j = sdi->getMemberIndex(k);
928 ASSERT(j>=0&&j<particles.
getSize());
929 Float* pos = particles[j].getPos();
930 Float* vel = particles[j].getVel();
933 Float vrel[3] = { vel[0] - velcm[0],
936 pos[0] += _dt * vrel[0] * kappa_inv_m_one;
937 pos[1] += _dt * vrel[1] * kappa_inv_m_one;
938 pos[2] += _dt * vrel[2] * kappa_inv_m_one;
944 inline void updateCenterOfMassForBinaryWithSlowDownInner() {
945 int n = binary_slowdown.
getSize();
946 for (
int i=1; i<n; i++) {
947 auto& sdi = binary_slowdown[i];
948 int i1 = sdi->getMemberIndex(0);
949 int i2 = sdi->getMemberIndex(1);
950 ASSERT(i1>=0&&i1<particles.
getSize());
951 ASSERT(i2>=0&&i2<particles.
getSize());
953 Float m1 = particles[i1].mass;
954 Float* pos1 = particles[i1].getPos();
955 Float* vel1 = particles[i1].getVel();
956 Float m2 = particles[i2].mass;
957 Float* pos2 = particles[i2].getPos();
958 Float* vel2 = particles[i2].getVel();
962 Float mcminv = 1.0/mcm;
965 Float* pos = sdi->getPos();
966 pos[0] = (m1*pos1[0] + m2*pos2[0])*mcminv;
967 pos[1] = (m1*pos1[1] + m2*pos2[1])*mcminv;
968 pos[2] = (m1*pos1[2] + m2*pos2[2])*mcminv;
970 Float* vel = sdi->getVel();
971 vel[0] = (m1*vel1[0] + m2*vel2[0])*mcminv;
972 vel[1] = (m1*vel1[1] + m2*vel2[1])*mcminv;
973 vel[2] = (m1*vel1[2] + m2*vel2[2])*mcminv;
980 inline void calcEkinSlowDownInner(
const Float& _ekin) {
981 int n = binary_slowdown.
getSize();
983 const Float kappa_inv_global = 1.0/binary_slowdown[0]->slowdown.getSlowDownFactor();
985 for (
int i=1; i<n; i++) {
986 auto& sdi = binary_slowdown[i];
988 Float kappa = sdi->slowdown.getSlowDownFactor();
989 Float kappa_inv_m_one = 1.0/kappa - 1.0;
990 Float* velcm = sdi->getVel();
991 for (
int k=0; k<2; k++) {
992 int j = sdi->getMemberIndex(k);
993 ASSERT(j>=0&&j<particles.
getSize());
994 Float* vel = particles[j].getVel();
997 Float vrel[3] = { vel[0] - velcm[0],
1001 de += kappa_inv_m_one * particles[j].mass * (vrel[0]*vrel[0] + vrel[1]*vrel[1] + vrel[2]*vrel[2]);
1004 ekin_sd_ = (_ekin + 0.5*de)*kappa_inv_global;
1012 auto& sdi_new = _binary_slowdown.getLastMember();
1016 else return _c1+_c2;
1023 void findSlowDownInner(
const Float _time) {
1024 auto& bin_root = info.getBinaryTreeRoot();
1026 int ncount[2]={0,0};
1027 int nsd = bin_root.processTreeIter(binary_slowdown, ncount[0], ncount[1], findSlowDownInnerBinaryIter);
1028 ASSERT(nsd==binary_slowdown.
getSize()-1);
1030 for (
int i=1; i<=nsd; i++) {
1031 #ifdef AR_SLOWDOWN_MASSRATIO
1032 const Float mass_ratio = manager->slowdown_mass_ref/binary_slowdown[i].bin->mass;
1034 const Float mass_ratio = 1.0;
1037 binary_slowdown[i]->slowdown.setUpdateTime(time_);
1041 #endif // AR_SLOWDOWN_ARRAY
1045 inline void calcEKin(){
1047 const int num = particles.
getSize();
1049 for (
int i=0; i<num; i++) {
1050 const Float *vi=pdat[i].getVel();
1051 ekin_ += 0.5 * pdat[i].mass * (vi[0]*vi[0]+vi[1]*vi[1]+vi[2]*vi[2]);
1053 #ifdef AR_SLOWDOWN_ARRAY
1054 calcEkinSlowDownInner(ekin_);
1062 inline void kickVel(
const Float _dt) {
1063 const int num = particles.
getSize();
1066 for (
int i=0; i<num; i++) {
1068 Float* vel = pdat[i].getVel();
1070 Float* pert= force[i].acc_pert;
1072 vel[0] += _dt * (acc[0] + pert[0]);
1073 vel[1] += _dt * (acc[1] + pert[1]);
1074 vel[2] += _dt * (acc[2] + pert[2]);
1076 #ifdef AR_SLOWDOWN_ARRAY
1078 updateCenterOfMassForBinaryWithSlowDownInner();
1086 inline void driftTimeAndPos(
const Float _dt) {
1091 const int num = particles.
getSize();
1093 #ifdef AR_SLOWDOWN_ARRAY
1094 const Float kappa_inv = 1.0/binary_slowdown[0]->slowdown.getSlowDownFactor();
1095 const Float dt_sd = _dt * kappa_inv;
1097 for (
int i=0; i<num; i++) {
1098 Float* pos = pdat[i].getPos();
1099 Float* vel = pdat[i].getVel();
1100 pos[0] += dt_sd * vel[0];
1101 pos[1] += dt_sd * vel[1];
1102 pos[2] += dt_sd * vel[2];
1106 correctPosSlowDownInner(_dt, kappa_inv);
1108 for (
int i=0; i<num; i++) {
1109 Float* pos = pdat[i].getPos();
1110 Float* vel = pdat[i].getVel();
1111 pos[0] += _dt * vel[0];
1112 pos[1] += _dt * vel[1];
1113 pos[2] += _dt * vel[2];
1122 inline Float calcAccPotAndGTKickInv() {
1140 #ifdef AR_SLOWDOWN_ARRAY
1142 correctAccPotGTKickInvSlowDownInner(gt_kick_inv);
1167 inline void kickEtotAndGTDrift(
const Float _dt) {
1170 const int num = particles.
getSize();
1173 for (
int i=0;i<num;i++) {
1174 Float mass= pdat[i].mass;
1175 Float* vel = pdat[i].getVel();
1177 Float* gtgrad=force[i].gtgrad;
1178 de += mass * (vel[0] * pert[0] +
1181 dg += (vel[0] * gtgrad[0] +
1182 vel[1] * gtgrad[1] +
1183 vel[2] * gtgrad[2]);
1185 etot_ref_ += _dt * de;
1187 #ifdef AR_SLOWDOWN_ARRAY
1188 etot_sd_ref_ += _dt * de;
1191 const Float kappa_inv_global = 1.0/binary_slowdown[0]->slowdown.getSlowDownFactor();
1192 int n = binary_slowdown.
getSize();
1193 for (
int i=1; i<n; i++) {
1194 auto& sdi = binary_slowdown[i];
1196 Float kappa = sdi->slowdown.getSlowDownFactor();
1197 Float kappa_inv = 1.0/kappa;
1198 Float* velcm = sdi->getVel();
1199 for (
int k=0; k<2; k++) {
1200 int j = sdi->getMemberIndex(k);
1202 ASSERT(j<particles.
getSize());
1203 Float* gtgrad=force_[j].gtgrad;
1204 Float* vel = particles[j].getVel();
1205 Float vrel[3] = { vel[0] - velcm[0],
1208 dg += (vrel[0] * (kappa_inv-1)* gtgrad[0] +
1209 vrel[1] * (kappa_inv-1)* gtgrad[1] +
1210 vrel[2] * (kappa_inv-1)* gtgrad[2]);
1214 gt_drift_inv_ += _dt * dg *kappa_inv_global;
1216 gt_drift_inv_ += _dt * dg;
1225 inline void kickEtot(const Float _dt) {
1227 const int num = particles.
getSize();
1230 for (
int i=0;i<num;i++) {
1231 Float mass= pdat[i].mass;
1232 Float* vel = pdat[i].getVel();
1234 de += mass * (vel[0] * pert[0] +
1238 #ifdef AR_SLOWDOWN_ARRAY
1239 etot_sd_ref_ += _dt * de;
1241 etot_ref_ += _dt * de;
1245 #endif // AR_SLOWDOWN_TREE
1249 _bin.vel[0]= _bin.vel[1] = _bin.vel[2] = 0.0;
1250 Float mcm_inv = 1.0/_bin.mass;
1251 for (
int k=0; k<2; k++) {
1254 updateBinaryVelIter(*bink);
1255 _bin.vel[0] += bink->mass*bink->vel[0];
1256 _bin.vel[1] += bink->mass*bink->vel[1];
1257 _bin.vel[2] += bink->mass*bink->vel[2];
1261 _bin.vel[0] += pk->mass*pk->vel[0];
1262 _bin.vel[1] += pk->mass*pk->vel[1];
1263 _bin.vel[2] += pk->mass*pk->vel[2];
1266 _bin.vel[0] *= mcm_inv;
1267 _bin.vel[1] *= mcm_inv;
1268 _bin.vel[2] *= mcm_inv;
1273 _bin.pos[0]= _bin.pos[1] = _bin.pos[2] = 0.0;
1274 _bin.vel[0]= _bin.vel[1] = _bin.vel[2] = 0.0;
1275 Float mcm_member = 0.0;
1276 for (
int k=0; k<2; k++) {
1279 updateBinaryCMIter(*bink);
1280 mcm_member += bink->mass;
1281 _bin.pos[0] += bink->mass*bink->pos[0];
1282 _bin.pos[1] += bink->mass*bink->pos[1];
1283 _bin.pos[2] += bink->mass*bink->pos[2];
1284 _bin.vel[0] += bink->mass*bink->vel[0];
1285 _bin.vel[1] += bink->mass*bink->vel[1];
1286 _bin.vel[2] += bink->mass*bink->vel[2];
1290 mcm_member += pk->mass;
1291 _bin.pos[0] += pk->mass*pk->pos[0];
1292 _bin.pos[1] += pk->mass*pk->pos[1];
1293 _bin.pos[2] += pk->mass*pk->pos[2];
1294 _bin.vel[0] += pk->mass*pk->vel[0];
1295 _bin.vel[1] += pk->mass*pk->vel[1];
1296 _bin.vel[2] += pk->mass*pk->vel[2];
1299 Float mcm_inv = 1.0/mcm_member;
1300 _bin.mass = mcm_member;
1303 _bin.vel[0] *= mcm_inv;
1304 _bin.vel[1] *= mcm_inv;
1305 _bin.vel[2] *= mcm_inv;
1306 _bin.pos[0] *= mcm_inv;
1307 _bin.pos[1] *= mcm_inv;
1308 _bin.pos[2] *= mcm_inv;
1314 for (
int k=0; k<2; k++) {
1317 setBinaryCMZeroIter(*bink);
1324 bool check = _check;
1325 for (
int k=0; k<2; k++) {
1328 check=updateBinarySemiEccPeriodIter(*bink, _G, _time, _check);
1331 if ((_time>_bin.stab_check_time&&_bin.stab>1.0&&_bin.m1>0.0&&_bin.m2>0.0)||check) {
1333 _bin.stab_check_time = _time + _bin.period;
1340 #ifdef AR_SLOWDOWN_TREE
1346 void updateSlowDownAndCorrectEnergy(
const bool _update_energy_flag,
const bool _stable_check_flag) {
1347 auto& bin_root = info.getBinaryTreeRoot();
1348 auto& sd_root = bin_root.slowdown;
1351 Float sd_backup = sd_root.getSlowDownFactor();
1357 sd_root.pert_in = manager->
interaction.calcPertFromBinary(bin_root);
1358 sd_root.pert_out = 0.0;
1360 manager->
interaction.calcSlowDownPert(sd_root.pert_out, t_min_sq, getTime(), particles.
cm, perturber);
1361 sd_root.timescale = std::min(sd_root.getTimescaleMax(), sqrt(t_min_sq));
1364 if (_stable_check_flag) {
1366 Float stab = bin_root.stableCheckIter(bin_root,10000*bin_root.period);
1367 Float apo = bin_root.semi*(1+bin_root.ecc);
1368 if (stab<1.0 && apo<info.r_break_crit) {
1369 sd_root.period = bin_root.period;
1370 sd_root.calcSlowDownFactor();
1372 else sd_root.setSlowDownFactor(1.0);
1381 else if (bin_root.semi>0) {
1382 sd_root.period = bin_root.period;
1383 sd_root.calcSlowDownFactor();
1385 else sd_root.setSlowDownFactor(1.0);
1391 Float sd_org_inner_max = 0.0;
1392 bool inner_sd_change_flag=
false;
1393 int n_bin = info.binarytree.getSize();
1394 for (
int i=0; i<n_bin-1; i++) {
1395 auto& bini = info.binarytree[i];
1397 bini.calcCenterOfMass();
1398 calcSlowDownInnerBinary(bini);
1401 sd_org_inner_max = std::max(bini.slowdown.getSlowDownFactorOrigin(),sd_org_inner_max);
1402 inner_sd_change_flag=
true;
1407 if (_update_energy_flag) {
1408 Float ekin_sd_bk = ekin_sd_;
1409 Float epot_sd_bk = epot_sd_;
1410 Float H_sd_bk = getHSlowDown();
1411 if(inner_sd_change_flag) {
1413 Float gt_kick_inv_new = calcAccPotAndGTKickInv();
1414 gt_drift_inv_ += gt_kick_inv_new - gt_kick_inv_;
1415 gt_kick_inv_ = gt_kick_inv_new;
1417 calcAccPotAndGTKickInv();
1422 Float kappa_inv = 1.0/sd_root.getSlowDownFactor();
1424 Float gt_kick_inv_new = gt_kick_inv_*sd_backup*kappa_inv;
1425 gt_drift_inv_ += gt_kick_inv_new - gt_kick_inv_;
1426 gt_kick_inv_ = gt_kick_inv_new;
1428 ekin_sd_ = ekin_*kappa_inv;
1429 epot_sd_ = epot_*kappa_inv;
1431 Float de_sd = (ekin_sd_ - ekin_sd_bk) + (epot_sd_ - epot_sd_bk);
1432 etot_sd_ref_ += de_sd;
1434 Float dH_sd = getHSlowDown() - H_sd_bk;
1437 de_sd_change_cum_ += de_sd;
1438 dH_sd_change_cum_ += dH_sd;
1441 #elif AR_SLOWDOWN_ARRAY
1447 void updateSlowDownAndCorrectEnergy(
const bool _update_energy_flag,
const bool _stable_check_flag) {
1448 auto& bin_root = *binary_slowdown[0];
1449 auto& sd_root = bin_root.slowdown;
1451 Float sd_backup = sd_root.getSlowDownFactor();
1457 sd_root.pert_in = manager->
interaction.calcPertFromBinary(bin_root);
1458 sd_root.pert_out = 0.0;
1460 manager->
interaction.calcSlowDownPert(sd_root.pert_out, t_min_sq, getTime(), particles.
cm, perturber);
1461 sd_root.timescale = std::min(sd_root.getTimescaleMax(), sqrt(t_min_sq));
1464 if (_stable_check_flag) {
1466 Float stab = bin_root.stableCheckIter(bin_root,10000*bin_root.period);
1468 sd_root.period = bin_root.period;
1469 sd_root.calcSlowDownFactor();
1471 else sd_root.setSlowDownFactor(1.0);
1479 else if (bin_root.semi>0) {
1480 sd_root.period = bin_root.period;
1481 sd_root.calcSlowDownFactor();
1483 else sd_root.setSlowDownFactor(1.0);
1490 int n = binary_slowdown.
getSize();
1491 bool modified_flag=
false;
1492 for (
int i=1; i<n; i++) {
1493 auto* sdi = binary_slowdown[i];
1495 sdi->calcCenterOfMass();
1496 calcSlowDownInnerBinary(*sdi);
1502 if (_update_energy_flag) {
1503 Float ekin_sd_bk = ekin_sd_;
1504 Float epot_sd_bk = epot_sd_;
1505 Float H_sd_bk = getHSlowDown();
1507 if (modified_flag) {
1510 correctAccPotGTKickInvSlowDownInner(gt_kick_inv_sdi);
1512 gt_drift_inv_ += gt_kick_inv_sdi - gt_kick_inv_;
1513 gt_kick_inv_ = gt_kick_inv_sdi;
1516 calcEkinSlowDownInner(ekin_);
1519 Float kappa_inv = 1.0/sd_root.getSlowDownFactor();
1521 Float gt_kick_inv_sdi = gt_kick_inv_*sd_backup*kappa_inv;
1522 gt_drift_inv_ += gt_kick_inv_sdi - gt_kick_inv_;
1523 gt_kick_inv_ = gt_kick_inv_sdi;
1526 ekin_sd_ = ekin_*kappa_inv;
1527 epot_sd_ = epot_*kappa_inv;
1530 Float de_sd = (ekin_sd_ - ekin_sd_bk) + (epot_sd_ - epot_sd_bk);
1531 etot_sd_ref_ += de_sd;
1533 Float dH_sd = getHSlowDown() - H_sd_bk;
1536 de_sd_change_cum_ += de_sd;
1537 dH_sd_change_cum_ += dH_sd;
1547 ASSERT(checkParams());
1550 const int n_particle = particles.
getSize();
1559 ASSERT(particles.
getSize()>=2);
1568 for (
int i=0; i<info.binarytree.getSize(); i++) {
1569 auto& bin = info.binarytree[i];
1570 bin.pos[0] -= particles.
cm.pos[0];
1571 bin.pos[1] -= particles.
cm.pos[1];
1572 bin.pos[2] -= particles.
cm.pos[2];
1573 bin.vel[0] -= particles.
cm.vel[0];
1574 bin.vel[1] -= particles.
cm.vel[1];
1575 bin.vel[2] -= particles.
cm.vel[2];
1578 ASSERT(info.getBinaryTreeRoot().pos[0]*info.getBinaryTreeRoot().pos[0]<1e-10);
1579 ASSERT(info.getBinaryTreeRoot().vel[0]*info.getBinaryTreeRoot().vel[0]<1e-10);
1581 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
1582 #ifdef AR_SLOWDOWN_TREE
1583 for (
int i=0; i<info.binarytree.getSize(); i++)
1587 binary_slowdown[0] = &info.getBinaryTreeRoot();
1590 SlowDown& slowdown_root = info.getBinaryTreeRoot().slowdown;
1596 findSlowDownInner(time_);
1602 updateSlowDownAndCorrectEnergy(
false,
true);
1605 gt_kick_inv_ = calcAccPotAndGTKickInv();
1608 gt_drift_inv_ = gt_kick_inv_;
1611 calcAccPotAndGTKickInv();
1616 etot_ref_ = ekin_ + epot_;
1617 etot_sd_ref_ = ekin_sd_ + epot_sd_;
1619 Float de_sd = etot_sd_ref_ - etot_ref_;
1622 de_sd_change_cum_ += de_sd;
1623 dH_sd_change_cum_ = 0.0;
1625 #else // No SLOWDOWN
1630 gt_kick_inv_ = manager->
interaction.calcAccPotAndGTKickInv(force_data, epot_, particle_data, n_particle, particles.
cm, perturber, _time);
1633 gt_drift_inv_ = gt_kick_inv_;
1636 manager->
interaction.calcAccPotAndGTKickInv(force_data, epot_, particle_data, n_particle, particles.
cm, perturber, _time);
1643 etot_ref_ = ekin_ + epot_;
1654 ASSERT(checkParams());
1660 const int nloop = manager->
step.getCDPairSize();
1662 for (
int i=0; i<nloop; i++) {
1664 Float ds_drift = manager->
step.getCK(i)*_ds;
1668 Float gt_drift_inv = gt_drift_inv_;
1670 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
1671 Float gt_drift_inv = manager->
interaction.calcGTDriftInv(ekin_sd_-etot_sd_ref_);
1678 Float dt_drift = ds_drift/gt_drift_inv;
1681 driftTimeAndPos(dt_drift);
1682 _time_table[i] = time_;
1685 Float ds_kick = manager->
step.getDK(i)*_ds;
1688 Float gt_kick_inv = calcAccPotAndGTKickInv();
1691 Float dt_kick = ds_kick/gt_kick_inv;
1694 kickVel(0.5*dt_kick);
1698 gt_kick_inv_ = gt_kick_inv;
1700 kickEtotAndGTDrift(dt_kick);
1706 kickVel(0.5*dt_kick);
1721 ASSERT(checkParams());
1727 const int nloop = manager->
step.getCDPairSize();
1729 const int n_particle = particles.
getSize();
1730 ASSERT(n_particle==2);
1732 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
1733 const Float kappa_inv = 1.0/info.getBinaryTreeRoot().slowdown.getSlowDownFactor();
1737 Float mass1 = particle_data[0].mass;
1738 Float* pos1 = particle_data[0].getPos();
1739 Float* vel1 = particle_data[0].getVel();
1741 Float mass2 = particle_data[1].mass;
1742 Float* pos2 = particle_data[1].getPos();
1743 Float* vel2 = particle_data[1].getVel();
1752 Float* gtgrad1 = force_data[0].gtgrad;
1753 Float* gtgrad2 = force_data[1].gtgrad;
1756 #ifdef AR_DEBUG_PRINT_DKD
1757 std::cout<<
"K "<<time_<<
" "
1758 <<pos2[0]-pos1[0]<<
" "<<pos2[1]-pos1[1]<<
" "<<pos2[2]-pos1[2]<<
" "
1759 <<vel2[0]-vel1[0]<<
" "<<vel2[1]-vel1[1]<<
" "<<vel2[2]-vel1[2]<<
" "
1760 <<ekin_<<
" "<<epot_<<
" "<<etot_ref_<<std::endl;
1763 for (
int i=0; i<nloop; i++) {
1768 Float gt_inv = gt_drift_inv_;
1770 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
1777 Float dt = ds/gt_inv;
1784 _time_table[i] = time_;
1786 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
1787 Float dt_sd = dt*kappa_inv;
1790 pos1[0] += dt_sd * vel1[0];
1791 pos1[1] += dt_sd * vel1[1];
1792 pos1[2] += dt_sd * vel1[2];
1794 pos2[0] += dt_sd * vel2[0];
1795 pos2[1] += dt_sd * vel2[1];
1796 pos2[2] += dt_sd * vel2[2];
1799 pos1[0] += dt * vel1[0];
1800 pos1[1] += dt * vel1[1];
1801 pos1[2] += dt * vel1[2];
1803 pos2[0] += dt * vel2[0];
1804 pos2[1] += dt * vel2[1];
1805 pos2[2] += dt * vel2[2];
1809 ds = manager->
step.getDK(i)*_ds;
1811 gt_inv = manager->
interaction.calcAccPotAndGTKickInv(force_data, epot_, particle_data, n_particle, particles.
cm, perturber, _time_table[i]);
1813 ASSERT(!
ISNAN(epot_));
1815 #ifdef AR_DEBUG_PRINT_DKD
1817 std::cout<<
"K "<<time_<<
" "
1818 <<pos2[0]-pos1[0]<<
" "<<pos2[1]-pos1[1]<<
" "<<pos2[2]-pos1[2]<<
" "
1819 <<vel2[0]-vel1[0]<<
" "<<vel2[1]-vel1[1]<<
" "<<vel2[2]-vel1[2]<<
" "
1820 <<ekin_<<
" "<<epot_<<
" "<<etot_ref_<<std::endl;
1824 Float dvel1[3], dvel2[3];
1826 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
1828 gt_inv *= kappa_inv;
1832 dvel1[0] = dt * (acc1[0]*kappa_inv + pert1[0]);
1833 dvel1[1] = dt * (acc1[1]*kappa_inv + pert1[1]);
1834 dvel1[2] = dt * (acc1[2]*kappa_inv + pert1[2]);
1836 dvel2[0] = dt * (acc2[0]*kappa_inv + pert2[0]);
1837 dvel2[1] = dt * (acc2[1]*kappa_inv + pert2[1]);
1838 dvel2[2] = dt * (acc2[2]*kappa_inv + pert2[2]);
1842 dvel1[0] = dt * (acc1[0] + pert1[0]);
1843 dvel1[1] = dt * (acc1[1] + pert1[1]);
1844 dvel1[2] = dt * (acc1[2] + pert1[2]);
1846 dvel2[0] = dt * (acc2[0] + pert2[0]);
1847 dvel2[1] = dt * (acc2[1] + pert2[1]);
1848 dvel2[2] = dt * (acc2[2] + pert2[2]);
1851 vel1[0] += dvel1[0];
1852 vel1[1] += dvel1[1];
1853 vel1[2] += dvel1[2];
1855 vel2[0] += dvel2[0];
1856 vel2[1] += dvel2[1];
1857 vel2[2] += dvel2[2];
1859 #ifdef AR_DEBUG_PRINT_DKD
1860 std::cout<<
"D "<<time_<<
" "
1861 <<pos2[0]-pos1[0]<<
" "<<pos2[1]-pos1[1]<<
" "<<pos2[2]-pos1[2]<<
" "
1862 <<vel2[0]-vel1[0]<<
" "<<vel2[1]-vel1[1]<<
" "<<vel2[2]-vel1[2]<<
" "
1863 <<ekin_<<
" "<<epot_<<
" "<<etot_ref_<<std::endl;
1867 etot_ref_ += 2.0*dt * (mass1* (vel1[0] * pert1[0] +
1868 vel1[1] * pert1[1] +
1869 vel1[2] * pert1[2]) +
1870 mass2* (vel2[0] * pert2[0] +
1871 vel2[1] * pert2[1] +
1872 vel2[2] * pert2[2]));
1876 gt_kick_inv_ = gt_inv;
1878 #if (defined AR_SLOWDOWN_ARRAY ) || (defined AR_SLOWDOWN_TREE)
1880 gt_drift_inv_ += 2.0*dt*kappa_inv*kappa_inv* (vel1[0] * gtgrad1[0] +
1881 vel1[1] * gtgrad1[1] +
1882 vel1[2] * gtgrad1[2] +
1883 vel2[0] * gtgrad2[0] +
1884 vel2[1] * gtgrad2[1] +
1885 vel2[2] * gtgrad2[2]);
1888 gt_drift_inv_ += 2.0*dt* (vel1[0] * gtgrad1[0] +
1889 vel1[1] * gtgrad1[1] +
1890 vel1[2] * gtgrad1[2] +
1891 vel2[0] * gtgrad2[0] +
1892 vel2[1] * gtgrad2[1] +
1893 vel2[2] * gtgrad2[2]);
1899 vel1[0] += dvel1[0];
1900 vel1[1] += dvel1[1];
1901 vel1[2] += dvel1[2];
1903 vel2[0] += dvel2[0];
1904 vel2[1] += dvel2[1];
1905 vel2[2] += dvel2[2];
1908 ekin_ = 0.5 * (mass1 * (vel1[0]*vel1[0]+vel1[1]*vel1[1]+vel1[2]*vel1[2]) +
1909 mass2 * (vel2[0]*vel2[0]+vel2[1]*vel2[1]+vel2[2]*vel2[2]));
1913 #if (defined AR_SLOWDOWN_ARRAY ) || (defined AR_SLOWDOWN_TREE)
1915 etot_sd_ref_ = etot_ref_*kappa_inv;
1916 ekin_sd_ = ekin_*kappa_inv;
1917 epot_sd_ = epot_*kappa_inv;
1927 ASSERT(checkParams());
1930 const Float dt_full = _time_end - time_;
1942 const int bk_data_size = getBackupDataSize();
1944 Float backup_data[bk_data_size];
1945 #ifdef AR_DEBUG_DUMP
1946 Float backup_data_init[bk_data_size];
1948 bool backup_flag=
true;
1951 const int cd_pair_size = manager->
step.getCDPairSize();
1952 Float time_table[cd_pair_size];
1955 Float ds[2] = {info.ds,info.ds};
1956 Float ds_init = info.ds;
1960 const int n_reduce_level_max=10;
1962 struct DsBackupManager{
1963 Float ds_backup[n_reduce_level_max+1];
1964 int n_step_wait_recover_ds[n_reduce_level_max+1];
1967 DsBackupManager(
const Float _ds) { initial(_ds), n_reduce_level = -1; }
1969 void initial(
const Float _ds) {
1970 for (
int i=0; i<n_reduce_level_max; i++) {
1972 n_step_wait_recover_ds[i] = 0;
1977 bool shiftReduceLevel() {
1978 if (n_reduce_level>0) {
1979 for (
int i=0; i<n_reduce_level-1; i++) {
1980 ds_backup[i] =ds_backup[i+1];
1981 n_step_wait_recover_ds[i] = n_step_wait_recover_ds[i+1];
1990 void backup(
const Float _ds,
const Float _modify_factor) {
1992 if (n_reduce_level==n_reduce_level_max)
1993 n_step_wait_recover_ds[n_reduce_level] += 2*
to_int(1.0/_modify_factor);
1996 ds_backup[n_reduce_level] = _ds;
1997 n_step_wait_recover_ds[n_reduce_level] = 2*
to_int(1.0/_modify_factor);
2002 bool countAndRecover(
Float &_ds,
Float &_modify_factor,
const bool _recover_flag) {
2003 if (n_reduce_level>=0) {
2004 if (n_step_wait_recover_ds[n_reduce_level] ==0) {
2005 if (_recover_flag) {
2006 _modify_factor = ds_backup[n_reduce_level]/_ds;
2007 _ds = ds_backup[n_reduce_level];
2008 n_step_wait_recover_ds[n_reduce_level] = -1;
2014 n_step_wait_recover_ds[n_reduce_level]--;
2021 } ds_backup(info.ds);
2023 int reduce_ds_count=0;
2024 Float step_modify_factor=1.0;
2025 Float previous_step_modify_factor=1.0;
2026 Float previous_error_ratio=-1;
2027 bool previous_is_restore=
false;
2031 bool time_end_flag=
false;
2034 long long unsigned int step_count=0;
2035 long long unsigned int step_count_tsyn=0;
2037 bin_interrupt.
time_now=time_ + info.time_offset;
2038 bin_interrupt.
time_end=_time_end + info.time_offset;
2042 const int n_particle = particles.
getSize();
2053 bool warning_print_once=
true;
2055 #ifdef AR_DEBUG_DUMP
2057 backupIntData(backup_data_init);
2060 #ifdef AR_SLOWDOWN_ARRAY
2063 if (n_particle >2) {
2064 int nold = binary_slowdown.
getSize();
2065 findSlowDownInner(time_);
2066 int nnew = binary_slowdown.
getSize();
2068 if (nold>0&&nnew==0) {
2070 gt_drift_inv_ = gt_kick_inv_;
2074 if (n_particle >2) findSlowDownInner(time_);
2078 #ifdef AR_SLOWDOWN_TREE
2080 updateSlowDownAndCorrectEnergy(
true,
true);
2085 for (
int i=0; i<info.binarytree.getSize(); i++)
2086 info.binarytree[i].stab_check_time = time_;
2091 bool binary_update_flag=
false;
2092 auto& bin_root = info.getBinaryTreeRoot();
2093 auto& G = manager->
interaction.gravitational_constant;
2098 bin_interrupt.
time_now = time_ + info.time_offset;
2099 bin_interrupt.
time_end = _time_end + info.time_offset;
2105 manager->
interaction.modifyAndInterruptIter(bin_interrupt, bin_root);
2109 if (bin_interrupt.
status!=InterruptStatus::none) {
2118 return bin_interrupt;
2123 if (bin_interrupt.
status==InterruptStatus::destroy) {
2126 for (
int j=0; j<n_particle; j++) {
2127 ASSERT(particles[j].mass==0.0);
2130 de_change_interrupt_ -= etot_ref_;
2131 dH_change_interrupt_ -= getH();
2132 ekin_ = epot_ = etot_ref_ = 0.0;
2133 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
2134 de_sd_change_cum_ -= etot_sd_ref_;
2135 dH_sd_change_interrupt_ -= getHSlowDown();
2136 ekin_sd_ = epot_sd_ = etot_sd_ref_ = 0.0;
2138 #ifdef AR_DEBUG_PRINT
2139 std::cerr<<
"Interrupt condition triggered! Destroy";
2140 std::cerr<<
" Time: "<<time_;
2141 bin_interrupt.
adr->printColumnTitle(std::cerr);
2142 std::cerr<<std::endl;
2143 bin_interrupt.
adr->printColumn(std::cerr);
2144 std::cerr<<std::endl;
2145 Tparticle::printColumnTitle(std::cerr);
2146 std::cerr<<std::endl;
2147 for (
int j=0; j<2; j++) {
2148 bin_interrupt.
adr->getMember(j)->printColumn(std::cerr);
2149 std::cerr<<std::endl;
2154 setBinaryCMZeroIter(bin_root);
2162 Float dt = _time_end - time_;
2165 return bin_interrupt;
2168 Float ekin_bk = ekin_;
2169 Float epot_bk = epot_;
2170 Float H_bk = getH();
2172 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
2173 Float ekin_sd_bk = ekin_sd_;
2174 Float epot_sd_bk = epot_sd_;
2175 Float H_sd_bk = getHSlowDown();
2179 info.generateBinaryTree(particles, G);
2182 binary_update_flag =
true;
2190 Float gt_kick_inv_new = calcAccPotAndGTKickInv();
2191 Float d_gt_kick_inv = gt_kick_inv_new - gt_kick_inv_;
2193 if (fabs(d_gt_kick_inv)/std::max(fabs(gt_kick_inv_),fabs(gt_kick_inv_new)) >1e-3)
2194 gt_drift_inv_ = gt_kick_inv_new;
2196 gt_drift_inv_ += d_gt_kick_inv;
2197 gt_kick_inv_ = gt_kick_inv_new;
2199 calcAccPotAndGTKickInv();
2213 Float de = (ekin_ - ekin_bk) + (epot_ - epot_bk);
2215 de_change_interrupt_ += de;
2216 dH_change_interrupt_ += getH() - H_bk;
2218 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
2219 Float de_sd = (ekin_sd_ - ekin_sd_bk) + (epot_sd_ - epot_sd_bk);
2220 etot_sd_ref_ += de_sd;
2222 Float dH_sd = getHSlowDown() - H_sd_bk;
2225 de_sd_change_interrupt_ += de_sd;
2226 dH_sd_change_interrupt_ += dH_sd;
2227 de_sd_change_cum_ += de_sd;
2228 dH_sd_change_cum_ += dH_sd;
2231 #ifdef AR_DEBUG_PRINT
2232 std::cerr<<
"Interrupt condition triggered!";
2233 std::cerr<<
" Time: "<<time_;
2234 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
2235 std::cerr<<
" Energy change: dE_SD: "<<de_sd<<
" dH_SD: "<<dH_sd;
2236 std::cerr<<
" Slowdown: "<<bin_root.slowdown.getSlowDownFactor()<<std::endl;
2238 bin_interrupt.
adr->printColumnTitle(std::cerr);
2239 std::cerr<<std::endl;
2240 bin_interrupt.
adr->printColumn(std::cerr);
2241 std::cerr<<std::endl;
2242 Tparticle::printColumnTitle(std::cerr);
2243 std::cerr<<std::endl;
2244 for (
int j=0; j<2; j++) {
2245 bin_interrupt.
adr->getMember(j)->printColumn(std::cerr);
2246 std::cerr<<std::endl;
2257 if (bin_interrupt.
status==InterruptStatus::merge) {
2260 int index_mass_last=-1;
2261 for (
int j=0; j<n_particle; j++) {
2262 if (particles[j].mass>0.0) {
2268 if (count_mass==1) {
2269 ASSERT(index_mass_last<n_particle&&index_mass_last>=0);
2270 auto& p = particles[index_mass_last];
2271 Float dt = _time_end - time_;
2272 p.pos[0] += dt * p.vel[0];
2273 p.pos[1] += dt * p.vel[1];
2274 p.pos[2] += dt * p.vel[2];
2284 return bin_interrupt;
2287 if (count_mass==2) {
2288 info.fix_step_option=FixStepOption::later;
2295 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
2296 updateSlowDownAndCorrectEnergy(
true,
true);
2299 info.ds = info.calcDsKeplerBinaryTree(*bin_interrupt.
adr, manager->
step.getOrder(), G, manager->
ds_scale);
2300 Float ds_max = manager->
step.calcStepModifyFactorFromErrorRatio(2.0)*ds_init;
2301 Float ds_min = manager->
step.calcStepModifyFactorFromErrorRatio(0.5)*ds_init;
2302 if (info.ds>ds_max || info.ds<ds_min) {
2303 #ifdef AR_DEBUG_PRINT
2304 std::cerr<<
"Change ds after interruption: ds(init): "<<ds_init<<
" ds(new): "<<info.ds<<
" ds(now): "<<ds[0]<<std::endl;
2307 ds[0] = std::min(ds[0], info.ds);
2308 ds[1] = std::min(ds[1], info.ds);
2309 ds_backup.initial(info.ds);
2312 else info.ds = ds_init;
2315 if (bin_interrupt_return.
status!=InterruptStatus::none) {
2316 if (bin_interrupt_return.
adr!= bin_interrupt.
adr) {
2318 bin_interrupt_return.
adr = &(info.getBinaryTreeRoot());
2320 if (bin_interrupt.
status==InterruptStatus::merge)
2321 bin_interrupt_return.
status = InterruptStatus::merge;
2323 else bin_interrupt_return = bin_interrupt;
2325 bin_interrupt.
clear();
2331 if (!time_end_flag&&!binary_update_flag) {
2332 bool update_flag=updateBinarySemiEccPeriodIter(bin_root, G, time_);
2334 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
2335 updateSlowDownAndCorrectEnergy(
true,
true);
2341 #ifdef AR_DEBUG_PRINT
2342 std::cerr<<
"Update binary tree orbits, time= "<<time_<<
"\n";
2344 info.ds = info.calcDsKeplerBinaryTree(bin_root, manager->
step.getOrder(), G, manager->
ds_scale);
2345 if (abs(ds_init-info.ds)/ds_init>0.1) {
2346 #ifdef AR_DEBUG_PRINT
2347 std::cerr<<
"Change ds after update binary orbit: ds(init): "<<ds_init<<
" ds(new): "<<info.ds<<
" ds(now): "<<ds[0]<<std::endl;
2350 ds[0] = std::min(ds[0], info.ds);
2351 ds[1] = std::min(ds[1], info.ds);
2352 ds_backup.initial(info.ds);
2358 int bk_return_size = backupIntData(backup_data);
2359 ASSERT(bk_return_size == bk_data_size);
2360 (void)bk_return_size;
2364 int bk_return_size = restoreIntData(backup_data);
2365 ASSERT(bk_return_size == bk_data_size);
2366 (void)bk_return_size;
2372 updateBinaryCMIter(info.getBinaryTreeRoot());
2380 ASSERT(!
ISINF(ds[ds_switch]));
2381 if(n_particle==2) integrateTwoOneStep(ds[ds_switch], time_table);
2382 else integrateOneStep(ds[ds_switch], time_table);
2392 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
2393 Float energy_error_bk = getEnergyErrorSlowDownFromBackup(backup_data);
2394 Float etot_ref_bk = getEtotSlowDownRefFromBackup(backup_data);
2395 Float energy_error = getEnergyErrorSlowDown();
2396 Float H_bk = getHSlowDownFromBackup(backup_data);
2397 Float H = getHSlowDown();
2399 Float energy_error_bk = getEnergyErrorFromBackup(backup_data);
2400 Float etot_ref_bk = getEtotRefFromBackup(backup_data);
2401 Float energy_error = getEnergyError();
2402 Float H_bk = getHFromBackup(backup_data);
2405 Float energy_error_diff = energy_error - energy_error_bk;
2407 Float energy_error_rel_abs = abs(energy_error_diff/etot_ref_bk);
2410 Float integration_error_rel_abs = abs(H-H_bk);
2412 Float integration_error_rel_cum_abs = abs(H);
2414 Float integration_error_ratio = energy_error_rel_max/integration_error_rel_abs;
2417 Float time_diff_rel = (_time_end - time_)/dt_full;
2420 auto regularStepFactor = [](
const Float _fac) {
2422 if (_fac<1)
while (fac>_fac) fac *= 0.5;
2424 while (fac<=_fac) fac *= 2.0;
2430 Float error_increase_ratio_regular = manager->
step.calcErrorRatioFromStepModifyFactor(2.0);
2433 auto printMessage = [&](
const char* message) {
2434 std::cerr<<message<<std::endl;
2435 std::cerr<<
" T: "<<time_
2436 <<
" dT_err/T: "<<time_diff_rel
2437 <<
" ds: "<<ds[ds_switch]
2438 <<
" ds_init: "<<ds_init
2439 <<
" |Int_err/E|: "<<integration_error_rel_abs
2440 <<
" |Int_err_cum/E|: "<<integration_error_rel_cum_abs
2441 <<
" |dE/E|: "<<energy_error_rel_abs
2442 <<
" dE_cum: "<<energy_error
2443 <<
" Etot_sd: "<<etot_ref_bk
2444 <<
" T_end_flag: "<<time_end_flag
2445 <<
" Step_count: "<<step_count;
2446 switch (info.fix_step_option) {
2447 case FixStepOption::always:
2448 std::cerr<<
" Fix: always"<<std::endl;
2450 case FixStepOption::later:
2451 std::cerr<<
" Fix: later"<<std::endl;
2453 case FixStepOption::none:
2454 std::cerr<<
" Fix: none"<<std::endl;
2461 #ifdef AR_COLLECT_DS_MODIFY_INFO
2462 auto collectDsModifyInfo = [&](
const char* error_message) {
2463 std::cerr<<error_message<<
": "
2464 <<
"time "<<time_<<
" "
2465 <<
"ds_new "<<ds[1-ds_switch]<<
" "
2466 <<
"ds_init "<<ds_init<<
" "
2467 <<
"modify "<<step_modify_factor<<
" "
2468 <<
"steps "<<step_count<<
" "
2469 <<
"n_mods "<<reduce_ds_count<<
" "
2470 <<
"err "<<integration_error_rel_abs<<
" "
2471 <<
"err/max "<<1.0/integration_error_ratio<<
" "
2472 <<
"errcum/E "<<integration_error_rel_cum_abs<<
" "
2474 <<
"n_ptcl "<<n_particle<<
" ";
2475 for (
int i=0; i<info.binarytree.getSize(); i++) {
2476 auto& bini = info.binarytree[i];
2477 std::cerr<<
"semi "<<bini.semi<<
" "
2478 <<
"ecc "<<bini.ecc<<
" "
2479 <<
"period "<<bini.period<<
" "
2480 <<
"m1 "<<bini.m1<<
" "
2481 <<
"m2 "<<bini.m2<<
" "
2482 <<
"stab "<<bini.stab<<
" "
2483 <<
"sd "<<bini.slowdown.getSlowDownFactor()<<
" "
2484 <<
"sd_org "<<bini.slowdown.getSlowDownFactorOrigin()<<
" "
2485 <<
"pert_in "<<bini.slowdown.getPertIn()<<
" "
2486 <<
"pert_out "<<bini.slowdown.getPertOut()<<
" ";
2488 std::cerr<<std::endl;
2496 printMessage(
"Warning: step count is signficiant large");
2497 for (
int i=0; i<info.binarytree.getSize(); i++){
2498 auto& bin = info.binarytree[i];
2499 std::cerr<<
" Binary["<<i<<
"]: "
2500 <<
" i1="<<bin.getMemberIndex(0)
2501 <<
" i2="<<bin.getMemberIndex(1)
2504 <<
" semi= "<<bin.semi
2506 <<
" period= "<<bin.period
2507 <<
" stab= "<<bin.stab
2508 <<
" SD= "<<bin.slowdown.getSlowDownFactor()
2509 <<
" SD_org= "<<bin.slowdown.getSlowDownFactorOrigin()
2510 <<
" Tscale= "<<bin.slowdown.timescale
2511 <<
" pert_in= "<<bin.slowdown.pert_in
2512 <<
" pert_out= "<<bin.slowdown.pert_out;
2513 std::cerr<<std::endl;
2514 warning_print_once =
false;
2520 #ifdef AR_DEBUG_DUMP
2521 if (!info.dump_flag) {
2522 DATADUMP(
"dump_large_step");
2523 info.dump_flag=
true;
2549 printMessage(
"Error! step count after time synchronization is too large");
2550 printColumnTitle(std::cerr,20,info.binarytree.getSize());
2551 std::cerr<<std::endl;
2552 printColumn(std::cerr,20,info.binarytree.getSize());
2553 std::cerr<<std::endl;
2555 #ifdef AR_DEBUG_DUMP
2556 if (!info.dump_flag) {
2557 DATADUMP(
"dump_large_step");
2558 info.dump_flag=
true;
2565 #ifdef AR_DEEP_DEBUG
2567 std::cerr<<
"Timetable: ";
2568 for (
int i=0; i<cd_pair_size; i++) std::cerr<<
" "<<time_table[manager->
step.getSortCumSumCKIndex(i)];
2569 std::cerr<<std::endl;
2572 ASSERT(!
ISNAN(integration_error_rel_abs));
2575 if(integration_error_rel_abs>energy_error_rel_max && info.fix_step_option!=FixStepOption::always) {
2577 bool check_flag =
true;
2580 if (previous_step_modify_factor!=1.0) {
2581 ASSERT(previous_error_ratio>0.0);
2584 if (integration_error_ratio>0.5*previous_error_ratio) check_flag=
false;
2593 step_modify_factor = std::max(regularStepFactor(manager->
step.calcStepModifyFactorFromErrorRatio(integration_error_ratio)),
Float(0.125));
2594 ASSERT(step_modify_factor>0.0);
2596 previous_step_modify_factor = step_modify_factor;
2597 previous_error_ratio = integration_error_ratio;
2599 ds[ds_switch] *= step_modify_factor;
2600 ds[1-ds_switch] = ds[ds_switch];
2604 ds_backup.initial(info.ds);
2606 backup_flag =
false;
2607 #ifdef AR_COLLECT_DS_MODIFY_INFO
2608 collectDsModifyInfo(
"Large_energy_error");
2613 else if (info.fix_step_option==FixStepOption::none) {
2617 step_modify_factor = std::max(regularStepFactor(manager->
step.calcStepModifyFactorFromErrorRatio(integration_error_ratio)),
Float(0.125));
2618 ASSERT(step_modify_factor>0.0);
2620 previous_step_modify_factor = step_modify_factor;
2621 previous_error_ratio = integration_error_ratio;
2623 ds_backup.backup(ds[ds_switch], step_modify_factor);
2624 if(previous_is_restore) reduce_ds_count++;
2626 ds[ds_switch] *= step_modify_factor;
2627 ds[1-ds_switch] = ds[ds_switch];
2628 ASSERT(!
ISINF(ds[ds_switch]));
2638 backup_flag =
false;
2639 #ifdef AR_COLLECT_DS_MODIFY_INFO
2640 collectDsModifyInfo(
"Large_energy_error");
2654 if(!time_end_flag&&dt<0) {
2656 step_modify_factor = std::min(std::max(regularStepFactor(manager->
step.calcStepModifyFactorFromErrorRatio(abs(_time_end/dt))),
Float(0.0625)),
Float(0.5));
2657 ASSERT(step_modify_factor>0.0);
2658 previous_step_modify_factor = step_modify_factor;
2659 previous_error_ratio = integration_error_ratio;
2661 ds[ds_switch] *= step_modify_factor;
2662 ds[1-ds_switch] = ds[ds_switch];
2663 ASSERT(!
ISINF(ds[ds_switch]));
2668 ds_backup.initial(info.ds);
2671 ds_backup.backup(ds[ds_switch], step_modify_factor);
2674 backup_flag =
false;
2676 #ifdef AR_COLLECT_DS_MODIFY_INFO
2677 collectDsModifyInfo(
"Negative_step");
2689 previous_step_modify_factor = 1.0;
2690 previous_error_ratio = -1.0;
2693 if(time_ < _time_end - time_error){
2695 if(info.fix_step_option==FixStepOption::none && !time_end_flag) {
2697 previous_is_restore=ds_backup.countAndRecover(ds[1-ds_switch], step_modify_factor, integration_error_ratio>error_increase_ratio_regular);
2698 if (previous_is_restore) {
2701 #ifdef AR_COLLECT_DS_MODIFY_INFO
2702 collectDsModifyInfo(
"Reuse_backup_ds");
2706 else if(integration_error_rel_abs<0.5*energy_error_rel_max && dt>0.0 && dt_full/dt>std::max(100.0,0.02*manager->
step_count_max)) {
2707 Float integration_error_ratio = energy_error_rel_max/integration_error_rel_abs;
2708 Float step_modify_factor = std::min(
Float(100.0),manager->
step.calcStepModifyFactorFromErrorRatio(integration_error_ratio));
2709 ASSERT(step_modify_factor>0.0);
2710 ds[1-ds_switch] *= step_modify_factor;
2711 info.ds = ds[1-ds_switch];
2712 ASSERT(!
ISINF(ds[1-ds_switch]));
2713 #ifdef AR_DEBUG_PRINT
2714 std::cerr<<
"Energy error is small enough for increase step, integration_error_rel_abs="<<integration_error_rel_abs
2715 <<
" energy_error_rel_max="<<energy_error_rel_max<<
" step_modify_factor="<<step_modify_factor<<
" new ds="<<ds[1-ds_switch]<<std::endl;
2721 if(time_end_flag && ds[ds_switch]==ds[1-ds_switch]) {
2724 Float dt_end = _time_end - time_;
2727 step_modify_factor = std::min(std::max(regularStepFactor(manager->
step.calcStepModifyFactorFromErrorRatio(abs(_time_end/dt))),
Float(0.0625)),
Float(0.5));
2728 ASSERT(step_modify_factor>0.0);
2730 ds[ds_switch] *= step_modify_factor;
2731 ds[1-ds_switch] = ds[ds_switch];
2732 ASSERT(!
ISINF(ds[ds_switch]));
2734 else if (n_step_end>1 && dt<0.3*dt_end) {
2737 ds[1-ds_switch] = ds[ds_switch] * dt_end/dt;
2738 ASSERT(!
ISINF(ds[1-ds_switch]));
2739 #ifdef AR_DEEP_DEBUG
2740 std::cerr<<
"Time step dt(real) "<<dt<<
" <0.3*(time_end-time)(real) "<<dt_end<<
" enlarge step factor: "<<dt_end/dt<<
" new ds: "<<ds[1-ds_switch]<<std::endl;
2747 ds[ds_switch] = ds[1-ds_switch];
2748 ASSERT(!
ISINF(ds[ds_switch]));
2749 ds_switch = 1-ds_switch;
2751 if (dt>0) backup_flag =
true;
2752 else backup_flag =
false;
2754 else if(time_ > _time_end + time_error) {
2755 time_end_flag =
true;
2756 backup_flag =
false;
2763 for(i=0; i<cd_pair_size; i++) {
2764 k = manager->
step.getSortCumSumCKIndex(i);
2765 if(_time_end<time_table[k])
break;
2768 ASSERT(time_table[k]>0.0);
2769 ds[ds_switch] *= manager->
step.getSortCumSumCK(i)*_time_end/time_table[k];
2770 ds[1-ds_switch] = ds[ds_switch];
2771 ASSERT(!
ISINF(ds[ds_switch]));
2772 #ifdef AR_DEEP_DEBUG
2773 std::cerr<<
"Time_end reach, time[k]= "<<time_table[k]<<
" time= "<<time_<<
" time_end/time[k]="<<_time_end/time_table[k]<<
" CumSum_CK="<<manager->
step.getSortCumSumCK(i)<<
" ds(next) = "<<ds[ds_switch]<<
" ds(next_next) = "<<ds[1-ds_switch]<<
"\n";
2778 Float time_prev = time_table[manager->
step.getSortCumSumCKIndex(i-1)];
2779 Float dt_k = time_table[k] - time_prev;
2780 Float ds_tmp = ds[ds_switch];
2782 Float cck_prev = manager->
step.getSortCumSumCK(i-1);
2783 Float cck = manager->
step.getSortCumSumCK(i);
2785 ASSERT(!
ISINF(cck_prev));
2786 ds[ds_switch] *= cck_prev;
2787 ASSERT(!
ISINF(ds[ds_switch]));
2790 ds[1-ds_switch] = ds_tmp*(cck-cck_prev)*std::min(
Float(1.0),(_time_end-time_prev+time_error)/dt_k);
2791 ASSERT(!
ISINF(ds[1-ds_switch]));
2793 #ifdef AR_DEEP_DEBUG
2794 std::cerr<<
"Time_end reach, time_prev= "<<time_prev<<
" time[k]= "<<time_table[k]<<
" time= "<<time_<<
" (time_end-time_prev)/dt="<<(_time_end-time_prev)/dt<<
" CumSum_CK="<<cck<<
" CumSum_CK(prev)="<<cck_prev<<
" ds(next) = "<<ds[ds_switch]<<
" ds(next_next) = "<<ds[1-ds_switch]<<
" \n";
2799 #ifdef AR_DEEP_DEBUG
2800 std::cerr<<
"Finish, time_diff_rel = "<<time_diff_rel<<
" integration_error_rel_abs = "<<integration_error_rel_abs<<std::endl;
2822 return bin_interrupt_return;
2831 Float mcm=0.0, pos_cm[3]={0.0,0.0,0.0}, vel_cm[3]={0.0,0.0,0.0};
2833 for (
int i=0; i<particles.
getSize(); i++) {
2834 const Float *ri = particle_data[i].pos;
2835 const Float *vi = particle_data[i].getVel();
2836 const Float mi = particle_data[i].mass;
2838 pos_cm[0] += ri[0] * mi;
2839 pos_cm[1] += ri[1] * mi;
2840 pos_cm[2] += ri[2] * mi;
2842 vel_cm[0] += vi[0] * mi;
2843 vel_cm[1] += vi[1] * mi;
2844 vel_cm[2] += vi[2] * mi;
2854 for (
int i=0; i<particles.
getSize(); i++) {
2855 Float *ri = particle_data[i].pos;
2856 Float *vi = particle_data[i].getVel();
2867 #ifdef AR_SLOWDOWN_ARRAY
2872 template <
class Tptcl>
2873 void writeBackSlowDownParticles(
const Tptcl& _particle_cm) {
2878 const Float kappa_inv = 1.0/binary_slowdown[0]->slowdown.getSlowDownFactor();
2879 for (
int i=0; i<particles.
getSize(); i++) {
2881 particle_adr[i]->mass = particle_data[i].mass;
2883 particle_adr[i]->pos[0] = particle_data[i].pos[0] + _particle_cm.pos[0];
2884 particle_adr[i]->pos[1] = particle_data[i].pos[1] + _particle_cm.pos[1];
2885 particle_adr[i]->pos[2] = particle_data[i].pos[2] + _particle_cm.pos[2];
2887 particle_adr[i]->vel[0] = particle_data[i].vel[0]*kappa_inv + _particle_cm.vel[0];
2888 particle_adr[i]->vel[1] = particle_data[i].vel[1]*kappa_inv + _particle_cm.vel[1];
2889 particle_adr[i]->vel[2] = particle_data[i].vel[2]*kappa_inv + _particle_cm.vel[2];
2893 int nsd= binary_slowdown.
getSize();
2894 for (
int i=1; i<nsd; i++) {
2895 auto& sdi = binary_slowdown[i];
2897 Float kappa = sdi->slowdown.getSlowDownFactor();
2898 Float kappa_inv_m_one = (1.0/kappa - 1.0)*kappa_inv;
2899 Float* velcm = sdi->getVel();
2900 for (
int k=0; k<2; k++) {
2901 int j = sdi->getMemberIndex(k);
2902 ASSERT(j>=0&&j<particles.
getSize());
2903 Float* vel = particle_data[j].getVel();
2906 Float vrel[3] = { vel[0] - velcm[0],
2909 particle_adr[j]->vel[0] += vrel[0] * kappa_inv_m_one;
2910 particle_adr[j]->vel[1] += vrel[1] * kappa_inv_m_one;
2911 particle_adr[j]->vel[2] += vrel[2] * kappa_inv_m_one;
2917 #ifdef AR_SLOWDOWN_TREE
2926 template <
class Tptcl>
2928 Float inv_nest_sd = _inv_nest_sd_up/_bin.slowdown.getSlowDownFactor();
2929 Float* vel_cm = _bin.getVel();
2930 for (
int k=0; k<2; k++) {
2933 Float* vel = bink->getVel();
2934 Float vel_sd[3] = {(vel[0] - vel_cm[0]) * inv_nest_sd + _vel_sd_up[0],
2935 (vel[1] - vel_cm[1]) * inv_nest_sd + _vel_sd_up[1],
2936 (vel[2] - vel_cm[2]) * inv_nest_sd + _vel_sd_up[2]};
2937 writeBackSlowDownParticlesIter(_particle_cm, vel_sd, inv_nest_sd, *bink);
2941 auto& pk = particles[i];
2943 Float* vel = pk.getVel();
2944 Float vel_sd[3] = {(vel[0] - vel_cm[0]) * inv_nest_sd + _vel_sd_up[0],
2945 (vel[1] - vel_cm[1]) * inv_nest_sd + _vel_sd_up[1],
2946 (vel[2] - vel_cm[2]) * inv_nest_sd + _vel_sd_up[2]};
2947 pk_adr->mass = pk.mass;
2949 pk_adr->pos[0] = pk.pos[0] + _particle_cm.pos[0];
2950 pk_adr->pos[1] = pk.pos[1] + _particle_cm.pos[1];
2951 pk_adr->pos[2] = pk.pos[2] + _particle_cm.pos[2];
2953 pk_adr->vel[0] = vel_sd[0] + _particle_cm.vel[0];
2954 pk_adr->vel[1] = vel_sd[1] + _particle_cm.vel[1];
2955 pk_adr->vel[2] = vel_sd[2] + _particle_cm.vel[2];
2964 template <
class Tptcl>
2965 void writeBackSlowDownParticles(
const Tptcl& _particle_cm) {
2967 auto& bin_root=info.getBinaryTreeRoot();
2968 Float vel_cm[3] = {0.0,0.0,0.0};
2969 Float sd_factor=1.0;
2970 writeBackSlowDownParticlesIter(_particle_cm, vel_cm, sd_factor, bin_root);
2977 template <
class Tptcl>
2983 for (
int i=0; i<particles.
getSize(); i++) {
2984 *(Tptcl*)particle_adr[i] = particle_data[i];
2988 for (
int i=0; i<particles.
getSize(); i++) {
2989 Tptcl pc = particle_data[i];
2991 pc.pos[0] = particle_data[i].pos[0] + particles.
cm.pos[0];
2992 pc.pos[1] = particle_data[i].pos[1] + particles.
cm.pos[1];
2993 pc.pos[2] = particle_data[i].pos[2] + particles.
cm.pos[2];
2995 pc.vel[0] = particle_data[i].vel[0] + particles.
cm.vel[0];
2996 pc.vel[1] = particle_data[i].vel[1] + particles.
cm.vel[1];
2997 pc.vel[2] = particle_data[i].vel[2] + particles.
cm.vel[2];
2999 *(Tptcl*)particle_adr[i] = pc;
3036 return ekin_ + epot_;
3044 int n_particle = particles.
getSize();
3045 for (
int i=0; i<n_particle; i++) {
3046 epert += force_[i].pot_pert*particles[i].mass;
3055 return ekin_ + epot_ - etot_ref_;
3060 return -_bk[1] + _bk[2] + _bk[3];
3070 return _bk[2] + _bk[3];
3075 de_change_interrupt_ = 0.0;
3076 dH_change_interrupt_ = 0.0;
3081 return de_change_interrupt_;
3086 return dH_change_interrupt_;
3093 return (ekin_ + epot_ - etot_ref_)/gt_kick_inv_;
3095 return manager->
interaction.calcH(ekin_ - etot_ref_, epot_);
3101 Float& etot_ref =_bk[1];
3102 Float& ekin = _bk[2];
3103 Float& epot = _bk[3];
3105 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
3107 Float& gt_kick_inv = _bk[14];
3110 Float& gt_kick_inv = _bk[7];
3112 return (ekin + epot - etot_ref)/gt_kick_inv;
3115 return manager->
interaction.calcH(ekin - etot_ref, epot);
3121 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
3122 void resetDESlowDownChangeCum() {
3124 de_sd_change_cum_ = 0.0;
3125 dH_sd_change_cum_ = 0.0;
3129 Float getDESlowDownChangeCum()
const {
3130 return de_sd_change_cum_;
3134 Float getDHSlowDownChangeCum()
const {
3135 return dH_sd_change_cum_;
3139 void resetDESlowDownChangeBinaryInterrupt() {
3140 de_sd_change_interrupt_ = 0.0;
3141 dH_sd_change_interrupt_ = 0.0;
3145 Float getDESlowDownChangeBinaryInterrupt()
const {
3146 return de_sd_change_interrupt_;
3150 Float getDHSlowDownChangeBinaryInterrupt()
const {
3151 return dH_sd_change_interrupt_;
3157 Float getEkinSlowDown()
const {
3164 Float getEpotSlowDown()
const {
3171 Float getEtotSlowDownRef()
const {
3172 return etot_sd_ref_;
3178 Float getEtotSlowDown()
const {
3179 return ekin_sd_ + epot_sd_;
3185 Float getEnergyErrorSlowDown()
const {
3186 return ekin_sd_ + epot_sd_ - etot_sd_ref_;
3190 Float getEnergyErrorSlowDownFromBackup(
Float* _bk)
const {
3191 return -_bk[6] + _bk[7] + _bk[8];
3195 Float getHSlowDown()
const {
3198 return (ekin_sd_ + epot_sd_ - etot_sd_ref_)/gt_kick_inv_;
3200 return manager->
interaction.calcH(ekin_sd_ - etot_sd_ref_, epot_sd_);
3205 Float getHSlowDownFromBackup(
Float* _bk)
const {
3206 Float& etot_sd_ref =_bk[6];
3207 Float& ekin_sd = _bk[7];
3208 Float& epot_sd = _bk[8];
3211 Float& gt_kick_inv = _bk[14];
3213 return (ekin_sd + epot_sd - etot_sd_ref)/gt_kick_inv;
3215 return manager->
interaction.calcH(ekin_sd - etot_sd_ref, epot_sd);
3220 Float getEtotSlowDownRefFromBackup(
Float* _bk)
const {
3225 Float getEtotSlowDownFromBackup(
Float* _bk)
const {
3226 return _bk[7] + _bk[8];
3234 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
3252 _bk[bk_size++] = time_;
3253 _bk[bk_size++] = etot_ref_;
3254 _bk[bk_size++] = ekin_;
3255 _bk[bk_size++] = epot_;
3256 _bk[bk_size++] = de_change_interrupt_;
3257 _bk[bk_size++] = dH_change_interrupt_;
3258 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
3259 _bk[bk_size++] = etot_sd_ref_;
3260 _bk[bk_size++] = ekin_sd_;
3261 _bk[bk_size++] = epot_sd_;
3262 _bk[bk_size++] = de_sd_change_cum_;
3263 _bk[bk_size++] = dH_sd_change_cum_;
3264 _bk[bk_size++] = de_sd_change_interrupt_;
3265 _bk[bk_size++] = dH_sd_change_interrupt_;
3269 _bk[bk_size++] = gt_drift_inv_;
3270 _bk[bk_size++] = gt_kick_inv_;
3286 time_ = _bk[bk_size++];
3287 etot_ref_ = _bk[bk_size++];
3288 ekin_ = _bk[bk_size++];
3289 epot_ = _bk[bk_size++];
3290 de_change_interrupt_= _bk[bk_size++];
3291 dH_change_interrupt_= _bk[bk_size++];
3293 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
3294 etot_sd_ref_ = _bk[bk_size++];
3295 ekin_sd_ = _bk[bk_size++];
3296 epot_sd_ = _bk[bk_size++];
3298 de_sd_change_cum_= _bk[bk_size++];
3299 dH_sd_change_cum_= _bk[bk_size++];
3300 de_sd_change_interrupt_= _bk[bk_size++];
3301 dH_sd_change_interrupt_= _bk[bk_size++];
3304 gt_drift_inv_ = _bk[bk_size++];
3305 gt_kick_inv_ = _bk[bk_size++];
3320 Float getGTDriftInv()
const {
3321 return gt_drift_inv_;
3332 template<
class Tptcl>
3333 void printGroupInfo(
const int _type, std::ostream& _fout,
const int _width,
const Tptcl* _pcm=NULL) {
3334 auto& bin_root = info.getBinaryTreeRoot();
3338 bool reset_flag = (_type==1 && bin_root.semi<0 && bin_root.ecca>0);
3340 if (info.checkAndSetBinaryPairIDIter(bin_root, reset_flag)) {
3341 if (_type==0)
return;
3342 else if (!reset_flag)
return;
3345 Float pos_cm[3], vel_cm[3];
3346 auto& pcm_loc = particles.
cm;
3348 pos_cm[0] = pcm_loc.pos[0] + _pcm->pos[0];
3349 pos_cm[1] = pcm_loc.pos[1] + _pcm->pos[1];
3350 pos_cm[2] = pcm_loc.pos[2] + _pcm->pos[2];
3351 vel_cm[0] = pcm_loc.vel[0] + _pcm->vel[0];
3352 vel_cm[1] = pcm_loc.vel[1] + _pcm->vel[1];
3353 vel_cm[2] = pcm_loc.vel[2] + _pcm->vel[2];
3356 pos_cm[0] = pcm_loc.pos[0];
3357 pos_cm[1] = pcm_loc.pos[1];
3358 pos_cm[2] = pcm_loc.pos[2];
3359 vel_cm[0] = pcm_loc.vel[0];
3360 vel_cm[1] = pcm_loc.vel[1];
3361 vel_cm[2] = pcm_loc.vel[2];
3363 #pragma omp critical
3365 _fout<<std::setw(_width)<<_type
3366 <<std::setw(_width)<<bin_root.getMemberN()
3367 <<std::setw(_width)<<time_ + info.time_offset;
3368 _fout<<std::setw(_width)<<pos_cm[0]
3369 <<std::setw(_width)<<pos_cm[1]
3370 <<std::setw(_width)<<pos_cm[2]
3371 <<std::setw(_width)<<vel_cm[0]
3372 <<std::setw(_width)<<vel_cm[1]
3373 <<std::setw(_width)<<vel_cm[2];
3374 bin_root.printBinaryTreeIter(_fout, _width);
3394 _fout<<std::setw(_width)<<
"Time"
3395 <<std::setw(_width)<<
"dE"
3396 <<std::setw(_width)<<
"Etot"
3397 <<std::setw(_width)<<
"Ekin"
3398 <<std::setw(_width)<<
"Epot"
3399 <<std::setw(_width)<<
"Gt_drift"
3400 <<std::setw(_width)<<
"H"
3401 <<std::setw(_width)<<
"dE_intr"
3402 <<std::setw(_width)<<
"dH_intr";
3403 perturber.printColumnTitle(_fout, _width);
3404 info.printColumnTitle(_fout, _width);
3406 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
3407 _fout<<std::setw(_width)<<
"dE_SD"
3408 <<std::setw(_width)<<
"Etot_SD"
3409 <<std::setw(_width)<<
"Ekin_SD"
3410 <<std::setw(_width)<<
"Epot_SD"
3411 <<std::setw(_width)<<
"dE_SDC_cum"
3412 <<std::setw(_width)<<
"dH_SDC_cum"
3413 <<std::setw(_width)<<
"dE_SDC_intr"
3414 <<std::setw(_width)<<
"dH_SDC_intr";
3415 _fout<<std::setw(_width)<<
"N_SD";
3416 for (
int i=0; i<_n_sd; i++) {
3417 _fout<<std::setw(_width)<<
"I1"
3418 <<std::setw(_width)<<
"I2";
3419 SlowDown::printColumnTitle(_fout, _width);
3431 void printColumn(std::ostream & _fout,
const int _width=20,
const int _n_sd=0){
3432 _fout<<std::setw(_width)<<getTime()
3433 <<std::setw(_width)<<getEnergyError()
3434 <<std::setw(_width)<<etot_ref_
3435 <<std::setw(_width)<<ekin_
3436 <<std::setw(_width)<<epot_
3437 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
3439 <<std::setw(_width)<<1.0/gt_drift_inv_
3441 <<std::setw(_width)<<1.0/manager->
interaction.calcGTDriftInv(ekin_sd_-etot_sd_ref_)
3443 <<std::setw(_width)<<getHSlowDown()
3446 <<std::setw(_width)<<1.0/gt_drift_inv_
3448 <<std::setw(_width)<<1.0/manager->
interaction.calcGTDriftInv(ekin_-etot_ref_)
3450 <<std::setw(_width)<<getH()
3452 <<std::setw(_width)<<de_change_interrupt_
3453 <<std::setw(_width)<<dH_change_interrupt_;
3454 perturber.printColumn(_fout, _width);
3455 info.printColumn(_fout, _width);
3457 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
3458 _fout<<std::setw(_width)<<getEnergyErrorSlowDown()
3459 <<std::setw(_width)<<etot_sd_ref_
3460 <<std::setw(_width)<<ekin_sd_
3461 <<std::setw(_width)<<epot_sd_
3462 <<std::setw(_width)<<de_sd_change_cum_
3463 <<std::setw(_width)<<dH_sd_change_cum_
3464 <<std::setw(_width)<<de_sd_change_interrupt_
3465 <<std::setw(_width)<<dH_sd_change_interrupt_;
3467 #ifdef AR_SLOWDOWN_ARRAY
3468 int n_sd_now = binary_slowdown.
getSize();
3469 _fout<<std::setw(_width)<<n_sd_now;
3470 for (
int i=0; i<_n_sd; i++) {
3472 _fout<<std::setw(_width)<<binary_slowdown[i]->getMemberIndex(0)
3473 <<std::setw(_width)<<binary_slowdown[i]->getMemberIndex(1);
3474 binary_slowdown[i]->slowdown.printColumn(_fout, _width);
3477 _fout<<std::setw(_width)<<-1
3478 <<std::setw(_width)<<-1;
3483 int n_sd_now = info.binarytree.getSize();
3484 _fout<<std::setw(_width)<<n_sd_now;
3485 for (
int i=0; i<_n_sd; i++) {
3487 _fout<<std::setw(_width)<<info.binarytree[i].getMemberIndex(0)
3488 <<std::setw(_width)<<info.binarytree[i].getMemberIndex(1);
3489 info.binarytree[i].slowdown.printColumn(_fout, _width);
3492 _fout<<std::setw(_width)<<-1
3493 <<std::setw(_width)<<-1;
3506 fwrite(&time_,
sizeof(
Float), 1, _fout);
3507 fwrite(&etot_ref_,
sizeof(
Float), 1, _fout);
3508 fwrite(&ekin_,
sizeof(
Float), 1, _fout);
3509 fwrite(&epot_,
sizeof(
Float), 1, _fout);
3511 fwrite(>_drift_inv_,
sizeof(
Float), 1, _fout);
3514 fwrite(&size,
sizeof(
int), 1, _fout);
3515 for (
int i=0; i<size; i++) force_[i].writeBinary(_fout);
3518 perturber.writeBinary(_fout);
3519 info.writeBinary(_fout);
3527 size_t rcount = fread(&time_,
sizeof(
Float), 1, _fin);
3528 rcount += fread(&etot_ref_,
sizeof(
Float), 1, _fin);
3529 rcount += fread(&ekin_,
sizeof(
Float), 1, _fin);
3530 rcount += fread(&epot_,
sizeof(
Float), 1, _fin);
3532 std::cerr<<
"Error: Data reading fails! requiring data number is 4, only obtain "<<rcount<<
".\n";
3536 rcount = fread(>_drift_inv_,
sizeof(
Float), 1, _fin);
3538 std::cerr<<
"Error: Data reading fails! requiring data number is 1, only obtain "<<rcount<<
".\n";
3543 rcount = fread(&size,
sizeof(
int),1, _fin);
3545 std::cerr<<
"Error: Data reading fails! requiring data number is 1, only obtain "<<rcount<<
".\n";
3549 std::cerr<<
"Error: array size <0 "<<size<<
"<=0!\n";
3556 for (
int i=0; i<size; i++) force_[i].readBinary(_fin);
3561 perturber.readBinary(_fin);
3562 info.readBinary(_fin);