void oskar_element_evaluate( const oskar_Element* model, double orientation_x, double orientation_y, int offset_points, int num_points, const oskar_Mem* x, const oskar_Mem* y, const oskar_Mem* z, double frequency_hz, oskar_Mem* theta, oskar_Mem* phi, int offset_out, oskar_Mem* output, int* status) { double dipole_length_m; if (*status) return; if (!oskar_mem_is_complex(output)) { *status = OSKAR_ERR_BAD_DATA_TYPE; return; } oskar_mem_ensure(output, offset_out + num_points, status); oskar_mem_ensure(theta, num_points, status); oskar_mem_ensure(phi, num_points, status); /* Get the element model properties. */ const int element_type = model->element_type; const int taper_type = model->taper_type; const int id = oskar_find_closest_match_d(frequency_hz, oskar_element_num_freq(model), oskar_element_freqs_hz_const(model)); dipole_length_m = model->dipole_length; if (model->dipole_length_units == OSKAR_WAVELENGTHS) dipole_length_m *= (C_0 / frequency_hz); /* Compute modified theta and phi coordinates for dipole X. */ oskar_convert_enu_directions_to_theta_phi(offset_points, num_points, x, y, z, (M_PI/2) - orientation_x, theta, phi, status); /* Check if element type is isotropic. */ if (element_type == OSKAR_ELEMENT_TYPE_ISOTROPIC) oskar_mem_set_value_real(output, 1.0, offset_out, num_points, status); /* Evaluate polarised response if output array is matrix type. */ if (oskar_mem_is_matrix(output)) { const int offset_out_real = offset_out * 8; const int offset_out_cplx = offset_out * 4; if (oskar_element_has_x_spherical_wave_data(model, id)) oskar_evaluate_spherical_wave_sum(num_points, theta, phi, model->x_lmax[id], model->x_te[id], model->x_tm[id], 4, offset_out_cplx + 0, output, status); else if (oskar_element_has_x_spline_data(model, id)) { oskar_splines_evaluate(model->x_h_re[id], num_points, theta, phi, 8, offset_out_real + 0, output, status); oskar_splines_evaluate(model->x_h_im[id], num_points, theta, phi, 8, offset_out_real + 1, output, status); oskar_splines_evaluate(model->x_v_re[id], num_points, theta, phi, 8, offset_out_real + 2, output, status); oskar_splines_evaluate(model->x_v_im[id], num_points, theta, phi, 8, offset_out_real + 3, output, status); oskar_convert_ludwig3_to_theta_phi_components(num_points, phi, 4, offset_out_cplx + 0, output, status); } else if (element_type == OSKAR_ELEMENT_TYPE_DIPOLE) oskar_evaluate_dipole_pattern(num_points, theta, phi, frequency_hz, dipole_length_m, 4, offset_out_cplx + 0, output, status); else if (element_type == OSKAR_ELEMENT_TYPE_GEOMETRIC_DIPOLE) oskar_evaluate_geometric_dipole_pattern(num_points, theta, phi, 4, offset_out_cplx + 0, output, status); /* Compute modified theta and phi coordinates for dipole Y. */ oskar_convert_enu_directions_to_theta_phi(offset_points, num_points, x, y, z, (M_PI/2) - orientation_y, theta, phi, status); if (oskar_element_has_y_spherical_wave_data(model, id)) oskar_evaluate_spherical_wave_sum(num_points, theta, phi, model->y_lmax[id], model->y_te[id], model->y_tm[id], 4, offset_out_cplx + 2, output, status); else if (oskar_element_has_y_spline_data(model, id)) { oskar_splines_evaluate(model->y_h_re[id], num_points, theta, phi, 8, offset_out_real + 4, output, status); oskar_splines_evaluate(model->y_h_im[id], num_points, theta, phi, 8, offset_out_real + 5, output, status); oskar_splines_evaluate(model->y_v_re[id], num_points, theta, phi, 8, offset_out_real + 6, output, status); oskar_splines_evaluate(model->y_v_im[id], num_points, theta, phi, 8, offset_out_real + 7, output, status); oskar_convert_ludwig3_to_theta_phi_components(num_points, phi, 4, offset_out_cplx + 2, output, status); } else if (element_type == OSKAR_ELEMENT_TYPE_DIPOLE) oskar_evaluate_dipole_pattern(num_points, theta, phi, frequency_hz, dipole_length_m, 4, offset_out_cplx + 2, output, status); else if (element_type == OSKAR_ELEMENT_TYPE_GEOMETRIC_DIPOLE) oskar_evaluate_geometric_dipole_pattern(num_points, theta, phi, 4, offset_out_cplx + 2, output, status); } else /* Scalar response. */ { const int offset_out_real = offset_out * 2; if (oskar_element_has_scalar_spline_data(model, id)) { oskar_splines_evaluate(model->scalar_re[id], num_points, theta, phi, 2, offset_out_real + 0, output, status); oskar_splines_evaluate(model->scalar_im[id], num_points, theta, phi, 2, offset_out_real + 1, output, status); } else if (element_type == OSKAR_ELEMENT_TYPE_DIPOLE) oskar_evaluate_dipole_pattern(num_points, theta, phi, frequency_hz, dipole_length_m, 1, offset_out, output, status); else if (element_type == OSKAR_ELEMENT_TYPE_GEOMETRIC_DIPOLE) oskar_evaluate_geometric_dipole_pattern(num_points, theta, phi, 1, offset_out, output, status); } /* Apply element tapering, if specified. */ if (taper_type == OSKAR_ELEMENT_TAPER_COSINE) oskar_apply_element_taper_cosine(num_points, model->cosine_power, theta, offset_out, output, status); else if (taper_type == OSKAR_ELEMENT_TAPER_GAUSSIAN) oskar_apply_element_taper_gaussian(num_points, model->gaussian_fwhm_rad, theta, offset_out, output, status); }
void oskar_element_evaluate(const oskar_Element* model, oskar_Mem* output, double orientation_x, double orientation_y, int num_points, const oskar_Mem* x, const oskar_Mem* y, const oskar_Mem* z, double frequency_hz, oskar_Mem* theta, oskar_Mem* phi, int* status) { int element_type, taper_type, freq_id; double dipole_length_m; /* Check if safe to proceed. */ if (*status) return; /* Check that the output array is complex. */ if (!oskar_mem_is_complex(output)) { *status = OSKAR_ERR_BAD_DATA_TYPE; return; } /* Resize output array if required. */ if ((int)oskar_mem_length(output) < num_points) oskar_mem_realloc(output, num_points, status); /* Get the element model properties. */ element_type = model->element_type; taper_type = model->taper_type; dipole_length_m = model->dipole_length; if (model->dipole_length_units == OSKAR_WAVELENGTHS) dipole_length_m *= (C_0 / frequency_hz); /* Check if element type is isotropic. */ if (element_type == OSKAR_ELEMENT_TYPE_ISOTROPIC) oskar_mem_set_value_real(output, 1.0, 0, 0, status); /* Ensure there is enough space in the theta and phi work arrays. */ if ((int)oskar_mem_length(theta) < num_points) oskar_mem_realloc(theta, num_points, status); if ((int)oskar_mem_length(phi) < num_points) oskar_mem_realloc(phi, num_points, status); /* Compute modified theta and phi coordinates for dipole X. */ oskar_convert_enu_directions_to_theta_phi(num_points, x, y, z, M_PI_2 - orientation_x, theta, phi, status); /* Evaluate polarised response if output array is matrix type. */ if (oskar_mem_is_matrix(output)) { /* Check if spline data present for dipole X. */ if (oskar_element_has_x_spline_data(model)) { /* Get the frequency index. */ freq_id = oskar_find_closest_match_d(frequency_hz, oskar_element_num_freq(model), oskar_element_freqs_hz_const(model)); /* Evaluate spline pattern for dipole X. */ oskar_splines_evaluate(output, 0, 8, model->x_h_re[freq_id], num_points, theta, phi, status); oskar_splines_evaluate(output, 1, 8, model->x_h_im[freq_id], num_points, theta, phi, status); oskar_splines_evaluate(output, 2, 8, model->x_v_re[freq_id], num_points, theta, phi, status); oskar_splines_evaluate(output, 3, 8, model->x_v_im[freq_id], num_points, theta, phi, status); /* Convert from Ludwig-3 to spherical representation. */ oskar_convert_ludwig3_to_theta_phi_components(output, 0, 4, num_points, phi, status); } else if (element_type == OSKAR_ELEMENT_TYPE_DIPOLE) { /* Evaluate dipole pattern for dipole X. */ oskar_evaluate_dipole_pattern(output, num_points, theta, phi, frequency_hz, dipole_length_m, 0, 4, status); } else if (element_type == OSKAR_ELEMENT_TYPE_GEOMETRIC_DIPOLE) { /* Evaluate dipole pattern for dipole X. */ oskar_evaluate_geometric_dipole_pattern(output, num_points, theta, phi, 0, 4, status); } /* Compute modified theta and phi coordinates for dipole Y. */ oskar_convert_enu_directions_to_theta_phi(num_points, x, y, z, M_PI_2 - orientation_y, theta, phi, status); /* Check if spline data present for dipole Y. */ if (oskar_element_has_y_spline_data(model)) { /* Get the frequency index. */ freq_id = oskar_find_closest_match_d(frequency_hz, oskar_element_num_freq(model), oskar_element_freqs_hz_const(model)); /* Evaluate spline pattern for dipole Y. */ oskar_splines_evaluate(output, 4, 8, model->y_h_re[freq_id], num_points, theta, phi, status); oskar_splines_evaluate(output, 5, 8, model->y_h_im[freq_id], num_points, theta, phi, status); oskar_splines_evaluate(output, 6, 8, model->y_v_re[freq_id], num_points, theta, phi, status); oskar_splines_evaluate(output, 7, 8, model->y_v_im[freq_id], num_points, theta, phi, status); /* Convert from Ludwig-3 to spherical representation. */ oskar_convert_ludwig3_to_theta_phi_components(output, 2, 4, num_points, phi, status); } else if (element_type == OSKAR_ELEMENT_TYPE_DIPOLE) { /* Evaluate dipole pattern for dipole Y. */ oskar_evaluate_dipole_pattern(output, num_points, theta, phi, frequency_hz, dipole_length_m, 2, 4, status); } else if (element_type == OSKAR_ELEMENT_TYPE_GEOMETRIC_DIPOLE) { /* Evaluate dipole pattern for dipole Y. */ oskar_evaluate_geometric_dipole_pattern(output, num_points, theta, phi, 2, 4, status); } } /* Scalar response. */ else { /* Check if scalar spline data present. */ if (oskar_element_has_scalar_spline_data(model)) { /* Get the frequency index. */ freq_id = oskar_find_closest_match_d(frequency_hz, oskar_element_num_freq(model), oskar_element_freqs_hz_const(model)); oskar_splines_evaluate(output, 0, 2, model->scalar_re[freq_id], num_points, theta, phi, status); oskar_splines_evaluate(output, 1, 2, model->scalar_im[freq_id], num_points, theta, phi, status); } else if (element_type == OSKAR_ELEMENT_TYPE_DIPOLE) { oskar_evaluate_dipole_pattern(output, num_points, theta, phi, frequency_hz, dipole_length_m, 0, 1, status); } else if (element_type == OSKAR_ELEMENT_TYPE_GEOMETRIC_DIPOLE) { oskar_evaluate_geometric_dipole_pattern(output, num_points, theta, phi, 0, 1, status); } } /* Apply element tapering, if specified. */ if (taper_type == OSKAR_ELEMENT_TAPER_COSINE) { oskar_apply_element_taper_cosine(output, num_points, model->cosine_power, theta, status); } else if (taper_type == OSKAR_ELEMENT_TAPER_GAUSSIAN) { oskar_apply_element_taper_gaussian(output, num_points, model->gaussian_fwhm_rad, theta, status); } }