void free_camera(camera_info **camera) { SID_log("Freeing camera...", SID_LOG_OPEN); free_perspective(&((*camera)->perspective)); SID_free(SID_FARG(*camera)->mask_RGB); SID_free(SID_FARG(*camera)->mask_Y); SID_free(SID_FARG(*camera)->mask_RGBY); SID_free(SID_FARG(*camera)->mask_RGBY_MARKED); for(int i_depth = 0; i_depth < (*camera)->n_depth_alloc; i_depth++) { if((*camera)->image_RGB != NULL) free_image(&((*camera)->image_RGB[i_depth])); if((*camera)->image_RGB_left != NULL) free_image(&((*camera)->image_RGB_left[i_depth])); if((*camera)->image_RGB_right != NULL) free_image(&((*camera)->image_RGB_right[i_depth])); if((*camera)->image_Y != NULL) free_image(&((*camera)->image_Y[i_depth])); if((*camera)->image_Y_left != NULL) free_image(&((*camera)->image_Y_left[i_depth])); if((*camera)->image_Y_right != NULL) free_image(&((*camera)->image_Y_right[i_depth])); if((*camera)->image_RGBY != NULL) free_image(&((*camera)->image_RGBY[i_depth])); if((*camera)->image_RGBY_left != NULL) free_image(&((*camera)->image_RGBY_left[i_depth])); if((*camera)->image_RGBY_right != NULL) free_image(&((*camera)->image_RGBY_right[i_depth])); if((*camera)->image_RY != NULL) free_image(&((*camera)->image_RY[i_depth])); if((*camera)->image_RY_left != NULL) free_image(&((*camera)->image_RY_left[i_depth])); if((*camera)->image_RY_right != NULL) free_image(&((*camera)->image_RY_right[i_depth])); if((*camera)->image_GY != NULL) free_image(&((*camera)->image_GY[i_depth])); if((*camera)->image_GY_left != NULL) free_image(&((*camera)->image_GY_left[i_depth])); if((*camera)->image_GY_right != NULL) free_image(&((*camera)->image_GY_right[i_depth])); if((*camera)->image_BY != NULL) free_image(&((*camera)->image_BY[i_depth])); if((*camera)->image_BY_left != NULL) free_image(&((*camera)->image_BY_left[i_depth])); if((*camera)->image_BY_right != NULL) free_image(&((*camera)->image_BY_right[i_depth])); if((*camera)->image_RGBY_MARKED != NULL) free_image(&((*camera)->image_RGBY_MARKED[i_depth])); if((*camera)->image_RGBY_MARKED_left != NULL) free_image(&((*camera)->image_RGBY_MARKED_left[i_depth])); if((*camera)->image_RGBY_MARKED_right != NULL) free_image(&((*camera)->image_RGBY_MARKED_right[i_depth])); } SID_free(SID_FARG(*camera)->image_RGB); SID_free(SID_FARG(*camera)->image_RGB_left); SID_free(SID_FARG(*camera)->image_RGB_right); SID_free(SID_FARG(*camera)->image_Y); SID_free(SID_FARG(*camera)->image_Y_left); SID_free(SID_FARG(*camera)->image_Y_right); SID_free(SID_FARG(*camera)->image_RGBY); SID_free(SID_FARG(*camera)->image_RGBY_left); SID_free(SID_FARG(*camera)->image_RGBY_right); SID_free(SID_FARG(*camera)->image_RY); SID_free(SID_FARG(*camera)->image_RY_left); SID_free(SID_FARG(*camera)->image_RY_right); SID_free(SID_FARG(*camera)->image_GY); SID_free(SID_FARG(*camera)->image_GY_left); SID_free(SID_FARG(*camera)->image_GY_right); SID_free(SID_FARG(*camera)->image_BY); SID_free(SID_FARG(*camera)->image_BY_left); SID_free(SID_FARG(*camera)->image_BY_right); SID_free(SID_FARG(*camera)->image_RGBY_MARKED); SID_free(SID_FARG(*camera)->image_RGBY_MARKED_left); SID_free(SID_FARG(*camera)->image_RGBY_MARKED_right); SID_free(SID_FARG(*camera)->mask_RGB_left); SID_free(SID_FARG(*camera)->mask_Y_left); SID_free(SID_FARG(*camera)->mask_RGBY_left); SID_free(SID_FARG(*camera)->mask_RGBY_MARKED_left); SID_free(SID_FARG(*camera)->mask_RGB_right); SID_free(SID_FARG(*camera)->mask_Y_right); SID_free(SID_FARG(*camera)->mask_RGBY_right); SID_free(SID_FARG(*camera)->mask_RGBY_MARKED_right); if((*camera)->RGB_gamma != NULL) free_interpolate(SID_FARG(*camera)->RGB_gamma, NULL); if((*camera)->transfer_list != NULL) ADaPS_free(SID_FARG(*camera)->transfer_list); if((*camera)->Y_gamma != NULL) free_interpolate(SID_FARG(*camera)->Y_gamma, NULL); // Free camera depth information free_camera_depths(*camera); SID_free((void **)camera); SID_log("Done.", SID_LOG_CLOSE); }
int main(int argc, char *argv[]) { SID_Init(&argc, &argv, NULL); // Parse arguments char filename_cosmo[SID_MAX_FILENAME_LENGTH]; char filename_list_in[SID_MAX_FILENAME_LENGTH]; strcpy(filename_cosmo, argv[1]); strcpy(filename_list_in, argv[2]); // Read input list char * line = NULL; size_t line_length = 0; FILE * fp_in = fopen(filename_list_in, "r"); int n_list = count_lines_data(fp_in); double *a_list = (double *)SID_malloc(sizeof(double) * n_list); for(int i_list = 0; i_list < n_list; i_list++) { grab_next_line_data(fp_in, &line, &line_length); grab_double(line, 1, &(a_list[i_list])); } SID_free(SID_FARG line); double a_lo_table = a_list[0]; double a_hi_table = a_list[n_list - 1]; for(int i_list = 0; i_list < n_list; i_list++) { a_lo_table = GBP_MIN(a_lo_table, a_list[i_list]); a_hi_table = GBP_MAX(a_hi_table, a_list[i_list]); } a_lo_table = GBP_MIN(a_lo_table, 1e-4); SID_log("Creating extended snapshot list...", SID_LOG_OPEN); // Initialize cosmology cosmo_info *cosmo = NULL; read_gbpCosmo_file(&cosmo, filename_cosmo); // Creeate interpolation tables int n_table = 500; double *a_table = (double *)SID_malloc(n_table * sizeof(double)); double *t_table = (double *)SID_malloc(n_table * sizeof(double)); double *n_dyn_table = (double *)SID_malloc(n_table * sizeof(double)); double da_table = (a_hi_table - a_lo_table) / (double)(n_table - 1); for(int i_table = 0; i_table < n_table; i_table++) { // Expansion factor if(i_table == 0) a_table[i_table] = a_lo_table; else if(i_table == (n_table - 1)) a_table[i_table] = a_hi_table; else a_table[i_table] = a_table[0] + da_table * (double)i_table; // Cosmic time t_table[i_table] = t_age_a(a_table[i_table], &cosmo); // Number of dynamical times if(i_table == 0) n_dyn_table[i_table] = 0.; else n_dyn_table[i_table] = delta_n_dyn(a_table[0], a_table[i_table], &cosmo); } interp_info *n_of_a_interp = NULL; init_interpolate(a_table, n_dyn_table, n_table, gsl_interp_akima, &n_of_a_interp); // Generate desired table double a_last = 0.; double z_last = 0.; double t_last = 0.; double n_last = 0.; double a_i = 0.; double z_i = 1.e22; double t_i = 0.; double n_i = 0.; double da = 0.; double dz = 0.; double dt = 0.; double dn = 0.; int i_column = 1; printf("# Table of times, etc. generated from expansion factors in {%s}\n", filename_list_in); printf("# Column (%02d): snapshot number\n", i_column++); printf("# (%02d): a:=expansion factor\n", i_column++); printf("# (%02d): da\n", i_column++); printf("# (%02d): z:=redshift\n", i_column++); printf("# (%02d): dz\n", i_column++); printf("# (%02d): t:=cosmic time [years]\n", i_column++); printf("# (%02d): dt\n", i_column++); printf("# (%02d): n_dyn:=No. of dynamical times\n", i_column++); printf("# (%02d): dn_dyn\n", i_column++); for(int i_list = 0; i_list < n_list; i_list++) { a_last = a_i; z_last = z_i; t_last = t_i; n_last = n_i; a_i = a_list[i_list]; z_i = z_of_a(a_i); t_i = t_age_a(a_i, &cosmo) / S_PER_YEAR; n_i = interpolate(n_of_a_interp, a_i); da = a_i - a_last; dz = fabs(z_i - z_last); dt = t_i - t_last; dn = n_i - n_last; printf("%03d %le %le %le %le %le %le %le %le\n", i_list, a_i, da, z_i, dz, t_i, dt, n_i, dn); } // Clean-up SID_free(SID_FARG a_list); SID_free(SID_FARG a_table); SID_free(SID_FARG t_table); SID_free(SID_FARG n_dyn_table); free_interpolate(SID_FARG n_of_a_interp, NULL); free_cosmo(&cosmo); SID_log("Done.", SID_LOG_CLOSE); SID_Finalize(); }
void map_to_grid(size_t n_particles_local, GBPREAL * x_particles_local, GBPREAL * y_particles_local, GBPREAL * z_particles_local, GBPREAL * v_particles_local, GBPREAL * w_particles_local, cosmo_info *cosmo, double redshift, int distribution_scheme, double normalization_constant, field_info *field, field_info *field_norm, int mode) { size_t i_p; int i_k; size_t i_b; size_t i_grid; int i_coord; int i_i[3]; int j_i[3]; int k_i[3]; size_t n_particles; double v_p; double w_p; int flag_valued_particles; int flag_weight_particles; int flag_weight; int flag_active; int flag_viable; double k_mag; double dk; int n_powspec; int mode_powspec; size_t * n_mode_powspec; double * k_powspec; double * kmin_powspec; double * kmax_powspec; double * k_powspec_bin; double * P_powspec; double * dP_powspec; double k_min; double k_max; double norm_local; double normalization; GBPREAL x_i; GBPREAL x_particle_i; GBPREAL y_particle_i; GBPREAL z_particle_i; double kernal_offset; int W_search_lo; int W_search_hi; size_t receive_left_size = 0; size_t receive_right_size = 0; size_t index_best; int n_buffer[3]; size_t n_send_left; size_t n_send_right; size_t send_size_left; size_t send_size_right; GBPREAL * send_left = NULL; GBPREAL * send_right = NULL; GBPREAL * receive_left = NULL; GBPREAL * receive_right = NULL; GBPREAL * send_left_norm = NULL; GBPREAL * send_right_norm = NULL; GBPREAL * receive_left_norm = NULL; GBPREAL * receive_right_norm = NULL; double r_i, r_min, r_i_max = 0; double W_i; int index_i; interp_info *P_k_interp; double * r_Daub; double * W_Daub; double h_Hubble; int n_Daub; interp_info *W_r_Daub_interp = NULL; int i_rank; size_t buffer_index; int i_test; double accumulator; // Compute the total poulation size and print a status message calc_sum_global(&n_particles_local, &n_particles, 1, SID_SIZE_T, CALC_MODE_DEFAULT, SID_COMM_WORLD); SID_log("Distributing %zu items onto a %dx%dx%d grid...", SID_LOG_OPEN, n_particles, field->n[0], field->n[1], field->n[2]); // If we've been given a normalization field, make sure it's got the same geometry as the results field if(field_norm != NULL) { if(field->n_d != field_norm->n_d) SID_exit_error("grid dimension counts don't match (ie. %d!=%d)", SID_ERROR_LOGIC, field->n_d, field_norm->n_d); int i_d; for(i_d = 0; i_d < field->n_d; i_d++) { if(field->n[i_d] != field_norm->n[i_d]) SID_exit_error("grid dimension No. %d's sizes don't match (ie. %d!=%d)", SID_ERROR_LOGIC, i_d, field->n[i_d], field_norm->n[i_d]); if(field->n_R_local[i_d] != field_norm->n_R_local[i_d]) SID_exit_error("grid dimension No. %d's slab sizes don't match (ie. %d!=%d)", SID_ERROR_LOGIC, i_d, field->n_R_local[i_d], field_norm->n_R_local[i_d]); if(field->i_R_start_local[i_d] != field_norm->i_R_start_local[i_d]) SID_exit_error("grid dimension No. %d's start positions don't match (ie. %le!=%le)", SID_ERROR_LOGIC, i_d, field->i_R_start_local[i_d], field_norm->i_R_start_local[i_d]); if(field->i_R_stop_local[i_d] != field_norm->i_R_stop_local[i_d]) SID_exit_error("grid dimension No. %d's stop positions don't match (ie. %le!=%le)", SID_ERROR_LOGIC, i_d, field->i_R_stop_local[i_d], field_norm->i_R_stop_local[i_d]); } if(field->n_field != field_norm->n_field) SID_exit_error("grid field sizes don't match (ie. %d!=%d)", SID_ERROR_LOGIC, field->n_field, field_norm->n_field); if(field->n_field_R_local != field_norm->n_field_R_local) SID_exit_error("grid local field sizes don't match (ie. %d!=%d)", SID_ERROR_LOGIC, field->n_field_R_local, field_norm->n_field_R_local); if(field->total_local_size != field_norm->total_local_size) SID_exit_error("grid total local sizes don't match (ie. %d!=%d)", SID_ERROR_LOGIC, field->total_local_size, field_norm->total_local_size); } // Set some variables if(v_particles_local != NULL) flag_valued_particles = GBP_TRUE; else { flag_valued_particles = GBP_FALSE; v_p = 1.; } if(w_particles_local != NULL) flag_weight_particles = GBP_TRUE; else { flag_weight_particles = GBP_FALSE; w_p = 1.; } h_Hubble = ((double *)ADaPS_fetch(cosmo, "h_Hubble"))[0]; // Initializing the mass assignment scheme switch(distribution_scheme) { case MAP2GRID_DIST_DWT20: W_search_lo = 2; W_search_hi = 7; kernal_offset = 2.5; compute_Daubechies_scaling_fctns(20, 5, &r_Daub, &W_Daub, &n_Daub); init_interpolate(r_Daub, W_Daub, n_Daub, gsl_interp_cspline, &W_r_Daub_interp); SID_free(SID_FARG r_Daub); SID_free(SID_FARG W_Daub); SID_log("(using D20 scale function kernal)...", SID_LOG_CONTINUE); break; case MAP2GRID_DIST_DWT12: W_search_lo = 1; W_search_hi = 6; kernal_offset = 1.75; compute_Daubechies_scaling_fctns(12, 5, &r_Daub, &W_Daub, &n_Daub); init_interpolate(r_Daub, W_Daub, (size_t)n_Daub, gsl_interp_cspline, &W_r_Daub_interp); SID_free(SID_FARG r_Daub); SID_free(SID_FARG W_Daub); SID_log("(using D12 scale function kernal)...", SID_LOG_CONTINUE); break; case MAP2GRID_DIST_TSC: W_search_lo = 2; W_search_hi = 2; SID_log("(using triangular shaped function kernal)...", SID_LOG_CONTINUE); break; case MAP2GRID_DIST_CIC: SID_log("(using cloud-in-cell kernal)...", SID_LOG_CONTINUE); case MAP2GRID_DIST_NGP: default: W_search_lo = 1; W_search_hi = 1; SID_log("(using nearest grid point kernal)...", SID_LOG_CONTINUE); break; } // Initializing slab buffers n_send_left = (size_t)(field->n[0] * field->n[1] * W_search_lo); n_send_right = (size_t)(field->n[0] * field->n[1] * W_search_hi); send_size_left = n_send_left * sizeof(GBPREAL); send_size_right = n_send_right * sizeof(GBPREAL); send_left = (GBPREAL *)SID_calloc(send_size_left); send_right = (GBPREAL *)SID_calloc(send_size_right); receive_left = (GBPREAL *)SID_calloc(send_size_right); receive_right = (GBPREAL *)SID_calloc(send_size_left); if(field_norm != NULL) { send_left_norm = (GBPREAL *)SID_calloc(send_size_left); send_right_norm = (GBPREAL *)SID_calloc(send_size_right); receive_left_norm = (GBPREAL *)SID_calloc(send_size_right); receive_right_norm = (GBPREAL *)SID_calloc(send_size_left); } // Clear the field if(!SID_CHECK_BITFIELD_SWITCH(mode, MAP2GRID_MODE_NOCLEAN)) { SID_log("Clearing fields...", SID_LOG_OPEN); clear_field(field); if(field_norm != NULL) clear_field(field); SID_log("Done.", SID_LOG_CLOSE); } // It is essential that we not pad the field for the simple way that we add-in the boundary buffers below set_FFT_padding_state(field, GBP_FALSE); if(field_norm != NULL) set_FFT_padding_state(field_norm, GBP_FALSE); // Create the mass distribution SID_log("Performing grid assignment...", SID_LOG_OPEN | SID_LOG_TIMER); // Loop over all the objects pcounter_info pcounter; SID_Init_pcounter(&pcounter, n_particles_local, 10); for(i_p = 0, norm_local = 0.; i_p < n_particles_local; i_p++) { double norm_i; double value_i; if(flag_valued_particles) v_p = (double)(v_particles_local[i_p]); if(flag_weight_particles) w_p = (double)(w_particles_local[i_p]); norm_i = w_p; value_i = v_p * norm_i; // Particle's position x_particle_i = (GBPREAL)x_particles_local[i_p]; y_particle_i = (GBPREAL)y_particles_local[i_p]; z_particle_i = (GBPREAL)z_particles_local[i_p]; // Quantize it onto the grid x_particle_i /= (GBPREAL)field->dR[0]; y_particle_i /= (GBPREAL)field->dR[1]; z_particle_i /= (GBPREAL)field->dR[2]; i_i[0] = (int)x_particle_i; // position in grid-coordinates i_i[1] = (int)y_particle_i; // position in grid-coordinates i_i[2] = (int)z_particle_i; // position in grid-coordinates // Apply the kernel flag_viable = GBP_TRUE; double x_i_effective; for(j_i[0] = -W_search_lo; j_i[0] <= W_search_hi; j_i[0]++) { for(j_i[1] = -W_search_lo; j_i[1] <= W_search_hi; j_i[1]++) { for(j_i[2] = -W_search_lo; j_i[2] <= W_search_hi; j_i[2]++) { // Compute distance to each grid point being searched against ... flag_active = GBP_TRUE; for(i_coord = 0, W_i = 1.; i_coord < 3; i_coord++) { switch(i_coord) { case 0: x_i = (GBPREAL)(i_i[0] + j_i[0]) - x_particle_i; break; case 1: x_i = (GBPREAL)(i_i[1] + j_i[1]) - y_particle_i; break; case 2: x_i = (GBPREAL)(i_i[2] + j_i[2]) - z_particle_i; break; } switch(distribution_scheme) { // Distribute with a Daubechies wavelet transform of 12th or 20th order a la Cui et al '08 case MAP2GRID_DIST_DWT12: case MAP2GRID_DIST_DWT20: x_i_effective = x_i + kernal_offset; if(x_i_effective > 0.) W_i *= interpolate(W_r_Daub_interp, x_i_effective); else flag_active = GBP_FALSE; break; // Distribute using the triangular shaped cloud (TSC) method case MAP2GRID_DIST_TSC: if(x_i < 0.5) W_i *= (0.75 - x_i * x_i); else if(x_i < 1.5) W_i *= 0.5 * (1.5 - fabs(x_i)) * (1.5 - fabs(x_i)); else flag_active = GBP_FALSE; break; // Distribute using the cloud-in-cell (CIC) method case MAP2GRID_DIST_CIC: if(fabs(x_i) < 1.) W_i *= (1. - fabs(x_i)); else flag_active = GBP_FALSE; break; // Distribute using "nearest grid point" (NGP; ie. the simplest and default) method case MAP2GRID_DIST_NGP: default: if(fabs(x_i) <= 0.5 && flag_viable) W_i *= 1.; else flag_active = GBP_FALSE; break; } } if(flag_active) { // This flags-out regions of the kernal with no support to save some time // Set the grid indices (enforce periodic BCs; do x-coordinate last) ... // ... y-coordinate ... k_i[1] = (i_i[1] + j_i[1]); if(k_i[1] < 0) k_i[1] += field->n[1]; else k_i[1] = k_i[1] % field->n[1]; // ... z-coordinate ... k_i[2] = i_i[2] + j_i[2]; if(k_i[2] < 0) k_i[2] += field->n[2]; else k_i[2] = k_i[2] % field->n[2]; // ... x-coordinate ... // Depending on x-index, add contribution to the // local array or to the slab buffers. k_i[0] = (i_i[0] + j_i[0]); if(k_i[0] < field->i_R_start_local[0]) { k_i[0] -= (field->i_R_start_local[0] - W_search_lo); if(k_i[0] < 0) SID_exit_error("Left slab buffer limit exceeded by %d element(s).", SID_ERROR_LOGIC, -k_i[0]); send_left[index_FFT_R(field, k_i)] += W_i * value_i; if(field_norm != NULL) send_left_norm[index_FFT_R(field_norm, k_i)] += W_i * norm_i; } else if(k_i[0] > field->i_R_stop_local[0]) { k_i[0] -= (field->i_R_stop_local[0] + 1); if(k_i[0] >= W_search_hi) SID_exit_error("Right slab buffer limit exceeded by %d element(s).", SID_ERROR_LOGIC, k_i[0] - W_search_hi + 1); else { send_right[index_FFT_R(field, k_i)] += W_i * value_i; if(field_norm != NULL) send_right_norm[index_FFT_R(field_norm, k_i)] += W_i * norm_i; } } else { field->field_local[index_local_FFT_R(field, k_i)] += W_i * value_i; if(field_norm != NULL) field_norm->field_local[index_local_FFT_R(field_norm, k_i)] += W_i * norm_i; } flag_viable = GBP_FALSE; } } } } // Report the calculation's progress SID_check_pcounter(&pcounter, i_p); } SID_log("Done.", SID_LOG_CLOSE); // Perform exchange of slab buffers and add them to the local mass distribution. // Note: it's important that the FFT field not be padded (see above, where // this is set) for this to work the way it's done. SID_log("Adding-in the slab buffers...", SID_LOG_OPEN | SID_LOG_TIMER); // Numerator first ... exchange_slab_buffer_left(send_left, send_size_left, receive_right, &receive_right_size, &(field->slab)); exchange_slab_buffer_right(send_right, send_size_right, receive_left, &receive_left_size, &(field->slab)); for(i_b = 0; i_b < n_send_right; i_b++) field->field_local[i_b] += receive_left[i_b]; for(i_b = 0; i_b < n_send_left; i_b++) field->field_local[field->n_field_R_local - n_send_left + i_b] += receive_right[i_b]; // ... then denominator (if it's being used) if(field_norm != NULL) { exchange_slab_buffer_left(send_left_norm, send_size_left, receive_right_norm, &receive_right_size, &(field_norm->slab)); exchange_slab_buffer_right(send_right_norm, send_size_right, receive_left_norm, &receive_left_size, &(field_norm->slab)); for(i_b = 0; i_b < n_send_right; i_b++) field_norm->field_local[i_b] += receive_left_norm[i_b]; for(i_b = 0; i_b < n_send_left; i_b++) field_norm->field_local[field_norm->n_field_R_local - n_send_left + i_b] += receive_right[i_b]; } SID_free(SID_FARG send_left); SID_free(SID_FARG send_right); SID_free(SID_FARG receive_left); SID_free(SID_FARG receive_right); if(field_norm != NULL) { SID_free(SID_FARG send_left_norm); SID_free(SID_FARG send_right_norm); SID_free(SID_FARG receive_left_norm); SID_free(SID_FARG receive_right_norm); } SID_log("Done.", SID_LOG_CLOSE); // Recompute local normalization (more accurate for large sample sizes) if(!SID_CHECK_BITFIELD_SWITCH(mode, MAP2GRID_MODE_NONORM)) { SID_log("Applying normalization...", SID_LOG_OPEN); if(field_norm != NULL) { for(i_grid = 0; i_grid < field->n_field_R_local; i_grid++) { if(field_norm->field_local[i_grid] != 0) field->field_local[i_grid] /= field_norm->field_local[i_grid]; } } if(SID_CHECK_BITFIELD_SWITCH(mode, MAP2GRID_MODE_APPLYFACTOR)) { for(i_grid = 0; i_grid < field->n_field_R_local; i_grid++) field->field_local[i_grid] *= normalization_constant; } if(SID_CHECK_BITFIELD_SWITCH(mode, MAP2GRID_MODE_FORCENORM)) { norm_local = 0; for(i_grid = 0; i_grid < field->n_field_R_local; i_grid++) norm_local += (double)field->field_local[i_grid]; calc_sum_global(&norm_local, &normalization, 1, SID_DOUBLE, CALC_MODE_DEFAULT, SID_COMM_WORLD); double normalization_factor; normalization_factor = normalization_constant / normalization; for(i_grid = 0; i_grid < field->n_field_R_local; i_grid++) field->field_local[i_grid] *= normalization_factor; } SID_log("Done.", SID_LOG_CLOSE, normalization); } if(W_r_Daub_interp != NULL) free_interpolate(SID_FARG W_r_Daub_interp, NULL); SID_log("Done.", SID_LOG_CLOSE); }
int compute_group_analysis(halo_properties_info *properties, halo_profile_info *profile, double (*p_i_fctn) (void *,int,int), double (*v_i_fctn) (void *,int,int), size_t (*id_i_fctn)(void *,int), void *params, double box_size, double particle_mass, int n_particles, double expansion_factor, double *x, double *y, double *z, double *vx, double *vy, double *vz, double *R, size_t **R_index_in, int flag_manual_centre, int flag_compute_shapes, cosmo_info *cosmo){ size_t *R_index; int i,j; int i_profile; int j_profile; int k_profile; int n_profile; size_t i_particle; size_t j_particle; size_t k_particle; int next_bin_particle; interp_info *V_R_interpolate; interp_info *vir_interpolate; int i_bin; int n_in_bin; double n_per_bin; int n_cumulative; double V1; double V2; double dV; double dM; double sigma_r_mean; double sigma_t_mean; double sigma_T_mean; double sigma_P_mean; double sigma_mean; double x_COM_accumulator; double y_COM_accumulator; double z_COM_accumulator; double vx_COM_accumulator; double vy_COM_accumulator; double vz_COM_accumulator; double spin_x_accumulator; double spin_y_accumulator; double spin_z_accumulator; double r_xy; double v_tot,v_rad,v_tan; double v_x_mean,v_y_mean,v_z_mean,v_rad_mean; double shape_eigen_values[3]; double shape_eigen_vectors[3][3]; double x_COM,y_COM,z_COM,R_COM; double r_c[MAX_PROFILE_BINS_P1]; double v_c[MAX_PROFILE_BINS_P1]; double r_interp[MAX_PROFILE_BINS]; double y_interp[MAX_PROFILE_BINS]; size_t n_bins_temp; double V_max,R_max; double Delta,Omega; double norm; int flag_interpolated=FALSE; const gsl_interp_type *interp_type; double sigma_cor,sigma_halo; double M_cor,M_halo; double x_vir,gamma; double h_Hubble=((double *)ADaPS_fetch(cosmo,"h_Hubble"))[0]; double Omega_M =((double *)ADaPS_fetch(cosmo,"Omega_M"))[0]; double redshift=z_of_a(expansion_factor); Delta=Delta_vir(redshift,cosmo); Omega=1.; // Initialize properties properties->id_MBP =id_i_fctn(params,0);//id_array[index_MBP]; properties->n_particles =n_particles; properties->position_COM[0]=0.; properties->position_COM[1]=0.; properties->position_COM[2]=0.; properties->position_MBP[0]=(float)p_i_fctn(params,0,0);//(x_array[index_MBP]); properties->position_MBP[1]=(float)p_i_fctn(params,1,0);//(y_array[index_MBP]); properties->position_MBP[2]=(float)p_i_fctn(params,2,0);//(z_array[index_MBP]); properties->velocity_COM[0]=0.; properties->velocity_COM[1]=0.; properties->velocity_COM[2]=0.; properties->velocity_MBP[0]=(float)v_i_fctn(params,0,0);//(vx_array[index_MBP]); properties->velocity_MBP[1]=(float)v_i_fctn(params,1,0);//(vy_array[index_MBP]); properties->velocity_MBP[2]=(float)v_i_fctn(params,2,0);//(vz_array[index_MBP]); properties->M_vir =0.; properties->R_vir =0.; properties->R_halo =0.; properties->R_max =0.; properties->V_max =0.; properties->sigma_v =0.; properties->spin[0] =0.; properties->spin[1] =0.; properties->spin[2] =0.; properties->q_triaxial =1.; properties->s_triaxial =1.; for(i=0;i<3;i++){ for(j=0;j<3;j++) properties->shape_eigen_vectors[i][j]=0.; properties->shape_eigen_vectors[i][i]=1.; } // Set the number of profile bins and the number of particles per bin profile->n_bins=MAX(MIN_PROFILE_BINS,MIN((int)((6.2*log10((double)n_particles)-3.5)+((double)n_particles/1000.)+1),MAX_PROFILE_BINS)); n_per_bin =(double)(n_particles)/(double)profile->n_bins; // There's nothing to do if there are no particles if(n_particles==0) profile->n_bins=0; else{ // Create a v_c(0)=0 bin r_c[0]=0.; v_c[0]=0.; // Initialize profiles for(i_bin=0;i_bin<profile->n_bins;i_bin++){ profile->bins[i_bin].r_med =0.; profile->bins[i_bin].r_max =0.; profile->bins[i_bin].n_particles =0; profile->bins[i_bin].M_r =0.; profile->bins[i_bin].rho =0.; profile->bins[i_bin].overdensity =0.; profile->bins[i_bin].position_COM[0] =0.; profile->bins[i_bin].position_COM[1] =0.; profile->bins[i_bin].position_COM[2] =0.; profile->bins[i_bin].velocity_COM[0] =0.; profile->bins[i_bin].velocity_COM[1] =0.; profile->bins[i_bin].velocity_COM[2] =0.; profile->bins[i_bin].sigma_rad =0.; profile->bins[i_bin].sigma_tan =0.; profile->bins[i_bin].sigma_tot =0.; profile->bins[i_bin].spin[0] =0.; profile->bins[i_bin].spin[1] =0.; profile->bins[i_bin].spin[2] =0.; profile->bins[i_bin].q_triaxial =1.; profile->bins[i_bin].s_triaxial =1.; for(i=0;i<3;i++){ for(j=0;j<3;j++) profile->bins[i_bin].shape_eigen_vectors[i][j]=0.; profile->bins[i_bin].shape_eigen_vectors[i][i]=1.; } } // Fill temporary arrays for particle positions, radii (all w.r.t MBP) and velocities // Also, enforce periodic box on particle positions double x_cen; double y_cen; double z_cen; x_cen=(double)properties->position_MBP[0]; y_cen=(double)properties->position_MBP[1]; z_cen=(double)properties->position_MBP[2]; if(flag_manual_centre){ double x_cen_manual; double y_cen_manual; double z_cen_manual; // Compute a rough comoving centre for(j_particle=0;j_particle<n_particles;j_particle++){ x[j_particle]=d_periodic(p_i_fctn(params,0,j_particle)-x_cen,box_size);//(double)(x_array[k_particle])-x_cen,box_size); y[j_particle]=d_periodic(p_i_fctn(params,1,j_particle)-y_cen,box_size);//(double)(y_array[k_particle])-y_cen,box_size); z[j_particle]=d_periodic(p_i_fctn(params,2,j_particle)-z_cen,box_size);//(double)(z_array[k_particle])-z_cen,box_size); } // Refine it with shrinking spheres int n_iterations; n_iterations=compute_centroid3D(NULL, x, y, z, n_particles, 1e-3, // 1 kpc 0.75, 30, CENTROID3D_MODE_FACTOR|CENTROID3D_MODE_INPLACE, &x_cen_manual, &y_cen_manual, &z_cen_manual); x_cen+=x_cen_manual; y_cen+=y_cen_manual; z_cen+=z_cen_manual; properties->position_MBP[0]=x_cen; properties->position_MBP[1]=y_cen; properties->position_MBP[2]=z_cen; if(properties->position_MBP[0]< box_size) properties->position_MBP[0]+=box_size; if(properties->position_MBP[1]< box_size) properties->position_MBP[1]+=box_size; if(properties->position_MBP[2]< box_size) properties->position_MBP[2]+=box_size; if(properties->position_MBP[0]>=box_size) properties->position_MBP[0]-=box_size; if(properties->position_MBP[1]>=box_size) properties->position_MBP[1]-=box_size; if(properties->position_MBP[2]>=box_size) properties->position_MBP[2]-=box_size; } for(j_particle=0;j_particle<n_particles;j_particle++){ // ... halo-centric particle positions ... x[j_particle]=expansion_factor*d_periodic(p_i_fctn(params,0,j_particle)-x_cen,box_size);//((double)x_array[k_particle])-x_cen,box_size); y[j_particle]=expansion_factor*d_periodic(p_i_fctn(params,1,j_particle)-y_cen,box_size);//((double)y_array[k_particle])-y_cen,box_size); z[j_particle]=expansion_factor*d_periodic(p_i_fctn(params,2,j_particle)-z_cen,box_size);//((double)z_array[k_particle])-z_cen,box_size); // ... velocities ... vx[j_particle]=v_i_fctn(params,0,j_particle);//(double)(vx_array[k_particle]); vy[j_particle]=v_i_fctn(params,1,j_particle);//(double)(vy_array[k_particle]); vz[j_particle]=v_i_fctn(params,2,j_particle);//(double)(vz_array[k_particle]); // ... particle radii ... R[j_particle]=sqrt(x[j_particle]*x[j_particle]+y[j_particle]*y[j_particle]+z[j_particle]*z[j_particle]); } // Sort particles by radius merge_sort((void *)R,(size_t)n_particles,R_index_in,SID_DOUBLE,SORT_COMPUTE_INDEX,SORT_COMPUTE_NOT_INPLACE); R_index=(*R_index_in); // Use the average of the central 30 particles for the MBP velocity if we are // manually computing centres if(flag_manual_centre){ double vx_cen_temp=0.; double vy_cen_temp=0.; double vz_cen_temp=0.; int n_cen =0; for(i_particle=0;i_particle<MIN(30,n_particles);i_particle++){ vx_cen_temp+=vx[i_particle]; vy_cen_temp+=vy[i_particle]; vz_cen_temp+=vz[i_particle]; n_cen++; } properties->velocity_MBP[0]=vx_cen_temp/(double)n_cen; properties->velocity_MBP[1]=vy_cen_temp/(double)n_cen; properties->velocity_MBP[2]=vz_cen_temp/(double)n_cen; } // We need the COM velocity at R_vir before we can get halo centric velocities. Thus, // we need the overdensity profile first x_COM_accumulator =0.; y_COM_accumulator =0.; z_COM_accumulator =0.; vx_COM_accumulator =0.; vy_COM_accumulator =0.; vz_COM_accumulator =0.; V2 =0.; n_cumulative =0; for(i_bin=0,i_particle=0;i_bin<profile->n_bins;i_bin++,i_particle+=n_in_bin){ V1=V2; // Volumes // ... particle numbers ... if(i_bin<profile->n_bins-1) n_in_bin=(int)((double)(i_bin+1)*n_per_bin)-i_particle; else n_in_bin=n_particles-i_particle; n_cumulative +=n_in_bin; profile->bins[i_bin].n_particles =n_in_bin; // ... mass profile ... profile->bins[i_bin].M_r=particle_mass*(double)n_cumulative; // ... binning radii ... if(n_in_bin%2==1) profile->bins[i_bin].r_med=(float)R[R_index[i_particle+n_in_bin/2]]; else profile->bins[i_bin].r_med=0.5*(float)(R[R_index[i_particle+n_in_bin/2-1]]+R[R_index[i_particle+n_in_bin/2]]); profile->bins[i_bin].r_max=(float)R[R_index[i_particle+n_in_bin-1]]; // ... COM positions and velocities ... for(j_particle=0;j_particle<n_in_bin;j_particle++){ k_particle=R_index[i_particle+j_particle]; x_COM_accumulator += x[k_particle]; y_COM_accumulator += y[k_particle]; z_COM_accumulator += z[k_particle]; vx_COM_accumulator+=vx[k_particle]; vy_COM_accumulator+=vy[k_particle]; vz_COM_accumulator+=vz[k_particle]; } profile->bins[i_bin].position_COM[0]=(float)(x_COM_accumulator/(double)n_cumulative); profile->bins[i_bin].position_COM[1]=(float)(y_COM_accumulator/(double)n_cumulative); profile->bins[i_bin].position_COM[2]=(float)(z_COM_accumulator/(double)n_cumulative); profile->bins[i_bin].velocity_COM[0]=(float)(vx_COM_accumulator/(double)n_cumulative); profile->bins[i_bin].velocity_COM[1]=(float)(vy_COM_accumulator/(double)n_cumulative); profile->bins[i_bin].velocity_COM[2]=(float)(vz_COM_accumulator/(double)n_cumulative); // ... density ... V2=FOUR_THIRDS_PI*profile->bins[i_bin].r_max*profile->bins[i_bin].r_max*profile->bins[i_bin].r_max; // Volume dV=V2-V1; dM=particle_mass*(double)n_in_bin; profile->bins[i_bin].rho =(float)(dM/dV); profile->bins[i_bin].overdensity=(float)(profile->bins[i_bin].M_r/(V2*Omega*rho_crit_z(redshift,cosmo))); /// ... triaxiality ... if(flag_compute_shapes){ compute_triaxiality(x, y, z, (double)profile->bins[i_bin].position_COM[0], (double)profile->bins[i_bin].position_COM[1], (double)profile->bins[i_bin].position_COM[2], box_size, n_cumulative, R_index, shape_eigen_values, shape_eigen_vectors); profile->bins[i_bin].q_triaxial=(float)(shape_eigen_values[1]/shape_eigen_values[0]); profile->bins[i_bin].s_triaxial=(float)(shape_eigen_values[2]/shape_eigen_values[0]); for(i=0;i<3;i++) for(j=0;j<3;j++) profile->bins[i_bin].shape_eigen_vectors[i][j]=(float)shape_eigen_vectors[i][j]; } } // Interpolate to get R_vir flag_interpolated=FALSE; properties->R_halo=profile->bins[profile->n_bins-1].r_max; if(profile->n_bins>1){ // Remove any small-radius monotonic increases from the interpolation interval j_profile=0; while(profile->bins[j_profile].overdensity<=profile->bins[j_profile+1].overdensity && j_profile<profile->n_bins-2) j_profile++; // Only keep decreasing bins n_bins_temp=0; r_interp[n_bins_temp]=take_log10((double)profile->bins[j_profile].r_max); y_interp[n_bins_temp]=take_log10((double)profile->bins[j_profile].overdensity); n_bins_temp++; for(i_profile=j_profile+1;i_profile<profile->n_bins;i_profile++){ if(take_log10((double)profile->bins[i_profile].overdensity)<y_interp[n_bins_temp-1]){ r_interp[n_bins_temp]=take_log10((double)profile->bins[i_profile].r_max); y_interp[n_bins_temp]=take_log10((double)profile->bins[i_profile].overdensity); n_bins_temp++; } } if(n_bins_temp>1){ // Perform interpolation if(y_interp[0]>=take_log10(Delta) && y_interp[n_bins_temp-1]<=take_log10(Delta)){ if(n_bins_temp>9) interp_type=gsl_interp_cspline; else interp_type=gsl_interp_linear; interp_type=gsl_interp_linear; init_interpolate(y_interp,r_interp,n_bins_temp,interp_type,&vir_interpolate); properties->R_vir =(float)take_alog10(interpolate(vir_interpolate,take_log10(Delta))); free_interpolate(SID_FARG vir_interpolate,NULL); flag_interpolated=TRUE; } else if(y_interp[0]<take_log10(Delta)){ properties->R_vir=(float)take_alog10(r_interp[0]); flag_interpolated=FLAG_INTERP_MIN_BIN; } else{ properties->R_vir=(float)take_alog10(r_interp[n_bins_temp-1]); flag_interpolated=FLAG_INTERP_MAX_BIN; } } else{ properties->R_vir=(float)take_alog10(r_interp[0]); flag_interpolated=FLAG_INTERP_MIN_BIN; } } else{ properties->R_vir=profile->bins[0].r_max; flag_interpolated=FLAG_INTERP_MIN_BIN; } // Set the interpolation method if(n_bins_temp>9) interp_type=gsl_interp_cspline; else interp_type=gsl_interp_linear; interp_type=gsl_interp_linear; // Compute v_COM(R_vir) for(i_profile=0;i_profile<profile->n_bins;i_profile++) r_interp[i_profile]=(double)profile->bins[i_profile].r_max; if(flag_interpolated==TRUE){ for(i_profile=0;i_profile<profile->n_bins;i_profile++) y_interp[i_profile]=(double)profile->bins[i_profile].velocity_COM[0]; init_interpolate(r_interp,y_interp,profile->n_bins,interp_type,&vir_interpolate); properties->velocity_COM[0]=(float)interpolate(vir_interpolate,properties->R_vir); free_interpolate(SID_FARG vir_interpolate,NULL); for(i_profile=0;i_profile<profile->n_bins;i_profile++) y_interp[i_profile]=(double)profile->bins[i_profile].velocity_COM[1]; init_interpolate(r_interp,y_interp,profile->n_bins,interp_type,&vir_interpolate); properties->velocity_COM[1]=(float)interpolate(vir_interpolate,properties->R_vir); free_interpolate(SID_FARG vir_interpolate,NULL); for(i_profile=0;i_profile<profile->n_bins;i_profile++) y_interp[i_profile]=(double)profile->bins[i_profile].velocity_COM[2]; init_interpolate(r_interp,y_interp,profile->n_bins,interp_type,&vir_interpolate); properties->velocity_COM[2]=(float)interpolate(vir_interpolate,properties->R_vir); free_interpolate(SID_FARG vir_interpolate,NULL); } else{ if(flag_interpolated==FLAG_INTERP_MIN_BIN) i_profile=0; else if(flag_interpolated==FLAG_INTERP_MAX_BIN) i_profile=profile->n_bins-1; else SID_trap_error("Unrecognized value for flag_interpolated {%d}.",flag_interpolated); properties->velocity_COM[0]=(float)profile->bins[i_profile].velocity_COM[0]; properties->velocity_COM[1]=(float)profile->bins[i_profile].velocity_COM[1]; properties->velocity_COM[2]=(float)profile->bins[i_profile].velocity_COM[2]; } // Compute halo-centric particle velocities // Subtract COM mean and add Hubble flow for(j_particle=0;j_particle<n_particles;j_particle++){ vx[j_particle]+=x[j_particle]*H_convert(H_z(redshift,cosmo))-(double)properties->velocity_COM[0]; vy[j_particle]+=y[j_particle]*H_convert(H_z(redshift,cosmo))-(double)properties->velocity_COM[1]; vz[j_particle]+=z[j_particle]*H_convert(H_z(redshift,cosmo))-(double)properties->velocity_COM[2]; } // Compute remaining profiles ... spin_x_accumulator=0.; spin_y_accumulator=0.; spin_z_accumulator=0.; V2 =0.; n_cumulative =0; for(i_bin=0,i_particle=0;i_bin<profile->n_bins;i_bin++,i_particle+=n_in_bin){ V1=V2; // Volumes // ... particle numbers ... if(i_bin<profile->n_bins-1) n_in_bin=(int)((double)(i_bin+1)*n_per_bin)-i_particle; else n_in_bin=n_particles-i_particle; n_cumulative+=n_in_bin; // ... spins and mean velocities ... v_x_mean =0.; v_y_mean =0.; v_z_mean =0.; v_rad_mean=0.; for(j_particle=0;j_particle<n_in_bin;j_particle++){ k_particle=R_index[i_particle+j_particle]; // ... spins ... spin_x_accumulator+=(double)(y[k_particle]*vz[k_particle]-z[k_particle]*vy[k_particle]); spin_y_accumulator+=(double)(z[k_particle]*vx[k_particle]-x[k_particle]*vz[k_particle]); spin_z_accumulator+=(double)(x[k_particle]*vy[k_particle]-y[k_particle]*vx[k_particle]); // ... mean velocities (needed below for velocity dispersions) ... if(R[k_particle]>0.){ v_rad =(x[k_particle]*vx[k_particle]+y[k_particle]*vy[k_particle]+z[k_particle]*vz[k_particle])/R[k_particle]; v_x_mean +=vx[k_particle]; v_y_mean +=vy[k_particle]; v_z_mean +=vz[k_particle]; v_rad_mean+=v_rad; } } profile->bins[i_bin].spin[0]=(float)(spin_x_accumulator)/n_cumulative; profile->bins[i_bin].spin[1]=(float)(spin_y_accumulator)/n_cumulative; profile->bins[i_bin].spin[2]=(float)(spin_z_accumulator)/n_cumulative; v_x_mean /=(double)n_in_bin; v_y_mean /=(double)n_in_bin; v_z_mean /=(double)n_in_bin; v_rad_mean/=(double)n_in_bin; // ... velocity dispersions ... for(j_particle=0;j_particle<n_in_bin;j_particle++){ k_particle=R_index[i_particle+j_particle]; if(R[k_particle]>0.){ v_tot=sqrt(pow(vx[k_particle]-v_x_mean,2.)+pow(vy[k_particle]-v_y_mean,2.)+pow(vz[k_particle]-v_z_mean,2.)); v_rad=(x[k_particle]*(vx[k_particle]-v_x_mean)+y[k_particle]*(vy[k_particle]-v_y_mean)+z[k_particle]*(vz[k_particle]-v_z_mean))/R[k_particle]; v_tan=sqrt(v_tot*v_tot-v_rad*v_rad); profile->bins[i_bin].sigma_tot+=(float)((v_tot)*(v_tot)); profile->bins[i_bin].sigma_rad+=(float)((v_rad-v_rad_mean)*(v_rad-v_rad_mean)); profile->bins[i_bin].sigma_tan+=(float)((v_tan)*(v_tan)); } } profile->bins[i_bin].sigma_tot=(float)sqrt((double)profile->bins[i_bin].sigma_tot/(double)n_in_bin); profile->bins[i_bin].sigma_rad=(float)sqrt((double)profile->bins[i_bin].sigma_rad/(double)n_in_bin); profile->bins[i_bin].sigma_tan=(float)sqrt((double)profile->bins[i_bin].sigma_tan/(double)n_in_bin); // ... circular velocity; v_c(R) ... r_c[i_bin+1]=profile->bins[i_bin].r_max; v_c[i_bin+1]=sqrt(G_NEWTON*profile->bins[i_bin].M_r/(double)profile->bins[i_bin].r_max); } // Determine R_max and V_max from v_c(R)... R_max=(double)r_c[1]; // default for a monotonically increasing V_c(r) V_max=(double)v_c[1]; // default for a monotonically increasing V_c(r) if(profile->n_bins>1){ // Remove any large-radius monotonic increases from the interpolation interval k_profile=profile->n_bins; while(v_c[k_profile-1]<=v_c[k_profile] && k_profile>1) k_profile--; if(v_c[0]<=v_c[1] && k_profile==1) k_profile--; // If the profile is not monotonically increasing ... if(k_profile>0){ n_bins_temp=k_profile+1; // ...find the maximum (call its index j_profile) for(i_profile=0,j_profile=0;i_profile<n_bins_temp;i_profile++){ if(v_c[i_profile]>v_c[j_profile]) j_profile=i_profile; } // ...find bottom of range in which to search for maximum (call its index i_profile) i_profile=j_profile-1; while(v_c[i_profile]>=v_c[j_profile] && i_profile>0) i_profile--; // ...find top of range in which to search for maximum (call its index k_profile) k_profile=j_profile+1; while(v_c[k_profile]>=v_c[j_profile] && k_profile<n_bins_temp-1) k_profile++; // ... perform interpolation V_max=(double)v_c[j_profile]; R_max=(double)r_c[j_profile]; if(i_profile<j_profile && j_profile<k_profile){ if(n_bins_temp>9) interp_type=gsl_interp_cspline; else interp_type=gsl_interp_linear; interp_type=gsl_interp_linear; init_interpolate(r_c,v_c,n_bins_temp,gsl_interp_cspline,&V_R_interpolate); interpolate_maximum(V_R_interpolate, r_c[i_profile], r_c[j_profile], r_c[k_profile], 0.05, &R_max, &V_max); free_interpolate(SID_FARG V_R_interpolate,NULL); } } } properties->R_max=(float)R_max; properties->V_max=(float)V_max; if(profile->n_bins>9) interp_type=gsl_interp_cspline; else interp_type=gsl_interp_linear; interp_type=gsl_interp_linear; // Perform normal interpolation from profiles to get the rest of the global quantities if(flag_interpolated==TRUE){ // ... COM positions ... for(i_profile=0;i_profile<profile->n_bins;i_profile++) y_interp[i_profile]=(double)profile->bins[i_profile].position_COM[0]/expansion_factor; init_interpolate(r_interp,y_interp,profile->n_bins,interp_type,&vir_interpolate); properties->position_COM[0]=(float)interpolate(vir_interpolate,properties->R_vir); free_interpolate(SID_FARG vir_interpolate,NULL); for(i_profile=0;i_profile<profile->n_bins;i_profile++) y_interp[i_profile]=(double)profile->bins[i_profile].position_COM[1]/expansion_factor; init_interpolate(r_interp,y_interp,profile->n_bins,interp_type,&vir_interpolate); properties->position_COM[1]=(float)interpolate(vir_interpolate,properties->R_vir); free_interpolate(SID_FARG vir_interpolate,NULL); for(i_profile=0;i_profile<profile->n_bins;i_profile++) y_interp[i_profile]=(double)profile->bins[i_profile].position_COM[2]/expansion_factor; init_interpolate(r_interp,y_interp,profile->n_bins,interp_type,&vir_interpolate); properties->position_COM[2]=(float)interpolate(vir_interpolate,properties->R_vir); free_interpolate(SID_FARG vir_interpolate,NULL); // ... M_vir ... for(i_profile=0;i_profile<profile->n_bins;i_profile++) y_interp[i_profile]=(double)profile->bins[i_profile].M_r; init_interpolate(r_interp,y_interp,profile->n_bins,interp_type,&vir_interpolate); properties->M_vir=interpolate(vir_interpolate,properties->R_vir); free_interpolate(SID_FARG vir_interpolate,NULL); // ... sigma_v ... for(i_profile=0;i_profile<profile->n_bins;i_profile++) y_interp[i_profile]=(double)profile->bins[i_profile].sigma_tot; init_interpolate(r_interp,y_interp,profile->n_bins,interp_type,&vir_interpolate); properties->sigma_v=(float)interpolate(vir_interpolate,properties->R_vir); free_interpolate(SID_FARG vir_interpolate,NULL); // ... spin ... for(i_profile=0;i_profile<profile->n_bins;i_profile++) y_interp[i_profile]=(double)profile->bins[i_profile].spin[0]; init_interpolate(r_interp,y_interp,profile->n_bins,interp_type,&vir_interpolate); properties->spin[0]=(float)interpolate(vir_interpolate,properties->R_vir); free_interpolate(SID_FARG vir_interpolate,NULL); for(i_profile=0;i_profile<profile->n_bins;i_profile++) y_interp[i_profile]=(double)profile->bins[i_profile].spin[1]; init_interpolate(r_interp,y_interp,profile->n_bins,interp_type,&vir_interpolate); properties->spin[1]=(float)interpolate(vir_interpolate,properties->R_vir); free_interpolate(SID_FARG vir_interpolate,NULL); for(i_profile=0;i_profile<profile->n_bins;i_profile++) y_interp[i_profile]=(double)profile->bins[i_profile].spin[2]; init_interpolate(r_interp,y_interp,profile->n_bins,interp_type,&vir_interpolate); properties->spin[2]=(float)interpolate(vir_interpolate,properties->R_vir); free_interpolate(SID_FARG vir_interpolate,NULL); // ... triaxial axes ratios ... for(i_profile=0;i_profile<profile->n_bins;i_profile++) y_interp[i_profile]=(double)profile->bins[i_profile].q_triaxial; init_interpolate(r_interp,y_interp,profile->n_bins,interp_type,&vir_interpolate); properties->q_triaxial=(float)interpolate(vir_interpolate,properties->R_vir); free_interpolate(SID_FARG vir_interpolate,NULL); for(i_profile=0;i_profile<profile->n_bins;i_profile++) y_interp[i_profile]=(double)profile->bins[i_profile].s_triaxial; init_interpolate(r_interp,y_interp,profile->n_bins,interp_type,&vir_interpolate); properties->s_triaxial=(float)interpolate(vir_interpolate,properties->R_vir); free_interpolate(SID_FARG vir_interpolate,NULL); // ... shape eigen vectors ... for(i=0;i<3;i++){ for(j=0;j<3;j++){ for(i_profile=0;i_profile<profile->n_bins;i_profile++) y_interp[i_profile]=(double)cos(profile->bins[i_profile].shape_eigen_vectors[i][j]); init_interpolate(r_interp,y_interp,profile->n_bins,interp_type,&vir_interpolate); properties->shape_eigen_vectors[i][j]=(float)acos(MAX(0,MIN(1.,interpolate(vir_interpolate,properties->R_vir)))); free_interpolate(SID_FARG vir_interpolate,NULL); } norm=sqrt(properties->shape_eigen_vectors[i][0]*properties->shape_eigen_vectors[i][0]+ properties->shape_eigen_vectors[i][1]*properties->shape_eigen_vectors[i][1]+ properties->shape_eigen_vectors[i][2]*properties->shape_eigen_vectors[i][2]); for(j=0;j<3;j++) properties->shape_eigen_vectors[i][j]/=norm; } } // ... else apply defaults to faulty cases. else{ if(flag_interpolated==FLAG_INTERP_MIN_BIN) i_profile=0; else if(flag_interpolated==FLAG_INTERP_MAX_BIN) i_profile=profile->n_bins-1; else SID_trap_error("Unrecognized value for flag_interpolated {%d}.",flag_interpolated); // ... COM positions ... properties->position_COM[0]=(double)(profile->bins[i_profile].position_COM[0])/expansion_factor; properties->position_COM[1]=(double)(profile->bins[i_profile].position_COM[1])/expansion_factor; properties->position_COM[2]=(double)(profile->bins[i_profile].position_COM[2])/expansion_factor; // ... M_vir ... properties->M_vir=(double)profile->bins[i_profile].M_r; // ... sigma_v ... properties->sigma_v=(float)profile->bins[i_profile].sigma_tot; // ... spin ... properties->spin[0]=(float)profile->bins[i_profile].spin[0]; properties->spin[1]=(float)profile->bins[i_profile].spin[1]; properties->spin[2]=(float)profile->bins[i_profile].spin[2]; // ... triaxial axes ratios ... properties->q_triaxial=(float)profile->bins[i_profile].q_triaxial; properties->s_triaxial=(float)profile->bins[i_profile].s_triaxial; // ... shape eigen vectors ... for(i=0;i<3;i++){ for(j=0;j<3;j++) properties->shape_eigen_vectors[i][j]=(float)profile->bins[i_profile].shape_eigen_vectors[i][j]; norm=sqrt(properties->shape_eigen_vectors[i][0]*properties->shape_eigen_vectors[i][0]+ properties->shape_eigen_vectors[i][1]*properties->shape_eigen_vectors[i][1]+ properties->shape_eigen_vectors[i][2]*properties->shape_eigen_vectors[i][2]); for(j=0;j<3;j++) properties->shape_eigen_vectors[i][j]/=norm; } } // Enforce periodic box on COM position properties->position_COM[0]+=x_cen; properties->position_COM[1]+=y_cen; properties->position_COM[2]+=z_cen; if(properties->position_COM[0]< box_size) properties->position_COM[0]+=box_size; if(properties->position_COM[1]< box_size) properties->position_COM[1]+=box_size; if(properties->position_COM[2]< box_size) properties->position_COM[2]+=box_size; if(properties->position_COM[0]>=box_size) properties->position_COM[0]-=box_size; if(properties->position_COM[1]>=box_size) properties->position_COM[1]-=box_size; if(properties->position_COM[2]>=box_size) properties->position_COM[2]-=box_size; // Perform unit conversions // ... properties first ... properties->position_COM[0]*=h_Hubble/M_PER_MPC; properties->position_COM[1]*=h_Hubble/M_PER_MPC; properties->position_COM[2]*=h_Hubble/M_PER_MPC; properties->position_MBP[0]*=h_Hubble/M_PER_MPC; properties->position_MBP[1]*=h_Hubble/M_PER_MPC; properties->position_MBP[2]*=h_Hubble/M_PER_MPC; properties->velocity_COM[0]*=1e-3; properties->velocity_COM[1]*=1e-3; properties->velocity_COM[2]*=1e-3; properties->velocity_MBP[0]*=1e-3; properties->velocity_MBP[1]*=1e-3; properties->velocity_MBP[2]*=1e-3; properties->M_vir *=h_Hubble/M_SOL; properties->R_vir *=h_Hubble/M_PER_MPC; properties->R_halo *=h_Hubble/M_PER_MPC; properties->R_max *=h_Hubble/M_PER_MPC; properties->V_max *=1e-3; properties->sigma_v *=1e-3; properties->spin[0] *=1e-3*h_Hubble/M_PER_MPC; properties->spin[1] *=1e-3*h_Hubble/M_PER_MPC; properties->spin[2] *=1e-3*h_Hubble/M_PER_MPC; // ... then profiles ... for(i_bin=0;i_bin<profile->n_bins;i_bin++){ profile->bins[i_bin].r_med *=h_Hubble/M_PER_MPC; profile->bins[i_bin].r_max *=h_Hubble/M_PER_MPC; profile->bins[i_bin].M_r *=h_Hubble/M_SOL; profile->bins[i_bin].rho *=M_PER_MPC*M_PER_MPC*M_PER_MPC/(h_Hubble*h_Hubble*M_SOL); profile->bins[i_bin].position_COM[0]*=h_Hubble/M_PER_MPC; profile->bins[i_bin].position_COM[1]*=h_Hubble/M_PER_MPC; profile->bins[i_bin].position_COM[2]*=h_Hubble/M_PER_MPC; profile->bins[i_bin].velocity_COM[0]*=1e-3; profile->bins[i_bin].velocity_COM[1]*=1e-3; profile->bins[i_bin].velocity_COM[2]*=1e-3; profile->bins[i_bin].sigma_rad *=1e-3; profile->bins[i_bin].sigma_tan *=1e-3; profile->bins[i_bin].sigma_tot *=1e-3; profile->bins[i_bin].spin[0] *=1e-3*h_Hubble/M_PER_MPC; profile->bins[i_bin].spin[1] *=1e-3*h_Hubble/M_PER_MPC; profile->bins[i_bin].spin[2] *=1e-3*h_Hubble/M_PER_MPC; } } return(flag_interpolated); }