long AT_n_bins_for_single_impact_local_dose_distrib( const long n, const double E_MeV_u[], const long particle_no[], const long material_no, const long rdd_model, const double rdd_parameter[], const long er_model, const long N2, const long stopping_power_source_no) { /* get lowest and highest dose */ double d_max_Gy = 0.0; double d_min_Gy = 0.0; // TODO think if d_min calculations can be done in smarter way. LET is only needed for Geiss RDD long i; for (i = 0; i < n; i++){ double max_electron_range_m = AT_max_electron_range_m( E_MeV_u[i], (int)material_no, (int)er_model); double LET_MeV_cm2_g = AT_Stopping_Power_MeV_cm2_g_single( stopping_power_source_no, E_MeV_u[i], particle_no[i], material_no); double norm_constant_Gy = AT_RDD_precalculated_constant_Gy(max_electron_range_m, LET_MeV_cm2_g, E_MeV_u[i], particle_no[i], material_no, rdd_model, rdd_parameter, er_model); double current_d_min_Gy = AT_RDD_d_min_Gy( E_MeV_u[i], particle_no[i], material_no, rdd_model, rdd_parameter, er_model, norm_constant_Gy); double current_d_max_Gy = AT_RDD_d_max_Gy( E_MeV_u[i], particle_no[i], material_no, rdd_model, rdd_parameter, er_model, stopping_power_source_no); if(i == 0){ d_min_Gy = current_d_min_Gy; d_max_Gy = current_d_max_Gy; } else{ d_min_Gy = GSL_MIN(d_min_Gy, current_d_min_Gy); d_max_Gy = GSL_MAX(d_max_Gy, current_d_max_Gy); } } long n_bins_for_singe_impact_local_dose_ditrib = 0; // get number of bins needed to span that dose range if( (d_min_Gy > 0) && (d_max_Gy >0) ){ // OLD: // double tmp = log10(d_max_Gy/d_min_Gy) / log10(2.0) * ((double)N2); // n_bins_for_singe_impact_local_dose_ditrib = (long)(floor(tmp) + 1.0); AT_histo_n_bins( d_min_Gy, d_max_Gy, AT_N2_to_step(N2), AT_histo_log, &n_bins_for_singe_impact_local_dose_ditrib); } else { #ifndef NDEBUG printf("AT_n_bins_for_singe_impact_local_dose_ditrib: problem in evaluating n_bins_for_singe_impact_local_dose_ditrib: d_min = %g [Gy], d_max = %g [Gy] \n", d_min_Gy, d_max_Gy); exit(EXIT_FAILURE); #endif } return n_bins_for_singe_impact_local_dose_ditrib + 1; }
void AT_single_impact_local_dose_distrib( const long n, const double E_MeV_u[], const long particle_no[], const double fluence_cm2_or_dose_Gy[], const long material_no, const long rdd_model, const double rdd_parameter[], const long er_model, const long N2, const long n_bins_f1, const double f1_parameters[], const long stopping_power_source_no, double f1_d_Gy[], double f1_dd_Gy[], double frequency_1_Gy_f1[]) { long i, j; /* * Get relative fluence for beam components * Convert dose to fluence if necessary */ double* fluence_cm2 = (double*)calloc(n, sizeof(double)); if(fluence_cm2_or_dose_Gy[0] < 0){ double* dose_Gy = (double*)calloc(n, sizeof(double)); for (i = 0; i < n; i++){ dose_Gy[i] = -1.0 * fluence_cm2_or_dose_Gy[i]; } AT_fluence_cm2_from_dose_Gy( n, E_MeV_u, particle_no, dose_Gy, material_no, stopping_power_source_no, fluence_cm2); free( dose_Gy ); }else{ for (i = 0; i < n; i++){ fluence_cm2[i] = fluence_cm2_or_dose_Gy[i]; } } double* norm_fluence = (double*)calloc(n, sizeof(double)); AT_normalize( n, fluence_cm2, norm_fluence); free( fluence_cm2 ); /* * Prepare single impact local dose distribution histogram */ if(n_bins_f1 > 0){ const double step = AT_N2_to_step(N2); const long histo_type = AT_histo_log; // Find lowest and highest dose (looking at ALL particles) // TODO: redundant, already used in finding number of bins, replace double d_min_f1 = f1_parameters[0*AT_SC_F1_PARAMETERS_SINGLE_LENGTH + 3]; double d_max_f1 = f1_parameters[0*AT_SC_F1_PARAMETERS_SINGLE_LENGTH + 4]; for (i = 1; i < n; i++){ d_min_f1 = GSL_MIN(f1_parameters[i*AT_SC_F1_PARAMETERS_SINGLE_LENGTH + 3], d_min_f1); d_max_f1 = GSL_MAX(f1_parameters[i*AT_SC_F1_PARAMETERS_SINGLE_LENGTH + 4], d_max_f1); } double lowest_left_limit_f1 = d_min_f1; AT_histo_midpoints(n_bins_f1, lowest_left_limit_f1, step, histo_type, f1_d_Gy); AT_histo_bin_widths(n_bins_f1, lowest_left_limit_f1, step, histo_type, f1_dd_Gy); for (i = 0; i < n_bins_f1; i++){ frequency_1_Gy_f1[i] = 0.0; } /* * Fill histogram with single impact distribution(s) from individual components */ // loop over all components (i.e. particles and energies), compute contribution to f1 long n_bins_used = 1; for (i = 0; i < n; i++){ // Find lowest and highest dose for component double d_min_f1_comp = f1_parameters[i*AT_SC_F1_PARAMETERS_SINGLE_LENGTH + 3]; double d_max_f1_comp = f1_parameters[i*AT_SC_F1_PARAMETERS_SINGLE_LENGTH + 4]; // Find position and number of bins for component f1 in overall f1 long lowest_bin_no_comp = AT_histo_bin_no(n_bins_f1, lowest_left_limit_f1, step, histo_type, d_min_f1_comp); long highest_bin_no_comp = AT_histo_bin_no(n_bins_f1, lowest_left_limit_f1, step, histo_type, d_max_f1_comp); long n_bins_f1_comp = highest_bin_no_comp - lowest_bin_no_comp + 1; if (n_bins_f1_comp > 1){ /* * Compute component F1 (accumulated single impact density) * Computation is done with bin limits as sampling points and later differential * f1 will be computed (therefore we need one bin more) * The lowest and highest value for F1 have however to be adjusted as they might * not coincide with the actual min/max values for dose, r, and F1 resp. * They bin widths have to be the same though to assure the integral to be 1 * * At the limits F1 will be set to 0 and 1, resp. This enable to account for all * dose, e.g. also in the core, where many radii have the same dose. This procedure, * however, will only work with monotonously falling RDDs which we can assume for all * realistic cases. */ double* dose_left_limits_Gy_F1_comp = (double*)calloc(n_bins_f1_comp + 1, sizeof(double)); double* r_m_comp = (double*)calloc(n_bins_f1_comp + 1, sizeof(double)); double* F1_comp = (double*)calloc(n_bins_f1_comp + 1, sizeof(double)); // left limit of lowest bin for component double lowest_left_limit_f1_comp = 0.0; AT_histo_left_limit(n_bins_f1, lowest_left_limit_f1, step, histo_type, lowest_bin_no_comp, &lowest_left_limit_f1_comp); // get all left limits AT_histo_left_limits(n_bins_f1_comp + 1, lowest_left_limit_f1_comp, step, histo_type, dose_left_limits_Gy_F1_comp); // compute radius as function of dose (inverse RDD), // but not for lowest and highest value (i.e. 'n_bins_f1_comp - 1' // instead of 'n_bins_f1_comp + 1' and &dose_left_limits_Gy_F1_comp[1] // as entry point instead of dose_left_limits_Gy_F1_comp // exit in case of problems int inverse_RDD_status_code = AT_r_RDD_m ( n_bins_f1_comp - 1, &dose_left_limits_Gy_F1_comp[1], E_MeV_u[i], particle_no[i], material_no, rdd_model, rdd_parameter, er_model, stopping_power_source_no, &r_m_comp[1]); if( inverse_RDD_status_code != 0 ){ #ifndef NDEBUG printf("Problem in evaluating inverse RDD in AT_SC_get_f1, probably wrong combination of ER and RDD used\n"); #endif char rdd_model_name[100]; AT_RDD_name_from_number(rdd_model, rdd_model_name); char er_model_name[100]; getERName( er_model, er_model_name); #ifndef NDEBUG printf("rdd_model: %ld (%s), er_model: %ld (%s)\n", rdd_model, rdd_model_name, er_model, er_model_name); exit(EXIT_FAILURE); #endif } // compute F1 as function of radius // use F1 - 1 instead of F1 to avoid numeric cut-off problems double r_max_m_comp = f1_parameters[i * AT_SC_F1_PARAMETERS_SINGLE_LENGTH + 2]; for (j = 1; j < n_bins_f1_comp; j++){ F1_comp[j] = gsl_pow_2(r_m_comp[j] / r_max_m_comp); } // Set extreme values of F1 F1_comp[0] = 1.0; F1_comp[n_bins_f1_comp] = 0.0; // Write out F1 for debugging FILE* output = fopen("F1_output.csv", "w"); fprintf(output, "bin.no;r.m;d.Gy;F1\n"); for (j = 0; j < n_bins_f1_comp + 1; j++){ fprintf(output, "%ld;%7.6e;%7.6e;%7.6e\n", j, r_m_comp[j], dose_left_limits_Gy_F1_comp[j], F1_comp[j]); } fclose(output); // now compute f1 as the derivative of F1 and add to overall f1 double f1_comp; for (j = 0; j < n_bins_f1_comp; j++){ f1_comp = (F1_comp[j] - F1_comp[j + 1]) / (dose_left_limits_Gy_F1_comp[j + 1] - dose_left_limits_Gy_F1_comp[j]); frequency_1_Gy_f1[lowest_bin_no_comp + j] += norm_fluence[i] * f1_comp; } // adjust the density in first and last bin, because upper limit is not d.max.Gy and lower not d.min.Gy free(dose_left_limits_Gy_F1_comp); free(r_m_comp); free(F1_comp); } else{ // in case of n_bins_df == 1 (all doses fall into single bin, just add a value of 1.0 frequency_1_Gy_f1[lowest_bin_no_comp ] += norm_fluence[i] * 1.0 / f1_dd_Gy[lowest_bin_no_comp]; } // remember highest bin used n_bins_used = GSL_MAX(n_bins_used, highest_bin_no_comp); } // normalize f1 (should be ok anyway but there could be small round-off errors) double f1_norm = 0.0; for (i = 0; i < n_bins_f1; i++){ f1_norm += frequency_1_Gy_f1[i] * f1_dd_Gy[i]; } for (i = 0; i < n_bins_f1; i++){ frequency_1_Gy_f1[i] /= f1_norm; } } // if(f1_d_Gy != NULL) // Write out f1 for debugging FILE* output = fopen("f1_output.csv", "w"); fprintf(output, "bin.no;d.Gy;dd.Gy;f1\n"); for (int j = 0; j < n_bins_f1; j++){ fprintf(output, "%d;%7.6e;%7.6e;%7.6e\n", j, f1_d_Gy[j], f1_dd_Gy[j], frequency_1_Gy_f1[j]); } fclose(output); free( norm_fluence ); }