struct rebx_param* rebx_attach_param_node(void* const object, struct rebx_param* param){ void* ptr = rebx_get_param(object, param->name); if (ptr != NULL){ char str[300]; sprintf(str, "REBOUNDx Error: Parameter '%s' passed to rebx_add_param already exists.\n", param->name); reb_error(rebx_get_sim(object), str); return NULL; } switch(rebx_get_object_type(object)){ case REBX_OBJECT_TYPE_EFFECT: { struct rebx_effect* effect = (struct rebx_effect*)object; param->next = effect->ap; effect->ap = param; break; } case REBX_OBJECT_TYPE_PARTICLE: { struct reb_particle* p = (struct reb_particle*)object; param->next = p->ap; p->ap = param; break; } } return param; }
void rebx_integrate(struct reb_simulation* const sim, const double dt, struct rebx_effect* const effect){ if (effect->force == NULL){ char str[300]; sprintf(str, "REBOUNDx Error: rebx_integrate called with non-force effect '%s'.\n", effect->name); reb_error(sim, str); } struct rebx_extras* rebx = sim->extras; rebx_reset_accelerations(sim->particles, sim->N); switch(rebx->integrator){ case REBX_INTEGRATOR_IMPLICIT_MIDPOINT: rebx_integrator_implicit_midpoint_integrate(sim, dt, effect); break; case REBX_INTEGRATOR_RK2: rebx_integrator_rk2_integrate(sim, dt, effect); break; case REBX_INTEGRATOR_RK4: rebx_integrator_rk4_integrate(sim, dt, effect); break; case REBX_INTEGRATOR_EULER: rebx_integrator_euler_integrate(sim, dt, effect); break; case REBX_INTEGRATOR_NONE: break; default: break; } }
int reb_remove_by_hash(struct reb_simulation* const r, uint32_t hash, int keepSorted){ struct reb_particle* p = reb_get_particle_by_hash(r, hash); if(p == NULL){ reb_error(r,"Particle to be removed not found in simulation. Did not remove particle."); return 0; } else{ int index = reb_get_particle_index(p); return reb_remove(r, index, keepSorted); } }
struct rebx_effect* rebx_add(struct rebx_extras* rebx, const char* name){ struct rebx_effect* effect = rebx_add_effect(rebx, name); struct reb_simulation* sim = rebx->sim; if (effect->hash == reb_hash("modify_orbits_direct")){ effect->operator = rebx_modify_orbits_direct; } else if (effect->hash == reb_hash("modify_orbits_forces")){ sim->force_is_velocity_dependent = 1; effect->force = rebx_modify_orbits_forces; } else if(effect->hash == reb_hash("gr")){ sim->force_is_velocity_dependent = 1; effect->force = rebx_gr; } else if (effect->hash == reb_hash("gr_full")){ sim->force_is_velocity_dependent = 1; effect->force = rebx_gr_full; } else if (effect->hash == reb_hash("gr_potential")){ effect->force = rebx_gr_potential; } else if (effect->hash == reb_hash("modify_mass")){ effect->operator = rebx_modify_mass; } else if (effect->hash == reb_hash("radiation_forces")){ sim->force_is_velocity_dependent = 1; effect->force = rebx_radiation_forces; } else if (effect->hash == reb_hash("tides_precession")){ effect->force = rebx_tides_precession; } else if (effect->hash == reb_hash("central_force")){ effect->force = rebx_central_force; } else if (effect->hash == reb_hash("track_min_distance")){ effect->operator = rebx_track_min_distance; } else if (effect->hash == reb_hash("tides_synchronous_ecc_damping")){ sim->force_is_velocity_dependent = 1; effect->force = rebx_tides_synchronous_ecc_damping; } else if (effect->hash == reb_hash("gravitational_harmonics")){ effect->force = rebx_gravitational_harmonics; } else{ char str[100]; sprintf(str, "Effect '%s' passed to rebx_add not found.\n", name); reb_error(sim, str); } return effect; }
void* rebx_get_param_check(const void* const object, const char* const param_name, enum rebx_param_type param_type){ struct rebx_param* node = rebx_get_param_node(object, param_name); if (node == NULL){ return NULL; } if (node->param_type != param_type){ char str[300]; sprintf(str, "REBOUNDx Error: Parameter '%s' passed to rebx_get_param_check was found but was of wrong type. See documentation for your particular effect. In python, you might need to add a dot at the end of the number when assigning a parameter that REBOUNDx expects as a float.\n", param_name); reb_error(rebx_get_sim(object), str); return NULL; } return node->contents; }
static void reb_add_local(struct reb_simulation* const r, struct reb_particle pt){ if (reb_boundary_particle_is_in_box(r, pt)==0){ // reb_particle has left the box. Do not add. reb_error(r,"Particle outside of box boundaries. Did not add particle."); return; } while (r->allocatedN<=r->N){ r->allocatedN += 128; r->particles = realloc(r->particles,sizeof(struct reb_particle)*r->allocatedN); } r->particles[r->N] = pt; r->particles[r->N].sim = r; if (r->gravity==REB_GRAVITY_TREE || r->collision==REB_COLLISION_TREE){ reb_tree_add_particle_to_tree(r, r->N); } (r->N)++; }
void rebx_radiation_forces(struct reb_simulation* const sim, struct rebx_effect* const radiation_forces){ double* c = rebx_get_param_check(radiation_forces, "c", REBX_TYPE_DOUBLE); if (c == NULL){ reb_error(sim, "Need to set speed of light in radiation_forces effect. See examples in documentation.\n"); } const int N_real = sim->N - sim->N_var; struct reb_particle* const particles = sim->particles; int source_found=0; for (int i=0; i<N_real; i++){ if (rebx_get_param_check(&particles[i], "radiation_source", REBX_TYPE_INT) != NULL){ source_found = 1; rebx_calculate_radiation_forces(sim, *c, i); } } if (!source_found){ rebx_calculate_radiation_forces(sim, *c, 0); // default source to index 0 if "radiation_source" not found on any particle } }
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; }
struct rebx_param* rebx_add_param_node(void* const object, const char* const param_name, enum rebx_param_type param_type, const int ndim, const int* const shape){ struct rebx_param* newparam = rebx_create_param(); newparam->name = malloc(strlen(param_name) + 1); // +1 for \0 at end if (newparam->name != NULL){ strcpy(newparam->name, param_name); } newparam->hash = reb_hash(param_name); newparam->param_type = param_type; newparam->python_type = -1; // not used by C newparam->ndim = ndim; newparam->shape = NULL; newparam->size = 1; if (ndim > 0){ size_t shapesize = sizeof(int)*ndim; newparam->shape = malloc(shapesize); newparam->strides = malloc(shapesize); memcpy(newparam->shape, shape, shapesize); for(int i=ndim-1;i>=0;i--){ // going backward allows us to calculate strides at the same time newparam->strides[i] = newparam->size; // stride[i] is equal to the product of the shapes for all indices > i newparam->size *= shape[i]; } } size_t element_size = rebx_sizeof(param_type); if (element_size){ newparam->contents = malloc(element_size*newparam->size); // newparam->size = number of elements in array (1 if scalar) } else{ char str[300]; sprintf(str, "REBOUNDx Error: Parameter type '%d' passed to rebx_add_param_node not supported.\n", param_type); reb_error(rebx_get_sim(object), str); } newparam = rebx_attach_param_node(object, newparam); return newparam; }
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; }