/** * run the solver method */ FCSResult fcs_run(FCS handle, fcs_int local_particles, fcs_float *positions, fcs_float *charges, fcs_float *field, fcs_float *potentials) { const char *fnc_name = "fcs_run"; FCSResult result; CHECK_HANDLE_RETURN_RESULT(handle, fnc_name); if (local_particles < 0) return fcs_result_create(FCS_ERROR_WRONG_ARGUMENT, fnc_name, "number of local particles must be non negative"); if (fcs_get_values_changed(handle)) { result = fcs_tune(handle, local_particles, positions, charges); if (result != FCS_RESULT_SUCCESS) return result; } if (!fcs_init_check(handle) || !fcs_run_check(handle)) return fcs_result_create(FCS_ERROR_MISSING_ELEMENT, fnc_name, "not all needed data has been inserted into the given handle"); if (handle->run == NULL) return fcs_result_create(FCS_ERROR_NOT_IMPLEMENTED, fnc_name, "Running solver method '%s' not implemented", fcs_get_method_name(handle)); return handle->run(handle, local_particles, positions, charges, field, potentials); }
/* method to check if pepc parameters are entered into checked FCS */ FCSResult fcs_pepc_check(FCS handle) { const fcs_float *a,*b,*c; fcs_float eps, theta; FCSResult res; if ((res = fcs_pepc_get_epsilon(handle, &eps))) return res; if (eps == -1.0) return fcs_result_create(FCS_ERROR_MISSING_ELEMENT, __func__, "pepc: epsilon not set"); if ((res = fcs_pepc_get_theta(handle, &theta))) return res; if (theta == -1.0) return fcs_result_create(FCS_ERROR_MISSING_ELEMENT, __func__, "pepc: theta not set"); a = fcs_get_box_a(handle); b = fcs_get_box_b(handle); c = fcs_get_box_c(handle); if (!fcs_uses_principal_axes(a,b,c)) printf("%s\n", "WARNING: support of pepc for non-cubic simulation boxes currently is experimental."); if (!fcs_get_near_field_flag(handle)) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "pepc performs near field computations by itself!"); return FCS_RESULT_SUCCESS; }
/* method to check if p3m parameters are entered into FCS */ static FCSResult fcs_p3m_check(FCS handle, const char* fnc_name) { if (handle == NULL) return fcs_result_create(FCS_ERROR_NULL_ARGUMENT, fnc_name, "null pointer supplied as handle"); if (fcs_get_method(handle) != FCS_METHOD_P3M) return fcs_result_create(FCS_ERROR_WRONG_ARGUMENT, fnc_name, "Wrong method chosen. You should choose \"p3m\"."); return NULL; }
FCSResult mmm2d_tune(void* rd, fcs_int num_particles, fcs_float *positions, fcs_float *charges) { mmm2d_data_struct *d = (mmm2d_data_struct*)rd; const char* fnc_name = "mmm2d_tune"; FCSResult res; /* Check for charge existence and neutrality */ mmm2d_check_system_charges(d, num_particles, charges); if (!fcs_float_is_zero(d->total_charge)) return fcs_result_create(FCS_ERROR_LOGICAL_ERROR, fnc_name, "MMM2D requires a zero net charge."); d->my_bottom = d->comm.rank*d->box_l[2]/(fcs_float)(d->comm.size); /* Broadcast charges */ /* MPI_Bcast(&num_particles, 1, FCS_MPI_INT, 0, d->comm.mpicomm); MPI_Bcast(charges, num_particles, FCS_MPI_FLOAT, 0, d->comm.mpicomm); MPI_Bcast(positions, 3*num_particles, FCS_MPI_FLOAT, 0, d->comm.mpicomm); */ ///@TODO: skip next steps if d->needs_tuning==0. Check if this is flawless if(d->needs_tuning==0) return NULL; /* precalculate some constants */ mmm2d_setup_constants(d); /* tune near formula */ res=mmm2d_tune_near(d); if (res) return res; /* tune far formula */ if (d->comm.size*d->layers_per_node < 3) { d->far_cut = 0.0; if (d->dielectric_contrast_on) return fcs_result_create(FCS_ERROR_LOGICAL_ERROR, fnc_name, "Definition of dielectric contrasts requires more than 3 layers"); } else { res=mmm2d_tune_far(d); if (res) return res; } d->needs_tuning=0; /* printf("node %d, mmm2d_tune\n", d->comm.rank); printf("node %d: ux: %f, uy: %f\n", d->comm.rank, d->ux, d->uy); printf("node %d: min_far: %f, far_cut: %f\n", d->comm.rank, d->min_far, d->far_cut); printf("node %d: layer_h %f\n", d->comm.rank, d->layer_h); printf("node %d: n_layers %d\n", d->comm.rank, d->n_layers); */ return NULL; }
/** * set whether the virial should be computed */ FCSResult fcs_set_compute_virial(FCS handle, fcs_int compute_virial) { CHECK_HANDLE_RETURN_RESULT(handle, __func__); if (compute_virial != 0 && compute_virial != 1) return fcs_result_create(FCS_ERROR_WRONG_ARGUMENT, __func__, "parameter compute_virial must be 0 or 1"); if (handle->set_compute_virial == NULL) return fcs_result_create(FCS_ERROR_NOT_IMPLEMENTED, __func__, "Setting whether the virial should be computed not implemented for solver method '%s'", fcs_get_method_name(handle)); return handle->set_compute_virial(handle, compute_virial); }
/** * return the comuputed virial */ FCSResult fcs_get_virial(FCS handle, fcs_float *virial) { CHECK_HANDLE_RETURN_RESULT(handle, __func__); if (virial == NULL) return fcs_result_create(FCS_ERROR_NULL_ARGUMENT, __func__, "null pointer supplied as argument"); if (handle->get_virial == NULL) return fcs_result_create(FCS_ERROR_NOT_IMPLEMENTED, __func__, "Returning the computed virial not implemented for solver method '%s'", fcs_get_method_name(handle)); return handle->get_virial(handle, virial); }
/** * return whether the virial should be computed */ FCSResult fcs_get_compute_virial(FCS handle, fcs_int *compute_virial) { const char *fnc_name = "fcs_get_compute_virial"; CHECK_HANDLE_RETURN_RESULT(handle, fnc_name); if (compute_virial == NULL) return fcs_result_create(FCS_ERROR_NULL_ARGUMENT, fnc_name, "null pointer supplied as argument"); if (handle->get_compute_virial == NULL) return fcs_result_create(FCS_ERROR_NOT_IMPLEMENTED, fnc_name, "Returning whether the virial should be computed not implemented for solver method '%s'", fcs_get_method_name(handle)); return handle->get_compute_virial(handle, compute_virial); }
/* internal p3m-specific tuning function */ FCSResult fcs_p3m_tune(FCS handle, fcs_int local_particles, fcs_float *positions, fcs_float *charges) { char* fnc_name = "fcs_p3m_tune"; FCSResult result; result = fcs_p3m_check(handle, fnc_name); if (result != NULL) return result; /* Handle periodicity */ const fcs_int *periodicity = fcs_get_periodicity(handle); if (! (periodicity[0] && periodicity[1] && periodicity[2])) return fcs_result_create(FCS_ERROR_WRONG_ARGUMENT, fnc_name, "p3m requires periodic boundary conditions."); /* Handle box size */ const fcs_float *a = fcs_get_box_a(handle); const fcs_float *b = fcs_get_box_b(handle); const fcs_float *c = fcs_get_box_c(handle); if (!fcs_is_orthogonal(a, b, c)){ if (ifcs_p3m_check_triclinic_box(a[1],a[2],b[2])){ if(ifcs_p3m_set_triclinic_flag(handle->method_context)!=NULL) return ifcs_p3m_set_triclinic_flag(handle->method_context); } else return fcs_result_create(FCS_ERROR_WRONG_ARGUMENT, fnc_name, "p3m triclinic requires the box to be as follows: \n \ the first box vector is parallel to the x axis\n \ the second box vector is in the yz plane."); } else { if (!fcs_uses_principal_axes(a, b, c))
/** * set the error tolerance of the FCS solver */ FCSResult fcs_set_tolerance(FCS handle, fcs_int tolerance_type, fcs_float tolerance) { CHECK_HANDLE_RETURN_RESULT(handle, __func__); if (handle->set_tolerance == NULL) return fcs_result_create(FCS_ERROR_NOT_IMPLEMENTED, __func__, "Setting tolerance not implemented for solver method '%s'", fcs_get_method_name(handle)); return handle->set_tolerance(handle, tolerance_type, tolerance); }
FCSResult mmm2d_get_total_energy(void *rd, fcs_float *total_energy) { const char* fnc_name = "mmm2d_get_total_energy"; mmm2d_data_struct *d = (mmm2d_data_struct*)rd; if (d->require_total_energy) { *total_energy = d->total_energy; return NULL; } else return fcs_result_create(FCS_ERROR_LOGICAL_ERROR, fnc_name, "Trying to get total energy, but computation was not requested."); }
/** * 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)); }
/** * set whether resort support is requested */ FCSResult fcs_set_resort(FCS handle, fcs_int resort) { CHECK_HANDLE_RETURN_RESULT(handle, __func__); if (handle->set_resort == NULL) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "resorting not supported"); return handle->set_resort(handle, resort); }
/** * return the new local number of particles */ FCSResult fcs_get_resort_particles(FCS handle, fcs_int *resort_particles) { CHECK_HANDLE_RETURN_RESULT(handle, __func__); if (handle->get_resort_particles == NULL) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "resorting not supported"); return handle->get_resort_particles(handle, resort_particles); }
/** * return the user-defined cutoff radius for the near-field */ FCSResult fcs_get_r_cut(FCS handle, fcs_float *r_cut) { CHECK_HANDLE_RETURN_RESULT(handle, __func__); if (handle->get_r_cut == NULL) return fcs_result_create(FCS_ERROR_NOT_IMPLEMENTED, __func__, "Returning a user-defined cutoff radius for the near-field not implemented for solver method '%s'", fcs_get_method_name(handle)); return handle->get_r_cut(handle, r_cut); }
/** * run the solver method */ FCSResult fcs_run(FCS handle, fcs_int local_particles, fcs_float *positions, fcs_float *charges, fcs_float *field, fcs_float *potentials) { FCSResult result; CHECK_HANDLE_RETURN_RESULT(handle, __func__); if (local_particles < 0) return fcs_result_create(FCS_ERROR_WRONG_ARGUMENT, __func__, "number of local particles must be non negative"); if (fcs_get_values_changed(handle)) { result = fcs_tune(handle, local_particles, positions, charges); if (result != FCS_RESULT_SUCCESS) return result; } if (!fcs_init_check(handle) || !fcs_run_check(handle)) return fcs_result_create(FCS_ERROR_MISSING_ELEMENT, __func__, "not all needed data has been inserted into the given handle"); if (handle->run == NULL) return fcs_result_create(FCS_ERROR_NOT_IMPLEMENTED, __func__, "Running solver method '%s' not implemented", fcs_get_method_name(handle)); fcs_float original_box_origin[3] = { handle->box_origin[0], handle->box_origin[1], handle->box_origin[2] }; if (handle->shift_positions) { fcs_shift_positions(local_particles, positions, original_box_origin); handle->box_origin[0] = handle->box_origin[1] = handle->box_origin[2] = 0; } result = handle->run(handle, local_particles, positions, charges, field, potentials); if (handle->shift_positions) { fcs_unshift_positions(local_particles, positions, original_box_origin); handle->box_origin[0] = original_box_origin[0]; handle->box_origin[1] = original_box_origin[1]; handle->box_origin[2] = original_box_origin[2]; } return result; }
/** * disable a user-defined cutoff radius for the near-field */ FCSResult fcs_unset_r_cut(FCS handle) { const char *fnc_name = "fcs_unset_r_cut"; CHECK_HANDLE_RETURN_RESULT(handle, fnc_name); if (handle->unset_r_cut == NULL) return fcs_result_create(FCS_ERROR_NOT_IMPLEMENTED, fnc_name, "Disabling a user-defined cutoff radius for the near-field not implemented for solver method '%s'", fcs_get_method_name(handle)); return handle->unset_r_cut(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)); }
/** * return the new local number of particles */ FCSResult fcs_get_resort_particles(FCS handle, fcs_int *resort_particles) { const char *fnc_name = "fcs_get_resort_particles"; CHECK_HANDLE_RETURN_RESULT(handle, fnc_name); if (handle->get_resort_particles == NULL) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, fnc_name, "resorting not supported"); return handle->get_resort_particles(handle, resort_particles); }
/** * set whether resort support is requested */ FCSResult fcs_set_resort(FCS handle, fcs_int resort) { const char *fnc_name = "fcs_set_resort"; CHECK_HANDLE_RETURN_RESULT(handle, fnc_name); if (handle->set_resort == NULL) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, fnc_name, "resorting not supported"); return handle->set_resort(handle, resort); }
/* getter function for maximum fmm tree depth */ FCSResult fcs_fmm_get_maxdepth(FCS handle, fcs_int *depth) { FMM_CHECK_RETURN_RESULT(handle, __func__); if (!depth) return fcs_result_create(FCS_ERROR_NULL_ARGUMENT,__func__,"null pointer supplied for depth"); *depth = handle->fmm_param->maxdepth; return FCS_RESULT_SUCCESS; }
/* getter function for status of fmm define loadvector */ FCSResult fcs_fmm_get_define_loadvector(FCS handle, fcs_int *define_loadvector) { FMM_CHECK_RETURN_RESULT(handle, __func__); if (!define_loadvector) return fcs_result_create(FCS_ERROR_NULL_ARGUMENT,__func__,"null pointer supplied for define_loadvector"); *define_loadvector = handle->fmm_param->define_loadvector; return FCS_RESULT_SUCCESS; }
/* setter function for fmm parameter potential */ FCSResult fcs_fmm_set_potential(FCS handle, fcs_int potential) { FMM_CHECK_RETURN_RESULT(handle, __func__); if (!(potential == FCS_FMM_COULOMB || potential == FCS_FMM_CUSP)) return fcs_result_create(FCS_ERROR_WRONG_ARGUMENT,__func__,"invalid (fmm) potential chosen"); handle->fmm_param->potential = potential; return FCS_RESULT_SUCCESS; }
/* getter function for fmm parameter dipole correction */ FCSResult fcs_fmm_get_dipole_correction(FCS handle, fcs_int *dipole_correction) { FMM_CHECK_RETURN_RESULT(handle, __func__); if (!dipole_correction) return fcs_result_create(FCS_ERROR_NULL_ARGUMENT,__func__,"null pointer supplied for dipole_correction"); *dipole_correction = handle->fmm_param->dipole_correction; return FCS_RESULT_SUCCESS; }
/* getter function for fmm unroll limit */ FCSResult fcs_fmm_get_unroll_limit(FCS handle, fcs_int *limit) { FMM_CHECK_RETURN_RESULT(handle, __func__); if (!limit) return fcs_result_create(FCS_ERROR_NULL_ARGUMENT,__func__,"null pointer supplied for limit"); *limit = handle->fmm_param->limit; return FCS_RESULT_SUCCESS; }
/* setter function for status of fmm loadvector definition */ FCSResult fcs_fmm_set_define_loadvector(FCS handle, fcs_int define_loadvector) { FMM_CHECK_RETURN_RESULT(handle, __func__); if (define_loadvector != 1) return fcs_result_create(FCS_ERROR_WRONG_ARGUMENT,__func__,"invalid (fmm) define_loadvector chosen (only value 1 is current supported)"); handle->fmm_param->define_loadvector = define_loadvector; return FCS_RESULT_SUCCESS; }
/* getter function for fmm parameter potential */ FCSResult fcs_fmm_get_potential(FCS handle, fcs_int *potential) { FMM_CHECK_RETURN_RESULT(handle, __func__); if (!potential) return fcs_result_create(FCS_ERROR_NULL_ARGUMENT,__func__,"null pointer supplied for potential"); *potential = handle->fmm_param->potential; return FCS_RESULT_SUCCESS; }
/* setter function for fmm parameter cusp_radius */ FCSResult fcs_fmm_set_cusp_radius(FCS handle, fcs_float radius) { FMM_CHECK_RETURN_RESULT(handle, __func__); if (radius < 0.0) return fcs_result_create(FCS_ERROR_WRONG_ARGUMENT,__func__,"cusp radius must be non-negative"); handle->fmm_param->cusp_radius = radius; return FCS_RESULT_SUCCESS; }
/* getter function for fmm parameter cusp radius */ FCSResult fcs_fmm_get_cusp_radius(FCS handle, fcs_float *cusp_radius) { FMM_CHECK_RETURN_RESULT(handle, __func__); if (!cusp_radius) return fcs_result_create(FCS_ERROR_NULL_ARGUMENT,__func__,"null pointer supplied for cusp_radius"); *cusp_radius = handle->fmm_param->cusp_radius; return FCS_RESULT_SUCCESS; }
/** * return whether resort support is available */ FCSResult fcs_get_resort_availability(FCS handle, fcs_int *availability) { CHECK_HANDLE_RETURN_RESULT(handle, __func__); *availability = 0; if (handle->get_resort_availability == NULL) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "resorting not supported"); return handle->get_resort_availability(handle, availability); }
/* getter function for status of fmm load balancing */ FCSResult fcs_fmm_get_balanceload(FCS handle, fcs_int *load) { FMM_CHECK_RETURN_RESULT(handle, __func__); if (!load) return fcs_result_create(FCS_ERROR_NULL_ARGUMENT,__func__,"null pointer supplied for load"); *load = handle->fmm_param->balance; return FCS_RESULT_SUCCESS; }