3 #include "Common/Float.h"
4 #include "Common/binary_tree.h"
8 #include "Hermite/hermite_particle.h"
18 typedef H4::ParticleH4<PtclHard>
H4Ptcl;
21 #ifdef STELLAR_EVOLUTION
22 int stellar_evolution_option;
23 bool stellar_evolution_write_flag;
24 Float time_interrupt_max;
28 std::ofstream fout_sse;
29 std::ofstream fout_bse;
32 stellar_evolution_option(1), stellar_evolution_write_flag(true), time_interrupt_max(NUMERIC_FLOAT_MAX),
33 bse_manager(), fout_sse(), fout_bse() {}
36 stellar_evolution_option(0), stellar_evolution_write_flag(true), time_interrupt_max(NUMERIC_FLOAT_MAX){}
48 #ifdef STELLAR_EVOLUTION
49 ASSERT(time_interrupt_max>=0.0);
52 ASSERT(!stellar_evolution_write_flag||(stellar_evolution_write_flag&&fout_sse.is_open()));
53 ASSERT(!stellar_evolution_write_flag||(stellar_evolution_write_flag&&fout_bse.is_open()));
60 void print(std::ostream & _fout)
const{
61 _fout<<
"eps_sq : "<<
eps_sq<<std::endl
63 #ifdef STELLAR_EVOLUTION
64 _fout<<
"SE_opt : "<<stellar_evolution_option<<std::endl;
79 const Float mass1 = _p1.
mass;
80 const Float* pos1 = &_p1.
pos.x;
82 const Float mass2 = _p2.
mass;
83 const Float* pos2 = &_p2.
pos.x;
87 Float gm1m2 = gm1*mass2;
89 Float dr[3] = {pos2[0] -pos1[0],
92 Float r2 = dr[0]*dr[0] + dr[1]*dr[1] + dr[2]*dr[2];
93 Float inv_r = 1.0/sqrt(r2);
94 Float inv_r3 = inv_r*inv_r*inv_r;
96 Float* acc1 = _f1.acc_in;
97 Float* acc2 = _f2.acc_in;
107 Float gmor3_1 = gm2*inv_r3*k;
108 Float gmor3_2 = gm1*inv_r3*k;
110 Float inv_rk = inv_r*kpot;
111 Float gm1or = gm1*inv_rk;
112 Float gm2or = gm2*inv_rk;
113 Float gm1m2or = gm1m2*inv_rk;
115 Float gmor3_1 = gm2*inv_r3;
116 Float gmor3_2 = gm1*inv_r3;
118 Float gm1or = gm1*inv_r;
119 Float gm2or = gm2*inv_r;
120 Float gm1m2or = gm1m2*inv_r;
123 acc1[0] = gmor3_1 * dr[0];
124 acc1[1] = gmor3_1 * dr[1];
125 acc1[2] = gmor3_1 * dr[2];
129 acc2[0] = - gmor3_2 * dr[0];
130 acc2[1] = - gmor3_2 * dr[1];
131 acc2[2] = - gmor3_2 * dr[2];
139 Float gm1m2or3 = gm1m2*inv_r3*k;
141 Float gm1m2or3 = gm1m2*inv_r3;
143 Float* gtgrad1 = _f1.gtgrad;
144 Float* gtgrad2 = _f2.gtgrad;
145 gtgrad1[0] = gm1m2or3 * dr[0];
146 gtgrad1[1] = gm1m2or3 * dr[1];
147 gtgrad1[2] = gm1m2or3 * dr[2];
149 gtgrad2[0] = - gtgrad1[0];
150 gtgrad2[1] = - gtgrad1[1];
151 gtgrad2[2] = - gtgrad1[2];
158 Float gt_kick_inv = gm1m2or;
173 Float gt_kick_inv = Float(0.0);
175 for (
int i=0; i<_n_particle; i++) {
176 const Float massi = _particles[i].
mass;
177 const Float* posi = &_particles[i].
pos.x;
178 Float* acci = _force[i].acc_in;
179 acci[0] = acci[1] = acci[2] = Float(0.0);
182 Float* gtgradi = _force[i].gtgrad;
183 gtgradi[0] = gtgradi[1] = gtgradi[2] = Float(0.0);
186 Float poti = Float(0.0);
187 Float gtki = Float(0.0);
189 for (
int j=0; j<_n_particle; j++) {
191 const Float massj = _particles[j].
mass;
192 const Float* posj = &_particles[j].
pos.x;
193 Float dr[3] = {posj[0] -posi[0],
196 Float r2 = dr[0]*dr[0] + dr[1]*dr[1] + dr[2]*dr[2];
197 Float inv_r = 1.0/sqrt(r2);
198 Float inv_r3 = inv_r*inv_r*inv_r;
210 acci[0] += gmor3 * dr[0];
211 acci[1] += gmor3 * dr[1];
212 acci[2] += gmor3 * dr[2];
215 Float gmimjor3 = massi*gmor3;
216 gtgradi[0] += gmimjor3 * dr[0];
217 gtgradi[1] += gmimjor3 * dr[1];
218 gtgradi[2] += gmimjor3 * dr[2];
225 _epot += poti * massi;
226 gt_kick_inv += gtki * massi;
243 static const Float inv3 = 1.0 / 3.0;
246 const int n_pert = _perturber.neighbor_address.getSize();
247 const int n_pert_single = _perturber.n_neighbor_single;
248 const int n_pert_group = _perturber.n_neighbor_group;
254 auto* pert_adr = _perturber.neighbor_address.getDataAddress();
256 Float xp[n_pert][3], xcm[3], m[n_pert];
258 H4::NBAdr<PtclHard>::Group* ptclgroup[n_pert_group];
260 int n_single_count=0;
262 for (
int j=0; j<n_pert; j++) {
263 H4::NBAdr<PtclHard>::Single* pertj;
265 if (pert_adr[j].type==H4::NBType::group) {
266 pertj = &(((H4::NBAdr<PtclHard>::Group*)pert_adr[j].adr)->cm);
267 k = n_group_count + n_pert_single;
268 ptclgroup[n_group_count] = (H4::NBAdr<PtclHard>::Group*)pert_adr[j].adr;
272 pertj = (H4::NBAdr<PtclHard>::Single*)pert_adr[j].adr;
274 changeover[n_single_count] = &pertj->changeover;
278 Float
dt = time - pertj->time;
280 xp[k][0] = pertj->pos[0] +
dt*(pertj->vel[0] + 0.5*
dt*(pertj->acc0[0] + inv3*
dt*pertj->acc1[0]));
281 xp[k][1] = pertj->pos[1] +
dt*(pertj->vel[1] + 0.5*
dt*(pertj->acc0[1] + inv3*
dt*pertj->acc1[1]));
282 xp[k][2] = pertj->pos[2] +
dt*(pertj->vel[2] + 0.5*
dt*(pertj->acc0[2] + inv3*
dt*pertj->acc1[2]));
287 ASSERT(n_single_count == n_pert_single);
288 ASSERT(n_group_count == n_pert_group);
290 Float
dt = time - _particle_cm.time;
292 xcm[0] = _particle_cm.pos[0] +
dt*(_particle_cm.vel[0] + 0.5*
dt*(_particle_cm.acc0[0] + inv3*
dt*_particle_cm.acc1[0]));
293 xcm[1] = _particle_cm.pos[1] +
dt*(_particle_cm.vel[1] + 0.5*
dt*(_particle_cm.acc0[1] + inv3*
dt*_particle_cm.acc1[1]));
294 xcm[2] = _particle_cm.pos[2] +
dt*(_particle_cm.vel[2] + 0.5*
dt*(_particle_cm.acc0[2] + inv3*
dt*_particle_cm.acc1[2]));
297 Float acc_pert_cm[3]={0.0, 0.0, 0.0};
301 for (
int i=0; i<_n_particle; i++) {
302 Float* acc_pert = _force[i].acc_pert;
303 Float& pot_pert = _force[i].pot_pert;
304 const auto& pi = _particles[i];
306 acc_pert[0] = acc_pert[1] = acc_pert[2] = Float(0.0);
310 xi[0] = pi.pos[0] + xcm[0];
311 xi[1] = pi.pos[1] + xcm[1];
312 xi[2] = pi.pos[2] + xcm[2];
315 for (
int j=0; j<n_pert_single; j++) {
316 Float dr[3] = {xp[j][0] - xi[0],
319 Float r2 = dr[0]*dr[0] + dr[1]*dr[1] + dr[2]*dr[2] +
eps_sq;
324 Float gmor3 = gm/r3 * k;
326 acc_pert[0] += gmor3 * dr[0];
327 acc_pert[1] += gmor3 * dr[1];
328 acc_pert[2] += gmor3 * dr[2];
332 for (
int j=n_pert_single; j<n_pert; j++) {
333 Float dr[3] = {xp[j][0] - xi[0],
336 Float r2 = dr[0]*dr[0] + dr[1]*dr[1] + dr[2]*dr[2] +
eps_sq;
338 const int jk = j-n_pert_single;
339 auto* ptcl_mem = ptclgroup[jk]->getDataAddress();
341 for (
int k=0; k<ptclgroup[jk]->getSize(); k++) {
347 acc_pert[0] += gmor3 * dr[0];
348 acc_pert[1] += gmor3 * dr[1];
349 acc_pert[2] += gmor3 * dr[2];
353 acc_pert_cm[0] += pi.mass *acc_pert[0];
354 acc_pert_cm[1] += pi.mass *acc_pert[1];
355 acc_pert_cm[2] += pi.mass *acc_pert[2];
365 acc_pert_cm[0] /= mcm;
366 acc_pert_cm[1] /= mcm;
367 acc_pert_cm[2] /= mcm;
370 for (
int i=0; i<_n_particle; i++) {
371 Float* acc_pert = _force[i].acc_pert;
372 Float& pot_pert = _force[i].pot_pert;
373 const auto& pi = _particles[i];
374 acc_pert[0] -= acc_pert_cm[0];
375 acc_pert[1] -= acc_pert_cm[1];
376 acc_pert[2] -= acc_pert_cm[2];
378 pot_pert -= acc_pert[0]*pi.
pos[0] + acc_pert[1]*pi.pos[1] + acc_pert[2]*pi.pos[2];
383 if (pi.pos*pi.pos<pi.changeover.getRout()*pi.changeover.getRout()) {
395 for(
int i=0; i<_n_particle; i++) {
396 Float* acc_pert = _force[i].acc_pert;
397 Float& pot_pert = _force[i].pot_pert;
398 const auto& pi = _particles[i];
399 acc_pert[0] = acc_pert[1] = acc_pert[2] = pot_pert = Float(0.0);
401 if (pi.pos*pi.pos<pi.changeover.getRout()*pi.changeover.getRout()) {
428 calcAccPert(_force, _particles, _n_particle, _particle_cm, _perturber, _time);
436 Float force2 = _force[0]*_force[0]+_force[1]*_force[1]+_force[2]*_force[2];
437 #ifdef AR_SLOWDOWN_PERT_R4
441 return sqrt(force/(_mp*_mpert))*force;
447 Float apo = _bin.semi*(1.0+_bin.ecc);
448 Float apo2 = apo*apo;
449 #ifdef AR_SLOWDOWN_PERT_R4
450 return (_bin.m1*_bin.m2)/(apo2*apo2);
452 return (_bin.m1*_bin.m2)/(apo2*apo);
457 static Float
calcPertFromMR(
const Float _r,
const Float _mp,
const Float _mpert) {
459 #ifdef AR_SLOWDOWN_PERT_R4
460 return _mp*_mpert/(r2*r2);
462 return (_mp*_mpert)/(r2*_r);
466 #if (defined AR_SLOWDOWN_ARRAY) || (defined AR_SLOWDOWN_TREE)
469 void calcSlowDownTimeScale(Float& _t_min_sq,
const Float dv[3],
const Float dr[3],
const Float& r,
const Float& gm) {
472 Float v2 = dv[0]*dv[0] + dv[1]*dv[1] + dv[2]*dv[2];
473 Float drdv = dr[0]*dv[0] + dr[1]*dv[1] + dr[2]*dv[2];
475 Float semi = 1.0/(2.0/r - v2/gm);
478 _t_min_sq =
std::min(_t_min_sq, r2/v2);
480 Float ra_fact = (1 - r/semi);
481 Float e2 = drdv*drdv/(gm*semi) + ra_fact*ra_fact;
482 Float r_vrmax = semi*(1-e2);
487 Float vrmax_sq = e2*gm/r_vrmax;
492 _t_min_sq =
std::min(_t_min_sq, semi*semi/vrmax_sq);
496 Float rovr = r2/abs(drdv);
497 _t_min_sq =
std::min(_t_min_sq, rovr*rovr);
509 void calcSlowDownPertOne(Float& _pert_out, Float& _t_min_sq,
const PtclHard& pi,
const PtclHard& pj) {
510 Float dr[3] = {pj.
pos[0] - pi.
pos[0],
513 Float r2 = dr[0]*dr[0] + dr[1]*dr[1] + dr[2]*dr[2];
517 #ifdef AR_SLOWDOWN_TIMESCALE
518 Float dv[3] = {pj.
vel[0] - pi.
vel[0],
525 calcSlowDownTimeScale(_t_min_sq, dv, dr, r, gm);
541 void calcSlowDownPert(Float& _pert_out, Float& _t_min_sq,
const Float& _time,
const H4Ptcl& _particle_cm,
const ARPerturber& _perturber) {
542 static const Float inv3 = 1.0 / 3.0;
544 const int n_pert = _perturber.neighbor_address.getSize();
548 auto* pert_adr = _perturber.neighbor_address.getDataAddress();
551 Float
dt = _time - _particle_cm.time;
553 xcm[0] = _particle_cm.pos[0] +
dt*(_particle_cm.vel[0] + 0.5*
dt*(_particle_cm.acc0[0] + inv3*
dt*_particle_cm.acc1[0]));
554 xcm[1] = _particle_cm.pos[1] +
dt*(_particle_cm.vel[1] + 0.5*
dt*(_particle_cm.acc0[1] + inv3*
dt*_particle_cm.acc1[1]));
555 xcm[2] = _particle_cm.pos[2] +
dt*(_particle_cm.vel[2] + 0.5*
dt*(_particle_cm.acc0[2] + inv3*
dt*_particle_cm.acc1[2]));
557 Float mcm = _particle_cm.mass;
558 auto& chi = _particle_cm.changeover;
560 #ifdef AR_SLOWDOWN_TIMESCALE
564 vcm[0] = _particle_cm.vel[0] +
dt*(_particle_cm.acc0[0] + 0.5*
dt*_particle_cm.acc1[0]);
565 vcm[1] = _particle_cm.vel[1] +
dt*(_particle_cm.acc0[1] + 0.5*
dt*_particle_cm.acc1[1]);
566 vcm[2] = _particle_cm.vel[2] +
dt*(_particle_cm.acc0[2] + 0.5*
dt*_particle_cm.acc1[2]);
569 for (
int j=0; j<n_pert; j++) {
570 H4::NBAdr<PtclHard>::Single* pertj;
571 if (pert_adr[j].type==H4::NBType::group) pertj = &(((H4::NBAdr<PtclHard>::Group*)pert_adr[j].adr)->cm);
572 else pertj = (H4::NBAdr<PtclHard>::Single*)pert_adr[j].adr;
574 Float
dt = _time - pertj->time;
576 xp[0] = pertj->pos[0] +
dt*(pertj->vel[0] + 0.5*
dt*(pertj->acc0[0] + inv3*
dt*pertj->acc1[0]));
577 xp[1] = pertj->pos[1] +
dt*(pertj->vel[1] + 0.5*
dt*(pertj->acc0[1] + inv3*
dt*pertj->acc1[1]));
578 xp[2] = pertj->pos[2] +
dt*(pertj->vel[2] + 0.5*
dt*(pertj->acc0[2] + inv3*
dt*pertj->acc1[2]));
580 Float mj = pertj->mass;
582 auto& chj = pertj->changeover;
584 Float dr[3] = {xp[0] - xcm[0],
588 Float r2 = dr[0]*dr[0] + dr[1]*dr[1] + dr[2]*dr[2] +
eps_sq;
593 #ifdef AR_SLOWDOWN_TIMESCALE
595 vp[0] = pertj->vel[0] +
dt*(pertj->acc0[0] + 0.5*
dt*pertj->acc1[0]);
596 vp[1] = pertj->vel[1] +
dt*(pertj->acc0[1] + 0.5*
dt*pertj->acc1[1]);
597 vp[2] = pertj->vel[2] +
dt*(pertj->acc0[2] + 0.5*
dt*pertj->acc1[2]);
599 Float dv[3] = {vp[0] - vcm[0],
606 calcSlowDownTimeScale(_t_min_sq, dv, dr, r, gm);
612 _pert_out += _perturber.soft_pert_min;
624 template <
class Tparticle>
626 #ifdef STELLAR_EVOLUTION
636 if (_p.time_interrupt<=_time_end&&stellar_evolution_option>0) {
642 Float
dt = _time_end - _p.time_record;
647 int event_flag = bse_manager.
evolveStar(_p.star, output,
dt);
651 std::cerr<<
"SSE Error: ID= "<<_p.id;
652 _p.star.print(std::cerr);
653 output.
print(std::cerr);
654 std::cerr<<std::endl;
656 std::cout<<std::flush;
657 std::cerr<<std::flush;
662 double dt_miss = bse_manager.
getDTMiss(output);
663 _p.time_record +=
dt-dt_miss;
671 if (dm==0.0) modify_flag = 0;
674 _p.mass = bse_manager.
getMass(_p.star);
680 if (stellar_evolution_write_flag&&event_flag>=1) {
683 fout_sse<<
"Type_change ";
698 for (
int k=0; k<3; k++) _p.vel[k] += dv[k];
700 if (stellar_evolution_write_flag) {
713 _p.group_data.artificial.setParticleTypeToUnused();
721 #endif // STELLAR_EVOLUTION
732 int modify_return = 0;
733 #ifdef STELLAR_EVOLUTION
734 int modify_branch[2];
735 if (_bin.getMemberN()>2) {
736 for (
int k=0; k<2; k++) {
737 if (_bin.isMemberTree(k)) {
739 modify_return =
std::max(modify_return, modify_branch[k]);
743 else if (stellar_evolution_option>0) {
745 modify_branch[k] =
modifyOneParticle(*_bin.getMember(k), _bin.getMember(k)->time_record, _bin_interrupt.time_now);
746 modify_return =
std::max(modify_return, modify_branch[k]);
748 if (modify_branch[k]>0&&_bin_interrupt.status == AR::InterruptStatus::none) {
749 _bin_interrupt.status = AR::InterruptStatus::change;
750 _bin_interrupt.adr = &_bin;
756 if (modify_branch[0]>0&&modify_branch[1]>0) {
757 _bin_interrupt.adr = &_bin;
759 if (_bin_interrupt.status == AR::InterruptStatus::destroy) {
761 if (!(modify_branch[0]==3&&modify_branch[1]==3))
762 _bin_interrupt.status = AR::InterruptStatus::merge;
766 auto* p1 = _bin.getLeftMember();
767 auto* p2 = _bin.getRightMember();
769 COMM::Vector3<Float> pos_red(p2->pos[0] - p1->pos[0], p2->pos[1] - p1->pos[1], p2->pos[2] - p1->pos[2]);
770 COMM::Vector3<Float> vel_red(p2->vel[0] - p1->vel[0], p2->vel[1] - p1->vel[1], p2->vel[2] - p1->vel[2]);
771 Float drdv = pos_red * vel_red;
774 auto postProcess =[&](
StarParameterOut* out, Float* pos_cm, Float*vel_cm, Float& semi, Float& ecc,
int binary_type_final) {
776 if (_bin_interrupt.status == AR::InterruptStatus::none)
777 _bin_interrupt.status = AR::InterruptStatus::change;
782 p1->time_record = _bin_interrupt.time_now - bse_manager.
getDTMiss(out[0]);
783 p2->time_record = _bin_interrupt.time_now - bse_manager.
getDTMiss(out[1]);
786 p1->time_interrupt =
std::min(p1->time_record + bse_manager.
getTimeStepBinary(p1->star, p2->star, semi, ecc, binary_type_final), time_interrupt_max);
787 p2->time_interrupt = p1->time_interrupt;
807 p1->mass = bse_manager.
getMass(p1->star);
808 p2->mass = bse_manager.
getMass(p2->star);
815 bool mass_zero_flag =
false;
818 if (p1->mass==0.0&&p2->mass==0.0) {
819 p1->group_data.artificial.setParticleTypeToUnused();
820 p2->group_data.artificial.setParticleTypeToUnused();
821 _bin_interrupt.status = AR::InterruptStatus::destroy;
823 mass_zero_flag =
true;
828 p1->group_data.artificial.setParticleTypeToUnused();
829 _bin_interrupt.status = AR::InterruptStatus::merge;
833 for (
int k=0; k<3; k++) {
834 p2->pos[k] = pos_cm[k];
835 p2->vel[k] = vel_cm[k];
838 mass_zero_flag =
true;
842 p2->group_data.artificial.setParticleTypeToUnused();
843 _bin_interrupt.status = AR::InterruptStatus::merge;
847 for (
int k=0; k<3; k++) {
848 p1->pos[k] = pos_cm[k];
849 p1->vel[k] = vel_cm[k];
852 mass_zero_flag =
true;
856 bool kick_flag=
false;
857 for (
int k=0; k<2; k++) {
859 auto* pk = _bin.getMember(k);
873 for (
int k=0; k<3; k++) pk->vel[k] += dv[k];
877 if (!kick_flag && !mass_zero_flag) {
879 if (ecc>=0.0&&ecc<=1.0) {
904 if(_bin.semi>0) _bin.semi = -_bin.semi;
920 if (mass_zero_flag) {
926 bool check_flag =
false;
927 if (stellar_evolution_option>0) {
928 int binary_type_p1 =
static_cast<int>(p1->getBinaryInterruptState());
929 int binary_type_p2 =
static_cast<int>(p2->getBinaryInterruptState());
930 int binary_type_init = 0;
931 if (binary_type_p1==binary_type_p2) binary_type_init = binary_type_p1;
934 double time_check =
std::min(p1->time_interrupt, p2->time_interrupt);
935 Float
dt = _bin_interrupt.time_now -
std::max(p1->time_record,p2->time_record);
936 if (time_check<=_bin_interrupt.time_now&&dt>0) check_flag =
true;
940 Float t_record_min =
std::min(p1->time_record,p2->time_record);
943 if (t_record_min<_bin_interrupt.time_now&&_bin.semi>0 && (!bse_manager.
isMassTransfer(binary_type_init)) && (!bse_manager.
isDisrupt(binary_type_init))) {
944 check_flag=bse_manager.
isCallBSENeeded(p1->star, p2->star, _bin.semi, _bin.ecc,
dt);
951 _bin_interrupt.adr = &_bin;
954 if (p1->time_record!=p2->time_record) {
955 if (p1->time_record<p2->time_record) {
956 p1->time_interrupt = p1->time_record;
960 p2->time_interrupt = p2->time_record;
964 Float
dt = _bin_interrupt.time_now -
std::max(p1->time_record,p2->time_record);
969 Float ecc = _bin.ecc;
971 Float semi = _bin.semi;
973 Float mtot = p1->mass+p2->mass;
974 Float period = _bin.period;
978 Float pos_cm[3], vel_cm[3];
979 for (
int k=0; k<3; k++) {
980 pos_cm[k] = (p1->mass*p1->pos[k] + p2->mass*p2->pos[k])/mtot;
981 vel_cm[k] = (p1->mass*p1->vel[k] + p2->mass*p2->vel[k])/mtot;
989 int event_flag = bse_manager.
evolveBinary(p1->star, p2->star, out[0], out[1], semi, period, ecc, bin_event, binary_type_init,
dt);
993 std::cerr<<
"BSE Error! ";
994 std::cerr<<
" ID="<<p1->id<<
" "<<p2->id<<
" ";
995 std::cerr<<
" semi[R*]: "
996 <<_bin.semi*bse_manager.
rscale
999 std::cerr<<
" Init: Star1: ";
1000 p1_star_bk.
print(std::cerr);
1001 std::cerr<<
" Star2: ";
1002 p2_star_bk.
print(std::cerr);
1003 std::cerr<<
" final: Star1: ";
1004 p1->star.print(std::cerr);
1005 out[0].
print(std::cerr);
1006 std::cerr<<
" Star2: ";
1007 p2->star.print(std::cerr);
1008 out[1].
print(std::cerr);
1009 std::cerr<<std::endl;
1012 std::cout<<std::flush;
1013 std::cerr<<std::flush;
1018 int binary_type_final=0;
1021 for (
int i=0; i<nmax; i++) {
1022 int binary_type = bin_event.
getType(i);
1023 if (binary_type>0) {
1024 bool first_event = (i==0);
1025 if (stellar_evolution_write_flag) {
1026 if ((first_event&&binary_type_init!=binary_type)||!first_event) {
1028 #pragma omp critical
1035 fout_bse<<std::endl;
1049 if (binary_type>0) event_flag =
std::max(event_flag, 1);
1051 else if (bse_manager.
isDisrupt(binary_type)) event_flag =
std::max(event_flag, 3);
1052 else if (bse_manager.
isMerger(binary_type)) event_flag =
std::max(event_flag, 4);
1053 binary_type_final = binary_type;
1055 else if(binary_type<0)
break;
1059 mtot = bse_manager.
getMass(p1->star) + bse_manager.
getMass(p2->star);
1062 postProcess(out, pos_cm, vel_cm, semi, ecc, binary_type_final);
1068 if (_bin_interrupt.status!=AR::InterruptStatus::merge&&_bin_interrupt.status!=AR::InterruptStatus::destroy) {
1070 auto merge = [&](
const Float& dr,
const Float& t_peri,
const Float& sd_factor) {
1071 _bin_interrupt.adr = &_bin;
1079 if (stellar_evolution_option>0) {
1080 if (p1->time_record<_bin_interrupt.time_now) {
1081 p1->time_interrupt = p1->time_record;
1084 if (p2->time_record<_bin_interrupt.time_now) {
1085 p2->time_interrupt = p2->time_record;
1089 ASSERT(p1->star.tphys==p2->star.tphys);
1094 Float pos_cm[3], vel_cm[3];
1095 Float mtot = p1->mass+p2->mass;
1097 for (
int k=0; k<3; k++) {
1098 pos_cm[k] = (p1->mass*p1->pos[k] + p2->mass*p2->pos[k])/mtot;
1099 vel_cm[k] = (p1->mass*p1->vel[k] + p2->mass*p2->vel[k])/mtot;
1102 p1_star_bk = p1->star;
1103 p2_star_bk = p2->star;
1105 Float semi = _bin.semi;
1106 Float ecc = _bin.ecc;
1107 bse_manager.
merge(p1->star, p2->star, out[0], out[1], semi, ecc);
1109 postProcess(out, pos_cm, vel_cm, semi, ecc, 0);
1110 if (stellar_evolution_write_flag&&(p1->mass==0.0||p2->mass==0.0)) {
1111 #pragma omp critical
1113 fout_bse<<
"Dynamic_merge: "
1119 #ifndef DYNAMIC_MERGER_LESS_OUTPUT
1130 fout_bse<<std::endl;
1137 #else //not BSE_BASE
1139 std::cerr<<
"Binary Merge: time: "<<_bin_interrupt.time_now<<std::endl;
1140 _bin.Binary::printColumnTitle(std::cerr);
1143 std::cerr<<std::endl;
1144 _bin.Binary::printColumn(std::cerr);
1147 std::cerr<<std::endl;
1152 p1->time_record = _bin_interrupt.time_now;
1153 p2->time_record = _bin_interrupt.time_now;
1156 Float mcm = p1->mass + p2->mass;
1157 for (
int k=0; k<3; k++) {
1158 p1->pos[k] = (p1->mass*p1->pos[k] + p2->mass*p2->pos[k])/mcm;
1159 p1->vel[k] = (p1->mass*p1->vel[k] + p2->mass*p2->vel[k])/mcm;
1169 if (_bin_interrupt.status == AR::InterruptStatus::none)
1170 _bin_interrupt.status = AR::InterruptStatus::merge;
1176 p2->group_data.artificial.setParticleTypeToUnused();
1185 (p1->time_interrupt<_bin_interrupt.time_now && p2->time_interrupt<_bin_interrupt.time_now) &&
1186 (p1->getBinaryPairID()==p2->id||p2->getBinaryPairID()==p1->id)) {
1187 Float dr[3] = {p1->pos[0] - p2->pos[0],
1188 p1->pos[1] - p2->pos[1],
1189 p1->pos[2] - p2->pos[2]};
1190 Float dr2 = dr[0]*dr[0] + dr[1]*dr[1] + dr[2]*dr[2];
1191 merge(std::sqrt(dr2), 0.0, 1.0);
1195 Float radius = p1->radius + p2->radius;
1198 if (_bin.slowdown.getSlowDownFactor()>1.0) {
1201 _bin.particleToSemiEcc(_bin.semi, _bin.ecc, _bin.r, drdv, *_bin.getLeftMember(), *_bin.getRightMember(),
gravitational_constant);
1202 Float peri = _bin.semi*(1 - _bin.ecc);
1203 if (peri<radius && p1->getBinaryPairID()!=p2->id&&p2->getBinaryPairID()!=p1->id) {
1204 Float ecc_anomaly = _bin.calcEccAnomaly(_bin.r);
1205 Float mean_anomaly = _bin.calcMeanAnomaly(ecc_anomaly, _bin.ecc);
1207 Float t_peri = mean_anomaly/mean_motion;
1208 if (drdv<0 && t_peri<_bin_interrupt.time_end-_bin_interrupt.time_now) {
1209 Float dr[3] = {p1->pos[0] - p2->pos[0],
1210 p1->pos[1] - p2->pos[1],
1211 p1->pos[2] - p2->pos[2]};
1212 Float dr2 = dr[0]*dr[0] + dr[1]*dr[1] + dr[2]*dr[2];
1213 merge(std::sqrt(dr2), t_peri, _bin.slowdown.getSlowDownFactor());
1215 else if (_bin.semi>0||(_bin.semi<0&&drdv<0)) {
1216 p1->setBinaryPairID(p2->id);
1217 p2->setBinaryPairID(p1->id);
1220 p1->time_interrupt =
std::min(_bin_interrupt.time_now + drdv<0 ? t_peri : (_bin.period - t_peri), time_interrupt_max);
1221 p2->time_interrupt = p1->time_interrupt;
1227 Float dr[3] = {p1->pos[0] - p2->pos[0],
1228 p1->pos[1] - p2->pos[1],
1229 p1->pos[2] - p2->pos[2]};
1230 Float dr2 = dr[0]*dr[0] + dr[1]*dr[1] + dr[2]*dr[2];
1231 if (dr2<radius*radius) merge(std::sqrt(dr2), 0.0, 1.0);
1235 if (_bin.semi<0.0) {
1236 Float dr[3] = {p1->pos[0] - p2->pos[0],
1237 p1->pos[1] - p2->pos[1],
1238 p1->pos[2] - p2->pos[2]};
1239 Float dr2 = dr[0]*dr[0] + dr[1]*dr[1] + dr[2]*dr[2];
1240 if (dr2<radius*radius) merge(std::sqrt(dr2), 0.0, 1.0);
1248 if (stellar_evolution_option==2 && p1->mass>0 && p2->mass>0) {
1250 if (p1->getBinaryInterruptState() == BinaryInterruptState::tide) {
1253 if (p2->getBinaryInterruptState() == BinaryInterruptState::tide) {
1258 int binary_type_p1 =
static_cast<int>(p1->getBinaryInterruptState());
1259 int binary_type_p2 =
static_cast<int>(p2->getBinaryInterruptState());
1260 long long int pair_id1 = p1->getBinaryPairID();
1261 long long int pair_id2 = p2->getBinaryPairID();
1262 bool tide_flag =
true;
1263 if ((binary_type_p1 != binary_type_p2) || (pair_id1 != p2->id) || (pair_id2 != p1->id)) tide_flag =
false;
1265 || bse_manager.
isMerger(binary_type_p1)
1266 || bse_manager.
isDisrupt(binary_type_p1)
1267 || binary_type_p1 == 14)
1270 bool change_flag=
false;
1272 Float poly_type1=0, poly_type2=0;
1273 Float Etid=0, Ltid=0;
1274 Float semi = _bin.semi;
1275 Float ecc = _bin.ecc;
1278 if (p1->star.kw>=10&&p1->star.kw<15&&p2->star.kw>=10&&p2->star.kw<15) {
1282 Float dr[3] = {p1->pos[0] - p2->pos[0],
1283 p1->pos[1] - p2->pos[1],
1284 p1->pos[2] - p2->pos[2]};
1285 Float dr2 = dr[0]*dr[0] + dr[1]*dr[1] + dr[2]*dr[2];
1286 merge(std::sqrt(dr2), 0.0, 1.0);
1288 else change_flag =
true;
1291 else if (
std::min(p1->star.kw, p2->star.kw)<13) {
1292 poly_type1 = (p1->star.kw<=2) ? 3.0 : 1.5;
1293 poly_type2 = (p2->star.kw<=2) ? 3.0 : 1.5;
1295 change_flag = (Etid>0);
1297 Float sd_factor_ext = _bin.slowdown.getSlowDownFactor() - 1.5;
1298 if (change_flag && sd_factor_ext>0) {
1299 for (Float k=0; k<sd_factor_ext; k=k+1.0) {
1301 if (etid_k==0)
break;
1309 _bin_interrupt.adr = &_bin;
1312 if (_bin_interrupt.status == AR::InterruptStatus::none)
1313 _bin_interrupt.status = AR::InterruptStatus::change;
1315 p1->pos += _bin.pos;
1316 p2->pos += _bin.pos;
1317 p1->vel += _bin.vel;
1318 p2->vel += _bin.vel;
1320 p1->setBinaryPairID(p2->id);
1321 p2->setBinaryPairID(p1->id);
1322 p1->setBinaryInterruptState(BinaryInterruptState::tide);
1323 p2->setBinaryInterruptState(BinaryInterruptState::tide);
1327 #pragma omp critical
1344 _bin.BinarySlowDown::printColumn(fout_bse,
WRITE_WIDTH);
1347 fout_bse<<std::endl;
1358 return modify_return;
1367 return _ekin_minus_etot;
1374 Float
calcH(Float _ekin_minus_etot, Float _epot) {
1375 return log(_ekin_minus_etot) - log(-_epot);
1383 fwrite(&
eps_sq,
sizeof(Float),1,_fp);
1385 #ifdef STELLAR_EVOLUTION
1386 fwrite(&stellar_evolution_option,
sizeof(
int),1,_fp);
1387 fwrite(&stellar_evolution_write_flag,
sizeof(
bool),1,_fp);
1395 size_t rcount = fread(&
eps_sq,
sizeof(Float),1,_fin);
1398 std::cerr<<
"Error: Data reading fails! requiring data number is 2, only obtain "<<rcount<<
".\n";
1401 #ifdef STELLAR_EVOLUTION
1402 rcount += fread(&stellar_evolution_option,
sizeof(
int),1,_fin);
1403 rcount += fread(&stellar_evolution_write_flag,
sizeof(
bool),1,_fin);
1405 std::cerr<<
"Error: Data reading fails! requiring data number is 4, only obtain "<<rcount<<
".\n";