void rebx_pre_timestep_modifications(struct reb_simulation* sim){ struct rebx_extras* rebx = sim->extras; struct rebx_effect* current = rebx->effects; const double dt2 = sim->dt/2.; while(current != NULL){ if(current->operator_order == 2){ // if order = 1, only apply post_timestep if(current->operator != NULL){ // Always apply operator if set if(sim->integrator==REB_INTEGRATOR_IAS15 && sim->ri_ias15.epsilon != 0){ reb_warning(sim, "REBOUNDx: Can't use second order scheme with adaptive timesteps (IAS15). Must use operator_order = 1 or apply as force to get sensible results."); } current->operator(sim, current, dt2, REBX_TIMING_PRE_TIMESTEP); } else{ // It's a force: numerically integrate as operator if flag set if(current->force_as_operator == 1){ if(sim->integrator==REB_INTEGRATOR_IAS15 && sim->ri_ias15.epsilon != 0){ reb_warning(sim, "REBOUNDx: Can't use second order scheme with adaptive timesteps (IAS15). Must use operator_order = 1 or apply as force to get sensible results."); } rebx_integrate(sim, dt2, current); } } } current = current->next; } }
struct reb_simulation* reb_create_simulation_from_binary(char* filename){ enum reb_input_binary_messages warnings = REB_INPUT_BINARY_WARNING_NONE; struct reb_simulation* r = reb_create_simulation_from_binary_with_messages(filename,&warnings); if (warnings & REB_INPUT_BINARY_WARNING_VERSION){ reb_warning(r,"Binary file was saved with a different version of REBOUND. Binary format might have changed."); } if (warnings & REB_INPUT_BINARY_WARNING_PARTICLES){ reb_warning(r,"Binary file might be corrupted. Number of particles found does not match expected number."); } if (warnings & REB_INPUT_BINARY_WARNING_VARCONFIG){ reb_warning(r,"Binary file might be corrupted. Number of variational config structs found does not match number of variational config structs expected."); } if (warnings & REB_INPUT_BINARY_WARNING_POINTERS){ reb_warning(r,"You have to reset function pointers after creating a reb_simulation struct with a binary file."); } if (warnings & REB_INPUT_BINARY_ERROR_NOFILE){ reb_error(r,"Cannot read binary file. Check filename and file contents."); } return r; }
void rebx_additional_forces(struct reb_simulation* sim){ struct rebx_extras* rebx = sim->extras; struct rebx_effect* current = rebx->effects; while(current != NULL){ if(current->force != NULL && current->force_as_operator == 0){ if(sim->force_is_velocity_dependent && sim->integrator==REB_INTEGRATOR_WHFAST){ reb_warning(sim, "REBOUNDx: Passing a velocity-dependent force to WHFAST. Need to apply as an operator."); } const double N = sim->N - sim->N_var; current->force(sim, current, sim->particles, N); } current = current->next; } }
void rebx_initialize(struct reb_simulation* sim, struct rebx_extras* rebx){ sim->extras = rebx; rebx->sim = sim; rebx->params_to_be_freed = NULL; rebx->effects = NULL; rebx->integrator = REBX_INTEGRATOR_IMPLICIT_MIDPOINT; if(sim->additional_forces || sim->pre_timestep_modifications || sim->post_timestep_modifications){ reb_warning(sim, "REBOUNDx overwrites sim->additional_forces, sim->pre_timestep_modifications and sim->post_timestep_modifications. If you want to use REBOUNDx together with your own custom functions that use these callbacks, you should add them through REBOUNDx. See https://github.com/dtamayo/reboundx/blob/master/ipython_examples/Custom_Effects.ipynb for a tutorial."); } // Have to set all the following at initialization since we can't know // which will be needed from added effects. User could set force_as_operator after the fact. sim->additional_forces = rebx_additional_forces; sim->pre_timestep_modifications = rebx_pre_timestep_modifications; sim->post_timestep_modifications = rebx_post_timestep_modifications; }
int reb_remove(struct reb_simulation* const r, int index, int keepSorted){ if (r->ri_hermes.global){ // This is a mini simulation. Need to remove particle from two simulations. struct reb_simulation* global = r->ri_hermes.global; //remove from global and update global arrays int global_index = global->ri_hermes.global_index_from_mini_index[index]; reb_remove(global,global_index,1); //Shifting array values (filled with 0/1) for(int k=global_index;k<global->N;k++){ global->ri_hermes.is_in_mini[k] = global->ri_hermes.is_in_mini[k+1]; } //Shifting array values (filled with index values) global->ri_hermes.global_index_from_mini_index_N--; for(int k=index;k<global->ri_hermes.global_index_from_mini_index_N;k++){ global->ri_hermes.global_index_from_mini_index[k] = global->ri_hermes.global_index_from_mini_index[k+1]; } //Depreciating all index values larger than global_index for(int k=0;k<global->ri_hermes.global_index_from_mini_index_N;k++){ if(global->ri_hermes.global_index_from_mini_index[k] > global_index){ global->ri_hermes.global_index_from_mini_index[k]--; } } } if (r->integrator == REB_INTEGRATOR_MERCURIUS && r->ri_mercurius.mode==1){ struct reb_simulation_integrator_mercurius* rim = &(r->ri_mercurius); struct reb_simulation_integrator_whfast* riw = &(r->ri_whfast); //remove from global and update global arrays int global_index = -1; int count = -1; for(int k=0;k<rim->globalN;k++){ if (rim->encounterIndicies[k]){ count++; } if (count==index){ global_index = k; break; } } if (global_index==-1){ reb_error(r, "Error finding particle in global simulation."); } rim->globalN--; if(global_index<rim->globalNactive){ rim->globalNactive--; } for(int j=global_index; j<rim->globalN; j++){ rim->encounterParticles[j] = rim->encounterParticles[j+1]; // These are the global particles riw->p_jh[j] = riw->p_jh[j+1]; rim->p_hold[j] = rim->p_hold[j+1]; rim->encounterIndicies[j] = rim->encounterIndicies[j+1]; rim->rhill[j] = rim->rhill[j+1]; } // Update additional parameter for local for(int j=index; j<r->N-1; j++){ rim->encounterRhill[j] = rim->encounterRhill[j+1]; } } if (r->N==1){ r->N = 0; if(r->free_particle_ap){ r->free_particle_ap(&r->particles[index]); } reb_warning(r, "Last particle removed."); return 1; } if (index >= r->N){ char warning[1024]; sprintf(warning, "Index %d passed to particles_remove was out of range (N=%d). Did not remove particle.", index, r->N); reb_error(r, warning); return 0; } if (r->N_var){ reb_error(r, "Removing particles not supported when calculating MEGNO. Did not remove particle."); return 0; } if(keepSorted){ r->N--; if(r->free_particle_ap){ r->free_particle_ap(&r->particles[index]); } if(index<r->N_active){ r->N_active--; } for(int j=index; j<r->N; j++){ r->particles[j] = r->particles[j+1]; } if (r->tree_root){ reb_error(r, "REBOUND cannot remove a particle a tree and keep the particles sorted. Did not remove particle."); return 0; } }else{ if (r->tree_root){ // Just flag particle, will be removed in tree_update. r->particles[index].y = nan(""); if(r->free_particle_ap){ r->free_particle_ap(&r->particles[index]); } }else{ r->N--; if(r->free_particle_ap){ r->free_particle_ap(&r->particles[index]); } r->particles[index] = r->particles[r->N]; } } return 1; }
static void reb_integrator_hermes_check_for_encounter(struct reb_simulation* global){ struct reb_simulation* mini = global->ri_hermes.mini; const int _N_active = ((global->N_active==-1)?global->N:global->N_active) - global->N_var; struct reb_particle* global_particles = global->particles; struct reb_particle p0 = global_particles[0]; double hill_switch_factor = global->ri_hermes.hill_switch_factor; double hill_switch_factor2 = hill_switch_factor*hill_switch_factor; double min_dt_enc2 = INFINITY; for (int i=0; i<_N_active; i++){ struct reb_particle pi = global_particles[i]; double radius_check = global->ri_hermes.radius_switch_factor*pi.r; double radius_check2 = radius_check*radius_check; const double dxi = p0.x - pi.x; const double dyi = p0.y - pi.y; const double dzi = p0.z - pi.z; const double r0i2 = dxi*dxi + dyi*dyi + dzi*dzi; const double mi = pi.m/(p0.m*3.); double rhi = pow(mi*mi*r0i2*r0i2*r0i2,1./6.); for(int j=i+1;j<global->N;j++){ struct reb_particle pj = global_particles[j]; const double dxj = p0.x - pj.x; const double dyj = p0.y - pj.y; const double dzj = p0.z - pj.z; const double r0j2 = dxj*dxj + dyj*dyj + dzj*dzj; const double mj = pj.m/(p0.m*3.); double rhj = pow(mj*mj*r0j2*r0j2*r0j2,1./6.); const double rh_sum = rhi+rhj; const double rh_sum2 = rh_sum*rh_sum; const double dx = pi.x - pj.x; const double dy = pi.y - pj.y; const double dz = pi.z - pj.z; const double rij2 = dx*dx + dy*dy + dz*dz; if(rij2 < hill_switch_factor2*rh_sum2 || rij2 < radius_check2){ global->ri_hermes.mini_active = 1; // Monitor hill radius/relative velocity const double dvx = pi.vx - pj.vx; const double dvy = pi.vy - pj.vy; const double dvz = pi.vz - pj.vz; const double vij2 = dvx*dvx + dvy*dvy + dvz*dvz; const double dt_enc2 = hill_switch_factor2*rh_sum2/vij2; min_dt_enc2 = MIN(min_dt_enc2,dt_enc2); if (j>=_N_active && global->ri_hermes.is_in_mini[j]==0){//make sure not already added // Add particle to mini simulation reb_add(mini,pj); global->ri_hermes.is_in_mini[j] = 1; if (global->ri_hermes.global_index_from_mini_index_N>=global->ri_hermes.global_index_from_mini_index_Nmax){ while(global->ri_hermes.global_index_from_mini_index_N>=global->ri_hermes.global_index_from_mini_index_Nmax) global->ri_hermes.global_index_from_mini_index_Nmax += 32; global->ri_hermes.global_index_from_mini_index = realloc(global->ri_hermes.global_index_from_mini_index,global->ri_hermes.global_index_from_mini_index_Nmax*sizeof(int)); } global->ri_hermes.global_index_from_mini_index[global->ri_hermes.global_index_from_mini_index_N] = j; global->ri_hermes.global_index_from_mini_index_N++; } } } } if (global->ri_hermes.timestep_too_large_warning==0 && min_dt_enc2 < 16.*global->dt*global->dt){ global->ri_hermes.timestep_too_large_warning = 1; reb_warning(global,"The timestep is likely too large. Close encounters might be missed. Decrease the timestep or increase the switching radius. This warning will appear only once."); } }