/* initialization function for basic pepc parameters */ FCSResult fcs_pepc_init(FCS handle) { handle->shift_positions = 1; handle->destroy = fcs_pepc_destroy; handle->set_parameter = fcs_pepc_set_parameter; handle->print_parameters = fcs_pepc_print_parameters; handle->tune = fcs_pepc_tune; handle->run = fcs_pepc_run; handle->set_compute_virial = fcs_pepc_require_virial; handle->get_virial = fcs_pepc_get_virial; handle->pepc_param = malloc(sizeof(*handle->pepc_param)); handle->pepc_param->theta = 0.6; handle->pepc_param->epsilon = 0.0; handle->pepc_param->require_virial = 0; handle->pepc_param->num_walk_threads = 3; handle->pepc_param->load_balancing = 0; handle->pepc_param->dipole_correction = 1; handle->pepc_param->npm = -45.0; handle->pepc_param->debug_level = 0; fcs_pepc_internal_t *pepc_internal; MPI_Comm comm = fcs_get_communicator(handle); MPI_Fint fcomm = MPI_Comm_c2f(comm); pepc_scafacos_initialize(&fcomm); handle->method_context = malloc(sizeof(fcs_pepc_internal_t)); pepc_internal = (fcs_pepc_internal_t*) handle->method_context; pepc_internal->work_length = -1; pepc_internal->work = NULL; return FCS_RESULT_SUCCESS; }
/** * @brief function to check whether all initial parameters are set * @param handle FCS-object representing an FCS solver * @return whether all initial parameters are set */ static fcs_int fcs_init_check(FCS handle) { if (handle == FCS_NULL) return 0; return (fcs_get_method(handle) != FCS_METHOD_NONE && fcs_get_communicator(handle) != MPI_COMM_NULL); }
/** * sort additional byte particle data */ FCSResult fcs_resort_bytes(FCS handle, void *src, void *dst, fcs_int n) { CHECK_HANDLE_RETURN_RESULT(handle, __func__); if (handle->resort_bytes == NULL) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "resorting not supported"); return handle->resort_bytes(handle, src, dst, n, fcs_get_communicator(handle)); }
/** * sort additional float particle data */ FCSResult fcs_resort_floats(FCS handle, fcs_float *src, fcs_float *dst, fcs_int n) { const char* fnc_name = "fcs_resort_floats"; CHECK_HANDLE_RETURN_RESULT(handle, fnc_name); if (handle->resort_floats == NULL) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, fnc_name, "resorting not supported"); return handle->resort_floats(handle, src, dst, n, fcs_get_communicator(handle)); }
/* clean-up function for pepc */ FCSResult fcs_pepc_destroy(FCS handle) { MPI_Comm comm = fcs_get_communicator(handle); MPI_Fint fcomm = MPI_Comm_c2f(comm); pepc_scafacos_finalize(&fcomm); if(((fcs_pepc_internal_t*)fcs_get_method_context(handle))->work != NULL){ free(((fcs_pepc_internal_t*)fcs_get_method_context(handle))->work); } free(handle->method_context); free(handle->pepc_param); return FCS_RESULT_SUCCESS; }
/* internal fmm-specific run function */ FCSResult fcs_fmm_run(FCS handle, fcs_int local_particles, fcs_float *positions, fcs_float *charges, fcs_float *field, fcs_float *potentials) { FCSResult result; long long ll_tp; long long ll_lp; long long ll_absrel; long long ll_dip_corr; const fcs_int* periodicity; long long* ll_periodicity; int i; fcs_float tolerance_energy; fcs_float period_length; void* params; fcs_int dotune; long long r; const fcs_float* box_vector; void* loadptr = NULL; FMM_CHECK_RETURN_RESULT(handle, __func__); result = fcs_fmm_check(handle, local_particles); CHECK_RESULT_RETURN(result); ll_periodicity = (long long*)malloc(3*sizeof(long long)); ll_tp = (long long)fcs_get_total_particles(handle); ll_lp = (long long)local_particles; fcs_int absrel; fcs_fmm_get_absrel(handle, &absrel); ll_absrel = absrel; fcs_fmm_get_tolerance_energy(handle, &tolerance_energy); fcs_int dip_corr; fcs_fmm_get_dipole_correction(handle, &dip_corr); ll_dip_corr = dip_corr; periodicity = fcs_get_periodicity(handle); for (i = 0; i < 3; i++) ll_periodicity[i] = (long long)periodicity[i]; params = fcs_get_method_context(handle); box_vector = fcs_get_box_a(handle); period_length = fcs_norm(box_vector); fcs_fmm_get_internal_tuning( handle, &dotune ); if (dotune != FCS_FMM_INHOMOGENOUS_SYSTEM && dotune != FCS_FMM_HOMOGENOUS_SYSTEM) { result = fcs_result_create(FCS_ERROR_WRONG_ARGUMENT, __func__, "wrong kind of internal tuning chosen"); return result; } long long ll_unroll_limit = handle->fmm_param->limit; long long ll_maxdepth = handle->fmm_param->maxdepth; long long ll_balance_load = handle->fmm_param->balance; long long define_loadvector = handle->fmm_param->define_loadvector; if (define_loadvector == 1) { handle->fmm_param->define_loadvector = 0; long long ll_loadvectorsize = ll_loadvectorsize = 229074;/*local_particles*4;*/ fcs_float val = 1e0; loadptr = malloc(sizeof(ll_loadvectorsize)*ll_loadvectorsize); fmm_cinitload(params,loadptr,ll_loadvectorsize); fmm_csetload(params,val); } int old_fcs_mpi_fmm_sort_front_part = fcs_mpi_fmm_sort_front_part; int comm_size; MPI_Comm_size(fcs_get_communicator(handle), &comm_size); fcs_float max_merge_move = fcs_pow(fcs_norm(fcs_get_box_a(handle)) * fcs_norm(fcs_get_box_b(handle)) * fcs_norm(fcs_get_box_c(handle)) / comm_size, 1.0 / 3.0); fcs_float max_particle_move; MPI_Allreduce(&handle->fmm_param->max_particle_move, &max_particle_move, 1, FCS_MPI_FLOAT, MPI_MAX, fcs_get_communicator(handle)); if (max_particle_move >= 0 && max_particle_move < max_merge_move) { /* fmm_csetpresorted(params, 1);*/ fcs_mpi_fmm_sort_front_part = 0; fcs_mpi_fmm_sort_front_merge_presorted = 1; } else { /* fmm_csetpresorted(params, 0);*/ fcs_mpi_fmm_sort_front_merge_presorted = 0; } fcs_fmm_resort_destroy(&handle->fmm_param->fmm_resort); if (handle->fmm_param->resort) fcs_fmm_resort_create(&handle->fmm_param->fmm_resort, local_particles, fcs_get_communicator(handle)); fmm_cinitresort(params, handle->fmm_param->fmm_resort); fmm_csetresort(params, (long long) handle->fmm_param->resort); fmm_crun(ll_lp,positions,charges,potentials,field,handle->fmm_param->virial,ll_tp,ll_absrel,tolerance_energy, ll_dip_corr, ll_periodicity, period_length, dotune, ll_maxdepth,ll_unroll_limit,ll_balance_load,params, &r); fcs_mpi_fmm_sort_front_part = old_fcs_mpi_fmm_sort_front_part; free(ll_periodicity); if (loadptr) free(loadptr); if (r == 0) { result = fcs_result_create(FCS_ERROR_FORTRAN_CALL, __func__, "error in fmm_run (FORTRAN)"); return result; } return FCS_RESULT_SUCCESS; }
/* method to check if fmm parameters are consistent with requirements */ FCSResult fcs_fmm_check(FCS handle, fcs_int local_particles) { const fcs_float *a,*b,*c; fcs_float norm[3],period_length; const fcs_int *periodicity; MPI_Comm comm; fcs_int total_particles; int comm_size; int i,p,ok; fcs_int absrel; fcs_fmm_get_absrel(handle, &absrel); if (absrel == -1) return fcs_result_create(FCS_ERROR_MISSING_ELEMENT, __func__, "fmm: absrel not set"); fcs_float tolerance_energy; fcs_fmm_get_tolerance_energy(handle, &tolerance_energy); if (tolerance_energy == -1.0) return fcs_result_create(FCS_ERROR_MISSING_ELEMENT, __func__, "fmm: energy tolerance not set"); comm = fcs_get_communicator(handle); MPI_Comm_size(comm, &comm_size); total_particles = fcs_get_total_particles(handle); if (total_particles < comm_size) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "fmm: there have to be at least as much particles as processes"); if (local_particles <= 0) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "fmm: each process has to receive at least one particle"); a = fcs_get_box_a(handle); norm[0] = fcs_norm(a); b = fcs_get_box_b(handle); norm[1] = fcs_norm(b); c = fcs_get_box_c(handle); norm[2] = fcs_norm(c); periodicity = fcs_get_periodicity(handle); p = 0; ok = 1; for (i = 0; i < 3; ++i) if (periodicity[i]) { if (0==p) period_length = norm[i]; else ok = ok && fcs_float_is_equal( period_length, norm[i] ); p++; } if (p && !(fcs_uses_principal_axes(a,b,c))) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "fmm: with periodic boundaries, box must be arranged along principle axes"); if (p && !ok) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "fmm: all periodic directions must have equal length"); if (p && (p<3)) { ok = 1; for (i = 0; i < 3; ++i) if (!periodicity[i]) ok = ok && (norm[i] <= period_length); if (!ok) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "fmm: axes in non-periodic directions must not be longer than periodic ones"); } return FCS_RESULT_SUCCESS; }
FCSResult fcs_vmg_tune(FCS handle, fcs_int local_particles, fcs_int local_max_particles, fcs_float* positions, fcs_float* charges) { FCSResult result; /* * Set default parameters if no parameters were specified */ result = fcs_vmg_set_default(handle); if (result) return result; /* * Check parameters */ result = fcs_vmg_check(handle); if (result) return result; /* * Setup vmg solver */ fcs_int level; fcs_int max_iter; fcs_int smoothing_steps; fcs_int cycle_type; fcs_float precision; fcs_int near_field_cells; fcs_int interpolation_order; fcs_int discretization_order; result = fcs_vmg_get_max_level(handle, &level); if (result) return result; fcs_int* periodic = fcs_get_periodicity(handle); result = fcs_vmg_get_max_iterations(handle, &max_iter); if (result) return result; result = fcs_vmg_get_smoothing_steps(handle, &smoothing_steps); if (result) return result; result = fcs_vmg_get_cycle_type(handle, &cycle_type); if (result) return result; result = fcs_vmg_get_precision(handle, &precision); if (result) return result; fcs_float *offset = fcs_get_offset(handle); fcs_float* box_a = fcs_get_box_a(handle); result = fcs_vmg_get_near_field_cells(handle, &near_field_cells); if (result) return result; result = fcs_vmg_get_interpolation_order(handle, &interpolation_order); if (result) return result; result = fcs_vmg_get_discretization_order(handle, &discretization_order); if (result) return result; MPI_Comm comm = fcs_get_communicator(handle); VMG_fcs_setup(level, periodic, max_iter, smoothing_steps, cycle_type, precision, offset, box_a[0], near_field_cells, interpolation_order, discretization_order, comm); result = fcs_vmg_library_check(handle); if (result) return result; return NULL; }
/** * @brief function to set default values if no values are set * @param handle the FCS-obect into which the default parameters will be entered * @return FCSResult-object containing the return state */ extern FCSResult fcs_vmg_set_default(FCS handle) { MPI_Comm comm; int rank; const char fnc_name[] = "fcs_vmg_set_default"; comm = fcs_get_communicator(handle); MPI_Comm_rank(comm, &rank); if (handle == NULL) return fcsResult_create(FCS_NULL_ARGUMENT, fnc_name, "null pointer supplied as handle"); if (fcs_get_method(handle) != FCS_VMG) return fcsResult_create(FCS_WRONG_ARGUMENT, fnc_name, "Wrong method chosen. You should choose \"vmg\"."); fcs_int max_level; fcs_vmg_get_max_level(handle, &max_level); if (max_level < 0) { max_level = 6; #ifdef FCS_ENABLE_DEBUG if (rank == 0) printf("%s: Parameter %s not set. Set default to %d.\n", fnc_name, "max_level", max_level); #endif fcs_vmg_set_max_level(handle, max_level); } fcs_int max_iter; fcs_vmg_get_max_iterations(handle, &max_iter); if (max_iter < 0) { max_iter = 15; #ifdef FCS_ENABLE_DEBUG if (rank == 0) printf("%s: Parameter %s not set. Set default to %d.\n", fnc_name, "max_iterations", max_iter); #endif fcs_vmg_set_max_iterations(handle, max_iter); } fcs_int smoothing_steps; fcs_vmg_get_smoothing_steps(handle, &smoothing_steps); if (smoothing_steps < 0) { smoothing_steps = 3; #ifdef FCS_ENABLE_DEBUG if (rank == 0) printf("%s: Parameter %s not set. Set default to %d.\n", fnc_name, "smoothing_steps", smoothing_steps); #endif fcs_vmg_set_smoothing_steps(handle, smoothing_steps); } fcs_int cycle_type; fcs_vmg_get_cycle_type(handle, &cycle_type); if (cycle_type < 0) { cycle_type = 1; #ifdef FCS_ENABLE_DEBUG if (rank == 0) printf("%s: Parameter %s not set. Set default to %d.\n", fnc_name, "cycle_type", cycle_type); #endif fcs_vmg_set_cycle_type(handle, cycle_type); } fcs_float precision; fcs_vmg_get_precision(handle, &precision); if (precision < 0.0) { precision = 1.0e-8; #ifdef FCS_ENABLE_DEBUG if (rank == 0) printf("%s: Parameter %s not set. Set default to %e.\n", fnc_name, "precision", precision); #endif fcs_vmg_set_precision(handle, precision); } fcs_int near_field_cells; fcs_vmg_get_near_field_cells(handle, &near_field_cells); if (near_field_cells < 0) { near_field_cells = 4; #ifdef FCS_ENABLE_DEBUG if (rank == 0) printf("%s: Parameter %s not set. Set default to %d.\n", fnc_name, "near_field_cells", near_field_cells); #endif fcs_vmg_set_near_field_cells(handle, near_field_cells); } fcs_int interpolation_order; fcs_vmg_get_interpolation_order(handle, &interpolation_order); if (interpolation_order < 0) { interpolation_order = 5; #ifdef FCS_ENABLE_DEBUG if (rank == 0) printf("%s: Parameter %s not set. Set default to %d.\n", fnc_name, "interpolation_order", interpolation_order); #endif fcs_vmg_set_interpolation_order(handle, interpolation_order); } fcs_int discretization_order; fcs_vmg_get_discretization_order(handle, &discretization_order); if (discretization_order < 0) { discretization_order = 4; #ifdef FCS_ENABLE_DEBUG if (rank == 0) printf("%s: Parameter %s not set. Set default to %d.\n", fnc_name, "discretization_order", discretization_order); #endif fcs_vmg_set_discretization_order(handle, discretization_order); } return NULL; }