/** * print the parameters of an FCS solver to stdout */ FCSResult fcs_print_parameters(FCS handle) { const char *fnc_name = "fcs_print_parameters"; FCSResult result; CHECK_HANDLE_RETURN_RESULT(handle, fnc_name); printf("chosen method: %s\n", fcs_get_method_name(handle)); printf("near field computations done by solver: %c\n", (fcs_get_near_field_flag(handle)?'T':'F')); printf("box vectors: [%10.4" FCS_LMOD_FLOAT "f %10.4" FCS_LMOD_FLOAT "f %10.4" FCS_LMOD_FLOAT "f], [%10.4" FCS_LMOD_FLOAT "f %10.4" FCS_LMOD_FLOAT "f %10.4" FCS_LMOD_FLOAT "f], [%10.4" FCS_LMOD_FLOAT "f %10.4" FCS_LMOD_FLOAT "f %10.4" FCS_LMOD_FLOAT "f]\n", fcs_get_box_a(handle)[0], fcs_get_box_a(handle)[1], fcs_get_box_a(handle)[2], fcs_get_box_b(handle)[0], fcs_get_box_b(handle)[1], fcs_get_box_b(handle)[2], fcs_get_box_c(handle)[0], fcs_get_box_c(handle)[1], fcs_get_box_c(handle)[2]); printf("box origin: [%10.4" FCS_LMOD_FLOAT "f %10.4" FCS_LMOD_FLOAT "f %10.4" FCS_LMOD_FLOAT "f]\n", fcs_get_box_origin(handle)[0], fcs_get_box_origin(handle)[1], fcs_get_box_origin(handle)[2]); printf("periodicity: %c %c %c\n", ((fcs_get_periodicity(handle)[0] == 1)?'T':'F'), ((fcs_get_periodicity(handle)[1] == 1)?'T':'F'),((fcs_get_periodicity(handle)[2] == 1)?'T':'F')); printf("total particles: %" FCS_LMOD_INT "d\n", fcs_get_total_particles(handle)); printf("solver specific data:\n"); if (handle->print_parameters) { result = handle->print_parameters(handle); if (result != FCS_RESULT_SUCCESS) fcs_result_print_result(result); } result = fcs_common_print_parameters(handle); if (result != FCS_RESULT_SUCCESS) fcs_result_print_result(result); return FCS_RESULT_SUCCESS; }
/* 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))
/** * compute the correction to the field and total energy */ FCSResult fcs_compute_dipole_correction(FCS handle, fcs_int local_particles, fcs_float* positions, fcs_float *charges, fcs_float epsilon, fcs_float *field_correction, fcs_float *energy_correction) { const char *fnc_name = "fcs_compute_dipole_correction"; CHECK_HANDLE_RETURN_RESULT(handle, fnc_name); /* Local dipole moment */ fcs_float local_dipole_moment[3] = {0.0, 0.0, 0.0}; /* Global dipole moment */ fcs_float dipole_moment[3]; fcs_int pid; fcs_int dim; if (fcs_float_is_zero(epsilon) || epsilon > 0.0) { /* Compute the global dipole moment */ for (pid = 0; pid < local_particles; pid++) for (dim = 0; dim < 3; dim++) local_dipole_moment[dim] += charges[pid]*positions[pid*3+dim]; MPI_Allreduce(local_dipole_moment, dipole_moment, 3, FCS_MPI_FLOAT, MPI_SUM, handle->communicator); 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); /* Volume of the parallelepiped */ fcs_float volume = a[0] * (b[1]*c[2] - b[2]*c[1]) + a[1] * (b[2]*c[0] - b[0]*c[2]) + a[2] * (b[0]*c[1] - b[1]*c[0]); fcs_float pref = 4.0*3.14159265358979323846264338328 / (3.0*volume*(epsilon + 1.0)); if (energy_correction) *energy_correction = 0.5*pref*(dipole_moment[0]*dipole_moment[0] + dipole_moment[1]*dipole_moment[1] + dipole_moment[2]*dipole_moment[2]); if (field_correction) { field_correction[0] = -pref*dipole_moment[0]; field_correction[1] = -pref*dipole_moment[1]; field_correction[2] = -pref*dipole_moment[2]; } } else { /* metallic BC (epsilon=+infty) */ if (energy_correction) *energy_correction = 0.0; if (field_correction) { field_correction[0] = 0.0; field_correction[1] = 0.0; field_correction[2] = 0.0; } } return FCS_RESULT_SUCCESS; }
FCSResult fcs_mmm1d_tune(FCS handle, fcs_int local_particles, fcs_int local_max_particles, fcs_float *positions, fcs_float *charges) { char* fnc_name = "fcs_mmm1d_tune"; FCSResult result; result = fcs_mmm1d_check(handle, fnc_name); if (result != NULL) return result; /* Check box periodicity */ fcs_int *periodicity = fcs_get_periodicity(handle); if (periodicity[0] != 0 || periodicity[1] != 0 || periodicity[2] != 1) return fcsResult_create(FCS_LOGICAL_ERROR, fnc_name, "mmm1d requires z-axis periodic boundary."); /* Check box shape */ fcs_float *a = fcs_get_box_a(handle); fcs_float *b = fcs_get_box_b(handle); fcs_float *c = fcs_get_box_c(handle); if (!fcs_is_cubic(a, b, c)) return fcsResult_create(FCS_LOGICAL_ERROR, fnc_name, "mmm1d requires a cubic box."); mmm1d_set_box_a(handle->method_context, a[0]); mmm1d_set_box_b(handle->method_context, b[1]); mmm1d_set_box_c(handle->method_context, c[2]); /* Effectively, tune initializes the algorithm */ result = mmm1d_tune(handle->method_context, local_particles, positions, charges); return result; }
/* 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; }
/* internal p3m-specific tuning function */ FCSResult fcs_mmm2d_tune(FCS handle, fcs_int local_particles, fcs_float *positions, fcs_float *charges) { FCSResult result; MMM2D_CHECK_RETURN_RESULT(handle, __func__); /* Check box periodicity */ const fcs_int *periodicity = fcs_get_periodicity(handle); if (periodicity[0] != 1 || periodicity[1] != 1 || periodicity[2] != 0) return fcs_result_create(FCS_ERROR_WRONG_ARGUMENT, __func__, "mmm2d requires x and y-axis periodic boundaries."); /* Check box shape */ ///@TODO: check for rectangular box geometry (any fcs adequate method?) 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)) return fcs_result_create(FCS_ERROR_WRONG_ARGUMENT, __func__, "p3m requires the box to be orthorhombic."); if (!fcs_uses_principal_axes(a, b, c)) return fcs_result_create(FCS_ERROR_WRONG_ARGUMENT, __func__, "p3m requires the box vectors to be parallel to the principal axes."); */ mmm2d_set_box_a(handle->method_context, a[0]); mmm2d_set_box_b(handle->method_context, b[1]); mmm2d_set_box_c(handle->method_context, c[2]); /* Effectively, tune initializes the algorithm */ result = mmm2d_tune(handle->method_context, local_particles, positions, charges); return result; }
/* 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; }
/* internal fmm-specific tuning function */ FCSResult fcs_fmm_tune(FCS handle, fcs_int local_particles, fcs_float *positions, fcs_float *charges) { FCSResult result; fcs_int dotune; 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; long long wignersize; 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); 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; fcs_fmm_get_internal_tuning( handle, &dotune ); if (dotune == FCS_FMM_INHOMOGENOUS_SYSTEM) { if (define_loadvector == 1) { handle->fmm_param->define_loadvector = 0; long long ll_loadvectorsize = 4*local_particles; fcs_float val = 1e0; loadptr = malloc(sizeof(ll_loadvectorsize)*ll_loadvectorsize); fmm_cinitload(params,loadptr,ll_loadvectorsize); fmm_csetload(params,val); } fmm_ctune(ll_lp,positions,charges,ll_tp,ll_absrel,tolerance_energy,ll_dip_corr, ll_periodicity, period_length, ll_maxdepth, ll_unroll_limit, ll_balance_load,params, &wignersize, &r); } else if ( dotune == FCS_FMM_HOMOGENOUS_SYSTEM ) { fmm_ctunehomogen(params,&wignersize, &r); } else { result = fcs_result_create(FCS_ERROR_WRONG_ARGUMENT, __func__, "wrong kind of internal tuning chosen"); return result; } if (handle->fmm_param->wignerptr == NULL || handle->fmm_param->wignersize < wignersize) { if (handle->fmm_param->wignerptr) free(handle->fmm_param->wignerptr); handle->fmm_param->wignersize = wignersize; handle->fmm_param->wignerptr = malloc(wignersize); } fmm_ccomputewigner(handle->fmm_param->wignerptr,params,dotune); free(ll_periodicity); if (loadptr) free(loadptr); if (r == 0) { result = fcs_result_create(FCS_ERROR_FORTRAN_CALL, __func__, "error in fmm_ctune (FORTRAN)"); return result; } return FCS_RESULT_SUCCESS; }
FCSResult fcs_fmm_check(FCS handle) { const fcs_float *a,*b,*c; const fcs_int *periodicity; int i,p; 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 deltaE; fcs_fmm_get_deltaE(handle, &deltaE); if (deltaE == -1.0) return fcs_result_create(FCS_ERROR_MISSING_ELEMENT, __func__, "fmm: deltaE not set"); a = fcs_get_box_a(handle); b = fcs_get_box_b(handle); c = fcs_get_box_c(handle); periodicity = fcs_get_periodicity(handle); p = 0; for (i = 0; i < 3; ++i) if (periodicity[i]) p++; switch(p) { case 0: return FCS_RESULT_SUCCESS; case 1: for (i = 0; i < 3; ++i) if (periodicity[i]) break; switch(i) { case 0: if (!( (fcs_norm(a) >= fcs_norm(b)) && (fcs_norm(a) >= fcs_norm(c)) )) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "fmm: longest box vector not in direction of 1D-periodicity direction"); return FCS_RESULT_SUCCESS; case 1: if (!( (fcs_norm(b) >= fcs_norm(a)) && (fcs_norm(b) >= fcs_norm(a)) )) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "fmm: longest box vector not in direction of 1D-periodicity direction"); return FCS_RESULT_SUCCESS; case 2: if (!( (fcs_norm(c) >= fcs_norm(a)) && (fcs_norm(c) >= fcs_norm(b)) )) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "fmm: longest box vector not in direction of 1D-periodicity direction"); return FCS_RESULT_SUCCESS; } case 2: for (i = 0; i < 3; ++i) if (!periodicity[i]) break; switch(i) { case 0: if (!( (fcs_float_is_equal(fcs_norm(b),fcs_norm(c))) && (fcs_norm(b) >= fcs_norm(a)) )) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "fmm: longest box vector not in direction of 2D-periodicity direction"); return FCS_RESULT_SUCCESS; case 1: if (!( (fcs_float_is_equal(fcs_norm(a),fcs_norm(c))) && (fcs_norm(a) >= fcs_norm(b)) )) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "fmm: longest box vector not in direction of 2D-periodicity direction"); return FCS_RESULT_SUCCESS; case 2: if (!( (fcs_float_is_equal(fcs_norm(a),fcs_norm(b))) && (fcs_norm(a) >= fcs_norm(c)) )) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "fmm: longest box vector not in direction of 2D-periodicity direction"); return FCS_RESULT_SUCCESS; } case 3: if (!(fcs_uses_principal_axes(a,b,c))) return fcs_result_create(FCS_ERROR_INCOMPATIBLE_METHOD, __func__, "fmm: cannot use a non-cubic system in 3D-periodicity"); return FCS_RESULT_SUCCESS; } 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; }
extern FCSResult fcs_vmg_check(FCS handle) { char fnc_name[] = "fcs_vmg_check"; FCSResult result; fcs_int max_level; result = fcs_vmg_get_max_level(handle, &max_level); if (result != NULL) return result; if (max_level == -1) return fcsResult_create(FCS_MISSING_ELEMENT, fnc_name, "vmg finest level not set."); if (max_level < 3) return fcsResult_create(FCS_LOGICAL_ERROR, fnc_name, "vmg finest level must be greater than 2."); fcs_int max_iterations; result = fcs_vmg_get_max_iterations(handle, &max_iterations); if (result != NULL) return result; if (max_iterations == -1) return fcsResult_create(FCS_MISSING_ELEMENT, fnc_name, "vmg maximum number of iterations not set."); if (max_iterations < 1) return fcsResult_create(FCS_LOGICAL_ERROR, fnc_name, "vmg maximum number of iterations must be positive."); fcs_int smoothing_steps; result = fcs_vmg_get_smoothing_steps(handle, &smoothing_steps); if (result != NULL) return result; if (smoothing_steps == -1) return fcsResult_create(FCS_MISSING_ELEMENT, fnc_name, "vmg number of smoothing steps not set."); if (smoothing_steps < 1) return fcsResult_create(FCS_LOGICAL_ERROR, fnc_name, "vmg number of smoothing steps must be positive."); fcs_int cycle_type; result = fcs_vmg_get_cycle_type(handle, &cycle_type); if (result != NULL) return result; if (cycle_type == -1) return fcsResult_create(FCS_MISSING_ELEMENT, fnc_name, "vmg cycle number not set."); if (cycle_type < 1) return fcsResult_create(FCS_LOGICAL_ERROR, fnc_name, "vmg cycle number must be positive."); fcs_float precision; result = fcs_vmg_get_precision(handle, &precision); if (result != NULL) return result; if (precision == -1.) return fcsResult_create(FCS_MISSING_ELEMENT, fnc_name, "vmg desired precision not set."); fcs_int near_field_cells; result = fcs_vmg_get_near_field_cells(handle, &near_field_cells); if (result != NULL) return result; if (near_field_cells == -1) return fcsResult_create(FCS_MISSING_ELEMENT, fnc_name, "vmg number of near field cells not set."); if (near_field_cells < 1) return fcsResult_create(FCS_LOGICAL_ERROR, fnc_name, "vmg number of near field cells must be positive."); fcs_int interpolation_order; result = fcs_vmg_get_interpolation_order(handle, &interpolation_order); if (result != NULL) return result; if (interpolation_order == -1) return fcsResult_create(FCS_MISSING_ELEMENT, fnc_name, "vmg interpolation order not set."); if (interpolation_order < 3) return fcsResult_create(FCS_LOGICAL_ERROR, fnc_name, "vmg interpolation order must be greater or equal three."); fcs_int discretization_order; result = fcs_vmg_get_discretization_order(handle, &discretization_order); if (result != NULL) return result; if (discretization_order == -1) return fcsResult_create(FCS_MISSING_ELEMENT, fnc_name, "vmg discretization order not set."); if (discretization_order != 2 && discretization_order != 4) return fcsResult_create(FCS_LOGICAL_ERROR, fnc_name, "vmg discretization order must be 2 or 4."); fcs_float* box_a = fcs_get_box_a(handle); fcs_float* box_b = fcs_get_box_b(handle); fcs_float* box_c = fcs_get_box_c(handle); if (!fcs_is_cubic(box_a, box_b, box_c)) return fcsResult_create(FCS_LOGICAL_ERROR, fnc_name, "vmg requires the box to be cubic."); if (!fcs_uses_principal_axes(box_a, box_b, box_c)) return fcsResult_create(FCS_LOGICAL_ERROR, fnc_name, "vmg requires the box vectors to be parallel to the principal axes."); return NULL; }
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; }
/* internal pepc-specific run function */ FCSResult fcs_pepc_run(FCS handle, fcs_int local_particles, fcs_float *positions, fcs_float *charges, fcs_float *field, fcs_float *potentials) { FCSResult result; fcs_int pcnt; fcs_int nparts_tot; fcs_pepc_internal_t *pepc_internal; nparts_tot = fcs_get_total_particles(handle); pepc_internal = (fcs_pepc_internal_t*) fcs_get_method_context(handle); if((local_particles != pepc_internal->work_length) || (handle->pepc_param->load_balancing==0)){ if(pepc_internal->work != NULL){ free(pepc_internal->work); } pepc_internal->work = (fcs_float*)malloc(sizeof(fcs_float)*local_particles); pepc_internal->work_length = local_particles; for(int pcnt=0; pcnt<pepc_internal->work_length; pcnt++) pepc_internal->work[pcnt] = 1.0; } result = fcs_pepc_check(handle); CHECK_RESULT_RETURN(result); fcs_int max_local_particles = fcs_get_max_local_particles(handle); if (local_particles > max_local_particles) max_local_particles = local_particles; if (handle->pepc_param->debug_level > 3) { printf("*** run pepc kernel\n"); printf("** local particles: %" FCS_LMOD_INT "d\n", local_particles); printf("** max local particles: %" FCS_LMOD_INT "d\n", max_local_particles); printf("** total particles: %" FCS_LMOD_INT "d\n", nparts_tot); printf("** epsilon: %" FCS_LMOD_FLOAT "f\n", handle->pepc_param->epsilon); printf("** theta: %" FCS_LMOD_FLOAT "f\n", handle->pepc_param->theta); printf("** npm: %" FCS_LMOD_FLOAT "f\n", handle->pepc_param->npm); printf("** debug_level: %" FCS_LMOD_INT "d\n", handle->pepc_param->debug_level); printf("** require virial: %" FCS_LMOD_INT "d\n", handle->pepc_param->require_virial); printf("** num walk threads: %" FCS_LMOD_INT "d\n", handle->pepc_param->num_walk_threads); printf("** dipole correction: %" FCS_LMOD_INT "d\n", handle->pepc_param->dipole_correction); printf("** use load balancing: %" FCS_LMOD_INT "d\n", handle->pepc_param->load_balancing); printf("** size int: %d\n", (int)sizeof(fcs_int)); printf("** size float: %d\n", (int)sizeof(fcs_float)); printf("** debug lattice pointers: %p\n", fcs_get_box_a(handle)); printf("** debug lattice pointers: %p\n", fcs_get_box_b(handle)); printf("** debug lattice pointers: %p\n", fcs_get_box_c(handle)); printf("** debug output lattice in x %" FCS_LMOD_FLOAT "f %" FCS_LMOD_FLOAT "f %" FCS_LMOD_FLOAT "f\n", fcs_get_box_a(handle)[0], fcs_get_box_a(handle)[1], fcs_get_box_a(handle)[2]); printf("** debug output lattice in y %" FCS_LMOD_FLOAT "f %" FCS_LMOD_FLOAT "f %" FCS_LMOD_FLOAT "f\n", fcs_get_box_b(handle)[0], fcs_get_box_b(handle)[1], fcs_get_box_b(handle)[2]); printf("** debug output lattice in z %" FCS_LMOD_FLOAT "f %" FCS_LMOD_FLOAT "f %" FCS_LMOD_FLOAT "f\n", fcs_get_box_c(handle)[0], fcs_get_box_c(handle)[1], fcs_get_box_c(handle)[2]); } pepc_scafacos_run(&local_particles, &nparts_tot, positions, charges, field, potentials, pepc_internal->work, ((fcs_pepc_internal_t*)(handle->method_context))->virial, fcs_get_box_a(handle), fcs_get_box_b(handle), fcs_get_box_c(handle), fcs_get_periodicity(handle), &handle->pepc_param->dipole_correction, &handle->pepc_param->epsilon, &handle->pepc_param->theta, &handle->pepc_param->debug_level, &handle->pepc_param->num_walk_threads, &handle->pepc_param->npm); if (handle->pepc_param->debug_level > 3) { printf("virial(0,0) %12.4e\n", ((fcs_pepc_internal_t*)(handle->method_context))->virial[0]); for(pcnt=0; pcnt<local_particles; pcnt++) printf("** e-field dump, particle %" FCS_LMOD_INT "d, (ex,ey,ez): %" FCS_LMOD_FLOAT "f, %" FCS_LMOD_FLOAT "f, %" FCS_LMOD_FLOAT "f\n", pcnt, field[pcnt+0], field[pcnt+1], field[pcnt+2]); } return FCS_RESULT_SUCCESS; }